Skip to content

Commit 3c11ed6

Browse files
DATAREDIS-547 - Fix query execution when derived criteria is empty.
We now make sure to pipe finder queries without any criteria to the according find all method. This allows usage of `PagingAndSortingRepository.findAllBy(Pageable page)` as well as finders without any criteria like `findTop3By()`.
1 parent e43d1cd commit 3c11ed6

File tree

4 files changed

+111
-15
lines changed

4 files changed

+111
-15
lines changed

src/main/java/org/springframework/data/redis/core/RedisKeyValueAdapter.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@
6060
import org.springframework.data.redis.util.ByteUtils;
6161
import org.springframework.data.util.CloseableIterator;
6262
import org.springframework.util.Assert;
63-
import org.springframework.util.NumberUtils;
6463
import org.springframework.util.ObjectUtils;
6564

6665
/**
@@ -346,6 +345,10 @@ public Void doInRedis(RedisConnection connection) throws DataAccessException {
346345
* @see org.springframework.data.keyvalue.core.KeyValueAdapter#getAllOf(java.io.Serializable)
347346
*/
348347
public List<?> getAllOf(final Serializable keyspace) {
348+
return getAllOf(keyspace, -1, -1);
349+
}
350+
351+
public List<?> getAllOf(final Serializable keyspace, int offset, int rows) {
349352

350353
final byte[] binKeyspace = toBytes(keyspace);
351354

@@ -358,7 +361,15 @@ public Set<byte[]> doInRedis(RedisConnection connection) throws DataAccessExcept
358361
});
359362

