Skip to content

Commit bd7e40e

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 bd7e40e

File tree

47 files changed

+1817
-535
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1817
-535
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/ExecutableFindByAnalyticsOperation.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@
1919
import java.util.Optional;
2020
import java.util.stream.Stream;
2121

22-
import com.couchbase.client.java.analytics.AnalyticsScanConsistency;
23-
import com.couchbase.client.java.query.QueryScanConsistency;
2422
import org.springframework.dao.IncorrectResultSizeDataAccessException;
2523
import org.springframework.data.couchbase.core.query.AnalyticsQuery;
2624
import org.springframework.lang.Nullable;
2725

26+
import com.couchbase.client.java.analytics.AnalyticsScanConsistency;
27+
2828
public interface ExecutableFindByAnalyticsOperation {
2929

3030
/**
@@ -114,17 +114,30 @@ interface FindByAnalyticsWithQuery<T> extends TerminatingFindByAnalytics<T> {
114114

115115
}
116116

117+
@Deprecated
117118
interface FindByAnalyticsConsistentWith<T> extends FindByAnalyticsWithQuery<T> {
118119

119120
/**
120121
* Allows to override the default scan consistency.
121122
*
122123
* @param scanConsistency the custom scan consistency to use for this analytics query.
123124
*/
125+
@Deprecated
124126
FindByAnalyticsWithQuery<T> consistentWith(AnalyticsScanConsistency scanConsistency);
125127

126128
}
127129

128-
interface ExecutableFindByAnalytics<T> extends FindByAnalyticsConsistentWith<T> {}
130+
interface FindByAnalyticsWithConsistency<T> extends FindByAnalyticsWithQuery<T> {
131+
132+
/**
133+
* Allows to override the default scan consistency.
134+
*
135+
* @param scanConsistency the custom scan consistency to use for this analytics query.
136+
*/
137+
FindByAnalyticsWithQuery<T> withConsistency(AnalyticsScanConsistency scanConsistency);
138+
139+
}
140+
141+
interface ExecutableFindByAnalytics<T> extends FindByAnalyticsConsistentWith<T>, FindByAnalyticsWithConsistency<T> {}
129142

130143
}

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

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

18-
import org.springframework.data.couchbase.core.ReactiveFindByAnalyticsOperationSupport.ReactiveFindByAnalyticsSupport;
19-
2018
import java.util.List;
2119
import java.util.stream.Stream;
2220

21+
import org.springframework.data.couchbase.core.ReactiveFindByAnalyticsOperationSupport.ReactiveFindByAnalyticsSupport;
2322
import org.springframework.data.couchbase.core.query.AnalyticsQuery;
2423

2524
import com.couchbase.client.java.analytics.AnalyticsScanConsistency;
@@ -79,10 +78,16 @@ public TerminatingFindByAnalytics<T> matching(final AnalyticsQuery query) {
7978
}
8079

8180
@Override
81+
@Deprecated
8282
public FindByAnalyticsWithQuery<T> consistentWith(final AnalyticsScanConsistency scanConsistency) {
8383
return new ExecutableFindByAnalyticsSupport<>(template, domainType, query, scanConsistency);
8484
}
8585

86+
@Override
87+
public FindByAnalyticsWithQuery<T> withConsistency(final AnalyticsScanConsistency scanConsistency) {
88+
return new ExecutableFindByAnalyticsSupport<>(template, domainType, query, scanConsistency);
89+
}
90+
8691
@Override
8792
public Stream<T> stream() {
8893
return reactiveSupport.all().toStream();

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: 72 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,104 @@ 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+
}
131+
132+
}
133+
134+
@Deprecated
135+
interface FindByQueryConsistentWith<T> {
136+
137+
/**
138+
* Allows to override the default scan consistency.
139+
*
140+
* @param scanConsistency the custom scan consistency to use for this query.
141+
*/
142+
@Deprecated
143+
ExecutableFindByQuery<T> consistentWith(QueryScanConsistency scanConsistency);
119144

120145
}
121146

