#414 - Adopt SpEL support to use ReactiveEvaluationContextProvider.

We now defer query creation to obtain and resolve SpEL expression dependencies using reactive SpEL context extensions.
This commit is contained in:
Mark Paluch
2020-08-05 12:17:35 +02:00
parent d3276b9d7e
commit ecbb8d8e78
13 changed files with 336 additions and 173 deletions

View File

@@ -15,13 +15,11 @@
*/
package org.springframework.data.r2dbc.repository.query;
import kotlin.Unit;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.reactivestreams.Publisher;
import org.springframework.core.KotlinDetector;
import org.springframework.data.mapping.model.EntityInstantiators;
import org.springframework.data.r2dbc.convert.EntityRowMapper;
import org.springframework.data.r2dbc.convert.R2dbcConverter;
@@ -34,10 +32,10 @@ import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.repository.query.ResultProcessor;
import org.springframework.data.repository.query.ReturnedType;
import org.springframework.data.util.ReflectionUtils;
import org.springframework.r2dbc.core.DatabaseClient;
import org.springframework.r2dbc.core.FetchSpec;
import org.springframework.r2dbc.core.RowsFetchSpec;
import org.springframework.data.util.ReflectionUtils;
import org.springframework.util.Assert;
/**
@@ -86,29 +84,15 @@ public abstract class AbstractR2dbcQuery implements RepositoryQuery {
*/
public Object execute(Object[] parameters) {
return method.hasReactiveWrapperParameter() ? executeDeferred(parameters)
: execute(new RelationalParametersParameterAccessor(method, parameters));
RelationalParameterAccessor parameterAccessor = new RelationalParametersParameterAccessor(method, parameters);
return createQuery(parameterAccessor).flatMapMany(it -> executeQuery(parameterAccessor, it));
}
@SuppressWarnings("unchecked")
private Object executeDeferred(Object[] parameters) {
R2dbcParameterAccessor parameterAccessor = new R2dbcParameterAccessor(method, parameters);
if (getQueryMethod().isCollectionQuery()) {
return Flux.defer(() -> (Publisher<Object>) execute(parameterAccessor));
}
return Mono.defer(() -> (Mono<Object>) execute(parameterAccessor));
}
private Object execute(RelationalParameterAccessor parameterAccessor) {
// TODO: ConvertingParameterAccessor
BindableQuery query = createQuery(parameterAccessor);
private Publisher<?> executeQuery(RelationalParameterAccessor parameterAccessor, BindableQuery it) {
ResultProcessor processor = method.getResultProcessor().withDynamicProjection(parameterAccessor);
DatabaseClient.GenericExecuteSpec boundQuery = query.bind(databaseClient.sql(query));
DatabaseClient.GenericExecuteSpec boundQuery = it.bind(databaseClient.sql(it));
FetchSpec<?> fetchSpec;
if (requiresMapping()) {
@@ -178,9 +162,9 @@ public abstract class AbstractR2dbcQuery implements RepositoryQuery {
* Creates a {@link BindableQuery} instance using the given {@link ParameterAccessor}
*
* @param accessor must not be {@literal null}.
* @return the {@link BindableQuery}.
* @return a mono emitting a {@link BindableQuery}.
*/
protected abstract BindableQuery createQuery(RelationalParameterAccessor accessor);
protected abstract Mono<BindableQuery> createQuery(RelationalParameterAccessor accessor);
private static class FetchSpecAdapter<T> implements FetchSpec<T> {

View File

@@ -0,0 +1,80 @@
/*
* Copyright 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.r2dbc.repository.query;
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.r2dbc.core.Parameter;
/**
* Simple {@link R2dbcSpELExpressionEvaluator} implementation using {@link ExpressionParser} and
* {@link EvaluationContext}.
*
* @author Mark Paluch
* @since 1.2
*/
class DefaultR2dbcSpELExpressionEvaluator implements R2dbcSpELExpressionEvaluator {
private final ExpressionParser parser;
private final EvaluationContext context;
DefaultR2dbcSpELExpressionEvaluator(ExpressionParser parser, EvaluationContext context) {
this.parser = parser;
this.context = context;
}
/**
* Return a {@link SpELExpressionEvaluator} that does not support expression evaluation.
*
* @return a {@link SpELExpressionEvaluator} that does not support expression evaluation.
*/
public static R2dbcSpELExpressionEvaluator unsupported() {
return NoOpExpressionEvaluator.INSTANCE;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.model.R2dbcSpELExpressionEvaluator#evaluate(java.lang.String)
*/
@Override
public Parameter evaluate(String expression) {
Expression expr = parser.parseExpression(expression);
Object value = expr.getValue(context, Object.class);
Class<?> valueType = expr.getValueType(context);
return org.springframework.r2dbc.core.Parameter.fromOrEmpty(value, valueType != null ? valueType : Object.class);
}
/**
* {@link SpELExpressionEvaluator} that does not support SpEL evaluation.
*
* @author Mark Paluch
*/
enum NoOpExpressionEvaluator implements R2dbcSpELExpressionEvaluator {
INSTANCE;
@Override
public Parameter evaluate(String expression) {
throw new UnsupportedOperationException("Expression evaluation not supported");
}
}
}

View File

@@ -25,12 +25,7 @@ import java.util.regex.Pattern;
import org.springframework.data.relational.repository.query.RelationalParameterAccessor;
import org.springframework.data.repository.query.Parameter;
import org.springframework.data.repository.query.Parameters;
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.r2dbc.core.DatabaseClient;
import org.springframework.util.Assert;
/**
* {@link ExpressionEvaluatingParameterBinder} allows to evaluate, convert and bind parameters to placeholders within a
@@ -41,10 +36,6 @@ import org.springframework.util.Assert;
*/
class ExpressionEvaluatingParameterBinder {
private final SpelExpressionParser expressionParser;
private final QueryMethodEvaluationContextProvider evaluationContextProvider;
private final ExpressionQuery expressionQuery;
private final Map<String, Boolean> namedParameters = new ConcurrentHashMap<>();
@@ -52,19 +43,9 @@ class ExpressionEvaluatingParameterBinder {
/**
* Creates new {@link ExpressionEvaluatingParameterBinder}
*
* @param expressionParser must not be {@literal null}.
* @param evaluationContextProvider must not be {@literal null}.
* @param expressionQuery must not be {@literal null}.
*/
ExpressionEvaluatingParameterBinder(SpelExpressionParser expressionParser,
QueryMethodEvaluationContextProvider evaluationContextProvider, ExpressionQuery expressionQuery) {
Assert.notNull(expressionParser, "ExpressionParser must not be null");
Assert.notNull(evaluationContextProvider, "EvaluationContextProvider must not be null");
Assert.notNull(expressionQuery, "ExpressionQuery must not be null");
this.expressionParser = expressionParser;
this.evaluationContextProvider = evaluationContextProvider;
ExpressionEvaluatingParameterBinder(ExpressionQuery expressionQuery) {
this.expressionQuery = expressionQuery;
}
@@ -74,28 +55,28 @@ class ExpressionEvaluatingParameterBinder {
*
* @param bindSpec must not be {@literal null}.
* @param parameterAccessor must not be {@literal null}.
* @param evaluator must not be {@literal null}.
*/
public DatabaseClient.GenericExecuteSpec bind(DatabaseClient.GenericExecuteSpec bindSpec,
RelationalParameterAccessor parameterAccessor) {
DatabaseClient.GenericExecuteSpec bind(DatabaseClient.GenericExecuteSpec bindSpec,
RelationalParameterAccessor parameterAccessor, R2dbcSpELExpressionEvaluator evaluator) {
Object[] values = parameterAccessor.getValues();
Parameters<?, ?> bindableParameters = parameterAccessor.getBindableParameters();
DatabaseClient.GenericExecuteSpec bindSpecToUse = bindExpressions(bindSpec, values, bindableParameters);
DatabaseClient.GenericExecuteSpec bindSpecToUse = bindExpressions(bindSpec, evaluator);
bindSpecToUse = bindParameters(bindSpecToUse, parameterAccessor.hasBindableNullValue(), values, bindableParameters);
return bindSpecToUse;
}
private DatabaseClient.GenericExecuteSpec bindExpressions(DatabaseClient.GenericExecuteSpec bindSpec, Object[] values,
Parameters<?, ?> bindableParameters) {
private DatabaseClient.GenericExecuteSpec bindExpressions(DatabaseClient.GenericExecuteSpec bindSpec,
R2dbcSpELExpressionEvaluator evaluator) {
DatabaseClient.GenericExecuteSpec bindSpecToUse = bindSpec;
for (ParameterBinding binding : expressionQuery.getBindings()) {
org.springframework.r2dbc.core.Parameter valueForBinding = getParameterValueForBinding(bindableParameters, values,
binding);
org.springframework.r2dbc.core.Parameter valueForBinding = evaluator.evaluate(binding.getExpression());
if (valueForBinding.isEmpty()) {
bindSpecToUse = bindSpecToUse.bindNull(binding.getParameterName(), valueForBinding.getType());
@@ -108,13 +89,11 @@ class ExpressionEvaluatingParameterBinder {
}
private DatabaseClient.GenericExecuteSpec bindParameters(DatabaseClient.GenericExecuteSpec bindSpec,
boolean bindableNull, Object[] values,
Parameters<?, ?> bindableParameters) {
boolean bindableNull, Object[] values, Parameters<?, ?> bindableParameters) {
DatabaseClient.GenericExecuteSpec bindSpecToUse = bindSpec;
int bindingIndex = 0;
for (Parameter bindableParameter : bindableParameters) {
Object value = values[bindableParameter.getIndex()];
@@ -161,37 +140,4 @@ class ExpressionEvaluatingParameterBinder {
});
}
/**
* Returns the value to be used for the given {@link ParameterBinding}.
*
* @param parameters must not be {@literal null}.
* @param binding must not be {@literal null}.
* @return the value used for the given {@link ParameterBinding}.
*/
private org.springframework.r2dbc.core.Parameter getParameterValueForBinding(Parameters<?, ?> parameters,
Object[] values,
ParameterBinding binding) {
return evaluateExpression(binding.getExpression(), parameters, values);
}
/**
* Evaluates the given {@code expressionString}.
*
* @param expressionString must not be {@literal null} or empty.
* @param parameters must not be {@literal null}.
* @param parameterValues must not be {@literal null}.
* @return the value of the {@code expressionString} evaluation.
*/
private org.springframework.r2dbc.core.Parameter evaluateExpression(String expressionString,
Parameters<?, ?> parameters,
Object[] parameterValues) {
EvaluationContext evaluationContext = evaluationContextProvider.getEvaluationContext(parameters, parameterValues);
Expression expression = expressionParser.parseExpression(expressionString);
Object value = expression.getValue(evaluationContext, Object.class);
Class<?> valueType = expression.getValueType(evaluationContext);
return org.springframework.r2dbc.core.Parameter.fromOrEmpty(value, valueType != null ? valueType : Object.class);
}
}

View File

@@ -19,6 +19,7 @@ import java.util.ArrayList;
import java.util.List;
import org.springframework.data.repository.query.SpelQueryContext;
import org.springframework.data.spel.ExpressionDependencies;
/**
* Query using Spring Expression Language to indicate parameter bindings. Queries using SpEL use {@code :#{…}} to

View File

@@ -15,6 +15,8 @@
*/
package org.springframework.data.r2dbc.repository.query;
import reactor.core.publisher.Mono;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -85,21 +87,24 @@ public class PartTreeR2dbcQuery extends AbstractR2dbcQuery {
* @see org.springframework.data.r2dbc.repository.query.AbstractR2dbcQuery#createQuery(org.springframework.data.relational.repository.query.RelationalParameterAccessor)
*/
@Override
protected BindableQuery createQuery(RelationalParameterAccessor accessor) {
protected Mono<BindableQuery> createQuery(RelationalParameterAccessor accessor) {
ReturnedType returnedType = processor.withDynamicProjection(accessor).getReturnedType();
List<String> projectedProperties = Collections.emptyList();
return Mono.fromSupplier(() -> {
if (returnedType.needsCustomConstruction()) {
projectedProperties = new ArrayList<>(returnedType.getInputProperties());
}
ReturnedType returnedType = processor.withDynamicProjection(accessor).getReturnedType();
List<String> projectedProperties = Collections.emptyList();
RelationalEntityMetadata<?> entityMetadata = getQueryMethod().getEntityInformation();
R2dbcQueryCreator queryCreator = new R2dbcQueryCreator(tree, dataAccessStrategy, entityMetadata, accessor,
projectedProperties);
PreparedOperation<?> preparedQuery = queryCreator.createQuery(getDynamicSort(accessor));
if (returnedType.needsCustomConstruction()) {
projectedProperties = new ArrayList<>(returnedType.getInputProperties());
}
return new PreparedOperationBindableQuery(preparedQuery);
RelationalEntityMetadata<?> entityMetadata = getQueryMethod().getEntityInformation();
R2dbcQueryCreator queryCreator = new R2dbcQueryCreator(tree, dataAccessStrategy, entityMetadata, accessor,
projectedProperties);
PreparedOperation<?> preparedQuery = queryCreator.createQuery(getDynamicSort(accessor));
return new PreparedOperationBindableQuery(preparedQuery);
});
}
private Sort getDynamicSort(RelationalParameterAccessor accessor) {

View File

@@ -41,7 +41,7 @@ import org.springframework.util.ClassUtils;
*/
interface R2dbcQueryExecution {
Object execute(FetchSpec<?> query, Class<?> type, SqlIdentifier tableName);
Publisher<?> execute(FetchSpec<?> query, Class<?> type, SqlIdentifier tableName);
/**
* An {@link R2dbcQueryExecution} that wraps the results of the given delegate with the given result processing.
@@ -60,8 +60,8 @@ interface R2dbcQueryExecution {
* @see org.springframework.data.r2dbc.repository.query.R2dbcQueryExecution#execute(org.springframework.data.r2dbc.function.FetchSpec, java.lang.Class, java.lang.String)
*/
@Override
public Object execute(FetchSpec<?> query, Class<?> type, SqlIdentifier tableName) {
return this.converter.convert(this.delegate.execute(query, type, tableName));
public Publisher<?> execute(FetchSpec<?> query, Class<?> type, SqlIdentifier tableName) {
return (Publisher<?>) this.converter.convert(this.delegate.execute(query, type, tableName));
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 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.r2dbc.repository.query;
import org.springframework.r2dbc.core.Parameter;
/**
* SPI for components that can evaluate Spring EL expressions and return {@link Parameter}.
*
* @author Mark Paluch
* @since 1.2
*/
interface R2dbcSpELExpressionEvaluator {
/**
* Evaluates the given expression.
*
* @param expression
* @return
*/
Parameter evaluate(String expression);
}

View File

@@ -15,10 +15,18 @@
*/
package org.springframework.data.r2dbc.repository.query;
import reactor.core.publisher.Mono;
import java.util.ArrayList;
import java.util.List;
import org.springframework.data.r2dbc.convert.R2dbcConverter;
import org.springframework.data.r2dbc.repository.Query;
import org.springframework.data.relational.repository.query.RelationalParameterAccessor;
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
import org.springframework.data.repository.query.ReactiveQueryMethodEvaluationContextProvider;
import org.springframework.data.spel.ExpressionDependencies;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.r2dbc.core.DatabaseClient;
import org.springframework.util.Assert;
@@ -35,6 +43,9 @@ public class StringBasedR2dbcQuery extends AbstractR2dbcQuery {
private final ExpressionQuery expressionQuery;
private final ExpressionEvaluatingParameterBinder binder;
private final ExpressionParser expressionParser;
private final ReactiveQueryMethodEvaluationContextProvider evaluationContextProvider;
private final ExpressionDependencies expressionDependencies;
/**
* Creates a new {@link StringBasedR2dbcQuery} for the given {@link StringBasedR2dbcQuery}, {@link DatabaseClient},
@@ -47,8 +58,7 @@ public class StringBasedR2dbcQuery extends AbstractR2dbcQuery {
* @param evaluationContextProvider must not be {@literal null}.
*/
public StringBasedR2dbcQuery(R2dbcQueryMethod queryMethod, DatabaseClient databaseClient, R2dbcConverter converter,
SpelExpressionParser expressionParser, QueryMethodEvaluationContextProvider evaluationContextProvider) {
ExpressionParser expressionParser, ReactiveQueryMethodEvaluationContextProvider evaluationContextProvider) {
this(queryMethod.getRequiredAnnotatedQuery(), queryMethod, databaseClient, converter, expressionParser,
evaluationContextProvider);
}
@@ -64,15 +74,33 @@ public class StringBasedR2dbcQuery extends AbstractR2dbcQuery {
* @param evaluationContextProvider must not be {@literal null}.
*/
public StringBasedR2dbcQuery(String query, R2dbcQueryMethod method, DatabaseClient databaseClient,
R2dbcConverter converter, SpelExpressionParser expressionParser,
QueryMethodEvaluationContextProvider evaluationContextProvider) {
R2dbcConverter converter, ExpressionParser expressionParser,
ReactiveQueryMethodEvaluationContextProvider evaluationContextProvider) {
super(method, databaseClient, converter);
this.expressionParser = expressionParser;
this.evaluationContextProvider = evaluationContextProvider;
Assert.hasText(query, "Query must not be empty");
this.expressionQuery = ExpressionQuery.create(query);
this.binder = new ExpressionEvaluatingParameterBinder(expressionParser, evaluationContextProvider, expressionQuery);
this.binder = new ExpressionEvaluatingParameterBinder(expressionQuery);
this.expressionDependencies = createExpressionDependencies();
}
private ExpressionDependencies createExpressionDependencies() {
if (expressionQuery.getBindings().isEmpty()) {
return ExpressionDependencies.none();
}
List<ExpressionDependencies> dependencies = new ArrayList<>();
for (ExpressionQuery.ParameterBinding binding : expressionQuery.getBindings()) {
dependencies.add(ExpressionDependencies.discover(expressionParser.parseExpression(binding.getExpression())));
}
return ExpressionDependencies.merged(dependencies);
}
/*
@@ -89,19 +117,28 @@ public class StringBasedR2dbcQuery extends AbstractR2dbcQuery {
* @see org.springframework.data.r2dbc.repository.query.AbstractR2dbcQuery#createQuery(org.springframework.data.relational.repository.query.RelationalParameterAccessor)
*/
@Override
protected BindableQuery createQuery(RelationalParameterAccessor accessor) {
protected Mono<BindableQuery> createQuery(RelationalParameterAccessor accessor) {
return new BindableQuery() {
return getSpelEvaluator(accessor).map(evaluator -> new BindableQuery() {
@Override
public DatabaseClient.GenericExecuteSpec bind(DatabaseClient.GenericExecuteSpec bindSpec) {
return binder.bind(bindSpec, accessor);
return binder.bind(bindSpec, accessor, evaluator);
}
@Override
public String get() {
return expressionQuery.getQuery();
}
};
});
}
private Mono<R2dbcSpELExpressionEvaluator> getSpelEvaluator(RelationalParameterAccessor accessor) {
return evaluationContextProvider
.getEvaluationContextLater(getQueryMethod().getParameters(), accessor.getValues(), expressionDependencies)
.<R2dbcSpELExpressionEvaluator> map(
context -> new DefaultR2dbcSpELExpressionEvaluator(expressionParser, context))
.defaultIfEmpty(DefaultR2dbcSpELExpressionEvaluator.unsupported());
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright 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.r2dbc.repository.support;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParseException;
import org.springframework.expression.ParserContext;
/**
* Caching variant of {@link ExpressionParser}. This implementation does not support
* {@link #parseExpression(String, ParserContext) parsing with ParseContext}.
*
* @author Mark Paluch
* @since 1.2
*/
class CachingExpressionParser implements ExpressionParser {
private final ExpressionParser delegate;
private final Map<String, Expression> cache = new ConcurrentHashMap<>();
CachingExpressionParser(ExpressionParser delegate) {
this.delegate = delegate;
}
/*
* (non-Javadoc)
* @see org.springframework.expression.ExpressionParser#parseExpression(java.lang.String)
*/
@Override
public Expression parseExpression(String expressionString) throws ParseException {
return cache.computeIfAbsent(expressionString, delegate::parseExpression);
}
/*
* (non-Javadoc)
* @see org.springframework.expression.ExpressionParser#parseExpression(java.lang.String, org.springframework.expression.ParserContext)
*/
@Override
public Expression parseExpression(String expressionString, ParserContext context) throws ParseException {
throw new UnsupportedOperationException("Parsing using ParserContext is not supported");
}
}

View File

@@ -39,7 +39,9 @@ import org.springframework.data.repository.core.support.ReactiveRepositoryFactor
import org.springframework.data.repository.query.QueryLookupStrategy;
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
import org.springframework.data.repository.query.ReactiveQueryMethodEvaluationContextProvider;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.lang.Nullable;
import org.springframework.r2dbc.core.DatabaseClient;
@@ -74,6 +76,7 @@ public class R2dbcRepositoryFactory extends ReactiveRepositoryFactorySupport {
this.dataAccessStrategy = dataAccessStrategy;
this.converter = dataAccessStrategy.getConverter();
this.mappingContext = this.converter.getMappingContext();
setEvaluationContextProvider(ReactiveQueryMethodEvaluationContextProvider.DEFAULT);
}
/**
@@ -90,6 +93,7 @@ public class R2dbcRepositoryFactory extends ReactiveRepositoryFactorySupport {
this.dataAccessStrategy = operations.getDataAccessStrategy();
this.converter = dataAccessStrategy.getConverter();
this.mappingContext = this.converter.getMappingContext();
setEvaluationContextProvider(ReactiveQueryMethodEvaluationContextProvider.DEFAULT);
}
/*
@@ -122,7 +126,8 @@ public class R2dbcRepositoryFactory extends ReactiveRepositoryFactorySupport {
@Override
protected Optional<QueryLookupStrategy> getQueryLookupStrategy(@Nullable Key key,
QueryMethodEvaluationContextProvider evaluationContextProvider) {
return Optional.of(new R2dbcQueryLookupStrategy(this.databaseClient, evaluationContextProvider, this.converter,
return Optional.of(new R2dbcQueryLookupStrategy(this.databaseClient,
(ReactiveQueryMethodEvaluationContextProvider) evaluationContextProvider, this.converter,
this.dataAccessStrategy));
}
@@ -151,17 +156,19 @@ public class R2dbcRepositoryFactory extends ReactiveRepositoryFactorySupport {
private static class R2dbcQueryLookupStrategy implements QueryLookupStrategy {
private final DatabaseClient databaseClient;
private final QueryMethodEvaluationContextProvider evaluationContextProvider;
private final ReactiveQueryMethodEvaluationContextProvider evaluationContextProvider;
private final R2dbcConverter converter;
private final ReactiveDataAccessStrategy dataAccessStrategy;
private final ExpressionParser parser = new CachingExpressionParser(EXPRESSION_PARSER);
R2dbcQueryLookupStrategy(DatabaseClient databaseClient,
QueryMethodEvaluationContextProvider evaluationContextProvider, R2dbcConverter converter,
ReactiveQueryMethodEvaluationContextProvider evaluationContextProvider, R2dbcConverter converter,
ReactiveDataAccessStrategy dataAccessStrategy) {
this.databaseClient = databaseClient;
this.evaluationContextProvider = evaluationContextProvider;
this.converter = converter;
this.dataAccessStrategy = dataAccessStrategy;
}
/*
@@ -179,9 +186,9 @@ public class R2dbcRepositoryFactory extends ReactiveRepositoryFactorySupport {
if (namedQueries.hasQuery(namedQueryName)) {
String namedQuery = namedQueries.getQuery(namedQueryName);
return new StringBasedR2dbcQuery(namedQuery, queryMethod, this.databaseClient, this.converter,
EXPRESSION_PARSER, this.evaluationContextProvider);
parser, this.evaluationContextProvider);
} else if (queryMethod.hasAnnotatedQuery()) {
return new StringBasedR2dbcQuery(queryMethod, this.databaseClient, this.converter, EXPRESSION_PARSER,
return new StringBasedR2dbcQuery(queryMethod, this.databaseClient, this.converter, parser,
this.evaluationContextProvider);
} else {
return new PartTreeR2dbcQuery(queryMethod, this.databaseClient, this.converter, this.dataAccessStrategy);

View File

@@ -23,6 +23,7 @@ import org.springframework.data.r2dbc.core.ReactiveDataAccessStrategy;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.data.repository.query.ReactiveQueryMethodEvaluationContextProvider;
import org.springframework.lang.Nullable;
import org.springframework.r2dbc.core.DatabaseClient;
import org.springframework.util.Assert;
@@ -52,6 +53,7 @@ public class R2dbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID exten
*/
public R2dbcRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
super(repositoryInterface);
setEvaluationContextProvider(ReactiveQueryMethodEvaluationContextProvider.DEFAULT);
}
/**

View File

@@ -38,7 +38,6 @@ import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.data.annotation.Id;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.r2dbc.convert.R2dbcConverter;
import org.springframework.r2dbc.core.DatabaseClient;
import org.springframework.data.r2dbc.core.DefaultReactiveDataAccessStrategy;
import org.springframework.data.r2dbc.core.ReactiveDataAccessStrategy;
import org.springframework.data.r2dbc.dialect.DialectResolver;
@@ -49,6 +48,7 @@ import org.springframework.data.relational.core.mapping.Table;
import org.springframework.data.relational.repository.query.RelationalParametersParameterAccessor;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
import org.springframework.r2dbc.core.DatabaseClient;
/**
* Unit tests for {@link PartTreeR2dbcQuery}.
@@ -97,7 +97,7 @@ public class PartTreeR2dbcQueryUnitTests {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByFirstName", String.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
BindableQuery bindableQuery = r2dbcQuery.createQuery(getAccessor(queryMethod, new Object[] { "John" }));
BindableQuery bindableQuery = createQuery(queryMethod, r2dbcQuery, "John");
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".first_name = $1");
@@ -109,7 +109,7 @@ public class PartTreeR2dbcQueryUnitTests {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByFirstName", String.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
BindableQuery bindableQuery = r2dbcQuery.createQuery((getAccessor(queryMethod, new Object[] { null })));
BindableQuery bindableQuery = createQuery(queryMethod, r2dbcQuery, new Object[] { null });
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".first_name IS NULL");
@@ -121,7 +121,7 @@ public class PartTreeR2dbcQueryUnitTests {
R2dbcQueryMethod queryMethod = getQueryMethod("existsByFirstName", String.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
BindableQuery query = r2dbcQuery.createQuery((getAccessor(queryMethod, new Object[] { "John" })));
BindableQuery query = createQuery(queryMethod, r2dbcQuery, "John");
assertThat(query.get())
.isEqualTo("SELECT " + TABLE + ".id FROM " + TABLE + " WHERE " + TABLE + ".first_name = $1 LIMIT 1");
@@ -133,7 +133,7 @@ public class PartTreeR2dbcQueryUnitTests {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByLastNameAndFirstName", String.class, String.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
BindableQuery bindableQuery = r2dbcQuery.createQuery(getAccessor(queryMethod, new Object[] { "Doe", "John" }));
BindableQuery bindableQuery = createQuery(r2dbcQuery, getAccessor(queryMethod, new Object[] { "Doe", "John" }));
assertThat(bindableQuery.get()).isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE
+ ".last_name = $1 AND (" + TABLE + ".first_name = $2)");
@@ -145,7 +145,7 @@ public class PartTreeR2dbcQueryUnitTests {
R2dbcQueryMethod queryMethod = getQueryMethod("findAllByLastNameOrFirstName", String.class, String.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
BindableQuery bindableQuery = r2dbcQuery.createQuery(getAccessor(queryMethod, new Object[] { "Doe", "John" }));
BindableQuery bindableQuery = createQuery(r2dbcQuery, getAccessor(queryMethod, new Object[] { "Doe", "John" }));
assertThat(bindableQuery.get()).isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE
+ ".last_name = $1 OR (" + TABLE + ".first_name = $2)");
@@ -160,7 +160,7 @@ public class PartTreeR2dbcQueryUnitTests {
Date from = new Date();
Date to = new Date();
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { from, to });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".date_of_birth BETWEEN $1 AND $2");
@@ -180,7 +180,7 @@ public class PartTreeR2dbcQueryUnitTests {
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { 30 });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".age < $1");
@@ -193,7 +193,7 @@ public class PartTreeR2dbcQueryUnitTests {
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { 30 });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".age <= $1");
@@ -206,7 +206,7 @@ public class PartTreeR2dbcQueryUnitTests {
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { 30 });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".age > $1");
@@ -219,7 +219,7 @@ public class PartTreeR2dbcQueryUnitTests {
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { 30 });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".age >= $1");
@@ -232,7 +232,7 @@ public class PartTreeR2dbcQueryUnitTests {
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { new Date() });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".date_of_birth > $1");
@@ -244,7 +244,7 @@ public class PartTreeR2dbcQueryUnitTests {
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { new Date() });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".date_of_birth < $1");
@@ -257,7 +257,7 @@ public class PartTreeR2dbcQueryUnitTests {
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[0]);
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".age IS NULL");
@@ -270,7 +270,7 @@ public class PartTreeR2dbcQueryUnitTests {
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[0]);
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".age IS NOT NULL");
@@ -283,7 +283,7 @@ public class PartTreeR2dbcQueryUnitTests {
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "%John%" });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".first_name LIKE $1");
@@ -296,7 +296,7 @@ public class PartTreeR2dbcQueryUnitTests {
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "%John%" });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".first_name NOT LIKE $1");
@@ -309,7 +309,7 @@ public class PartTreeR2dbcQueryUnitTests {
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "Jo" });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".first_name LIKE $1");
@@ -323,7 +323,7 @@ public class PartTreeR2dbcQueryUnitTests {
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "Jo" });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
DatabaseClient.GenericExecuteSpec bindSpecMock = mock(DatabaseClient.GenericExecuteSpec.class);
bindableQuery.bind(bindSpecMock);
@@ -337,7 +337,7 @@ public class PartTreeR2dbcQueryUnitTests {
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "hn" });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".first_name LIKE $1");
@@ -351,7 +351,7 @@ public class PartTreeR2dbcQueryUnitTests {
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "hn" });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
DatabaseClient.GenericExecuteSpec bindSpecMock = mock(DatabaseClient.GenericExecuteSpec.class);
bindableQuery.bind(bindSpecMock);
@@ -365,7 +365,7 @@ public class PartTreeR2dbcQueryUnitTests {
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "oh" });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".first_name LIKE $1");
@@ -379,7 +379,7 @@ public class PartTreeR2dbcQueryUnitTests {
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "oh" });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
DatabaseClient.GenericExecuteSpec bindSpecMock = mock(DatabaseClient.GenericExecuteSpec.class);
bindableQuery.bind(bindSpecMock);
@@ -393,7 +393,7 @@ public class PartTreeR2dbcQueryUnitTests {
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "oh" });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".first_name NOT LIKE $1");
@@ -407,7 +407,7 @@ public class PartTreeR2dbcQueryUnitTests {
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "oh" });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
DatabaseClient.GenericExecuteSpec bindSpecMock = mock(DatabaseClient.GenericExecuteSpec.class);
bindableQuery.bind(bindSpecMock);
@@ -421,7 +421,7 @@ public class PartTreeR2dbcQueryUnitTests {
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "oh" });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".age = $1 ORDER BY last_name DESC");
@@ -433,7 +433,7 @@ public class PartTreeR2dbcQueryUnitTests {
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "oh" });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".age = $1 ORDER BY last_name ASC");
@@ -445,7 +445,7 @@ public class PartTreeR2dbcQueryUnitTests {
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "Doe" });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".last_name != $1");
@@ -459,7 +459,7 @@ public class PartTreeR2dbcQueryUnitTests {
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod,
new Object[] { Collections.singleton(25) });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".age IN ($1)");
@@ -472,7 +472,7 @@ public class PartTreeR2dbcQueryUnitTests {
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod,
new Object[] { Collections.singleton(25) });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".age NOT IN ($1)");
@@ -485,7 +485,7 @@ public class PartTreeR2dbcQueryUnitTests {
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[0]);
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".active = TRUE");
@@ -498,7 +498,7 @@ public class PartTreeR2dbcQueryUnitTests {
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[0]);
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".active = FALSE");
@@ -511,7 +511,7 @@ public class PartTreeR2dbcQueryUnitTests {
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "John" });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE UPPER(" + TABLE + ".first_name) = UPPER($1)");
@@ -525,7 +525,7 @@ public class PartTreeR2dbcQueryUnitTests {
dataAccessStrategy);
assertThatIllegalStateException()
.isThrownBy(() -> r2dbcQuery.createQuery(getAccessor(queryMethod, new Object[] { 1L })));
.isThrownBy(() -> createQuery(r2dbcQuery, getAccessor(queryMethod, new Object[] { 1L })));
}
@Test // gh-282
@@ -554,7 +554,7 @@ public class PartTreeR2dbcQueryUnitTests {
dataAccessStrategy);
assertThatIllegalArgumentException()
.isThrownBy(() -> r2dbcQuery.createQuery(getAccessor(queryMethod, new Object[0])));
.isThrownBy(() -> createQuery(r2dbcQuery, getAccessor(queryMethod, new Object[0])));
}
@Test // gh-282
@@ -565,7 +565,7 @@ public class PartTreeR2dbcQueryUnitTests {
dataAccessStrategy);
assertThatIllegalArgumentException()
.isThrownBy(() -> r2dbcQuery.createQuery(getAccessor(queryMethod, new Object[0])));
.isThrownBy(() -> createQuery(r2dbcQuery, getAccessor(queryMethod, new Object[0])));
}
@Test // gh-282
@@ -575,7 +575,7 @@ public class PartTreeR2dbcQueryUnitTests {
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "John" });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".first_name = $1 LIMIT 3");
@@ -588,7 +588,7 @@ public class PartTreeR2dbcQueryUnitTests {
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "John" });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
assertThat(bindableQuery.get())
.isEqualTo("SELECT " + ALL_FIELDS + " FROM " + TABLE + " WHERE " + TABLE + ".first_name = $1 LIMIT 1");
@@ -601,7 +601,7 @@ public class PartTreeR2dbcQueryUnitTests {
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
RelationalParametersParameterAccessor accessor = getAccessor(queryMethod, new Object[] { "John" });
BindableQuery bindableQuery = r2dbcQuery.createQuery(accessor);
BindableQuery bindableQuery = createQuery(r2dbcQuery, accessor);
assertThat(bindableQuery.get()).isEqualTo("DELETE FROM " + TABLE + " WHERE " + TABLE + ".first_name = $1");
}
@@ -612,7 +612,7 @@ public class PartTreeR2dbcQueryUnitTests {
R2dbcQueryMethod queryMethod = getQueryMethod("findDistinctByFirstName", String.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
BindableQuery bindableQuery = r2dbcQuery.createQuery(getAccessor(queryMethod, new Object[] { "John" }));
BindableQuery bindableQuery = createQuery(queryMethod, r2dbcQuery, "John");
assertThat(bindableQuery.get()).isEqualTo("SELECT " + DISTINCT + " " + TABLE + ".first_name, " + TABLE
+ ".foo FROM " + TABLE + " WHERE " + TABLE + ".first_name = $1");
@@ -624,12 +624,20 @@ public class PartTreeR2dbcQueryUnitTests {
R2dbcQueryMethod queryMethod = getQueryMethod("countByFirstName", String.class);
PartTreeR2dbcQuery r2dbcQuery = new PartTreeR2dbcQuery(queryMethod, databaseClient, r2dbcConverter,
dataAccessStrategy);
BindableQuery query = r2dbcQuery.createQuery((getAccessor(queryMethod, new Object[] { "John" })));
BindableQuery query = createQuery(queryMethod, r2dbcQuery, "John");
assertThat(query.get())
.isEqualTo("SELECT COUNT(users.id) FROM " + TABLE + " WHERE " + TABLE + ".first_name = $1");
}
private BindableQuery createQuery(R2dbcQueryMethod queryMethod, PartTreeR2dbcQuery r2dbcQuery, Object... parameters) {
return createQuery(r2dbcQuery, getAccessor(queryMethod, parameters));
}
private BindableQuery createQuery(PartTreeR2dbcQuery r2dbcQuery, RelationalParametersParameterAccessor accessor) {
return r2dbcQuery.createQuery(accessor).block();
}
private R2dbcQueryMethod getQueryMethod(String methodName, Class<?>... parameterTypes) throws Exception {
Method method = UserRepository.class.getMethod(methodName, parameterTypes);
return new R2dbcQueryMethod(method, new DefaultRepositoryMetadata(UserRepository.class),

View File

@@ -28,21 +28,20 @@ import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.data.domain.Sort;
import org.springframework.data.geo.Point;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
import org.springframework.data.r2dbc.convert.MappingR2dbcConverter;
import org.springframework.r2dbc.core.DatabaseClient;
import org.springframework.r2dbc.core.DatabaseClient.GenericExecuteSpec;
import org.springframework.data.r2dbc.mapping.R2dbcMappingContext;
import org.springframework.data.r2dbc.repository.Query;
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.AbstractRepositoryMetadata;
import org.springframework.data.repository.query.ExtensionAwareQueryMethodEvaluationContextProvider;
import org.springframework.data.repository.query.Param;
import org.springframework.data.repository.query.ReactiveQueryMethodEvaluationContextProvider;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.r2dbc.core.DatabaseClient;
import org.springframework.r2dbc.core.DatabaseClient.GenericExecuteSpec;
import org.springframework.util.ReflectionUtils;
/**
@@ -81,7 +80,7 @@ public class StringBasedR2dbcQueryUnitTests {
StringBasedR2dbcQuery query = getQueryMethod("findByLastname", String.class);
R2dbcParameterAccessor accessor = new R2dbcParameterAccessor(query.getQueryMethod(), "White");
BindableQuery stringQuery = query.createQuery(accessor);
BindableQuery stringQuery = query.createQuery(accessor).block();
assertThat(stringQuery.get()).isEqualTo("SELECT * FROM person WHERE lastname = $1");
assertThat(stringQuery.bind(bindSpec)).isNotNull();
@@ -95,7 +94,7 @@ public class StringBasedR2dbcQueryUnitTests {
StringBasedR2dbcQuery query = getQueryMethod("findByLastnamePositional", String.class);
R2dbcParameterAccessor accessor = new R2dbcParameterAccessor(query.getQueryMethod(), "White");
BindableQuery stringQuery = query.createQuery(accessor);
BindableQuery stringQuery = query.createQuery(accessor).block();
assertThat(stringQuery.get()).isEqualTo("SELECT * FROM person WHERE lastname = $1");
assertThat(stringQuery.bind(bindSpec)).isNotNull();
@@ -109,7 +108,7 @@ public class StringBasedR2dbcQueryUnitTests {
StringBasedR2dbcQuery query = getQueryMethod("findByNamedParameter", String.class);
R2dbcParameterAccessor accessor = new R2dbcParameterAccessor(query.getQueryMethod(), "White");
BindableQuery stringQuery = query.createQuery(accessor);
BindableQuery stringQuery = query.createQuery(accessor).block();
assertThat(stringQuery.get()).isEqualTo("SELECT * FROM person WHERE lastname = :lastname");
assertThat(stringQuery.bind(bindSpec)).isNotNull();
@@ -123,7 +122,7 @@ public class StringBasedR2dbcQueryUnitTests {
StringBasedR2dbcQuery query = getQueryMethod("findByNamedBindMarker", String.class);
R2dbcParameterAccessor accessor = new R2dbcParameterAccessor(query.getQueryMethod(), "White");
BindableQuery stringQuery = query.createQuery(accessor);
BindableQuery stringQuery = query.createQuery(accessor).block();
assertThat(stringQuery.get()).isEqualTo("SELECT * FROM person WHERE lastname = @lastname");
assertThat(stringQuery.bind(bindSpec)).isNotNull();
@@ -137,7 +136,7 @@ public class StringBasedR2dbcQueryUnitTests {
StringBasedR2dbcQuery query = getQueryMethod("findNotByNamedBindMarker", String.class);
R2dbcParameterAccessor accessor = new R2dbcParameterAccessor(query.getQueryMethod(), "White");
BindableQuery stringQuery = query.createQuery(accessor);
BindableQuery stringQuery = query.createQuery(accessor).block();
assertThat(stringQuery.get()).isEqualTo("SELECT * FROM person WHERE lastname = :unknown");
assertThat(stringQuery.bind(bindSpec)).isNotNull();
@@ -151,7 +150,7 @@ public class StringBasedR2dbcQueryUnitTests {
StringBasedR2dbcQuery query = getQueryMethod("simpleSpel");
R2dbcParameterAccessor accessor = new R2dbcParameterAccessor(query.getQueryMethod());
BindableQuery stringQuery = query.createQuery(accessor);
BindableQuery stringQuery = query.createQuery(accessor).block();
assertThat(stringQuery.get()).isEqualTo("SELECT * FROM person WHERE lastname = :__synthetic_0__");
assertThat(stringQuery.bind(bindSpec)).isNotNull();
@@ -165,7 +164,7 @@ public class StringBasedR2dbcQueryUnitTests {
StringBasedR2dbcQuery query = getQueryMethod("simpleIndexedSpel", String.class);
R2dbcParameterAccessor accessor = new R2dbcParameterAccessor(query.getQueryMethod(), "White");
BindableQuery stringQuery = query.createQuery(accessor);
BindableQuery stringQuery = query.createQuery(accessor).block();
assertThat(stringQuery.get()).isEqualTo("SELECT * FROM person WHERE lastname = :__synthetic_0__");
assertThat(stringQuery.bind(bindSpec)).isNotNull();
@@ -180,7 +179,7 @@ public class StringBasedR2dbcQueryUnitTests {
StringBasedR2dbcQuery query = getQueryMethod("simplePositionalSpel", String.class, String.class);
R2dbcParameterAccessor accessor = new R2dbcParameterAccessor(query.getQueryMethod(), "White", "Walter");
BindableQuery stringQuery = query.createQuery(accessor);
BindableQuery stringQuery = query.createQuery(accessor).block();
assertThat(stringQuery.get())
.isEqualTo("SELECT * FROM person WHERE lastname = :__synthetic_0__ and firstname = :firstname");
@@ -197,7 +196,7 @@ public class StringBasedR2dbcQueryUnitTests {
StringBasedR2dbcQuery query = getQueryMethod("simpleNamedSpel", String.class, String.class);
R2dbcParameterAccessor accessor = new R2dbcParameterAccessor(query.getQueryMethod(), "White", "Walter");
BindableQuery stringQuery = query.createQuery(accessor);
BindableQuery stringQuery = query.createQuery(accessor).block();
assertThat(stringQuery.get())
.isEqualTo("SELECT * FROM person WHERE lastname = :__synthetic_0__ and firstname = :firstname");
@@ -214,7 +213,7 @@ public class StringBasedR2dbcQueryUnitTests {
StringBasedR2dbcQuery query = getQueryMethod("queryWithSpelObject", Person.class);
R2dbcParameterAccessor accessor = new R2dbcParameterAccessor(query.getQueryMethod(), new Person("Walter"));
BindableQuery stringQuery = query.createQuery(accessor);
BindableQuery stringQuery = query.createQuery(accessor).block();
assertThat(stringQuery.get()).isEqualTo("SELECT * FROM person WHERE lastname = :__synthetic_0__");
assertThat(stringQuery.bind(bindSpec)).isNotNull();
@@ -229,7 +228,7 @@ public class StringBasedR2dbcQueryUnitTests {
StringBasedR2dbcQuery query = getQueryMethod("queryWithUnusedParameter", String.class, Sort.class);
R2dbcParameterAccessor accessor = new R2dbcParameterAccessor(query.getQueryMethod(), "Walter", null);
BindableQuery stringQuery = query.createQuery(accessor);
BindableQuery stringQuery = query.createQuery(accessor).block();
assertThat(stringQuery.get()).isEqualTo("SELECT * FROM person WHERE lastname = :name");
assertThat(stringQuery.bind(bindSpec)).isNotNull();
@@ -245,7 +244,7 @@ public class StringBasedR2dbcQueryUnitTests {
R2dbcQueryMethod queryMethod = new R2dbcQueryMethod(method, metadata, factory, converter.getMappingContext());
return new StringBasedR2dbcQuery(queryMethod, databaseClient, converter, PARSER,
ExtensionAwareQueryMethodEvaluationContextProvider.DEFAULT);
ReactiveQueryMethodEvaluationContextProvider.DEFAULT);
}
@SuppressWarnings("unused")