Skip to content

Commit 9ebd3db

Browse files
marcingrzejszczakmp911de
authored andcommitted
Added support for Repository Query Method ValueExpressions.
Closes #1522 Original pull request: #1523
1 parent 77453ae commit 9ebd3db

File tree

10 files changed

+270
-91
lines changed

10 files changed

+270
-91
lines changed

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/BindingContext.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import java.util.Collections;
2020
import java.util.List;
2121

22-
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
22+
import org.springframework.data.mapping.model.ValueExpressionEvaluator;
2323
import org.springframework.data.repository.query.Parameter;
2424
import org.springframework.data.repository.query.ParameterAccessor;
2525
import org.springframework.lang.Nullable;
@@ -39,13 +39,13 @@ class BindingContext {
3939

4040
private final List<ParameterBinding> bindings;
4141

42-
private final SpELExpressionEvaluator evaluator;
42+
private final ValueExpressionEvaluator evaluator;
4343

4444
/**
4545
* Create new {@link BindingContext}.
4646
*/
47-
public BindingContext(CassandraParameters parameters, ParameterAccessor parameterAccessor,
48-
List<ParameterBinding> bindings, SpELExpressionEvaluator evaluator) {
47+
BindingContext(CassandraParameters parameters, ParameterAccessor parameterAccessor,
48+
List<ParameterBinding> bindings, ValueExpressionEvaluator evaluator) {
4949

5050
this.parameters = parameters;
5151
this.parameterAccessor = parameterAccessor;

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/QueryStatementCreator.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
import org.springframework.data.cassandra.repository.Query.Idempotency;
3333
import org.springframework.data.domain.Limit;
3434
import org.springframework.data.mapping.context.MappingContext;
35-
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
35+
import org.springframework.data.mapping.model.ValueExpressionEvaluator;
3636
import org.springframework.data.repository.query.QueryCreationException;
3737
import org.springframework.data.repository.query.ResultProcessor;
3838
import org.springframework.data.repository.query.ReturnedType;
@@ -249,7 +249,7 @@ private boolean allowsFiltering() {
249249
* @return the {@link Statement}.
250250
*/
251251
SimpleStatement select(StringBasedQuery stringBasedQuery, CassandraParameterAccessor parameterAccessor,
252-
SpELExpressionEvaluator evaluator) {
252+
ValueExpressionEvaluator evaluator) {
253253

254254
try {
255255

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/ReactiveStringBasedCassandraQuery.java

Lines changed: 60 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,17 @@
1717

1818
import reactor.core.publisher.Mono;
1919

20+
import org.springframework.core.env.StandardEnvironment;
2021
import org.springframework.data.cassandra.core.ReactiveCassandraOperations;
2122
import org.springframework.data.cassandra.repository.Query;
22-
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
23+
import org.springframework.data.expression.ReactiveValueEvaluationContextProvider;
24+
import org.springframework.data.expression.ValueEvaluationContextProvider;
25+
import org.springframework.data.expression.ValueExpressionParser;
26+
import org.springframework.data.mapping.model.ValueExpressionEvaluator;
2327
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
28+
import org.springframework.data.repository.query.QueryMethodValueEvaluationContextAccessor;
2429
import org.springframework.data.repository.query.ReactiveQueryMethodEvaluationContextProvider;
30+
import org.springframework.data.repository.query.ValueExpressionDelegate;
2531
import org.springframework.data.spel.ExpressionDependencies;
2632
import org.springframework.expression.ExpressionParser;
2733
import org.springframework.expression.spel.standard.SpelExpressionParser;
@@ -51,8 +57,9 @@ public class ReactiveStringBasedCassandraQuery extends AbstractReactiveCassandra
5157

5258
private final boolean isExistsQuery;
5359

54-
private final ExpressionParser expressionParser;
55-
private final ReactiveQueryMethodEvaluationContextProvider evaluationContextProvider;
60+
private final ValueExpressionDelegate delegate;
61+
62+
private final ReactiveValueEvaluationContextProvider valueEvaluationContextProvider;
5663

5764
/**
5865
* Create a new {@link ReactiveStringBasedCassandraQuery} for the given {@link CassandraQueryMethod},
@@ -66,7 +73,9 @@ public class ReactiveStringBasedCassandraQuery extends AbstractReactiveCassandra
6673
* {@link org.springframework.expression.spel.support.StandardEvaluationContext}.
6774
* @see org.springframework.data.cassandra.repository.query.ReactiveCassandraQueryMethod
6875
* @see org.springframework.data.cassandra.core.ReactiveCassandraOperations
76+
* @deprecated since 4.4, use the constructors accepting {@link ValueExpressionDelegate} instead.
6977
*/
78+
@Deprecated(since = "4.4")
7079
public ReactiveStringBasedCassandraQuery(ReactiveCassandraQueryMethod queryMethod,
7180
ReactiveCassandraOperations operations, ExpressionParser expressionParser,
7281
ReactiveQueryMethodEvaluationContextProvider evaluationContextProvider) {
@@ -86,19 +95,59 @@ public ReactiveStringBasedCassandraQuery(ReactiveCassandraQueryMethod queryMetho
8695
* {@link org.springframework.expression.spel.support.StandardEvaluationContext}.
8796
* @see org.springframework.data.cassandra.repository.query.ReactiveCassandraQueryMethod
8897
* @see org.springframework.data.cassandra.core.ReactiveCassandraOperations
98+
* @deprecated since 4.4, use the constructors accepting {@link ValueExpressionDelegate} instead.
8999
*/
100+
@Deprecated(since = "4.4")
90101
public ReactiveStringBasedCassandraQuery(String query, ReactiveCassandraQueryMethod method,
91102
ReactiveCassandraOperations operations, ExpressionParser expressionParser,
92103
ReactiveQueryMethodEvaluationContextProvider evaluationContextProvider) {
93104

105+
this(query, method, operations, new ValueExpressionDelegate(new QueryMethodValueEvaluationContextAccessor(new StandardEnvironment(), evaluationContextProvider.getEvaluationContextProvider()), ValueExpressionParser.create(() -> expressionParser)));
106+
}
107+
108+
/**
109+
* Create a new {@link ReactiveStringBasedCassandraQuery} for the given {@link CassandraQueryMethod},
110+
* {@link ReactiveCassandraOperations}, {@link ValueExpressionDelegate}
111+
*
112+
* @param queryMethod {@link ReactiveCassandraQueryMethod} on which this query is based.
113+
* @param operations {@link ReactiveCassandraOperations} used to perform data access in Cassandra.
114+
* @param delegate {@link ValueExpressionDelegate} used to parse expressions in the query.
115+
* @see org.springframework.data.cassandra.repository.query.ReactiveCassandraQueryMethod
116+
* @see org.springframework.data.cassandra.core.ReactiveCassandraOperations
117+
* @since 4.4
118+
*/
119+
public ReactiveStringBasedCassandraQuery(ReactiveCassandraQueryMethod queryMethod,
120+
ReactiveCassandraOperations operations, ValueExpressionDelegate delegate) {
121+
122+
this(queryMethod.getRequiredAnnotatedQuery(), queryMethod, operations, delegate);
123+
}
124+
125+
/**
126+
* Create a new {@link ReactiveStringBasedCassandraQuery} for the given {@code query}, {@link CassandraQueryMethod},
127+
* {@link ReactiveCassandraOperations}, {@link ValueExpressionDelegate}
128+
*
129+
* @param method {@link ReactiveCassandraQueryMethod} on which this query is based.
130+
* @param operations {@link ReactiveCassandraOperations} used to perform data access in Cassandra.
131+
* @param delegate {@link SpelExpressionParser} used to parse expressions in the query.
132+
* @see org.springframework.data.cassandra.repository.query.ReactiveCassandraQueryMethod
133+
* @see org.springframework.data.cassandra.core.ReactiveCassandraOperations
134+
* @since 4.4
135+
*/
136+
public ReactiveStringBasedCassandraQuery(String query, ReactiveCassandraQueryMethod method,
137+
ReactiveCassandraOperations operations, ValueExpressionDelegate delegate) {
138+
94139
super(method, operations);
95140

96141
Assert.hasText(query, "Query must not be empty");
97142

98-
this.expressionParser = expressionParser;
99-
this.evaluationContextProvider = evaluationContextProvider;
143+
this.delegate = delegate;
100144

101-
this.stringBasedQuery = new StringBasedQuery(query, method.getParameters(), expressionParser);
145+
this.stringBasedQuery = new StringBasedQuery(query, method.getParameters(), delegate);
146+
147+
ValueEvaluationContextProvider valueContextProvider = delegate.createValueContextProvider(
148+
method.getParameters());
149+
Assert.isInstanceOf(ReactiveValueEvaluationContextProvider.class, valueContextProvider, "ValueEvaluationContextProvider must be reactive");
150+
this.valueEvaluationContextProvider = (ReactiveValueEvaluationContextProvider) valueContextProvider;
102151

103152
if (method.hasAnnotatedQuery()) {
104153

@@ -126,10 +175,9 @@ public Mono<SimpleStatement> createQuery(CassandraParameterAccessor parameterAcc
126175
StringBasedQuery query = getStringBasedQuery();
127176
ConvertingParameterAccessor parameterAccessorToUse = new ConvertingParameterAccessor(
128177
getReactiveCassandraOperations().getConverter(), parameterAccessor);
129-
Mono<SpELExpressionEvaluator> spelEvaluator = getSpelEvaluatorFor(query.getExpressionDependencies(),
130-
parameterAccessorToUse);
131178

132-
return spelEvaluator.map(it -> getQueryStatementCreator().select(query, parameterAccessorToUse, it));
179+
return getValueExpressionEvaluatorLater(query.getExpressionDependencies(), parameterAccessor)
180+
.map(it -> getQueryStatementCreator().select(query, parameterAccessorToUse, it));
133181
}
134182

135183
@Override
@@ -152,21 +200,9 @@ protected boolean isModifyingQuery() {
152200
return false;
153201
}
154202

155-
/**
156-
* Obtain a {@link Mono publisher} emitting the {@link SpELExpressionEvaluator} suitable to evaluate expressions
157-
* backed by the given dependencies.
158-
*
159-
* @param dependencies must not be {@literal null}.
160-
* @param accessor must not be {@literal null}.
161-
* @return a {@link Mono} emitting the {@link SpELExpressionEvaluator} when ready.
162-
*/
163-
private Mono<SpELExpressionEvaluator> getSpelEvaluatorFor(ExpressionDependencies dependencies,
203+
private Mono<ValueExpressionEvaluator> getValueExpressionEvaluatorLater(ExpressionDependencies dependencies,
164204
CassandraParameterAccessor accessor) {
165-
166-
return evaluationContextProvider
167-
.getEvaluationContextLater(getQueryMethod().getParameters(), accessor.getValues(), dependencies)
168-
.map(evaluationContext -> (SpELExpressionEvaluator) new DefaultSpELExpressionEvaluator(expressionParser,
169-
evaluationContext))
170-
.defaultIfEmpty(DefaultSpELExpressionEvaluator.unsupported());
205+
return valueEvaluationContextProvider.getEvaluationContextLater(accessor.getValues(), dependencies)
206+
.map(evaluationContext -> new ValueExpressionDelegateValueExpressionEvaluator(delegate, valueExpression -> evaluationContext));
171207
}
172208
}

spring-data-cassandra/src/main/java/org/springframework/data/cassandra/repository/query/StringBasedCassandraQuery.java

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,14 @@
1515
*/
1616
package org.springframework.data.cassandra.repository.query;
1717

18+
import org.springframework.core.env.StandardEnvironment;
1819
import org.springframework.data.cassandra.core.CassandraOperations;
1920
import org.springframework.data.cassandra.repository.Query;
21+
import org.springframework.data.expression.ValueEvaluationContext;
22+
import org.springframework.data.expression.ValueExpressionParser;
2023
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
21-
import org.springframework.expression.EvaluationContext;
24+
import org.springframework.data.repository.query.QueryMethodValueEvaluationContextAccessor;
25+
import org.springframework.data.repository.query.ValueExpressionDelegate;
2226
import org.springframework.expression.ExpressionParser;
2327
import org.springframework.expression.spel.standard.SpelExpressionParser;
2428

@@ -46,8 +50,7 @@ public class StringBasedCassandraQuery extends AbstractCassandraQuery {
4650

4751
private final boolean isExistsQuery;
4852

49-
private final ExpressionParser expressionParser;
50-
private final QueryMethodEvaluationContextProvider evaluationContextProvider;
53+
private final ValueExpressionDelegate valueExpressionDelegate;
5154

5255
/**
5356
* Create a new {@link StringBasedCassandraQuery} for the given {@link CassandraQueryMethod},
@@ -60,35 +63,52 @@ public class StringBasedCassandraQuery extends AbstractCassandraQuery {
6063
* {@link org.springframework.expression.spel.support.StandardEvaluationContext}.
6164
* @see org.springframework.data.cassandra.repository.query.CassandraQueryMethod
6265
* @see org.springframework.data.cassandra.core.CassandraOperations
66+
* @deprecated use the constructor version with {@link ValueExpressionDelegate}
6367
*/
68+
@Deprecated(since = "4.4")
6469
public StringBasedCassandraQuery(CassandraQueryMethod queryMethod, CassandraOperations operations,
6570
ExpressionParser expressionParser, QueryMethodEvaluationContextProvider evaluationContextProvider) {
6671

6772
this(queryMethod.getRequiredAnnotatedQuery(), queryMethod, operations, expressionParser, evaluationContextProvider);
6873
}
6974

75+
/**
76+
* Create a new {@link StringBasedCassandraQuery} for the given {@link CassandraQueryMethod},
77+
* {@link CassandraOperations}, {@link ValueExpressionDelegate}.
78+
*
79+
* @param queryMethod {@link CassandraQueryMethod} on which this query is based.
80+
* @param operations {@link CassandraOperations} used to perform data access in Cassandra.
81+
* @param valueExpressionDelegate {@link ValueExpressionDelegate} used to parse expressions in the query.
82+
* @see org.springframework.data.cassandra.repository.query.CassandraQueryMethod
83+
* @see org.springframework.data.cassandra.core.CassandraOperations
84+
* @since 4.4
85+
*/
86+
public StringBasedCassandraQuery(CassandraQueryMethod queryMethod, CassandraOperations operations,
87+
ValueExpressionDelegate valueExpressionDelegate) {
88+
89+
this(queryMethod.getRequiredAnnotatedQuery(), queryMethod, operations, valueExpressionDelegate);
90+
}
91+
7092
/**
7193
* Create a new {@link StringBasedCassandraQuery} for the given {@code query}, {@link CassandraQueryMethod},
72-
* {@link CassandraOperations}, {@link SpelExpressionParser}, and {@link QueryMethodEvaluationContextProvider}.
94+
* {@link CassandraOperations}, {@link ValueExpressionDelegate}.
7395
*
7496
* @param query {@link String} containing the Apache Cassandra CQL query to execute.
7597
* @param method {@link CassandraQueryMethod} on which this query is based.
7698
* @param operations {@link CassandraOperations} used to perform data access in Cassandra.
77-
* @param expressionParser {@link SpelExpressionParser} used to parse expressions in the query.
78-
* @param evaluationContextProvider {@link QueryMethodEvaluationContextProvider} used to access the potentially shared
79-
* {@link org.springframework.expression.spel.support.StandardEvaluationContext}.
99+
* @param valueExpressionDelegate {@link ValueExpressionDelegate} used to parse expressions in the query.
80100
* @see org.springframework.data.cassandra.repository.query.CassandraQueryMethod
81101
* @see org.springframework.data.cassandra.core.CassandraOperations
102+
* @since 4.4
82103
*/
83104
public StringBasedCassandraQuery(String query, CassandraQueryMethod method, CassandraOperations operations,
84-
ExpressionParser expressionParser, QueryMethodEvaluationContextProvider evaluationContextProvider) {
105+
ValueExpressionDelegate valueExpressionDelegate) {
85106

86107
super(method, operations);
87108

88-
this.expressionParser = expressionParser;
89-
this.evaluationContextProvider = evaluationContextProvider;
109+
this.valueExpressionDelegate = valueExpressionDelegate;
90110

91-
this.stringBasedQuery = new StringBasedQuery(query, method.getParameters(), expressionParser);
111+
this.stringBasedQuery = new StringBasedQuery(query, method.getParameters(), valueExpressionDelegate);
92112

93113
if (method.hasAnnotatedQuery()) {
94114

@@ -106,6 +126,26 @@ public StringBasedCassandraQuery(String query, CassandraQueryMethod method, Cass
106126
}
107127
}
108128

129+
/**
130+
* Create a new {@link StringBasedCassandraQuery} for the given {@code query}, {@link CassandraQueryMethod},
131+
* {@link CassandraOperations}, {@link SpelExpressionParser}, and {@link QueryMethodEvaluationContextProvider}.
132+
*
133+
* @param query {@link String} containing the Apache Cassandra CQL query to execute.
134+
* @param method {@link CassandraQueryMethod} on which this query is based.
135+
* @param operations {@link CassandraOperations} used to perform data access in Cassandra.
136+
* @param expressionParser {@link SpelExpressionParser} used to parse expressions in the query.
137+
* @param evaluationContextProvider {@link QueryMethodEvaluationContextProvider} used to access the potentially shared
138+
* {@link org.springframework.expression.spel.support.StandardEvaluationContext}.
139+
* @see org.springframework.data.cassandra.repository.query.CassandraQueryMethod
140+
* @see org.springframework.data.cassandra.core.CassandraOperations
141+
* @deprecated use the constructor version with {@link ValueExpressionDelegate}
142+
*/
143+
@Deprecated(since = "4.4")
144+
public StringBasedCassandraQuery(String query, CassandraQueryMethod method, CassandraOperations operations,
145+
ExpressionParser expressionParser, QueryMethodEvaluationContextProvider evaluationContextProvider) {
146+
this(query, method, operations, new ValueExpressionDelegate(new QueryMethodValueEvaluationContextAccessor(new StandardEnvironment(), evaluationContextProvider.getEvaluationContextProvider()), ValueExpressionParser.create(() -> expressionParser)));
147+
}
148+
109149
protected StringBasedQuery getStringBasedQuery() {
110150
return this.stringBasedQuery;
111151
}
@@ -116,11 +156,10 @@ public SimpleStatement createQuery(CassandraParameterAccessor parameterAccessor)
116156
StringBasedQuery query = getStringBasedQuery();
117157
ConvertingParameterAccessor parameterAccessorToUse = new ConvertingParameterAccessor(getOperations().getConverter(),
118158
parameterAccessor);
119-
EvaluationContext evaluationContext = evaluationContextProvider.getEvaluationContext(
120-
getQueryMethod().getParameters(), parameterAccessorToUse.getValues(), query.getExpressionDependencies());
159+
ValueEvaluationContext evaluationContext = valueExpressionDelegate.createValueContextProvider(
160+
getQueryMethod().getParameters()).getEvaluationContext(parameterAccessorToUse.getValues(), query.getExpressionDependencies());
121161

122-
return getQueryStatementCreator().select(query, parameterAccessorToUse,
123-
new DefaultSpELExpressionEvaluator(expressionParser, evaluationContext));
162+
return getQueryStatementCreator().select(query, parameterAccessorToUse, new ValueExpressionDelegateValueExpressionEvaluator(valueExpressionDelegate, valueExpression -> evaluationContext));
124163
}
125164

126165
@Override

0 commit comments

Comments
 (0)