diff --git a/src/main/java/org/springframework/data/couchbase/core/ReactiveUpsertByIdOperationSupport.java b/src/main/java/org/springframework/data/couchbase/core/ReactiveUpsertByIdOperationSupport.java
index 9dee87766..b92035905 100644
--- a/src/main/java/org/springframework/data/couchbase/core/ReactiveUpsertByIdOperationSupport.java
+++ b/src/main/java/org/springframework/data/couchbase/core/ReactiveUpsertByIdOperationSupport.java
@@ -97,7 +97,7 @@ private UpsertOptions buildUpsertOptions() {
} else if (durabilityLevel != DurabilityLevel.NONE) {
options.durability(durabilityLevel);
}
- if (expiry != null && !expiry.isZero()) {
+ if (expiry != null && ! expiry.isZero()) {
options.expiry(expiry);
} else if (domainType.isAnnotationPresent(Document.class)) {
Document documentAnn = domainType.getAnnotation(Document.class);
diff --git a/src/main/java/org/springframework/data/couchbase/repository/Query.java b/src/main/java/org/springframework/data/couchbase/repository/Query.java
index d18f90496..21562a787 100644
--- a/src/main/java/org/springframework/data/couchbase/repository/Query.java
+++ b/src/main/java/org/springframework/data/couchbase/repository/Query.java
@@ -23,7 +23,6 @@
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.
diff --git a/src/main/java/org/springframework/data/couchbase/repository/query/ReactiveStringN1qlBasedQuery.java b/src/main/java/org/springframework/data/couchbase/repository/query/ReactiveStringN1qlBasedQuery.java
deleted file mode 100644
index 5a1058a3d..000000000
--- a/src/main/java/org/springframework/data/couchbase/repository/query/ReactiveStringN1qlBasedQuery.java
+++ /dev/null
@@ -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.
- *
- * The statement can contain positional placeholders (eg. name = $1) that will map to the method's
- * parameters, in the same order.
- *
- * The statement can also contain SpEL expressions enclosed in #{ and }.
- *
- *
- * @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));
- }
-
-}
diff --git a/src/main/java/org/springframework/data/couchbase/repository/query/StringBasedN1qlQueryParser.java b/src/main/java/org/springframework/data/couchbase/repository/query/StringBasedN1qlQueryParser.java
index aea20d75e..b1e9e4956 100644
--- a/src/main/java/org/springframework/data/couchbase/repository/query/StringBasedN1qlQueryParser.java
+++ b/src/main/java/org/springframework/data/couchbase/repository/query/StringBasedN1qlQueryParser.java
@@ -32,9 +32,13 @@
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 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 parameterNames = new HashSet();
+ 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 String doParse(SpelExpressionParser parser, EvaluationContext evaluationC
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 @@ private PlaceholderType checkPlaceholders(String statement) {
}
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 N1qlSpelValues(String selectClause, String entityFields, String bucket, S
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