122-
interface FindByQueryConsistentWith<T> extends FindByQueryWithQuery<T> {
147+
interface FindByQueryWithConsistency<T> {
123148

124149
/**
125150
* Allows to override the default scan consistency.
126151
*
127152
* @param scanConsistency the custom scan consistency to use for this query.
128153
*/
129-
FindByQueryConsistentWith<T> consistentWith(QueryScanConsistency scanConsistency);
154+
ExecutableFindByQuery<T> withConsistency(QueryScanConsistency scanConsistency);
130155

131156
}
132157

133-
interface FindByQueryInCollection<T> extends FindByQueryConsistentWith<T> {
158+
interface FindByQueryInCollection<T> {
134159

135160
/**
136161
* Allows to override the default scan consistency.
137162
*
138163
* @param collection the collection to use for this query.
139164
*/
140-
FindByQueryInCollection<T> inCollection(String collection);
165+
ExecutableFindByQuery<T> inCollection(String collection);
141166

142167
}
143168

144-
interface ExecutableFindByQuery<T> extends FindByQueryInCollection<T> {}
169+
/**
170+
* Result type override (Optional).
171+
*/
172+
interface FindByQueryWithProjection<T> {
173+
174+
/**
175+
* Define the target type fields should be mapped to. <br />
176+
* Skip this step if you are anyway only interested in the original domain type.
177+
*
178+
* @param resultType must not be {@literal null}.
179+
* @param <R> result type.
180+
* @return new instance of {@link FindByQueryWithProjection}.
181+
* @throws IllegalArgumentException if resultType is {@literal null}.
182+
*/
183+
<R> ExecutableFindByQuery<R> as(Class<R> resultType);
184+
185+
}
186+
187+
/**
188+
* Distinct Find support.
189+
*/
190+
interface FindByQueryDistinct<T> {
191+
192+
/**
193+
* Finds the distinct values for a specified {@literal field} across a single collection
194+
*
195+
* @param distinctFields name of the field. Must not be {@literal null}.
196+
* @return new instance of {@link ExecutableFindByQuery}.
197+
* @throws IllegalArgumentException if field is {@literal null}.
198+
*/
199+
ExecutableFindByQuery<T> distinct(String[] distinctFields);
200+
201+
}
202+
203+
/**
204+
* {@link ExecutableFindByQuery} provides methods for constructing lookup operations in a fluent way.
205+
*/
206+
207+
interface ExecutableFindByQuery<T>
208+
extends TerminatingFindByQuery<T>, FindByQueryWithQuery<T>, FindByQueryConsistentWith<T>,
209+
FindByQueryWithConsistency<T>, FindByQueryInCollection<T>, FindByQueryWithProjection<T>, FindByQueryDistinct<T> {}
145210

146211
}

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

Lines changed: 45 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,50 @@ 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+
@Deprecated
103+
public ExecutableFindByQuery<T> consistentWith(final QueryScanConsistency scanConsistency) {
104+
return new ExecutableFindByQuerySupport<>(template, domainType, returnType, query, scanConsistency, collection,
105+
distinctFields);
97106
}
98107

99108
@Override
100-
public FindByQueryInCollection<T> inCollection(final String collection) {
101-
return new ExecutableFindByQuerySupport<>(template, domainType, query, scanConsistency, collection);
109+
public ExecutableFindByQuery<T> withConsistency(final QueryScanConsistency scanConsistency) {
110+
return new ExecutableFindByQuerySupport<>(template, domainType, returnType, query, scanConsistency, collection,
111+
distinctFields);
112+
}
113+
114+
@Override
115+
public ExecutableFindByQuery<T> inCollection(final String collection) {
116+
Assert.hasText(collection, "Collection must not be null nor empty.");
117+
return new ExecutableFindByQuerySupport<>(template, domainType, returnType, query, scanConsistency, collection,
118+
distinctFields);
119+
}
120+
121+
@Override
122+
public <R> ExecutableFindByQuery<R> as(Class<R> returnType) {
123+
Assert.notNull(returnType, "returnType must not be null!");
124+
125+
return new ExecutableFindByQuerySupport<R>(template, domainType, returnType, query, scanConsistency, collection,
126+
distinctFields);
127+
}
128+
129+
@Override
130+
public ExecutableFindByQuery<T> distinct(String[] distinctFields) {
131+
Assert.notNull(distinctFields, "distinctFields must not be null!");
132+
return new ExecutableFindByQuerySupport<>(template, domainType, returnType, query, scanConsistency, collection,
133+
distinctFields);
102134
}
103135

104136
@Override
@@ -115,7 +147,6 @@ public long count() {
115147
public boolean exists() {
116148
return count() > 0;
117149
}
118-
119150
}
120151

121152
}

0 commit comments

Comments
 (0)