Skip to content

Adds ValueExpression support #1523

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-cassandra-parent</artifactId>
<version>4.4.0-SNAPSHOT</version>
<version>4.4.0-GH-1522-SNAPSHOT</version>
<packaging>pom</packaging>

<name>Spring Data for Apache Cassandra</name>
Expand Down Expand Up @@ -97,7 +97,7 @@
<hppc.version>0.5.4</hppc.version>
<multithreadedtc.version>1.01</multithreadedtc.version>
<project.type>multi</project.type>
<springdata.commons>3.4.0-SNAPSHOT</springdata.commons>
<springdata.commons>3.4.0-GH-3049-SNAPSHOT</springdata.commons>
</properties>

<dependencyManagement>
Expand Down
2 changes: 1 addition & 1 deletion spring-data-cassandra-distribution/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-cassandra-parent</artifactId>
<version>4.4.0-SNAPSHOT</version>
<version>4.4.0-GH-1522-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion spring-data-cassandra/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-cassandra-parent</artifactId>
<version>4.4.0-SNAPSHOT</version>
<version>4.4.0-GH-1522-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import java.util.Collections;
import java.util.List;

import org.springframework.data.mapping.model.SpELExpressionEvaluator;
import org.springframework.data.mapping.model.ValueExpressionEvaluator;
import org.springframework.data.repository.query.Parameter;
import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.lang.Nullable;
Expand All @@ -39,13 +39,13 @@ class BindingContext {

private final List<ParameterBinding> bindings;

private final SpELExpressionEvaluator evaluator;
private final ValueExpressionEvaluator evaluator;

/**
* Create new {@link BindingContext}.
*/
public BindingContext(CassandraParameters parameters, ParameterAccessor parameterAccessor,
List<ParameterBinding> bindings, SpELExpressionEvaluator evaluator) {
BindingContext(CassandraParameters parameters, ParameterAccessor parameterAccessor,
List<ParameterBinding> bindings, ValueExpressionEvaluator evaluator) {

this.parameters = parameters;
this.parameterAccessor = parameterAccessor;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright 2024 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.cassandra.repository.query;

import org.springframework.data.expression.ValueEvaluationContext;
import org.springframework.data.expression.ValueExpression;
import org.springframework.data.expression.ValueExpressionParser;
import org.springframework.data.mapping.model.ValueExpressionEvaluator;

/**
* @author Marcin Grzejszczak
* @author Mark Paluch
*/
class ContextualValueExpressionEvaluator implements ValueExpressionEvaluator {

private final ValueExpressionParser parser;

public ContextualValueExpressionEvaluator(ValueExpressionParser parser, ValueEvaluationContext evaluationContext) {
this.parser = parser;
this.evaluationContext = evaluationContext;
}

private final ValueEvaluationContext evaluationContext;

@SuppressWarnings("unchecked")
@Override
public <T> T evaluate(String expressionString) {
ValueExpression expression = parser.parse(expressionString);
return (T) expression.evaluate(evaluationContext);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
import org.springframework.data.cassandra.repository.Query.Idempotency;
import org.springframework.data.domain.Limit;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
import org.springframework.data.mapping.model.ValueExpressionEvaluator;
import org.springframework.data.repository.query.QueryCreationException;
import org.springframework.data.repository.query.ResultProcessor;
import org.springframework.data.repository.query.ReturnedType;
Expand Down Expand Up @@ -249,7 +249,7 @@ private boolean allowsFiltering() {
* @return the {@link Statement}.
*/
SimpleStatement select(StringBasedQuery stringBasedQuery, CassandraParameterAccessor parameterAccessor,
SpELExpressionEvaluator evaluator) {
ValueExpressionEvaluator evaluator) {

try {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,17 @@

import reactor.core.publisher.Mono;

import org.springframework.core.env.StandardEnvironment;
import org.springframework.data.cassandra.core.ReactiveCassandraOperations;
import org.springframework.data.cassandra.repository.Query;
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
import org.springframework.data.expression.ReactiveValueEvaluationContextProvider;
import org.springframework.data.expression.ValueEvaluationContextProvider;
import org.springframework.data.expression.ValueExpressionParser;
import org.springframework.data.mapping.model.ValueExpressionEvaluator;
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
import org.springframework.data.repository.query.QueryMethodValueEvaluationContextAccessor;
import org.springframework.data.repository.query.ReactiveQueryMethodEvaluationContextProvider;
import org.springframework.data.repository.query.ValueExpressionDelegate;
import org.springframework.data.spel.ExpressionDependencies;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
Expand All @@ -37,6 +43,7 @@
* index-based and expression parameters that are resolved during query execution.
*
* @author Mark Paluch
* @author Marcin Grzejszczak
* @see org.springframework.data.cassandra.repository.Query
* @see org.springframework.data.cassandra.repository.query.AbstractReactiveCassandraQuery
* @since 2.0
Expand All @@ -51,8 +58,9 @@ public class ReactiveStringBasedCassandraQuery extends AbstractReactiveCassandra

private final boolean isExistsQuery;

private final ExpressionParser expressionParser;
private final ReactiveQueryMethodEvaluationContextProvider evaluationContextProvider;
private final ValueExpressionDelegate delegate;

private final ReactiveValueEvaluationContextProvider valueEvaluationContextProvider;

/**
* Create a new {@link ReactiveStringBasedCassandraQuery} for the given {@link CassandraQueryMethod},
Expand All @@ -66,7 +74,9 @@ public class ReactiveStringBasedCassandraQuery extends AbstractReactiveCassandra
* {@link org.springframework.expression.spel.support.StandardEvaluationContext}.
* @see org.springframework.data.cassandra.repository.query.ReactiveCassandraQueryMethod
* @see org.springframework.data.cassandra.core.ReactiveCassandraOperations
* @deprecated since 4.4, use the constructors accepting {@link ValueExpressionDelegate} instead.
*/
@Deprecated(since = "4.4")
public ReactiveStringBasedCassandraQuery(ReactiveCassandraQueryMethod queryMethod,
ReactiveCassandraOperations operations, ExpressionParser expressionParser,
ReactiveQueryMethodEvaluationContextProvider evaluationContextProvider) {
Expand All @@ -86,19 +96,59 @@ public ReactiveStringBasedCassandraQuery(ReactiveCassandraQueryMethod queryMetho
* {@link org.springframework.expression.spel.support.StandardEvaluationContext}.
* @see org.springframework.data.cassandra.repository.query.ReactiveCassandraQueryMethod
* @see org.springframework.data.cassandra.core.ReactiveCassandraOperations
* @deprecated since 4.4, use the constructors accepting {@link ValueExpressionDelegate} instead.
*/
@Deprecated(since = "4.4")
public ReactiveStringBasedCassandraQuery(String query, ReactiveCassandraQueryMethod method,
ReactiveCassandraOperations operations, ExpressionParser expressionParser,
ReactiveQueryMethodEvaluationContextProvider evaluationContextProvider) {

this(query, method, operations, new ValueExpressionDelegate(new QueryMethodValueEvaluationContextAccessor(new StandardEnvironment(), evaluationContextProvider.getEvaluationContextProvider()), ValueExpressionParser.create(() -> expressionParser)));
}

/**
* Create a new {@link ReactiveStringBasedCassandraQuery} for the given {@link CassandraQueryMethod},
* {@link ReactiveCassandraOperations}, {@link ValueExpressionDelegate}
*
* @param queryMethod {@link ReactiveCassandraQueryMethod} on which this query is based.
* @param operations {@link ReactiveCassandraOperations} used to perform data access in Cassandra.
* @param delegate {@link ValueExpressionDelegate} used to parse expressions in the query.
* @see org.springframework.data.cassandra.repository.query.ReactiveCassandraQueryMethod
* @see org.springframework.data.cassandra.core.ReactiveCassandraOperations
* @since 4.4
*/
public ReactiveStringBasedCassandraQuery(ReactiveCassandraQueryMethod queryMethod,
ReactiveCassandraOperations operations, ValueExpressionDelegate delegate) {

this(queryMethod.getRequiredAnnotatedQuery(), queryMethod, operations, delegate);
}

/**
* Create a new {@link ReactiveStringBasedCassandraQuery} for the given {@code query}, {@link CassandraQueryMethod},
* {@link ReactiveCassandraOperations}, {@link ValueExpressionDelegate}
*
* @param method {@link ReactiveCassandraQueryMethod} on which this query is based.
* @param operations {@link ReactiveCassandraOperations} used to perform data access in Cassandra.
* @param delegate {@link SpelExpressionParser} used to parse expressions in the query.
* @see org.springframework.data.cassandra.repository.query.ReactiveCassandraQueryMethod
* @see org.springframework.data.cassandra.core.ReactiveCassandraOperations
* @since 4.4
*/
public ReactiveStringBasedCassandraQuery(String query, ReactiveCassandraQueryMethod method,
ReactiveCassandraOperations operations, ValueExpressionDelegate delegate) {

super(method, operations);

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

this.expressionParser = expressionParser;
this.evaluationContextProvider = evaluationContextProvider;
this.delegate = delegate;

this.stringBasedQuery = new StringBasedQuery(query, method.getParameters(), expressionParser);
this.stringBasedQuery = new StringBasedQuery(query, method.getParameters(), delegate);

ValueEvaluationContextProvider valueContextProvider = delegate.createValueContextProvider(
method.getParameters());
Assert.isInstanceOf(ReactiveValueEvaluationContextProvider.class, valueContextProvider, "ValueEvaluationContextProvider must be reactive");
this.valueEvaluationContextProvider = (ReactiveValueEvaluationContextProvider) valueContextProvider;

if (method.hasAnnotatedQuery()) {

Expand Down Expand Up @@ -126,10 +176,9 @@ public Mono<SimpleStatement> createQuery(CassandraParameterAccessor parameterAcc
StringBasedQuery query = getStringBasedQuery();
ConvertingParameterAccessor parameterAccessorToUse = new ConvertingParameterAccessor(
getReactiveCassandraOperations().getConverter(), parameterAccessor);
Mono<SpELExpressionEvaluator> spelEvaluator = getSpelEvaluatorFor(query.getExpressionDependencies(),
parameterAccessorToUse);

return spelEvaluator.map(it -> getQueryStatementCreator().select(query, parameterAccessorToUse, it));
return getValueExpressionEvaluatorLater(query.getExpressionDependencies(), parameterAccessor)
.map(it -> getQueryStatementCreator().select(query, parameterAccessorToUse, it));
}

@Override
Expand All @@ -152,21 +201,9 @@ protected boolean isModifyingQuery() {
return false;
}

/**
* Obtain a {@link Mono publisher} emitting the {@link SpELExpressionEvaluator} suitable to evaluate expressions
* backed by the given dependencies.
*
* @param dependencies must not be {@literal null}.
* @param accessor must not be {@literal null}.
* @return a {@link Mono} emitting the {@link SpELExpressionEvaluator} when ready.
*/
private Mono<SpELExpressionEvaluator> getSpelEvaluatorFor(ExpressionDependencies dependencies,
private Mono<ValueExpressionEvaluator> getValueExpressionEvaluatorLater(ExpressionDependencies dependencies,
CassandraParameterAccessor accessor) {

return evaluationContextProvider
.getEvaluationContextLater(getQueryMethod().getParameters(), accessor.getValues(), dependencies)
.map(evaluationContext -> (SpELExpressionEvaluator) new DefaultSpELExpressionEvaluator(expressionParser,
evaluationContext))
.defaultIfEmpty(DefaultSpELExpressionEvaluator.unsupported());
return valueEvaluationContextProvider.getEvaluationContextLater(accessor.getValues(), dependencies)
.map(evaluationContext -> new ContextualValueExpressionEvaluator(delegate, evaluationContext));
}
}
Loading