Skip to content

Commit de74b72

Browse files
authored
Merge branch 'main' into datacouch_1200_implement_distinct_derived_queries
2 parents 9d8249e + f0880da commit de74b72

File tree

6 files changed

+53
-30
lines changed

6 files changed

+53
-30
lines changed

src/main/java/org/springframework/data/couchbase/core/query/Query.java

-5
Original file line numberDiff line numberDiff line change
@@ -319,11 +319,6 @@ public String export(int[]... paramIndexPtrHolder) { // used only by tests
319319
return sb.toString();
320320
}
321321

322-
public String toN1qlSelectString(ReactiveCouchbaseTemplate template, String collectionName, Class domainClass,
323-
boolean isCount) {
324-
return toN1qlSelectString(template, collectionName, domainClass, null, isCount, null);
325-
}
326-
327322
public String toN1qlSelectString(ReactiveCouchbaseTemplate template, Class domainClass, boolean isCount) {
328323
return toN1qlSelectString(template, null, domainClass, null, isCount, null);
329324
}

src/main/java/org/springframework/data/couchbase/core/query/StringQuery.java

+16-4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919

2020
import com.couchbase.client.java.json.JsonArray;
2121
import com.couchbase.client.java.json.JsonValue;
22+
import org.springframework.data.couchbase.core.support.TemplateUtils;
23+
24+
import java.util.Locale;
2225

