DATACOUCH-616 - Fix parsing of String Query containing conditionals in quotes
For a query as below that has conditional portions, the parsing for
parameters was being done before the conditional portions were being
resolved, which left the parameters between quotes where they wre
not being recognized as query parameters.
@Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter} " +
" #{#projectIds != null ? 'AND iata IN $1' : ''} ")
Long count(@Param("projectIds") List<String> projectIds)
This commit is contained in:
@@ -23,7 +23,6 @@ import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.data.annotation.QueryAnnotation;
|
||||
import org.springframework.data.couchbase.core.CouchbaseTemplate;
|
||||
import org.springframework.data.couchbase.repository.query.StringN1qlBasedQuery;
|
||||
|
||||
/**
|
||||
* Annotation to support the use of N1QL queries with Couchbase.
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.couchbase.repository.query;
|
||||
|
||||
import static org.springframework.data.couchbase.core.query.N1QLExpression.*;
|
||||
|
||||
import org.springframework.data.couchbase.core.ReactiveCouchbaseOperations;
|
||||
import org.springframework.data.couchbase.core.query.N1QLExpression;
|
||||
import org.springframework.data.repository.query.ParameterAccessor;
|
||||
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
import org.springframework.data.repository.query.ReturnedType;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
|
||||
import com.couchbase.client.java.json.JsonValue;
|
||||
|
||||
/**
|
||||
* A reactive StringN1qlBasedQuery {@link RepositoryQuery} for Couchbase, based on N1QL and a String statement.
|
||||
* <p/>
|
||||
* The statement can contain positional placeholders (eg. <code>name = $1</code>) that will map to the method's
|
||||
* parameters, in the same order.
|
||||
* <p/>
|
||||
* The statement can also contain SpEL expressions enclosed in <code>#{</code> and <code>}</code>.
|
||||
* <p/>
|
||||
*
|
||||
* @author Subhashni Balakrishnan
|
||||
* @since 3.0
|
||||
*/
|
||||
public class ReactiveStringN1qlBasedQuery extends ReactiveAbstractN1qlBasedQuery {
|
||||
|
||||
private final StringBasedN1qlQueryParser queryParser;
|
||||
private final SpelExpressionParser parser;
|
||||
private final QueryMethodEvaluationContextProvider evaluationContextProvider;
|
||||
|
||||
public ReactiveStringN1qlBasedQuery(String statement, CouchbaseQueryMethod queryMethod,
|
||||
ReactiveCouchbaseOperations couchbaseOperations, SpelExpressionParser spelParser,
|
||||
QueryMethodEvaluationContextProvider evaluationContextProvider) {
|
||||
super(queryMethod, couchbaseOperations);
|
||||
|
||||
this.queryParser = new StringBasedN1qlQueryParser(statement, queryMethod, getCouchbaseOperations().getBucketName(),
|
||||
getCouchbaseOperations().getConverter(), getTypeField(), getTypeValue());
|
||||
this.parser = spelParser;
|
||||
this.evaluationContextProvider = evaluationContextProvider;
|
||||
}
|
||||
|
||||
protected String getTypeField() {
|
||||
return getCouchbaseOperations().getConverter().getTypeKey();
|
||||
}
|
||||
|
||||
protected String getTypeValue() {
|
||||
return getQueryMethod().getEntityInformation().getJavaType().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonValue getPlaceholderValues(ParameterAccessor accessor) {
|
||||
return this.queryParser.getPlaceholderValues(accessor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public N1QLExpression getExpression(ParameterAccessor accessor, Object[] runtimeParameters,
|
||||
ReturnedType returnedType) {
|
||||
EvaluationContext evaluationContext = evaluationContextProvider
|
||||
.getEvaluationContext(getQueryMethod().getParameters(), runtimeParameters);
|
||||
return x(queryParser.doParse(parser, evaluationContext, false));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,9 +32,13 @@ import org.springframework.data.couchbase.core.convert.CouchbaseConverter;
|
||||
import org.springframework.data.couchbase.core.query.N1QLExpression;
|
||||
import org.springframework.data.couchbase.repository.Query;
|
||||
import org.springframework.data.couchbase.repository.query.support.N1qlUtils;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.repository.query.Parameter;
|
||||
import org.springframework.data.repository.query.ParameterAccessor;
|
||||
import org.springframework.data.repository.query.QueryMethod;
|
||||
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
|
||||
import org.springframework.data.repository.query.ReturnedType;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.common.TemplateParserContext;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
@@ -42,6 +46,7 @@ import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import com.couchbase.client.java.json.JsonArray;
|
||||
import com.couchbase.client.java.json.JsonObject;
|
||||
import com.couchbase.client.java.json.JsonValue;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Subhashni Balakrishnan
|
||||
@@ -103,20 +108,23 @@ public class StringBasedN1qlQueryParser {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(StringBasedN1qlQueryParser.class);
|
||||
private final String statement;
|
||||
private final QueryMethod queryMethod;
|
||||
private final PlaceholderType placeHolderType;
|
||||
private PlaceholderType placeHolderType;
|
||||
private final N1qlSpelValues statementContext;
|
||||
private final N1qlSpelValues countContext;
|
||||
private final CouchbaseConverter couchbaseConverter;
|
||||
private final Collection<String> parameterNames = new HashSet<String>();
|
||||
public final N1QLExpression parsedExpression;
|
||||
|
||||
public StringBasedN1qlQueryParser(String statement, QueryMethod queryMethod, String bucketName,
|
||||
CouchbaseConverter couchbaseConverter, String typeField, String typeValue) {
|
||||
CouchbaseConverter couchbaseConverter, String typeField, String typeValue, ParameterAccessor accessor,
|
||||
SpelExpressionParser parser, QueryMethodEvaluationContextProvider evaluationContextProvider) {
|
||||
this.statement = statement;
|
||||
this.queryMethod = queryMethod;
|
||||
this.placeHolderType = checkPlaceholders(statement);
|
||||
this.statementContext = createN1qlSpelValues(bucketName, typeField, typeValue, false);
|
||||
this.countContext = createN1qlSpelValues(bucketName, typeField, typeValue, true);
|
||||
this.couchbaseConverter = couchbaseConverter;
|
||||
this.parsedExpression = getExpression(accessor, getParameters(accessor), null, parser, evaluationContextProvider);
|
||||
checkPlaceholders( this.parsedExpression.toString() );
|
||||
}
|
||||
|
||||
public static N1qlSpelValues createN1qlSpelValues(String bucketName, String typeField, String typeValue,
|
||||
@@ -151,7 +159,7 @@ public class StringBasedN1qlQueryParser {
|
||||
return parsedExpression.getValue(evaluationContext, String.class);
|
||||
}
|
||||
|
||||
private PlaceholderType checkPlaceholders(String statement) {
|
||||
private void checkPlaceholders(String statement) {
|
||||
|
||||
Matcher quoteMatcher = QUOTE_DETECTION_PATTERN.matcher(statement);
|
||||
Matcher positionMatcher = POSITIONAL_PLACEHOLDER_PATTERN.matcher(statement);
|
||||
@@ -192,11 +200,11 @@ public class StringBasedN1qlQueryParser {
|
||||
}
|
||||
|
||||
if (posCount > 0) {
|
||||
return PlaceholderType.POSITIONAL;
|
||||
placeHolderType = PlaceholderType.POSITIONAL;
|
||||
} else if (namedCount > 0) {
|
||||
return PlaceholderType.NAMED;
|
||||
placeHolderType = PlaceholderType.NAMED;
|
||||
} else {
|
||||
return PlaceholderType.NONE;
|
||||
placeHolderType = PlaceholderType.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,5 +410,39 @@ public class StringBasedN1qlQueryParser {
|
||||
this.returning = returning;
|
||||
}
|
||||
}
|
||||
// copied from StringN1qlBasedQuery
|
||||
private N1QLExpression getExpression(ParameterAccessor accessor, Object[] runtimeParameters,
|
||||
ReturnedType returnedType, SpelExpressionParser parser, QueryMethodEvaluationContextProvider evaluationContextProvider) {
|
||||
boolean isCountQuery = queryMethod.getName().toLowerCase().startsWith("count"); // should be queryMethod.isCountQuery()
|
||||
EvaluationContext evaluationContext = evaluationContextProvider
|
||||
.getEvaluationContext(queryMethod.getParameters(), runtimeParameters);
|
||||
N1QLExpression parsedStatement = x(this.doParse(parser, evaluationContext, isCountQuery));
|
||||
|
||||
Sort sort = accessor.getSort();
|
||||
if (sort.isSorted()) {
|
||||
N1QLExpression[] cbSorts = N1qlUtils.createSort(sort);
|
||||
parsedStatement = parsedStatement.orderBy(cbSorts);
|
||||
}
|
||||
if (queryMethod.isPageQuery()) {
|
||||
Pageable pageable = accessor.getPageable();
|
||||
Assert.notNull(pageable, "Pageable must not be null!");
|
||||
parsedStatement = parsedStatement.limit(pageable.getPageSize()).offset(
|
||||
Math.toIntExact(pageable.getOffset()));
|
||||
} else if (queryMethod.isSliceQuery()) {
|
||||
Pageable pageable = accessor.getPageable();
|
||||
Assert.notNull(pageable, "Pageable must not be null!");
|
||||
parsedStatement = parsedStatement.limit(pageable.getPageSize() + 1).offset(
|
||||
Math.toIntExact(pageable.getOffset()));
|
||||
}
|
||||
return parsedStatement;
|
||||
}
|
||||
|
||||
// getExpression() could do this itself, but pass as an arg to be consistent with StringN1qlBasedQuery
|
||||
private static Object[] getParameters(ParameterAccessor accessor) {
|
||||
ArrayList<Object> params = new ArrayList<>();
|
||||
for (Object o : accessor) {
|
||||
params.add(o);
|
||||
}
|
||||
return params.toArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.data.couchbase.repository.query;
|
||||
|
||||
import static org.springframework.data.couchbase.core.query.N1QLExpression.*;
|
||||
|
||||
import org.springframework.data.couchbase.core.CouchbaseOperations;
|
||||
import org.springframework.data.couchbase.core.query.N1QLExpression;
|
||||
import org.springframework.data.couchbase.repository.query.support.N1qlUtils;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.repository.query.ParameterAccessor;
|
||||
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
import org.springframework.data.repository.query.ReturnedType;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import com.couchbase.client.java.json.JsonValue;
|
||||
|
||||
/**
|
||||
* A {@link RepositoryQuery} for Couchbase, based on N1QL and a String statement.
|
||||
* <p/>
|
||||
* The statement can contain positional placeholders (eg. <code>name = $1</code>) that will map to the method's
|
||||
* parameters, in the same order.
|
||||
* <p/>
|
||||
* The statement can also contain SpEL expressions enclosed in <code>#{</code> and <code>}</code>.
|
||||
* <p/>
|
||||
* There are couchbase-provided variables included for the {@link StringBasedN1qlQueryParser#SPEL_BUCKET bucket
|
||||
* namespace}, the {@link StringBasedN1qlQueryParser#SPEL_ENTITY ID and CAS fields} necessary for entity reconstruction
|
||||
* or a shortcut that covers {@link StringBasedN1qlQueryParser#SPEL_SELECT_FROM_CLAUSE SELECT AND FROM clauses}, along
|
||||
* with a variable for {@link StringBasedN1qlQueryParser#SPEL_FILTER WHERE clause filtering} of the correct entity.
|
||||
*
|
||||
* @author Simon Baslé
|
||||
* @author Subhashni Balakrishnan
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class StringN1qlBasedQuery extends AbstractN1qlBasedQuery {
|
||||
private final SpelExpressionParser parser;
|
||||
private final QueryMethodEvaluationContextProvider evaluationContextProvider;
|
||||
private final StringBasedN1qlQueryParser queryParser;
|
||||
|
||||
public StringN1qlBasedQuery(String statement, CouchbaseQueryMethod queryMethod,
|
||||
CouchbaseOperations couchbaseOperations, SpelExpressionParser spelParser,
|
||||
QueryMethodEvaluationContextProvider evaluationContextProvider) {
|
||||
super(queryMethod, couchbaseOperations);
|
||||
this.queryParser = new StringBasedN1qlQueryParser(statement, queryMethod, getCouchbaseOperations().getBucketName(),
|
||||
getCouchbaseOperations().getConverter(), getTypeField(), getTypeValue().getName());
|
||||
this.parser = spelParser;
|
||||
this.evaluationContextProvider = evaluationContextProvider;
|
||||
}
|
||||
|
||||
protected String getTypeField() {
|
||||
return getCouchbaseOperations().getConverter().getTypeKey();
|
||||
}
|
||||
|
||||
protected Class<?> getTypeValue() {
|
||||
return getQueryMethod().getEntityInformation().getJavaType();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonValue getPlaceholderValues(ParameterAccessor accessor) {
|
||||
return this.queryParser.getPlaceholderValues(accessor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public N1QLExpression getExpression(ParameterAccessor accessor, Object[] runtimeParameters,
|
||||
ReturnedType returnedType) {
|
||||
EvaluationContext evaluationContext = evaluationContextProvider
|
||||
.getEvaluationContext(getQueryMethod().getParameters(), runtimeParameters);
|
||||
N1QLExpression parsedStatement = x(this.queryParser.doParse(parser, evaluationContext, false));
|
||||
|
||||
Sort sort = accessor.getSort();
|
||||
if (sort.isSorted()) {
|
||||
N1QLExpression[] cbSorts = N1qlUtils.createSort(sort);
|
||||
parsedStatement = parsedStatement.orderBy(cbSorts);
|
||||
}
|
||||
if (queryMethod.isPageQuery()) {
|
||||
Pageable pageable = accessor.getPageable();
|
||||
Assert.notNull(pageable, "Pageable must not be null!");
|
||||
parsedStatement = parsedStatement.limit(pageable.getPageSize()).offset(Math.toIntExact(pageable.getOffset()));
|
||||
} else if (queryMethod.isSliceQuery()) {
|
||||
Pageable pageable = accessor.getPageable();
|
||||
Assert.notNull(pageable, "Pageable must not be null!");
|
||||
parsedStatement = parsedStatement.limit(pageable.getPageSize() + 1).offset(Math.toIntExact(pageable.getOffset()));
|
||||
}
|
||||
return parsedStatement;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected N1QLExpression getCount(ParameterAccessor accessor, Object[] runtimeParameters) {
|
||||
EvaluationContext evaluationContext = evaluationContextProvider
|
||||
.getEvaluationContext(getQueryMethod().getParameters(), runtimeParameters);
|
||||
return x(this.queryParser.doParse(parser, evaluationContext, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean useGeneratedCountQuery() {
|
||||
return this.queryParser.useGeneratedCountQuery();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -57,6 +57,7 @@ public class StringN1qlQueryCreator extends AbstractQueryCreator<Query, QueryCri
|
||||
private final QueryMethod queryMethod;
|
||||
private final CouchbaseConverter couchbaseConverter;
|
||||
private static final SpelExpressionParser SPEL_PARSER = new SpelExpressionParser();
|
||||
private final N1QLExpression parsedExpression;
|
||||
|
||||
public StringN1qlQueryCreator(final ParameterAccessor accessor, CouchbaseQueryMethod queryMethod,
|
||||
CouchbaseConverter couchbaseConverter, String bucketName,
|
||||
@@ -83,8 +84,9 @@ public class StringN1qlQueryCreator extends AbstractQueryCreator<Query, QueryCri
|
||||
throw new IllegalArgumentException("query has no inline Query or named Query not found");
|
||||
}
|
||||
this.queryParser = new StringBasedN1qlQueryParser(queryString, queryMethod, bucketName, couchbaseConverter,
|
||||
getTypeField(), getTypeValue());
|
||||
getTypeField(), getTypeValue(), accessor, SPEL_PARSER, evaluationContextProvider);
|
||||
this.parser = SPEL_PARSER;
|
||||
this.parsedExpression = this.queryParser.parsedExpression;
|
||||
}
|
||||
|
||||
protected QueryMethod getQueryMethod() {
|
||||
@@ -127,7 +129,6 @@ public class StringN1qlQueryCreator extends AbstractQueryCreator<Query, QueryCri
|
||||
|
||||
@Override
|
||||
protected Query complete(QueryCriteria criteria, Sort sort) {
|
||||
N1QLExpression parsedExpression = getExpression(accessor, getParameters(accessor), null /* returnedType */);
|
||||
Query q = new StringQuery(parsedExpression.toString()).with(sort);
|
||||
JsonValue params = queryParser.getPlaceholderValues(accessor);
|
||||
if (params instanceof JsonArray) {
|
||||
@@ -150,40 +151,4 @@ public class StringN1qlQueryCreator extends AbstractQueryCreator<Query, QueryCri
|
||||
}
|
||||
}
|
||||
|
||||
// copied from StringN1qlBasedQuery
|
||||
private N1QLExpression getExpression(ParameterAccessor accessor, Object[] runtimeParameters,
|
||||
ReturnedType returnedType) {
|
||||
EvaluationContext evaluationContext = evaluationContextProvider.getEvaluationContext(
|
||||
getQueryMethod().getParameters(), runtimeParameters);
|
||||
N1QLExpression parsedStatement = x(this.queryParser.doParse(parser, evaluationContext, false));
|
||||
|
||||
Sort sort = accessor.getSort();
|
||||
if (sort.isSorted()) {
|
||||
N1QLExpression[] cbSorts = N1qlUtils.createSort(sort);
|
||||
parsedStatement = parsedStatement.orderBy(cbSorts);
|
||||
}
|
||||
if (queryMethod.isPageQuery()) {
|
||||
Pageable pageable = accessor.getPageable();
|
||||
Assert.notNull(pageable, "Pageable must not be null!");
|
||||
parsedStatement = parsedStatement.limit(pageable.getPageSize()).offset(
|
||||
Math.toIntExact(pageable.getOffset()));
|
||||
} else if (queryMethod.isSliceQuery()) {
|
||||
Pageable pageable = accessor.getPageable();
|
||||
Assert.notNull(pageable, "Pageable must not be null!");
|
||||
parsedStatement = parsedStatement.limit(pageable.getPageSize() + 1).offset(
|
||||
Math.toIntExact(pageable.getOffset()));
|
||||
}
|
||||
return parsedStatement;
|
||||
}
|
||||
|
||||
// getExpression() could do this itself, but pass as an arg to be consistent with StringN1qlBasedQuery
|
||||
private static Object[] getParameters(ParameterAccessor accessor) {
|
||||
ArrayList<Object> params = new ArrayList<>();
|
||||
for (Object o : accessor) {
|
||||
params.add(o);
|
||||
}
|
||||
return params.toArray();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -18,14 +18,13 @@ package org.springframework.data.couchbase.domain;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import com.couchbase.client.java.query.QueryScanConsistency;
|
||||
import org.springframework.data.couchbase.repository.Query;
|
||||
import org.springframework.data.couchbase.repository.ScanConsistency;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import com.couchbase.client.java.query.QueryScanConsistency;
|
||||
|
||||
/**
|
||||
* template class for Reactive Couchbase operations
|
||||
*
|
||||
@@ -65,4 +64,11 @@ public interface AirportRepository extends PagingAndSortingRepository<Airport, S
|
||||
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
|
||||
long count();
|
||||
|
||||
@Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter} " +
|
||||
" #{#projectIds != null ? 'AND iata IN $1' : ''} " +
|
||||
" #{#planIds != null ? 'AND icao IN $2' : ''} " +
|
||||
" #{#active != null ? 'AND false = $3' : ''} ")
|
||||
@ScanConsistency(query = QueryScanConsistency.REQUEST_PLUS)
|
||||
Long countFancyExpression(@Param("projectIds") List<String> projectIds, @Param("planIds") List<String> planIds, @Param("active") Boolean active);
|
||||
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ import org.springframework.data.couchbase.core.mapping.Document;
|
||||
* @author Michael Reiche
|
||||
*/
|
||||
|
||||
@Document(expiry = 5)
|
||||
@Document(expiry = 1)
|
||||
public class UserAnnotated extends User {
|
||||
|
||||
public UserAnnotated(String id, String firstname, String lastname) {
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.springframework.data.couchbase.repository;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.Callable;
|
||||
@@ -131,6 +132,9 @@ public class CouchbaseRepositoryQueryIntegrationTests extends ClusterAwareIntegr
|
||||
airportRepository.save(airport);
|
||||
}
|
||||
|
||||
Long count = airportRepository.countFancyExpression( Arrays.asList("JFK"), Arrays.asList("jfk"), false);
|
||||
assertEquals( 1, count);
|
||||
|
||||
long airportCount = airportRepository.count();
|
||||
assertEquals(7, airportCount);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user