360363
List<Object> result = new ArrayList<Object>();
361-
for (byte[] key : ids) {
364+
365+
List<byte[]> keys = new ArrayList<byte[]>(ids);
366+
367+
offset = Math.max(0, offset);
368+
if (offset >= 0 && rows > 0) {
369+
keys = keys.subList(offset, Math.min(offset + rows, keys.size()));
370+
}
371+
372+
for (byte[] key : keys) {
362373
result.add(get(key, keyspace));
363374
}
364375
return result;

src/main/java/org/springframework/data/redis/core/RedisQueryEngine.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.springframework.data.redis.repository.query.RedisOperationChain;
3535
import org.springframework.data.redis.repository.query.RedisOperationChain.PathAndValue;
3636
import org.springframework.data.redis.util.ByteUtils;
37+
import org.springframework.util.CollectionUtils;
3738

3839
/**
3940
* Redis specific {@link QueryEngine} implementation.
@@ -67,9 +68,15 @@ public RedisQueryEngine(CriteriaAccessor<RedisOperationChain> criteriaAccessor,
6768
* @see org.springframework.data.keyvalue.core.QueryEngine#execute(java.lang.Object, java.lang.Object, int, int, java.io.Serializable, java.lang.Class)
6869
*/
6970
@Override
71+
@SuppressWarnings("unchecked")
7072
public <T> Collection<T> execute(final RedisOperationChain criteria, final Comparator<?> sort, final int offset,
7173
final int rows, final Serializable keyspace, Class<T> type) {
7274

75+
if (criteria == null
76+
|| (CollectionUtils.isEmpty(criteria.getOrSismember()) && CollectionUtils.isEmpty(criteria.getSismember()))) {
77+
return (Collection<T>) getAdapter().getAllOf(keyspace, offset, rows);
78+
}
79+
7380
RedisCallback<Map<byte[], Map<byte[], byte[]>>> callback = new RedisCallback<Map<byte[], Map<byte[], byte[]>>>() {
7481

7582
@Override
@@ -99,8 +106,9 @@ public Map<byte[], Map<byte[], byte[]>> doInRedis(RedisConnection connection) th
99106
return Collections.emptyMap();
100107
}
101108

102-
if (offset >= 0 && rows > 0) {
103-
allKeys = allKeys.subList(Math.max(0, offset), Math.min(offset + rows, allKeys.size()));
109+
int offsetToUse = Math.max(0, offset);
110+
if (rows > 0) {
111+
allKeys = allKeys.subList(Math.max(0, offsetToUse), Math.min(offsetToUse + rows, allKeys.size()));
104112
}
105113
for (byte[] id : allKeys) {
106114

@@ -171,8 +179,8 @@ private byte[][] keys(String prefix, Collection<PathAndValue> source) {
171179
int i = 0;
172180
for (PathAndValue pathAndValue : source) {
173181

174-
byte[] convertedValue = getAdapter().getConverter().getConversionService()
175-
.convert(pathAndValue.getFirstValue(), byte[].class);
182+
byte[] convertedValue = getAdapter().getConverter().getConversionService().convert(pathAndValue.getFirstValue(),
183+
byte[].class);
176184
byte[] fullPath = getAdapter().getConverter().getConversionService()
177185
.convert(prefix + pathAndValue.getPath() + ":", byte[].class);
178186

src/main/java/org/springframework/data/redis/repository/query/RedisQueryCreator.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2015 the original author or authors.
2+
* Copyright 2015-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@
2323
import org.springframework.data.repository.query.parser.AbstractQueryCreator;
2424
import org.springframework.data.repository.query.parser.Part;
2525
import org.springframework.data.repository.query.parser.PartTree;
26+
import org.springframework.util.CollectionUtils;
2627

2728
/**
2829
* Redis specific query creator.
@@ -87,11 +88,13 @@ protected KeyValueQuery<RedisOperationChain> complete(final RedisOperationChain
8788

8889
KeyValueQuery<RedisOperationChain> query = new KeyValueQuery<RedisOperationChain>(criteria);
8990

90-
if (query.getCritieria().getSismember().size() == 1 && query.getCritieria().getOrSismember().size() == 1) {
91+
if (query.getCritieria() != null && !CollectionUtils.isEmpty(query.getCritieria().getSismember())
92+
&& !CollectionUtils.isEmpty(query.getCritieria().getOrSismember()))
93+
if (query.getCritieria().getSismember().size() == 1 && query.getCritieria().getOrSismember().size() == 1) {
9194

92-
query.getCritieria().getOrSismember().add(query.getCritieria().getSismember().iterator().next());
93-
query.getCritieria().getSismember().clear();
94-
}
95+
query.getCritieria().getOrSismember().add(query.getCritieria().getSismember().iterator().next());
96+
query.getCritieria().getSismember().clear();
97+
}
9598

9699
if (sort != null) {
97100
query.setSort(sort);

src/test/java/org/springframework/data/redis/repository/RedisRepositoryIntegrationTestBase.java

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,9 @@
1515
*/
1616
package org.springframework.data.redis.repository;
1717

18+
import static org.hamcrest.CoreMatchers.*;
1819
import static org.hamcrest.collection.IsCollectionWithSize.*;
1920
import static org.hamcrest.collection.IsIterableContainingInAnyOrder.*;
20-
import static org.hamcrest.core.Is.*;
21-
import static org.hamcrest.core.IsCollectionContaining.*;
2221
import static org.junit.Assert.*;
2322

2423
import java.io.Serializable;
@@ -42,7 +41,7 @@
4241
import org.springframework.data.redis.core.index.IndexDefinition;
4342
import org.springframework.data.redis.core.index.Indexed;
4443
import org.springframework.data.redis.core.index.SimpleIndexDefinition;
45-
import org.springframework.data.repository.CrudRepository;
44+
import org.springframework.data.repository.PagingAndSortingRepository;
4645

4746
/**
4847
* Base for testing Redis repository support in different configurations.
@@ -190,7 +189,76 @@ public void findUsingOrReturnsResultCorrectly() {
190189
assertThat(eddardAndJon, containsInAnyOrder(eddard, jon));
191190
}
192191

193-
public static interface PersonRepository extends CrudRepository<Person, String> {
192+
/**
193+
* @see DATAREDIS-547
194+
*/
195+
@Test
196+
public void shouldApplyFirstKeywordCorrectly() {
197+
198+
Person eddard = new Person("eddard", "stark");
199+
Person robb = new Person("robb", "stark");
200+
Person jon = new Person("jon", "snow");
201+
202+
repo.save(Arrays.asList(eddard, robb, jon));
203+
204+
assertThat(repo.findFirstBy(), hasSize(1));
205+
}
206+
207+
/**
208+
* @see DATAREDIS-547
209+
*/
210+
@Test
211+
public void shouldApplyPageableCorrectlyWhenUsingFindAll() {
212+
213+
Person eddard = new Person("eddard", "stark");
214+
Person robb = new Person("robb", "stark");
215+
Person jon = new Person("jon", "snow");
216+
217+
repo.save(Arrays.asList(eddard, robb, jon));
218+
219+
Page<Person> firstPage = repo.findAll(new PageRequest(0, 2));
220+
assertThat(firstPage.getContent(), hasSize(2));
221+
assertThat(repo.findAll(firstPage.nextPageable()).getContent(), hasSize(1));
222+
}
223+
224+
/**
225+
* @see DATAREDIS-547
226+
*/
227+
@Test
228+
public void shouldApplyTopKeywordCorrectly() {
229+
230+
Person eddard = new Person("eddard", "stark");
231+
Person robb = new Person("robb", "stark");
232+
Person jon = new Person("jon", "snow");
233+
234+
repo.save(Arrays.asList(eddard, robb, jon));
235+
236+
assertThat(repo.findTop2By(), hasSize(2));
237+
}
238+
239+
/**
240+
* @see DATAREDIS-547
241+
*/
242+
@Test
243+
public void shouldApplyTopKeywordCorrectlyWhenCriteriaPresent() {
244+
245+
Person eddard = new Person("eddard", "stark");
246+
Person tyrion = new Person("tyrion", "lannister");
247+
Person robb = new Person("robb", "stark");
248+
Person jon = new Person("jon", "snow");
249+
Person arya = new Person("arya", "stark");
250+
251+
repo.save(Arrays.asList(eddard, tyrion, robb, jon, arya));
252+
253+
List<Person> result = repo.findTop2ByLastname("stark");
254+
255+
assertThat(result, hasSize(2));
256+
for (Person p : result) {
257+
assertThat(p.getLastname(), is("stark"));
258+
}
259+
}
260+
261+
public static interface PersonRepository extends PagingAndSortingRepository<Person, String> {
194262

195263
List<Person> findByFirstname(String firstname);
196264

@@ -201,6 +269,12 @@ public static interface PersonRepository extends CrudRepository<Person, String>
201269
List<Person> findByFirstnameAndLastname(String firstname, String lastname);
202270

203271
List<Person> findByFirstnameOrLastname(String firstname, String lastname);
272+
273+
List<Person> findFirstBy();
274+
275+
List<Person> findTop2By();
276+
277+
List<Person> findTop2ByLastname(String lastname);
204278
}
205279

206280
/**

0 commit comments

Comments
 (0)