@@ -18,7 +18,7 @@ package org.springframework.data.keyvalue.repository.query;
|
||||
import org.springframework.data.keyvalue.core.KeyValueOperations;
|
||||
import org.springframework.data.keyvalue.core.query.KeyValueQuery;
|
||||
import org.springframework.data.repository.query.QueryMethod;
|
||||
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
|
||||
import org.springframework.data.repository.query.ValueExpressionDelegate;
|
||||
import org.springframework.data.repository.query.parser.AbstractQueryCreator;
|
||||
import org.springframework.data.repository.query.parser.PartTree;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -36,9 +36,9 @@ public class CachingKeyValuePartTreeQuery extends KeyValuePartTreeQuery {
|
||||
private @Nullable KeyValueQuery<?> cachedQuery;
|
||||
|
||||
public CachingKeyValuePartTreeQuery(QueryMethod queryMethod,
|
||||
QueryMethodEvaluationContextProvider evaluationContextProvider, KeyValueOperations keyValueOperations,
|
||||
ValueExpressionDelegate valueExpressionDelegate, KeyValueOperations keyValueOperations,
|
||||
Class<? extends AbstractQueryCreator<?, ?>> queryCreator) {
|
||||
super(queryMethod, evaluationContextProvider, keyValueOperations, queryCreator);
|
||||
super(queryMethod, valueExpressionDelegate, keyValueOperations, queryCreator);
|
||||
}
|
||||
|
||||
protected KeyValueQuery<?> prepareQuery(Object[] parameters) {
|
||||
|
||||
@@ -21,6 +21,8 @@ import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.expression.ValueEvaluationContext;
|
||||
import org.springframework.data.expression.ValueEvaluationContextProvider;
|
||||
import org.springframework.data.keyvalue.core.IterableConverter;
|
||||
import org.springframework.data.keyvalue.core.KeyValueOperations;
|
||||
import org.springframework.data.keyvalue.core.SpelCriteria;
|
||||
@@ -28,14 +30,13 @@ import org.springframework.data.keyvalue.core.query.KeyValueQuery;
|
||||
import org.springframework.data.repository.query.ParameterAccessor;
|
||||
import org.springframework.data.repository.query.ParametersParameterAccessor;
|
||||
import org.springframework.data.repository.query.QueryMethod;
|
||||
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
import org.springframework.data.repository.query.ResultProcessor;
|
||||
import org.springframework.data.repository.query.ValueExpressionDelegate;
|
||||
import org.springframework.data.repository.query.parser.AbstractQueryCreator;
|
||||
import org.springframework.data.repository.query.parser.PartTree;
|
||||
import org.springframework.data.spel.EvaluationContextProvider;
|
||||
import org.springframework.data.util.Lazy;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.spel.standard.SpelExpression;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -54,22 +55,23 @@ public class KeyValuePartTreeQuery implements RepositoryQuery {
|
||||
private final Lazy<PartTree> partTree;
|
||||
private final QueryMethod queryMethod;
|
||||
private final KeyValueOperations keyValueOperations;
|
||||
private final QueryMethodEvaluationContextProvider evaluationContextProvider;
|
||||
private final ValueExpressionDelegate valueExpressionDelegate;
|
||||
private final QueryCreatorFactory<AbstractQueryCreator<KeyValueQuery<?>, ?>> queryCreatorFactory;
|
||||
private final ValueEvaluationContextProvider evaluationContextProvider;
|
||||
|
||||
/**
|
||||
* Creates a new {@link KeyValuePartTreeQuery} for the given {@link QueryMethod}, {@link EvaluationContextProvider},
|
||||
* {@link KeyValueOperations} and query creator type.
|
||||
*
|
||||
* @param queryMethod must not be {@literal null}.
|
||||
* @param evaluationContextProvider must not be {@literal null}.
|
||||
* @param valueExpressionDelegate must not be {@literal null}.
|
||||
* @param keyValueOperations must not be {@literal null}.
|
||||
* @param queryCreator must not be {@literal null}.
|
||||
*/
|
||||
public KeyValuePartTreeQuery(QueryMethod queryMethod, QueryMethodEvaluationContextProvider evaluationContextProvider,
|
||||
public KeyValuePartTreeQuery(QueryMethod queryMethod, ValueExpressionDelegate valueExpressionDelegate,
|
||||
KeyValueOperations keyValueOperations, Class<? extends AbstractQueryCreator<?, ?>> queryCreator) {
|
||||
|
||||
this(queryMethod, evaluationContextProvider, keyValueOperations,
|
||||
this(queryMethod, valueExpressionDelegate, keyValueOperations,
|
||||
new ConstructorCachingQueryCreatorFactory(queryCreator));
|
||||
}
|
||||
|
||||
@@ -79,17 +81,17 @@ public class KeyValuePartTreeQuery implements RepositoryQuery {
|
||||
* in charge of altering the query.
|
||||
*
|
||||
* @param queryMethod must not be {@literal null}.
|
||||
* @param evaluationContextProvider must not be {@literal null}.
|
||||
* @param valueExpressionDelegate must not be {@literal null}.
|
||||
* @param keyValueOperations must not be {@literal null}.
|
||||
* @param queryCreatorFactory must not be {@literal null}.
|
||||
* @since 2.0
|
||||
*/
|
||||
public KeyValuePartTreeQuery(QueryMethod queryMethod, QueryMethodEvaluationContextProvider evaluationContextProvider,
|
||||
public KeyValuePartTreeQuery(QueryMethod queryMethod, ValueExpressionDelegate valueExpressionDelegate,
|
||||
KeyValueOperations keyValueOperations,
|
||||
QueryCreatorFactory<AbstractQueryCreator<KeyValueQuery<?>, ?>> queryCreatorFactory) {
|
||||
|
||||
Assert.notNull(queryMethod, "Query method must not be null");
|
||||
Assert.notNull(evaluationContextProvider, "EvaluationContextProvider must not be null");
|
||||
Assert.notNull(valueExpressionDelegate, "ValueExpressionDelegate must not be null");
|
||||
Assert.notNull(keyValueOperations, "KeyValueOperations must not be null");
|
||||
Assert.notNull(queryCreatorFactory, "QueryCreatorFactory type must not be null");
|
||||
|
||||
@@ -97,8 +99,9 @@ public class KeyValuePartTreeQuery implements RepositoryQuery {
|
||||
.of(() -> new PartTree(queryMethod.getName(), queryMethod.getEntityInformation().getJavaType()));
|
||||
this.queryMethod = queryMethod;
|
||||
this.keyValueOperations = keyValueOperations;
|
||||
this.evaluationContextProvider = evaluationContextProvider;
|
||||
this.valueExpressionDelegate = valueExpressionDelegate;
|
||||
this.queryCreatorFactory = queryCreatorFactory;
|
||||
this.evaluationContextProvider = valueExpressionDelegate.createValueContextProvider(queryMethod.getParameters());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -160,9 +163,8 @@ public class KeyValuePartTreeQuery implements RepositoryQuery {
|
||||
if (criteria instanceof SpelCriteria || criteria instanceof SpelExpression) {
|
||||
|
||||
SpelExpression spelExpression = getSpelExpression(criteria);
|
||||
EvaluationContext context = this.evaluationContextProvider.getEvaluationContext(getQueryMethod().getParameters(),
|
||||
parameters);
|
||||
criteria = new SpelCriteria(spelExpression, context);
|
||||
ValueEvaluationContext context = this.evaluationContextProvider.getEvaluationContext(parameters);
|
||||
criteria = new SpelCriteria(spelExpression, context.getRequiredEvaluationContext());
|
||||
}
|
||||
|
||||
KeyValueQuery<?> query = new KeyValueQuery(criteria);
|
||||
|
||||
@@ -41,8 +41,8 @@ import org.springframework.data.repository.core.support.RepositoryFactorySupport
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy;
|
||||
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
|
||||
import org.springframework.data.repository.query.QueryMethod;
|
||||
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
|
||||
import org.springframework.data.repository.query.RepositoryQuery;
|
||||
import org.springframework.data.repository.query.ValueExpressionDelegate;
|
||||
import org.springframework.data.repository.query.parser.AbstractQueryCreator;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -175,8 +175,8 @@ public class KeyValueRepositoryFactory extends RepositoryFactorySupport {
|
||||
|
||||
@Override
|
||||
protected Optional<QueryLookupStrategy> getQueryLookupStrategy(@Nullable Key key,
|
||||
QueryMethodEvaluationContextProvider evaluationContextProvider) {
|
||||
return Optional.of(new KeyValueQueryLookupStrategy(key, evaluationContextProvider, this.keyValueOperations,
|
||||
ValueExpressionDelegate valueExpressionDelegate) {
|
||||
return Optional.of(new KeyValueQueryLookupStrategy(key, valueExpressionDelegate, this.keyValueOperations,
|
||||
this.queryCreator, this.repositoryQueryType));
|
||||
}
|
||||
|
||||
@@ -186,7 +186,7 @@ public class KeyValueRepositoryFactory extends RepositoryFactorySupport {
|
||||
*/
|
||||
private static class KeyValueQueryLookupStrategy implements QueryLookupStrategy {
|
||||
|
||||
private final QueryMethodEvaluationContextProvider evaluationContextProvider;
|
||||
private final ValueExpressionDelegate valueExpressionDelegate;
|
||||
private final KeyValueOperations keyValueOperations;
|
||||
|
||||
private final Class<? extends AbstractQueryCreator<?, ?>> queryCreator;
|
||||
@@ -194,22 +194,21 @@ public class KeyValueRepositoryFactory extends RepositoryFactorySupport {
|
||||
|
||||
/**
|
||||
* @param key
|
||||
* @param evaluationContextProvider
|
||||
* @param valueExpressionDelegate
|
||||
* @param keyValueOperations
|
||||
* @param queryCreator
|
||||
* @since 1.1
|
||||
*/
|
||||
public KeyValueQueryLookupStrategy(@Nullable Key key,
|
||||
QueryMethodEvaluationContextProvider evaluationContextProvider, KeyValueOperations keyValueOperations,
|
||||
Class<? extends AbstractQueryCreator<?, ?>> queryCreator,
|
||||
public KeyValueQueryLookupStrategy(@Nullable Key key, ValueExpressionDelegate valueExpressionDelegate,
|
||||
KeyValueOperations keyValueOperations, Class<? extends AbstractQueryCreator<?, ?>> queryCreator,
|
||||
Class<? extends RepositoryQuery> repositoryQueryType) {
|
||||
|
||||
Assert.notNull(evaluationContextProvider, "EvaluationContextProvider must not be null");
|
||||
Assert.notNull(valueExpressionDelegate, "ValueExpressionDelegate must not be null");
|
||||
Assert.notNull(keyValueOperations, "KeyValueOperations must not be null");
|
||||
Assert.notNull(queryCreator, "Query creator type must not be null");
|
||||
Assert.notNull(repositoryQueryType, "RepositoryQueryType type must not be null");
|
||||
|
||||
this.evaluationContextProvider = evaluationContextProvider;
|
||||
this.valueExpressionDelegate = valueExpressionDelegate;
|
||||
this.keyValueOperations = keyValueOperations;
|
||||
this.queryCreator = queryCreator;
|
||||
this.repositoryQueryType = repositoryQueryType;
|
||||
@@ -223,15 +222,15 @@ public class KeyValueRepositoryFactory extends RepositoryFactorySupport {
|
||||
QueryMethod queryMethod = new QueryMethod(method, metadata, factory);
|
||||
|
||||
Constructor<? extends KeyValuePartTreeQuery> constructor = (Constructor<? extends KeyValuePartTreeQuery>) ClassUtils
|
||||
.getConstructorIfAvailable(this.repositoryQueryType, QueryMethod.class,
|
||||
QueryMethodEvaluationContextProvider.class, KeyValueOperations.class, Class.class);
|
||||
.getConstructorIfAvailable(this.repositoryQueryType, QueryMethod.class, ValueExpressionDelegate.class,
|
||||
KeyValueOperations.class, Class.class);
|
||||
|
||||
Assert.state(constructor != null,
|
||||
String.format(
|
||||
"Constructor %s(QueryMethod, EvaluationContextProvider, KeyValueOperations, Class) not available",
|
||||
ClassUtils.getShortName(this.repositoryQueryType)));
|
||||
|
||||
return BeanUtils.instantiateClass(constructor, queryMethod, evaluationContextProvider, this.keyValueOperations,
|
||||
return BeanUtils.instantiateClass(constructor, queryMethod, valueExpressionDelegate, this.keyValueOperations,
|
||||
this.queryCreator);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import org.mockito.quality.Strictness;
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.annotation.Id;
|
||||
@@ -48,6 +50,7 @@ import org.springframework.util.ObjectUtils;
|
||||
* @author Tom Van Wemmel
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@MockitoSettings(strictness = Strictness.LENIENT)
|
||||
public abstract class AbstractQueryCreatorTestBase<QUERY_CREATOR extends AbstractQueryCreator<KeyValueQuery<CRITERIA>, ?>, CRITERIA> {
|
||||
|
||||
static final DateTimeFormatter FORMATTER = DateTimeFormatter.ISO_ZONED_DATE_TIME;
|
||||
|
||||
@@ -33,7 +33,7 @@ import org.springframework.data.keyvalue.core.SpelCriteria;
|
||||
import org.springframework.data.projection.ProjectionFactory;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.query.QueryMethod;
|
||||
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
|
||||
import org.springframework.data.repository.query.ValueExpressionDelegate;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
/**
|
||||
@@ -64,8 +64,8 @@ class CachingKeyValuePartTreeQueryUnitTests {
|
||||
QueryMethod qm = new QueryMethod(Repo.class.getMethod("findByFirstname", String.class), metadataMock,
|
||||
projectionFactoryMock);
|
||||
|
||||
KeyValuePartTreeQuery query = new CachingKeyValuePartTreeQuery(qm, QueryMethodEvaluationContextProvider.DEFAULT,
|
||||
kvOpsMock, SpelQueryCreator.class);
|
||||
KeyValuePartTreeQuery query = new CachingKeyValuePartTreeQuery(qm, ValueExpressionDelegate.create(), kvOpsMock,
|
||||
SpelQueryCreator.class);
|
||||
|
||||
Object[] args = new Object[] { "foo" };
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ import org.springframework.data.keyvalue.core.query.KeyValueQuery;
|
||||
import org.springframework.data.projection.ProjectionFactory;
|
||||
import org.springframework.data.repository.core.RepositoryMetadata;
|
||||
import org.springframework.data.repository.query.QueryMethod;
|
||||
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
|
||||
import org.springframework.data.repository.query.ValueExpressionDelegate;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
/**
|
||||
@@ -61,7 +61,7 @@ class KeyValuePartTreeQueryUnitTests {
|
||||
QueryMethod qm = new QueryMethod(Repo.class.getMethod("findByFirstname", String.class), metadataMock,
|
||||
projectionFactoryMock);
|
||||
|
||||
KeyValuePartTreeQuery query = new KeyValuePartTreeQuery(qm, QueryMethodEvaluationContextProvider.DEFAULT, kvOpsMock,
|
||||
KeyValuePartTreeQuery query = new KeyValuePartTreeQuery(qm, ValueExpressionDelegate.create(), kvOpsMock,
|
||||
SpelQueryCreator.class);
|
||||
|
||||
Object[] args = new Object[] { "foo" };
|
||||
@@ -84,8 +84,8 @@ class KeyValuePartTreeQueryUnitTests {
|
||||
QueryMethod qm = new QueryMethod(Repo.class.getMethod("findBy", Pageable.class), metadataMock,
|
||||
projectionFactoryMock);
|
||||
|
||||
KeyValuePartTreeQuery partTreeQuery = new KeyValuePartTreeQuery(qm, QueryMethodEvaluationContextProvider.DEFAULT,
|
||||
kvOpsMock, SpelQueryCreator.class);
|
||||
KeyValuePartTreeQuery partTreeQuery = new KeyValuePartTreeQuery(qm, ValueExpressionDelegate.create(), kvOpsMock,
|
||||
SpelQueryCreator.class);
|
||||
|
||||
KeyValueQuery<?> query = partTreeQuery.prepareQuery(new Object[] { PageRequest.of(2, 3) });
|
||||
|
||||
@@ -102,11 +102,11 @@ class KeyValuePartTreeQueryUnitTests {
|
||||
when(metadataMock.getReturnType(any(Method.class))).thenReturn((TypeInformation) TypeInformation.of(List.class));
|
||||
when(metadataMock.getReturnedDomainClass(any(Method.class))).thenReturn((Class) Person.class);
|
||||
|
||||
QueryMethod qm = new QueryMethod(Repo.class.getMethod("findProjectionByFirstname",String.class), metadataMock,
|
||||
QueryMethod qm = new QueryMethod(Repo.class.getMethod("findProjectionByFirstname", String.class), metadataMock,
|
||||
projectionFactoryMock);
|
||||
|
||||
KeyValuePartTreeQuery partTreeQuery = new KeyValuePartTreeQuery(qm, QueryMethodEvaluationContextProvider.DEFAULT,
|
||||
kvOpsMock, SpelQueryCreator.class);
|
||||
KeyValuePartTreeQuery partTreeQuery = new KeyValuePartTreeQuery(qm, ValueExpressionDelegate.create(), kvOpsMock,
|
||||
SpelQueryCreator.class);
|
||||
|
||||
KeyValueQuery<?> query = partTreeQuery.prepareQuery(new Object[] { "firstname" });
|
||||
partTreeQuery.doExecute(new Object[] { "firstname" }, query);
|
||||
@@ -119,14 +119,13 @@ class KeyValuePartTreeQueryUnitTests {
|
||||
void shouldApplyDerivedMaxResultsToQuery() throws SecurityException, NoSuchMethodException {
|
||||
|
||||
when(metadataMock.getDomainType()).thenReturn((Class) Person.class);
|
||||
when(metadataMock.getDomainTypeInformation()).thenReturn((TypeInformation) TypeInformation.of(Person.class));
|
||||
when(metadataMock.getReturnType(any(Method.class))).thenReturn((TypeInformation) TypeInformation.of(List.class));
|
||||
when(metadataMock.getReturnedDomainClass(any(Method.class))).thenReturn((Class) Person.class);
|
||||
|
||||
QueryMethod qm = new QueryMethod(Repo.class.getMethod("findTop3By"), metadataMock, projectionFactoryMock);
|
||||
|
||||
KeyValuePartTreeQuery partTreeQuery = new KeyValuePartTreeQuery(qm, QueryMethodEvaluationContextProvider.DEFAULT,
|
||||
kvOpsMock, SpelQueryCreator.class);
|
||||
KeyValuePartTreeQuery partTreeQuery = new KeyValuePartTreeQuery(qm, ValueExpressionDelegate.create(), kvOpsMock,
|
||||
SpelQueryCreator.class);
|
||||
|
||||
KeyValueQuery<?> query = partTreeQuery.prepareQuery(new Object[] {});
|
||||
|
||||
@@ -145,8 +144,8 @@ class KeyValuePartTreeQueryUnitTests {
|
||||
QueryMethod qm = new QueryMethod(Repo.class.getMethod("findTop3ByFirstname", String.class), metadataMock,
|
||||
projectionFactoryMock);
|
||||
|
||||
KeyValuePartTreeQuery partTreeQuery = new KeyValuePartTreeQuery(qm, QueryMethodEvaluationContextProvider.DEFAULT,
|
||||
kvOpsMock, SpelQueryCreator.class);
|
||||
KeyValuePartTreeQuery partTreeQuery = new KeyValuePartTreeQuery(qm, ValueExpressionDelegate.create(), kvOpsMock,
|
||||
SpelQueryCreator.class);
|
||||
|
||||
KeyValueQuery<?> query = partTreeQuery.prepareQuery(new Object[] { "firstname" });
|
||||
|
||||
@@ -167,8 +166,8 @@ class KeyValuePartTreeQueryUnitTests {
|
||||
QueryMethod qm = new QueryMethod(Repo.class.getMethod("existsByFirstname", String.class), metadataMock,
|
||||
projectionFactoryMock);
|
||||
|
||||
KeyValuePartTreeQuery partTreeQuery = new KeyValuePartTreeQuery(qm, QueryMethodEvaluationContextProvider.DEFAULT,
|
||||
kvOpsMock, SpelQueryCreator.class);
|
||||
KeyValuePartTreeQuery partTreeQuery = new KeyValuePartTreeQuery(qm, ValueExpressionDelegate.create(), kvOpsMock,
|
||||
SpelQueryCreator.class);
|
||||
|
||||
KeyValueQuery<?> query = partTreeQuery.prepareQuery(new Object[] { "firstname" });
|
||||
partTreeQuery.doExecute(new Object[] { "firstname" }, query);
|
||||
|
||||
Reference in New Issue
Block a user