From c761ba3c6dab2e3f3f03b78181d61a0ac7c11fcd Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 13 Dec 2021 10:01:33 +0100 Subject: [PATCH] Polishing. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce default exists(…) method on KeyValueAdapter to allow for store-specific optimizations of the exists method. Lazily construct a single PartTree instance for reuse. Refine generics. See #386 Original pull request: #386. --- .../data/keyvalue/core/KeyValueAdapter.java | 12 +++++++++++ .../keyvalue/core/KeyValueOperations.java | 10 +++++++++ .../data/keyvalue/core/KeyValueTemplate.java | 9 ++++++++ .../query/KeyValuePartTreeQuery.java | 21 +++++++++++-------- .../query/KeyValuePartTreeQueryUnitTests.java | 2 +- 5 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/springframework/data/keyvalue/core/KeyValueAdapter.java b/src/main/java/org/springframework/data/keyvalue/core/KeyValueAdapter.java index a3fcc78..84da3ab 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/KeyValueAdapter.java +++ b/src/main/java/org/springframework/data/keyvalue/core/KeyValueAdapter.java @@ -184,4 +184,16 @@ public interface KeyValueAdapter extends DisposableBean { * @return */ long count(KeyValueQuery query, String keyspace); + + /** + * Determine whether result of given {@link KeyValueQuery} within {@literal keyspace} contains at least one element. + * + * @param query must not be {@literal null}. + * @param keyspace must not be {@literal null}. + * @return + * @since 2.7 + */ + default boolean exists(KeyValueQuery query, String keyspace) { + return count(query, keyspace) > 0; + } } diff --git a/src/main/java/org/springframework/data/keyvalue/core/KeyValueOperations.java b/src/main/java/org/springframework/data/keyvalue/core/KeyValueOperations.java index 10457ab..70396fd 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/KeyValueOperations.java +++ b/src/main/java/org/springframework/data/keyvalue/core/KeyValueOperations.java @@ -177,6 +177,16 @@ public interface KeyValueOperations extends DisposableBean { */ long count(KeyValueQuery query, Class type); + /** + * Determine whether result of given {@link KeyValueQuery} contains at least one element. + * + * @param query + * @param type + * @return + * @since 2.7 + */ + boolean exists(KeyValueQuery query, Class type); + /** * @return mapping context in use. */ diff --git a/src/main/java/org/springframework/data/keyvalue/core/KeyValueTemplate.java b/src/main/java/org/springframework/data/keyvalue/core/KeyValueTemplate.java index bfef5cd..5eccab4 100644 --- a/src/main/java/org/springframework/data/keyvalue/core/KeyValueTemplate.java +++ b/src/main/java/org/springframework/data/keyvalue/core/KeyValueTemplate.java @@ -445,6 +445,15 @@ public class KeyValueTemplate implements KeyValueOperations, ApplicationEventPub return executeRequired(adapter -> adapter.count(query, resolveKeySpace(type))); } + /* + * (non-Javadoc) + * @see org.springframework.data.keyvalue.core.KeyValueOperations#count(org.springframework.data.keyvalue.core.query.KeyValueQuery, java.lang.Class) + */ + @Override + public boolean exists(KeyValueQuery query, Class type) { + return executeRequired(adapter -> adapter.exists(query, resolveKeySpace(type))); + } + /* * (non-Javadoc) * @see org.springframework.data.keyvalue.core.KeyValueOperations#getMappingContext() diff --git a/src/main/java/org/springframework/data/keyvalue/repository/query/KeyValuePartTreeQuery.java b/src/main/java/org/springframework/data/keyvalue/repository/query/KeyValuePartTreeQuery.java index 97f0707..bc8ba92 100644 --- a/src/main/java/org/springframework/data/keyvalue/repository/query/KeyValuePartTreeQuery.java +++ b/src/main/java/org/springframework/data/keyvalue/repository/query/KeyValuePartTreeQuery.java @@ -34,6 +34,7 @@ import org.springframework.data.repository.query.ResultProcessor; 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; @@ -50,9 +51,10 @@ import org.springframework.util.ClassUtils; */ public class KeyValuePartTreeQuery implements RepositoryQuery { - private final QueryMethodEvaluationContextProvider evaluationContextProvider; + private final Lazy partTree; private final QueryMethod queryMethod; private final KeyValueOperations keyValueOperations; + private final QueryMethodEvaluationContextProvider evaluationContextProvider; private final QueryCreatorFactory, ?>> queryCreatorFactory; /** @@ -83,13 +85,16 @@ public class KeyValuePartTreeQuery implements RepositoryQuery { * @since 2.0 */ public KeyValuePartTreeQuery(QueryMethod queryMethod, QueryMethodEvaluationContextProvider evaluationContextProvider, - KeyValueOperations keyValueOperations, QueryCreatorFactory queryCreatorFactory) { + KeyValueOperations keyValueOperations, + QueryCreatorFactory, ?>> queryCreatorFactory) { Assert.notNull(queryMethod, "Query method must not be null!"); Assert.notNull(evaluationContextProvider, "EvaluationContextprovider must not be null!"); Assert.notNull(keyValueOperations, "KeyValueOperations must not be null!"); Assert.notNull(queryCreatorFactory, "QueryCreatorFactory type must not be null!"); + this.partTree = Lazy + .of(() -> new PartTree(queryMethod.getName(), queryMethod.getEntityInformation().getJavaType())); this.queryMethod = queryMethod; this.keyValueOperations = keyValueOperations; this.evaluationContextProvider = evaluationContextProvider; @@ -130,17 +135,15 @@ public class KeyValuePartTreeQuery implements RepositoryQuery { : keyValueOperations.count(query, queryMethod.getEntityInformation().getJavaType()); return new PageImpl(IterableConverter.toList(result), page, count); - } else if (queryMethod.isCollectionQuery()) { return this.keyValueOperations.find(query, queryMethod.getEntityInformation().getJavaType()); - } else if (queryMethod.isQueryForEntity()) { Iterable result = this.keyValueOperations.find(query, queryMethod.getEntityInformation().getJavaType()); return result.iterator().hasNext() ? result.iterator().next() : null; - } else if (new PartTree(queryMethod.getName(), queryMethod.getEntityInformation().getJavaType()).isExistsProjection()) { - return keyValueOperations.count(query, queryMethod.getEntityInformation().getJavaType()) > 0; + } else if (partTree.get().isExistsProjection()) { + return keyValueOperations.exists(query, queryMethod.getEntityInformation().getJavaType()); } throw new UnsupportedOperationException("Query method not supported."); @@ -206,8 +209,7 @@ public class KeyValuePartTreeQuery implements RepositoryQuery { */ public KeyValueQuery createQuery(ParameterAccessor accessor) { - PartTree tree = new PartTree(getQueryMethod().getName(), getQueryMethod().getEntityInformation().getJavaType()); - + PartTree tree = this.partTree.get(); AbstractQueryCreator, ?> queryCreator = queryCreatorFactory.queryCreatorFor(tree, accessor); @@ -235,7 +237,7 @@ public class KeyValuePartTreeQuery implements RepositoryQuery { * @author Christoph Strobl * @since 2.0 */ - public interface QueryCreatorFactory { + public interface QueryCreatorFactory> { T queryCreatorFor(PartTree partTree, ParameterAccessor accessor); } @@ -260,6 +262,7 @@ public class KeyValuePartTreeQuery implements RepositoryQuery { } @Override + @SuppressWarnings("unchecked") public AbstractQueryCreator, ?> queryCreatorFor(PartTree partTree, ParameterAccessor accessor) { Assert.state(constructor != null, diff --git a/src/test/java/org/springframework/data/keyvalue/repository/query/KeyValuePartTreeQueryUnitTests.java b/src/test/java/org/springframework/data/keyvalue/repository/query/KeyValuePartTreeQueryUnitTests.java index 6b35c3f..dd51c0b 100644 --- a/src/test/java/org/springframework/data/keyvalue/repository/query/KeyValuePartTreeQueryUnitTests.java +++ b/src/test/java/org/springframework/data/keyvalue/repository/query/KeyValuePartTreeQueryUnitTests.java @@ -154,7 +154,7 @@ class KeyValuePartTreeQueryUnitTests { KeyValueQuery query = partTreeQuery.prepareQuery(new Object[] { "firstname" }); partTreeQuery.doExecute(new Object[] { "firstname" }, query); - verify(kvOpsMock).count(eq(query), eq(Person.class)); + verify(kvOpsMock).exists(eq(query), eq(Person.class)); } interface Repo {