Skip to content

Commit 6512c2c

Browse files
christophstroblodrotbohm
authored andcommitted
DATAMONGO-1057 - Fix SliceExecution skipping elements.
We now directly set the offset to use instead of reading it from the used pageable. This asserts that every single element is read from the store. Prior to this change the altered pageSize lead to an unintended increase of the number of elements to skip. Original pull request: #226.
1 parent 0eee05a commit 6512c2c

File tree

3 files changed

+100
-3
lines changed

3 files changed

+100
-3
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractMongoQuery.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import org.springframework.core.convert.ConversionService;
2222
import org.springframework.core.convert.support.DefaultConversionService;
2323
import org.springframework.data.domain.PageImpl;
24-
import org.springframework.data.domain.PageRequest;
2524
import org.springframework.data.domain.Pageable;
2625
import org.springframework.data.domain.Slice;
2726
import org.springframework.data.domain.SliceImpl;
@@ -211,6 +210,7 @@ public Object execute(Query query) {
211210
* {@link Execution} for {@link Slice} query methods.
212211
*
213212
* @author Oliver Gierke
213+
* @author Christoph Strobl
214214
* @since 1.5
215215
*/
216216

@@ -232,9 +232,9 @@ Object execute(Query query) {
232232

233233
MongoEntityMetadata<?> metadata = method.getEntityInformation();
234234
int pageSize = pageable.getPageSize();
235-
Pageable slicePageable = new PageRequest(pageable.getPageNumber(), pageSize + 1, pageable.getSort());
236235

237-
List result = operations.find(query.with(slicePageable), metadata.getJavaType(), metadata.getCollectionName());
236+
List result = operations.find(query.skip(pageable.getOffset()).limit(pageSize + 1).with(pageable.getSort()),
237+
metadata.getJavaType(), metadata.getCollectionName());
238238

239239
boolean hasNext = result.size() > pageSize;
240240

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import static org.hamcrest.Matchers.*;
2020
import static org.junit.Assert.*;
2121

22+
import java.util.ArrayList;
2223
import java.util.Arrays;
2324
import java.util.HashSet;
2425
import java.util.List;
@@ -1023,6 +1024,28 @@ public void executesSingleEntityQueryWithProjectionCorrectly() {
10231024
assertThat(result, is(notNullValue()));
10241025
assertThat(result.firstname, is("Carter"));
10251026
assertThat(result.lastname, is("Beauford"));
1027+
}
1028+
1029+
/**
1030+
* @see DATAMONGO-1057
1031+
*/
1032+
@Test
1033+
public void sliceShouldTraverseElementsWithoutSkippingOnes() {
1034+
1035+
repository.deleteAll();
1036+
1037+
List<Person> persons = new ArrayList<Person>(100);
1038+
for (int i = 0; i < 100; i++) {
1039+
// format firstname to assert sorting retains proper order
1040+
persons.add(new Person(String.format("%03d", i), "ln" + 1, 100));
1041+
}
1042+
1043+
repository.save(persons);
1044+
1045+
Slice<Person> slice = repository.findByAgeGreaterThan(50, new PageRequest(0, 20, Direction.ASC, "firstname"));
1046+
assertThat(slice, contains(persons.subList(0, 20).toArray()));
10261047

1048+
slice = repository.findByAgeGreaterThan(50, slice.nextPageable());
1049+
assertThat(slice, contains(persons.subList(20, 40).toArray()));
10271050
}
10281051
}

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/AbstractMongoQueryUnitTests.java

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
import org.springframework.data.domain.Page;
3737
import org.springframework.data.domain.PageRequest;
3838
import org.springframework.data.domain.Pageable;
39+
import org.springframework.data.domain.Slice;
40+
import org.springframework.data.domain.Sort;
3941
import org.springframework.data.mongodb.MongoDbFactory;
4042
import org.springframework.data.mongodb.core.MongoOperations;
4143
import org.springframework.data.mongodb.core.Person;
@@ -50,6 +52,8 @@
5052
import org.springframework.data.mongodb.repository.MongoRepository;
5153
import org.springframework.data.repository.core.RepositoryMetadata;
5254

55+
import com.mongodb.BasicDBObjectBuilder;
56+
import com.mongodb.DBObject;
5357
import com.mongodb.WriteResult;
5458

5559
/**
@@ -211,6 +215,73 @@ public void metadataShouldBeAddedToStringBasedQueryCorrectly() {
211215
assertThat(captor.getValue().getMeta().getComment(), is("comment"));
212216
}
213217

218+
/**
219+
* @see DATAMONGO-1057
220+
*/
221+
@Test
222+
public void slicedExecutionShouldRetainNrOfElementsToSkip() {
223+
224+
MongoQueryFake query = createQueryForMethod("findByLastname", String.class, Pageable.class);
225+
Pageable page1 = new PageRequest(0, 10);
226+
Pageable page2 = page1.next();
227+
228+
query.execute(new Object[] { "fake", page1 });
229+
query.execute(new Object[] { "fake", page2 });
230+
231+
ArgumentCaptor<Query> captor = ArgumentCaptor.forClass(Query.class);
232+
233+
verify(this.mongoOperationsMock, times(2))
234+
.find(captor.capture(), Matchers.eq(Person.class), Matchers.eq("persons"));
235+
236+
assertThat(captor.getAllValues().get(0).getSkip(), is(0));
237+
assertThat(captor.getAllValues().get(1).getSkip(), is(10));
238+
}
239+
240+
/**
241+
* @see DATAMONGO-1057
242+
*/
243+
@Test
244+
public void slicedExecutionShouldIncrementLimitByOne() {
245+
246+
MongoQueryFake query = createQueryForMethod("findByLastname", String.class, Pageable.class);
247+
Pageable page1 = new PageRequest(0, 10);
248+
Pageable page2 = page1.next();
249+
250+
query.execute(new Object[] { "fake", page1 });
251+
query.execute(new Object[] { "fake", page2 });
252+
253+
ArgumentCaptor<Query> captor = ArgumentCaptor.forClass(Query.class);
254+
255+
verify(this.mongoOperationsMock, times(2))
256+
.find(captor.capture(), Matchers.eq(Person.class), Matchers.eq("persons"));
257+
258+
assertThat(captor.getAllValues().get(0).getLimit(), is(11));
259+
assertThat(captor.getAllValues().get(1).getLimit(), is(11));
260+
}
261+
262+
/**
263+
* @see DATAMONGO-1057
264+
*/
265+
@Test
266+
public void slicedExecutionShouldRetainSort() {
267+
268+
MongoQueryFake query = createQueryForMethod("findByLastname", String.class, Pageable.class);
269+
Pageable page1 = new PageRequest(0, 10, Sort.Direction.DESC, "bar");
270+
Pageable page2 = page1.next();
271+
272+
query.execute(new Object[] { "fake", page1 });
273+
query.execute(new Object[] { "fake", page2 });
274+
275+
ArgumentCaptor<Query> captor = ArgumentCaptor.forClass(Query.class);
276+
277+
verify(this.mongoOperationsMock, times(2))
278+
.find(captor.capture(), Matchers.eq(Person.class), Matchers.eq("persons"));
279+
280+
DBObject expectedSortObject = new BasicDBObjectBuilder().add("bar", -1).get();
281+
assertThat(captor.getAllValues().get(0).getSortObject(), is(expectedSortObject));
282+
assertThat(captor.getAllValues().get(1).getSortObject(), is(expectedSortObject));
283+
}
284+
214285
private MongoQueryFake createQueryForMethod(String methodName, Class<?>... paramTypes) {
215286

216287
try {
@@ -272,5 +343,8 @@ private interface Repo extends MongoRepository<Person, Long> {
272343
@org.springframework.data.mongodb.repository.Query("{}")
273344
Page<Person> findByAnnotatedQuery(String firstnanme, Pageable pageable);
274345

346+
/** @see DATAMONGO-1057 */
347+
Slice<Person> findByLastname(String lastname, Pageable page);
348+
275349
}
276350
}

0 commit comments

Comments
 (0)