|
32 | 32 | import org.springframework.data.couchbase.core.query.N1QLExpression;
|
33 | 33 | import org.springframework.data.couchbase.repository.Query;
|
34 | 34 | import org.springframework.data.couchbase.repository.query.support.N1qlUtils;
|
| 35 | +import org.springframework.data.domain.Pageable; |
| 36 | +import org.springframework.data.domain.Sort; |
35 | 37 | import org.springframework.data.repository.query.Parameter;
|
36 | 38 | import org.springframework.data.repository.query.ParameterAccessor;
|
37 | 39 | import org.springframework.data.repository.query.QueryMethod;
|
| 40 | +import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider; |
| 41 | +import org.springframework.data.repository.query.ReturnedType; |
38 | 42 | import org.springframework.expression.EvaluationContext;
|
39 | 43 | import org.springframework.expression.common.TemplateParserContext;
|
40 | 44 | import org.springframework.expression.spel.standard.SpelExpressionParser;
|
41 | 45 |
|
42 | 46 | import com.couchbase.client.java.json.JsonArray;
|
43 | 47 | import com.couchbase.client.java.json.JsonObject;
|
44 | 48 | import com.couchbase.client.java.json.JsonValue;
|
| 49 | +import org.springframework.util.Assert; |
45 | 50 |
|
46 | 51 | /**
|
47 | 52 | * @author Subhashni Balakrishnan
|
@@ -103,20 +108,23 @@ public class StringBasedN1qlQueryParser {
|
103 | 108 | private static final Logger LOGGER = LoggerFactory.getLogger(StringBasedN1qlQueryParser.class);
|
104 | 109 | private final String statement;
|
105 | 110 | private final QueryMethod queryMethod;
|
106 |
| - private final PlaceholderType placeHolderType; |
| 111 | + private PlaceholderType placeHolderType; |
107 | 112 | private final N1qlSpelValues statementContext;
|
108 | 113 | private final N1qlSpelValues countContext;
|
109 | 114 | private final CouchbaseConverter couchbaseConverter;
|
110 | 115 | private final Collection<String> parameterNames = new HashSet<String>();
|
| 116 | + public final N1QLExpression parsedExpression; |
111 | 117 |
|
112 | 118 | public StringBasedN1qlQueryParser(String statement, QueryMethod queryMethod, String bucketName,
|
113 |
| - CouchbaseConverter couchbaseConverter, String typeField, String typeValue) { |
| 119 | + CouchbaseConverter couchbaseConverter, String typeField, String typeValue, ParameterAccessor accessor, |
| 120 | + SpelExpressionParser parser, QueryMethodEvaluationContextProvider evaluationContextProvider) { |
114 | 121 | this.statement = statement;
|
115 | 122 | this.queryMethod = queryMethod;
|
116 |
| - this.placeHolderType = checkPlaceholders(statement); |
117 | 123 | this.statementContext = createN1qlSpelValues(bucketName, typeField, typeValue, false);
|
118 | 124 | this.countContext = createN1qlSpelValues(bucketName, typeField, typeValue, true);
|
119 | 125 | this.couchbaseConverter = couchbaseConverter;
|
| 126 | + this.parsedExpression = getExpression(accessor, getParameters(accessor), null, parser, evaluationContextProvider); |
| 127 | + checkPlaceholders( this.parsedExpression.toString() ); |
120 | 128 | }
|
121 | 129 |
|
122 | 130 | public static N1qlSpelValues createN1qlSpelValues(String bucketName, String typeField, String typeValue,
|
@@ -151,7 +159,7 @@ public String doParse(SpelExpressionParser parser, EvaluationContext evaluationC
|
151 | 159 | return parsedExpression.getValue(evaluationContext, String.class);
|
152 | 160 | }
|
153 | 161 |
|
154 |
| - private PlaceholderType checkPlaceholders(String statement) { |
| 162 | + private void checkPlaceholders(String statement) { |
155 | 163 |
|
156 | 164 | Matcher quoteMatcher = QUOTE_DETECTION_PATTERN.matcher(statement);
|
157 | 165 | Matcher positionMatcher = POSITIONAL_PLACEHOLDER_PATTERN.matcher(statement);
|
@@ -192,11 +200,11 @@ private PlaceholderType checkPlaceholders(String statement) {
|
192 | 200 | }
|
193 | 201 |
|
194 | 202 | if (posCount > 0) {
|
195 |
| - return PlaceholderType.POSITIONAL; |
| 203 | + placeHolderType = PlaceholderType.POSITIONAL; |
196 | 204 | } else if (namedCount > 0) {
|
197 |
| - return PlaceholderType.NAMED; |
| 205 | + placeHolderType = PlaceholderType.NAMED; |
198 | 206 | } else {
|
199 |
| - return PlaceholderType.NONE; |
| 207 | + placeHolderType = PlaceholderType.NONE; |
200 | 208 | }
|
201 | 209 | }
|
202 | 210 |
|
@@ -402,5 +410,39 @@ public N1qlSpelValues(String selectClause, String entityFields, String bucket, S
|
402 | 410 | this.returning = returning;
|
403 | 411 | }
|
404 | 412 | }
|
| 413 | + // copied from StringN1qlBasedQuery |
| 414 | + private N1QLExpression getExpression(ParameterAccessor accessor, Object[] runtimeParameters, |
| 415 | + ReturnedType returnedType, SpelExpressionParser parser, QueryMethodEvaluationContextProvider evaluationContextProvider) { |
| 416 | + boolean isCountQuery = queryMethod.getName().toLowerCase().startsWith("count"); // should be queryMethod.isCountQuery() |
| 417 | + EvaluationContext evaluationContext = evaluationContextProvider |
| 418 | + .getEvaluationContext(queryMethod.getParameters(), runtimeParameters); |
| 419 | + N1QLExpression parsedStatement = x(this.doParse(parser, evaluationContext, isCountQuery)); |
| 420 | + |
| 421 | + Sort sort = accessor.getSort(); |
| 422 | + if (sort.isSorted()) { |
| 423 | + N1QLExpression[] cbSorts = N1qlUtils.createSort(sort); |
| 424 | + parsedStatement = parsedStatement.orderBy(cbSorts); |
| 425 | + } |
| 426 | + if (queryMethod.isPageQuery()) { |
| 427 | + Pageable pageable = accessor.getPageable(); |
| 428 | + Assert.notNull(pageable, "Pageable must not be null!"); |
| 429 | + parsedStatement = parsedStatement.limit(pageable.getPageSize()).offset( |
| 430 | + Math.toIntExact(pageable.getOffset())); |
| 431 | + } else if (queryMethod.isSliceQuery()) { |
| 432 | + Pageable pageable = accessor.getPageable(); |
| 433 | + Assert.notNull(pageable, "Pageable must not be null!"); |
| 434 | + parsedStatement = parsedStatement.limit(pageable.getPageSize() + 1).offset( |
| 435 | + Math.toIntExact(pageable.getOffset())); |
| 436 | + } |
| 437 | + return parsedStatement; |
| 438 | + } |
405 | 439 |
|
| 440 | + // getExpression() could do this itself, but pass as an arg to be consistent with StringN1qlBasedQuery |
| 441 | + private static Object[] getParameters(ParameterAccessor accessor) { |
| 442 | + ArrayList<Object> params = new ArrayList<>(); |
| 443 | + for (Object o : accessor) { |
| 444 | + params.add(o); |
| 445 | + } |
| 446 | + return params.toArray(); |
| 447 | + } |
406 | 448 | }
|
0 commit comments