2326
/**
2427
* Query created from the string in @Query annotation in the repository interface.
@@ -35,7 +38,7 @@
3538
*/
3639
public class StringQuery extends Query {
3740

38-
private String inlineN1qlQuery;
41+
private final String inlineN1qlQuery;
3942

4043
public StringQuery(String n1qlString) {
4144
inlineN1qlQuery = n1qlString;
@@ -55,6 +58,11 @@ private void appendInlineN1qlStatement(final StringBuilder sb) {
5558
public String toN1qlSelectString(ReactiveCouchbaseTemplate template, String collection, Class domainClass,
5659
Class resultClass, boolean isCount, String[] distinctFields) {
5760
final StringBuilder statement = new StringBuilder();
61+
boolean makeCount = isCount && inlineN1qlQuery != null
62+
&& !inlineN1qlQuery.toLowerCase(Locale.ROOT).contains("count(");
63+
if (makeCount) {
64+
statement.append("SELECT COUNT(*) AS " + TemplateUtils.SELECT_COUNT + " FROM (");
65+
}
5866
appendInlineN1qlStatement(statement); // apply the string statement
5967
// To use generated parameters for literals
6068
// we need to figure out if we must use positional or named parameters
@@ -68,9 +76,13 @@ public String toN1qlSelectString(ReactiveCouchbaseTemplate template, String coll
6876
paramIndexPtr = new int[] { -1 };
6977
}
7078
appendWhere(statement, paramIndexPtr, template.getConverter()); // criteria on this Query - should be empty for
71-
// StringQuery
72-
appendSort(statement);
73-
appendSkipAndLimit(statement);
79+
if (!isCount) {
80+
appendSort(statement);
81+
appendSkipAndLimit(statement);
82+
}
83+
if (makeCount) {
84+
statement.append(") predicate_query");
85+
}
7486
return statement.toString();
7587
}
7688

src/main/java/org/springframework/data/couchbase/repository/query/StringBasedN1qlQueryParser.java

+6-16
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616
package org.springframework.data.couchbase.repository.query;
1717

1818
import static org.springframework.data.couchbase.core.query.N1QLExpression.i;
19-
import static org.springframework.data.couchbase.core.query.N1QLExpression.meta;
20-
import static org.springframework.data.couchbase.core.query.N1QLExpression.path;
2119
import static org.springframework.data.couchbase.core.query.N1QLExpression.x;
2220
import static org.springframework.data.couchbase.core.support.TemplateUtils.SELECT_CAS;
2321
import static org.springframework.data.couchbase.core.support.TemplateUtils.SELECT_ID;
@@ -31,14 +29,12 @@
3129

3230
import org.slf4j.Logger;
3331
import org.slf4j.LoggerFactory;
34-
import org.springframework.core.convert.converter.Converter;
3532
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
3633
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty;
3734
import org.springframework.data.couchbase.core.query.N1QLExpression;
3835
import org.springframework.data.couchbase.repository.Query;
3936
import org.springframework.data.couchbase.repository.query.support.N1qlUtils;
4037
import org.springframework.data.domain.Pageable;
41-
import org.springframework.data.domain.Sort;
4238
import org.springframework.data.mapping.PersistentEntity;
4339
import org.springframework.data.mapping.PersistentPropertyPath;
4440
import org.springframework.data.mapping.PropertyHandler;
@@ -197,7 +193,7 @@ private void getProjectedFieldsInternal(String bucketName, CouchbasePersistentPr
197193
TypeInformation resultClass/*, String path*/) {
198194

199195
PersistentEntity persistentEntity = couchbaseConverter.getMappingContext().getPersistentEntity(resultClass);
200-
//CouchbasePersistentProperty property = path.getLeafProperty();
196+
// CouchbasePersistentProperty property = path.getLeafProperty();
201197
persistentEntity.doWithProperties(new PropertyHandler<CouchbasePersistentProperty>() {
202198
@Override
203199
public void doWithPersistentProperty(final CouchbasePersistentProperty prop) {
@@ -207,7 +203,8 @@ public void doWithPersistentProperty(final CouchbasePersistentProperty prop) {
207203
if (prop.isVersionProperty()) {
208204
return;
209205
}
210-
PersistentPropertyPath<CouchbasePersistentProperty> path = couchbaseConverter.getMappingContext().getPersistentPropertyPath(prop.getName(), resultClass.getType());
206+
PersistentPropertyPath<CouchbasePersistentProperty> path = couchbaseConverter.getMappingContext()
207+
.getPersistentPropertyPath(prop.getName(), resultClass.getType());
211208

212209
// The current limitation is that only top-level properties can be projected
213210
// This traversing of nested data structures would need to replicate the processing done by
@@ -495,16 +492,7 @@ private N1QLExpression getExpression(ParameterAccessor accessor, Object[] runtim
495492
runtimeParameters);
496493
N1QLExpression parsedStatement = x(this.doParse(parser, evaluationContext, isCountQuery));
497494

498-
Sort sort = accessor.getSort();
499-
if (sort.isSorted()) {
500-
N1QLExpression[] cbSorts = N1qlUtils.createSort(sort);
501-
parsedStatement = parsedStatement.orderBy(cbSorts);
502-
}
503-
if (queryMethod.isPageQuery()) {
504-
Pageable pageable = accessor.getPageable();
505-
Assert.notNull(pageable, "Pageable must not be null!");
506-
parsedStatement = parsedStatement.limit(pageable.getPageSize()).offset(Math.toIntExact(pageable.getOffset()));
507-
} else if (queryMethod.isSliceQuery()) {
495+
if (queryMethod.isSliceQuery()) {
508496
Pageable pageable = accessor.getPageable();
509497
Assert.notNull(pageable, "Pageable must not be null!");
510498
parsedStatement = parsedStatement.limit(pageable.getPageSize() + 1).offset(Math.toIntExact(pageable.getOffset()));
@@ -518,6 +506,8 @@ private static Object[] getParameters(ParameterAccessor accessor) {
518506
for (Object o : accessor) {
519507
params.add(o);
520508
}
509+
params.add(accessor.getPageable());
510+
params.add(accessor.getSort());
521511
return params.toArray();
522512
}
523513
}

src/main/java/org/springframework/data/couchbase/repository/query/StringN1qlQueryCreator.java

+13
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@
1919
import static org.springframework.data.couchbase.core.query.QueryCriteria.where;
2020

2121
import java.util.Iterator;
22+
import java.util.Optional;
2223

2324
import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
2425
import org.springframework.data.couchbase.core.mapping.CouchbasePersistentProperty;
2526
import org.springframework.data.couchbase.core.query.N1QLExpression;
2627
import org.springframework.data.couchbase.core.query.Query;
2728
import org.springframework.data.couchbase.core.query.QueryCriteria;
2829
import org.springframework.data.couchbase.core.query.StringQuery;
30+
import org.springframework.data.domain.Pageable;
2931
import org.springframework.data.domain.Sort;
3032
import org.springframework.data.mapping.Alias;
3133
import org.springframework.data.mapping.PersistentPropertyPath;
@@ -116,6 +118,17 @@ protected QueryCriteria create(final Part part, final Iterator<Object> iterator)
116118
return from(part, property, where(x(path.toDotPath())), iterator);
117119
}
118120

121+
@Override
122+
public Query createQuery() {
123+
Query q = this.createQuery((Optional.of(this.accessor).map(ParameterAccessor::getSort).orElse(Sort.unsorted())));
124+
Pageable pageable = accessor.getPageable();
125+
if (pageable.isPaged()) {
126+
q.skip(pageable.getOffset());
127+
q.limit(pageable.getPageSize());
128+
}
129+
return q;
130+
}
131+
119132
@Override
120133
protected QueryCriteria and(final Part part, final QueryCriteria base, final Iterator<Object> iterator) {
121134
if (base == null) {

src/test/java/org/springframework/data/couchbase/domain/AirportRepository.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ public interface AirportRepository extends CouchbaseRepository<Airport, String>,
114114
Long countFancyExpression(@Param("projectIds") List<String> projectIds, @Param("planIds") List<String> planIds,
115115
@Param("active") Boolean active);
116116

117-
@Query("SELECT 1 FROM `#{#n1ql.bucket}` WHERE 0 = 1")
117+
@Query("SELECT 1 FROM `#{#n1ql.bucket}` WHERE anything = 'count(*)'") // looks like count query, but is not
118118
Long countBad();
119119

120120
@Query("SELECT count(*) FROM `#{#n1ql.bucket}`")
@@ -123,6 +123,10 @@ Long countFancyExpression(@Param("projectIds") List<String> projectIds, @Param("
123123
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
124124
Page<Airport> findAllByIataNot(String iata, Pageable pageable);
125125

126+
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
127+
@Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter} AND iata != $1")
128+
Page<Airport> getAllByIataNot(String iata, Pageable pageable);
129+
126130
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
127131
Optional<Airport> findByIdAndIata(String id, String iata);
128132

@@ -138,6 +142,10 @@ Long countFancyExpression(@Param("projectIds") List<String> projectIds, @Param("
138142
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
139143
Long countDistinctIcaoBy();
140144

145+
@Query("SELECT 1 FROM `#{#n1ql.bucket}` WHERE #{#n1ql.filter} " + " #{#projectIds != null ? 'AND blah IN $1' : ''} "
146+
+ " #{#planIds != null ? 'AND blahblah IN $2' : ''} " + " #{#active != null ? 'AND false = $3' : ''} ")
147+
Long countOne();
148+
141149
@Retention(RetentionPolicy.RUNTIME)
142150
@Target({ ElementType.METHOD, ElementType.TYPE })
143151
// @Meta

src/test/java/org/springframework/data/couchbase/repository/CouchbaseRepositoryQueryIntegrationTests.java

+9-4
Original file line numberDiff line numberDiff line change
@@ -187,10 +187,9 @@ void annotatedFieldFindName() {
187187
assertEquals(person.getSalutation(), result.contentAsObject().get("prefix"));
188188
Person person2 = personRepository.findById(person.getId().toString()).get();
189189
assertEquals(person.getSalutation(), person2.getSalutation());
190-
// needs fix from datacouch_1184
191-
// List<Person> persons3 = personRepository.findBySalutation("Mrs");
192-
// assertEquals(1, persons3.size());
193-
// assertEquals(person.getSalutation(), persons3.get(0).getSalutation());
190+
List<Person> persons3 = personRepository.findBySalutation("Mrs");
191+
assertEquals(1, persons3.size());
192+
assertEquals(person.getSalutation(), persons3.get(0).getSalutation());
194193
} finally {
195194
personRepository.deleteById(person.getId().toString());
196195
}
@@ -442,6 +441,7 @@ public void testExpiryAnnotation() {
442441
void count() {
443442
String[] iatas = { "JFK", "IAD", "SFO", "SJC", "SEA", "LAX", "PHX" };
444443

444+
airportRepository.countOne();
445445
try {
446446
airportRepository.saveAll(
447447
Arrays.stream(iatas).map((iata) -> new Airport("airports::" + iata, iata, iata.toLowerCase(Locale.ROOT)))
@@ -450,6 +450,11 @@ void count() {
450450
Long count = airportRepository.countFancyExpression(asList("JFK"), asList("jfk"), false);
451451
assertEquals(1, count);
452452

453+
Pageable sPageable = PageRequest.of(0, 2).withSort(Sort.by("iata"));
454+
Page<Airport> sPage = airportRepository.getAllByIataNot("JFK", sPageable);
455+
assertEquals(iatas.length - 1, sPage.getTotalElements());
456+
assertEquals(sPageable.getPageSize(), sPage.getContent().size());
457+
453458
Pageable pageable = PageRequest.of(0, 2).withSort(Sort.by("iata"));
454459
Page<Airport> aPage = airportRepository.findAllByIataNot("JFK", pageable);
455460
assertEquals(iatas.length - 1, aPage.getTotalElements());

0 commit comments

Comments
 (0)