Skip to content

Commit c761ba3

Browse files
committed
Polishing.
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.
1 parent 8c32f0a commit c761ba3

File tree

5 files changed

+44
-10
lines changed

5 files changed

+44
-10
lines changed

src/main/java/org/springframework/data/keyvalue/core/KeyValueAdapter.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,4 +184,16 @@ default Iterable<?> find(KeyValueQuery<?> query, String keyspace) {
184184
* @return
185185
*/
186186
long count(KeyValueQuery<?> query, String keyspace);
187+
188+
/**
189+
* Determine whether result of given {@link KeyValueQuery} within {@literal keyspace} contains at least one element.
190+
*
191+
* @param query must not be {@literal null}.
192+
* @param keyspace must not be {@literal null}.
193+
* @return
194+
* @since 2.7
195+
*/
196+
default boolean exists(KeyValueQuery<?> query, String keyspace) {
197+
return count(query, keyspace) > 0;
198+
}
187199
}

src/main/java/org/springframework/data/keyvalue/core/KeyValueOperations.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,16 @@ public interface KeyValueOperations extends DisposableBean {
177177
*/
178178
long count(KeyValueQuery<?> query, Class<?> type);
179179

180+
/**
181+
* Determine whether result of given {@link KeyValueQuery} contains at least one element.
182+
*
183+
* @param query
184+
* @param type
185+
* @return
186+
* @since 2.7
187+
*/
188+
boolean exists(KeyValueQuery<?> query, Class<?> type);
189+
180190
/**
181191
* @return mapping context in use.
182192
*/

src/main/java/org/springframework/data/keyvalue/core/KeyValueTemplate.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,15 @@ public long count(KeyValueQuery<?> query, Class<?> type) {
445445
return executeRequired(adapter -> adapter.count(query, resolveKeySpace(type)));
446446
}
447447

448+
/*
449+
* (non-Javadoc)
450+
* @see org.springframework.data.keyvalue.core.KeyValueOperations#count(org.springframework.data.keyvalue.core.query.KeyValueQuery, java.lang.Class)
451+
*/
452+
@Override
453+
public boolean exists(KeyValueQuery<?> query, Class<?> type) {
454+
return executeRequired(adapter -> adapter.exists(query, resolveKeySpace(type)));
455+
}
456+
448457
/*
449458
* (non-Javadoc)
450459
* @see org.springframework.data.keyvalue.core.KeyValueOperations#getMappingContext()

src/main/java/org/springframework/data/keyvalue/repository/query/KeyValuePartTreeQuery.java

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.springframework.data.repository.query.parser.AbstractQueryCreator;
3535
import org.springframework.data.repository.query.parser.PartTree;
3636
import org.springframework.data.spel.EvaluationContextProvider;
37+
import org.springframework.data.util.Lazy;
3738
import org.springframework.expression.EvaluationContext;
3839
import org.springframework.expression.spel.standard.SpelExpression;
3940
import org.springframework.lang.Nullable;
@@ -50,9 +51,10 @@
5051
*/
5152
public class KeyValuePartTreeQuery implements RepositoryQuery {
5253

53-
private final QueryMethodEvaluationContextProvider evaluationContextProvider;
54+
private final Lazy<PartTree> partTree;
5455
private final QueryMethod queryMethod;
5556
private final KeyValueOperations keyValueOperations;
57+
private final QueryMethodEvaluationContextProvider evaluationContextProvider;
5658
private final QueryCreatorFactory<AbstractQueryCreator<KeyValueQuery<?>, ?>> queryCreatorFactory;
5759

5860
/**
@@ -83,13 +85,16 @@ public KeyValuePartTreeQuery(QueryMethod queryMethod, QueryMethodEvaluationConte
8385
* @since 2.0
8486
*/
8587
public KeyValuePartTreeQuery(QueryMethod queryMethod, QueryMethodEvaluationContextProvider evaluationContextProvider,
86-
KeyValueOperations keyValueOperations, QueryCreatorFactory queryCreatorFactory) {
88+
KeyValueOperations keyValueOperations,
89+
QueryCreatorFactory<AbstractQueryCreator<KeyValueQuery<?>, ?>> queryCreatorFactory) {
8790

8891
Assert.notNull(queryMethod, "Query method must not be null!");
8992
Assert.notNull(evaluationContextProvider, "EvaluationContextprovider must not be null!");
9093
Assert.notNull(keyValueOperations, "KeyValueOperations must not be null!");
9194
Assert.notNull(queryCreatorFactory, "QueryCreatorFactory type must not be null!");
9295

96+
this.partTree = Lazy
97+
.of(() -> new PartTree(queryMethod.getName(), queryMethod.getEntityInformation().getJavaType()));
9398
this.queryMethod = queryMethod;
9499
this.keyValueOperations = keyValueOperations;
95100
this.evaluationContextProvider = evaluationContextProvider;
@@ -130,17 +135,15 @@ protected Object doExecute(Object[] parameters, KeyValueQuery<?> query) {
130135
: keyValueOperations.count(query, queryMethod.getEntityInformation().getJavaType());
131136

132137
return new PageImpl(IterableConverter.toList(result), page, count);
133-
134138
} else if (queryMethod.isCollectionQuery()) {
135139

136140
return this.keyValueOperations.find(query, queryMethod.getEntityInformation().getJavaType());
137-
138141
} else if (queryMethod.isQueryForEntity()) {
139142

140143
Iterable<?> result = this.keyValueOperations.find(query, queryMethod.getEntityInformation().getJavaType());
141144
return result.iterator().hasNext() ? result.iterator().next() : null;
142-
} else if (new PartTree(queryMethod.getName(), queryMethod.getEntityInformation().getJavaType()).isExistsProjection()) {
143-
return keyValueOperations.count(query, queryMethod.getEntityInformation().getJavaType()) > 0;
145+
} else if (partTree.get().isExistsProjection()) {
146+
return keyValueOperations.exists(query, queryMethod.getEntityInformation().getJavaType());
144147
}
145148

146149
throw new UnsupportedOperationException("Query method not supported.");
@@ -206,8 +209,7 @@ private SpelExpression getSpelExpression(Object criteria) {
206209
*/
207210
public KeyValueQuery<?> createQuery(ParameterAccessor accessor) {
208211

209-
PartTree tree = new PartTree(getQueryMethod().getName(), getQueryMethod().getEntityInformation().getJavaType());
210-
212+
PartTree tree = this.partTree.get();
211213
AbstractQueryCreator<? extends KeyValueQuery<?>, ?> queryCreator = queryCreatorFactory.queryCreatorFor(tree,
212214
accessor);
213215

@@ -235,7 +237,7 @@ public QueryMethod getQueryMethod() {
235237
* @author Christoph Strobl
236238
* @since 2.0
237239
*/
238-
public interface QueryCreatorFactory<T extends AbstractQueryCreator> {
240+
public interface QueryCreatorFactory<T extends AbstractQueryCreator<?, ?>> {
239241

240242
T queryCreatorFor(PartTree partTree, ParameterAccessor accessor);
241243
}
@@ -260,6 +262,7 @@ private static class ConstructorCachingQueryCreatorFactory
260262
}
261263

262264
@Override
265+
@SuppressWarnings("unchecked")
263266
public AbstractQueryCreator<KeyValueQuery<?>, ?> queryCreatorFor(PartTree partTree, ParameterAccessor accessor) {
264267

265268
Assert.state(constructor != null,

src/test/java/org/springframework/data/keyvalue/repository/query/KeyValuePartTreeQueryUnitTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ void shouldUseCountForExists() throws NoSuchMethodException {
154154
KeyValueQuery<?> query = partTreeQuery.prepareQuery(new Object[] { "firstname" });
155155
partTreeQuery.doExecute(new Object[] { "firstname" }, query);
156156

157-
verify(kvOpsMock).count(eq(query), eq(Person.class));
157+
verify(kvOpsMock).exists(eq(query), eq(Person.class));
158158
}
159159

160160
interface Repo {

0 commit comments

Comments
 (0)