Skip to content

Commit cc249c8

Browse files
committed
DATACOUCH-588 - Part 2 of framework changes. Add support for projection and distinct.
Support for projection is only for properties of the top-level entity. For instance, in UserSubmission, only the properties below can be specified in the projection. Projection support does not provide means of specifying something like address.street - you can only project (or not project) the whole address property. However, the address type in your resultType could have a subset of the properties in Address. If the corresponding submissions in the resultType contained only the userId property public class UserSubmission extends ComparableEntity { private String id; private String username; private List<String> roles; private Address address; private List<Submission> submissions; Support for Distinct - I have appropriated the MongoDB model for Distinct. It defines a separate DistinctOperationSupport class (within ExecutableFindByQuerySupport) which supports the distinct( distinctFields ) api and execution. The DistinctOperationSupport class has only a distinctFields member, and a 'delegate' member, which is an ExecutableFindByQuerySupport object. TBH, I don't see the advantage over simply adding a distinctFields member to ExecutableFindByQuerySupport Amend #1 - changes as discussed in Pull Request - clean up test entity types Amend #2 - Eliminate DistinctOperationSupport class. In MongoDB, only distinct on a single field is supported, so the returnType from distinct was very different from the returnType of other query operations (all(), one() etc. (but so is count(), and it doesn't need it's own class)). In Couchbase, distinct on any fields in the entity is allowed - so the returned type could be the domainType or resultType. And as(resultType) still allows any resultType to be specified. This makes it unnecessary to have combinations of interfaces such as DistinctWithProjection and DistinctWithQuery. - Clean up the interfaces in ExecutableFindByQuery. There are two types of interfaces (a) the TerminatingFindByQuery which has the one(), oneValue() first(), firstValue(), all(), count(), exists() and stream(); and (b) the option interfaces (FindByQueryWithConsistency etc), which are essentially with-er interfaces. The changes are: 1) make all the with-er interfaces base interfaces instead of chaining them together. (I don't know why there isn't simply one interface with all the with-er methods). 2) make the ExecutableFindByQuery interface extend the Terminating interface and all the with-er interfaces. Amend #3 - Add execution support for collections Amend #4 - Add tests for collections. This includes a new CollectionAwareIntegrationTests class which extends a new JavaIntegratationTests class which extends the existing ClusterAwareIntegrationTests. - Fixed up several issues collections issues that were uncovered by the tests. - Did further cleanup of OperationSupport interfaces.
1 parent 3364e0f commit cc249c8

39 files changed

+1706
-505
lines changed

pom.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,14 @@
197197
<version>${kotlin}</version>
198198
<scope>test</scope>
199199
</dependency>
200+
201+
<dependency>
202+
<groupId>org.awaitility</groupId>
203+
<artifactId>awaitility</artifactId>
204+
<version>4.0.3</version>
205+
<scope>test</scope>
206+
</dependency>
207+
200208
</dependencies>
201209

202210
<repositories>

src/main/java/org/springframework/data/couchbase/core/ExecutableFindByIdOperation.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,28 +46,29 @@ interface TerminatingFindById<T> {
4646

4747
}
4848

49-
interface FindByIdWithCollection<T> extends TerminatingFindById<T> {
49+
interface FindByIdWithCollection<T> {
5050

5151
/**
5252
* Allows to specify a different collection than the default one configured.
5353
*
5454
* @param collection the collection to use in this scope.
5555
*/
56-
TerminatingFindById<T> inCollection(String collection);
56+
ExecutableFindById<T> inCollection(String collection);
5757

5858
}
5959

60-
interface FindByIdWithProjection<T> extends FindByIdWithCollection<T> {
60+
interface FindByIdWithProjection<T> {
6161

6262
/**
6363
* Load only certain fields for the document.
6464
*
6565
* @param fields the projected fields to load.
6666
*/
67-
FindByIdWithCollection<T> project(String... fields);
67+
ExecutableFindById<T> project(String... fields);
6868

6969
}
7070

71-
interface ExecutableFindById<T> extends FindByIdWithProjection<T> {}
71+
interface ExecutableFindById<T>
72+
extends TerminatingFindById<T>, FindByIdWithCollection<T>, FindByIdWithProjection<T> {}
7273

7374
}

src/main/java/org/springframework/data/couchbase/core/ExecutableFindByIdOperationSupport.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,11 @@
1515
*/
1616
package org.springframework.data.couchbase.core;
1717

18-
import org.springframework.data.couchbase.core.ReactiveFindByIdOperationSupport.ReactiveFindByIdSupport;
19-
2018
import java.util.Arrays;
2119
import java.util.Collection;
2220
import java.util.List;
2321

22+
import org.springframework.data.couchbase.core.ReactiveFindByIdOperationSupport.ReactiveFindByIdSupport;
2423
import org.springframework.util.Assert;
2524

2625
public class ExecutableFindByIdOperationSupport implements ExecutableFindByIdOperation {
@@ -63,13 +62,13 @@ public Collection<? extends T> all(final Collection<String> ids) {
6362
}
6463

6564
@Override
66-
public TerminatingFindById<T> inCollection(final String collection) {
65+
public ExecutableFindById<T> inCollection(final String collection) {
6766
Assert.hasText(collection, "Collection must not be null nor empty.");
6867
return new ExecutableFindByIdSupport<>(template, domainType, collection, fields);
6968
}
7069

7170
@Override
72-
public FindByIdWithCollection<T> project(String... fields) {
71+
public ExecutableFindById<T> project(String... fields) {
7372
Assert.notEmpty(fields, "Fields must not be null nor empty.");
7473
return new ExecutableFindByIdSupport<>(template, domainType, collection, Arrays.asList(fields));
7574
}

src/main/java/org/springframework/data/couchbase/core/ExecutableFindByQueryOperation.java

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import org.springframework.dao.IncorrectResultSizeDataAccessException;
2323
import org.springframework.data.couchbase.core.query.Query;
24+
import org.springframework.data.couchbase.core.query.QueryCriteriaDefinition;
2425
import org.springframework.lang.Nullable;
2526

2627
import com.couchbase.client.java.query.QueryScanConsistency;
@@ -107,40 +108,90 @@ default Optional<T> first() {
107108
* @author Christoph Strobl
108109
* @since 2.0
109110
*/
110-
interface FindByQueryWithQuery<T> extends TerminatingFindByQuery<T> {
111+
interface FindByQueryWithQuery<T> {
111112

112113
/**
113114
* Set the filter for the query to be used.
114115
*
115116
* @param query must not be {@literal null}.
116117
* @throws IllegalArgumentException if query is {@literal null}.
117118
*/
118-
TerminatingFindByQuery<T> matching(Query query);
119+
ExecutableFindByQuery<T> matching(Query query);
120+
121+
/**
122+
* Set the filter {@link QueryCriteriaDefinition criteria} to be used.
123+
*
124+
* @param criteria must not be {@literal null}.
125+
* @return new instance of {@link ExecutableFindByQuery}.
126+
* @throws IllegalArgumentException if criteria is {@literal null}.
127+
*/
128+
default ExecutableFindByQuery<T> matching(QueryCriteriaDefinition criteria) {
129+
return matching(Query.query(criteria));
130+
}
119131

120132
}
121133

122-
interface FindByQueryConsistentWith<T> extends FindByQueryWithQuery<T> {
134+
interface FindByQueryConsistentWith<T> {
123135

124136
/**
125137
* Allows to override the default scan consistency.
126138
*
127139
* @param scanConsistency the custom scan consistency to use for this query.
128140
*/
129-
FindByQueryConsistentWith<T> consistentWith(QueryScanConsistency scanConsistency);
141+
ExecutableFindByQuery<T> consistentWith(QueryScanConsistency scanConsistency);
130142

131143
}
132144

133-
interface FindByQueryInCollection<T> extends FindByQueryConsistentWith<T> {
145+
interface FindByQueryInCollection<T> {
134146

135147
/**
136148
* Allows to override the default scan consistency.
137149
*
138150
* @param collection the collection to use for this query.
139151
*/
140-
FindByQueryInCollection<T> inCollection(String collection);
152+
ExecutableFindByQuery<T> inCollection(String collection);
153+
154+
}
155+
156+
/**
157+
* Result type override (Optional).
158+
*/
159+
interface FindByQueryWithProjection<T> {
160+
161+
/**
162+
* Define the target type fields should be mapped to. <br />
163+
* Skip this step if you are anyway only interested in the original domain type.
164+
*
165+
* @param resultType must not be {@literal null}.
166+
* @param <R> result type.
167+
* @return new instance of {@link FindByQueryWithProjection}.
168+
* @throws IllegalArgumentException if resultType is {@literal null}.
169+
*/
170+
<R> ExecutableFindByQuery<R> as(Class<R> resultType);
141171

142172
}
143173

144-
interface ExecutableFindByQuery<T> extends FindByQueryInCollection<T> {}
174+
/**
175+
* Distinct Find support.
176+
*/
177+
interface FindByQueryDistinct<T> {
178+
179+
/**
180+
* Finds the distinct values for a specified {@literal field} across a single collection
181+
*
182+
* @param distinctFields name of the field. Must not be {@literal null}.
183+
* @return new instance of {@link ExecutableFindByQuery}.
184+
* @throws IllegalArgumentException if field is {@literal null}.
185+
*/
186+
ExecutableFindByQuery<T> distinct(String[] distinctFields);
187+
188+
}
189+
190+
/**
191+
* {@link ExecutableFindByQuery} provides methods for constructing lookup operations in a fluent way.
192+
*/
193+
194+
interface ExecutableFindByQuery<T> extends TerminatingFindByQuery<T>, FindByQueryWithQuery<T>,
195+
FindByQueryConsistentWith<T>, FindByQueryInCollection<T>, FindByQueryWithProjection<T>, FindByQueryDistinct<T> {}
145196

146197
}

src/main/java/org/springframework/data/couchbase/core/ExecutableFindByQueryOperationSupport.java

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import org.springframework.data.couchbase.core.ReactiveFindByQueryOperationSupport.ReactiveFindByQuerySupport;
2222
import org.springframework.data.couchbase.core.query.Query;
23+
import org.springframework.util.Assert;
2324

2425
import com.couchbase.client.java.query.QueryScanConsistency;
2526

@@ -41,28 +42,33 @@ public ExecutableFindByQueryOperationSupport(final CouchbaseTemplate template) {
4142

4243
@Override
4344
public <T> ExecutableFindByQuery<T> findByQuery(final Class<T> domainType) {
44-
return new ExecutableFindByQuerySupport<>(template, domainType, ALL_QUERY, QueryScanConsistency.NOT_BOUNDED,
45-
"_default._default");
45+
return new ExecutableFindByQuerySupport<T>(template, domainType, domainType, ALL_QUERY,
46+
QueryScanConsistency.NOT_BOUNDED, null, null);
4647
}
4748

4849
static class ExecutableFindByQuerySupport<T> implements ExecutableFindByQuery<T> {
4950

5051
private final CouchbaseTemplate template;
51-
private final Class<T> domainType;
52+
private final Class<?> domainType;
53+
private final Class<T> returnType;
5254
private final Query query;
5355
private final ReactiveFindByQuerySupport<T> reactiveSupport;
5456
private final QueryScanConsistency scanConsistency;
5557
private final String collection;
58+
private final String[] distinctFields;
5659

57-
ExecutableFindByQuerySupport(final CouchbaseTemplate template, final Class<T> domainType, final Query query,
58-
final QueryScanConsistency scanConsistency, final String collection) {
60+
ExecutableFindByQuerySupport(final CouchbaseTemplate template, final Class<?> domainType, final Class<T> returnType,
61+
final Query query, final QueryScanConsistency scanConsistency, final String collection,
62+
final String[] distinctFields) {
5963
this.template = template;
6064
this.domainType = domainType;
65+
this.returnType = returnType;
6166
this.query = query;
62-
this.reactiveSupport = new ReactiveFindByQuerySupport<T>(template.reactive(), domainType, query, scanConsistency,
63-
collection);
67+
this.reactiveSupport = new ReactiveFindByQuerySupport<T>(template.reactive(), domainType, returnType, query,
68+
scanConsistency, collection, distinctFields);
6469
this.scanConsistency = scanConsistency;
6570
this.collection = collection;
71+
this.distinctFields = distinctFields;
6672
}
6773

6874
@Override
@@ -81,24 +87,42 @@ public List<T> all() {
8187
}
8288

8389
@Override
84-
public TerminatingFindByQuery<T> matching(final Query query) {
90+
public ExecutableFindByQuery<T> matching(final Query query) {
8591
QueryScanConsistency scanCons;
8692
if (query.getScanConsistency() != null) {
8793
scanCons = query.getScanConsistency();
8894
} else {
8995
scanCons = scanConsistency;
9096
}
91-
return new ExecutableFindByQuerySupport<>(template, domainType, query, scanCons, collection);
97+
return new ExecutableFindByQuerySupport<>(template, domainType, returnType, query, scanCons, collection,
98+
distinctFields);
9299
}
93100

94101
@Override
95-
public FindByQueryConsistentWith<T> consistentWith(final QueryScanConsistency scanConsistency) {
96-
return new ExecutableFindByQuerySupport<>(template, domainType, query, scanConsistency, collection);
102+
public ExecutableFindByQuery<T> consistentWith(final QueryScanConsistency scanConsistency) {
103+
return new ExecutableFindByQuerySupport<>(template, domainType, returnType, query, scanConsistency, collection,
104+
distinctFields);
97105
}
98106

99107
@Override
100-
public FindByQueryInCollection<T> inCollection(final String collection) {
101-
return new ExecutableFindByQuerySupport<>(template, domainType, query, scanConsistency, collection);
108+
public ExecutableFindByQuery<T> inCollection(final String collection) {
109+
return new ExecutableFindByQuerySupport<>(template, domainType, returnType, query, scanConsistency, collection,
110+
distinctFields);
111+
}
112+
113+
@Override
114+
public <R> ExecutableFindByQuery<R> as(Class<R> returnType) {
115+
Assert.notNull(returnType, "returnType must not be null!");
116+
117+
return new ExecutableFindByQuerySupport<R>(template, domainType, returnType, query, scanConsistency, collection,
118+
distinctFields);
119+
}
120+
121+
@Override
122+
public ExecutableFindByQuery<T> distinct(String[] distinctFields) {
123+
Assert.notNull(distinctFields, "distinctFields must not be null!");
124+
return new ExecutableFindByQuerySupport<>(template, domainType, returnType, query, scanConsistency, collection,
125+
distinctFields);
102126
}
103127

104128
@Override
@@ -115,7 +139,6 @@ public long count() {
115139
public boolean exists() {
116140
return count() > 0;
117141
}
118-
119142
}
120143

121144
}

src/main/java/org/springframework/data/couchbase/core/ExecutableRemoveByQueryOperation.java

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,24 +31,32 @@ interface TerminatingRemoveByQuery<T> {
3131

3232
}
3333

34-
interface RemoveByQueryWithQuery<T> extends TerminatingRemoveByQuery<T> {
34+
interface RemoveByQueryWithQuery<T> {
3535

36-
TerminatingRemoveByQuery<T> matching(Query query);
36+
ExecutableRemoveByQuery<T> matching(Query query);
3737

3838
}
3939

40-
interface RemoveByQueryConsistentWith<T> extends RemoveByQueryWithQuery<T> {
40+
interface RemoveByQueryConsistentWith<T> {
4141

42-
RemoveByQueryWithQuery<T> consistentWith(QueryScanConsistency scanConsistency);
42+
@Deprecated
43+
ExecutableRemoveByQuery<T> consistentWith(QueryScanConsistency scanConsistency);
44+
45+
}
46+
47+
interface RemoveByQueryWithConsistency<T> {
48+
49+
ExecutableRemoveByQuery<T> withConsistency(QueryScanConsistency scanConsistency);
4350

4451
}
4552

4653
interface RemoveByQueryInCollection<T> extends RemoveByQueryConsistentWith<T> {
4754

48-
RemoveByQueryConsistentWith<T> inCollection(String collection);
55+
ExecutableRemoveByQuery<T> inCollection(String collection);
4956

5057
}
5158

52-
interface ExecutableRemoveByQuery<T> extends RemoveByQueryInCollection<T> {}
59+
interface ExecutableRemoveByQuery<T> extends TerminatingRemoveByQuery<T>, RemoveByQueryWithQuery<T>,
60+
RemoveByQueryWithConsistency<T>, RemoveByQueryInCollection<T> {}
5361

5462
}

src/main/java/org/springframework/data/couchbase/core/ExecutableRemoveByQueryOperationSupport.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public ExecutableRemoveByQueryOperationSupport(final CouchbaseTemplate template)
3535
@Override
3636
public <T> ExecutableRemoveByQuery<T> removeByQuery(Class<T> domainType) {
3737
return new ExecutableRemoveByQuerySupport<>(template, domainType, ALL_QUERY, QueryScanConsistency.NOT_BOUNDED,
38-
"_default._default");
38+
null);
3939
}
4040

4141
static class ExecutableRemoveByQuerySupport<T> implements ExecutableRemoveByQuery<T> {
@@ -64,17 +64,23 @@ public List<RemoveResult> all() {
6464
}
6565

6666
@Override
67-
public TerminatingRemoveByQuery<T> matching(final Query query) {
67+
public ExecutableRemoveByQuery<T> matching(final Query query) {
6868
return new ExecutableRemoveByQuerySupport<>(template, domainType, query, scanConsistency, collection);
6969
}
7070

7171
@Override
72-
public RemoveByQueryWithQuery<T> consistentWith(final QueryScanConsistency scanConsistency) {
72+
@Deprecated
73+
public ExecutableRemoveByQuery<T> consistentWith(final QueryScanConsistency scanConsistency) {
7374
return new ExecutableRemoveByQuerySupport<>(template, domainType, query, scanConsistency, collection);
7475
}
7576

7677
@Override
77-
public RemoveByQueryInCollection<T> inCollection(final String collection) {
78+
public ExecutableRemoveByQuery<T> withConsistency(final QueryScanConsistency scanConsistency) {
79+
return new ExecutableRemoveByQuerySupport<>(template, domainType, query, scanConsistency, collection);
80+
}
81+
82+
@Override
83+
public ExecutableRemoveByQuery<T> inCollection(final String collection) {
7884
return new ExecutableRemoveByQuerySupport<>(template, domainType, query, scanConsistency, collection);
7985
}
8086

src/main/java/org/springframework/data/couchbase/core/ReactiveFindByIdOperation.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ interface FindByIdWithCollection<T> extends TerminatingFindById<T> {
5656
*
5757
* @param collection the collection to use in this scope.
5858
*/
59-
TerminatingFindById<T> inCollection(String collection);
59+
ReactiveFindById<T> inCollection(String collection);
6060
}
6161

6262
interface FindByIdWithProjection<T> extends FindByIdWithCollection<T> {
@@ -66,10 +66,10 @@ interface FindByIdWithProjection<T> extends FindByIdWithCollection<T> {
6666
*
6767
* @param fields the projected fields to load.
6868
*/
69-
FindByIdWithCollection<T> project(String... fields);
69+
ReactiveFindById<T> project(String... fields);
7070

7171
}
7272

73-
interface ReactiveFindById<T> extends FindByIdWithProjection<T> {}
73+
interface ReactiveFindById<T> extends TerminatingFindById<T>, FindByIdWithCollection<T>, FindByIdWithProjection<T> {}
7474

7575
}

0 commit comments

Comments
 (0)