DATAMONGO-950 - Add support for limiting the query result in the query derivation mechanism.

When deriving the query from its method name we check for the limit set on the PartTree to pass this on to the created query. PagedExecution not takes the overall limit into account, skips a query execution entirely (if the Pageable is out of scope completely) or alters the query limits accordingly.

Note, that there has been significant rework of this compared to the pull request to avoid new API in Query and extensive changes in MongoTemplate's QueryCursorPreparer.

Original pull request: #191.
This commit is contained in:
Christoph Strobl
2014-06-18 09:34:51 +02:00
committed by Oliver Gierke
parent 9858dcd740
commit cbb32bd29d
4 changed files with 82 additions and 1 deletions

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.data.mongodb.repository.query;
import java.util.Collections;
import java.util.List;
import org.springframework.core.convert.ConversionService;
@@ -254,10 +255,26 @@ public abstract class AbstractMongoQuery implements RepositoryQuery {
Object execute(Query query) {
MongoEntityMetadata<?> metadata = method.getEntityInformation();
int overallLimit = query.getLimit();
long count = operations.count(query, metadata.getCollectionName());
count = overallLimit != 0 ? Math.min(count, query.getLimit()) : count;
List<?> result = operations.find(query.with(pageable), metadata.getJavaType(), metadata.getCollectionName());
boolean pageableOutOfScope = pageable.getOffset() > query.getLimit();
if (pageableOutOfScope) {
return new PageImpl<Object>(Collections.emptyList(), pageable, count);
}
// Apply raw pagination
query = query.with(pageable);
// Adjust limit if page would exceed the overall limit
if (overallLimit != 0 && pageable.getOffset() + pageable.getPageSize() > overallLimit) {
query.limit(overallLimit - pageable.getOffset());
}
List<?> result = operations.find(query, metadata.getJavaType(), metadata.getCollectionName());
return new PageImpl(result, pageable, count);
}
}

View File

@@ -73,6 +73,10 @@ public class PartTreeMongoQuery extends AbstractMongoQuery {
MongoQueryCreator creator = new MongoQueryCreator(tree, accessor, context, isGeoNearQuery);
Query query = creator.createQuery();
if (tree.isLimiting()) {
query.limit(tree.getMaxResults());
}
String fieldSpec = this.getQueryMethod().getFieldSpecification();
if (!StringUtils.hasText(fieldSpec)) {

View File

@@ -917,5 +917,54 @@ public abstract class AbstractPersonRepositoryIntegrationTests {
assertThat(result.getContent(), hasSize(2));
assertThat(result.getTotalPages(), is(2));
assertThat(result.getTotalElements(), is(3L));
}
/**
* @see DATAMONGO-950
*/
@Test
public void shouldLimitCollectionQueryToMaxResultsWhenPresent() {
repository.save(Arrays.asList(new Person("Bob-1", "Dylan"), new Person("Bob-2", "Dylan"), new Person("Bob-3",
"Dylan"), new Person("Bob-4", "Dylan"), new Person("Bob-5", "Dylan")));
List<Person> result = repository.findTop3ByLastnameStartingWith("Dylan");
assertThat(result.size(), is(3));
}
/**
* @see DATAMONGO-950
*/
@Test
public void shouldNotLimitPagedQueryWhenPageRequestWithinBounds() {
repository.save(Arrays.asList(new Person("Bob-1", "Dylan"), new Person("Bob-2", "Dylan"), new Person("Bob-3",
"Dylan"), new Person("Bob-4", "Dylan"), new Person("Bob-5", "Dylan")));
Page<Person> result = repository.findTop3ByLastnameStartingWith("Dylan", new PageRequest(0, 2));
assertThat(result.getContent().size(), is(2));
}
/**
* @see DATAMONGO-950
*/
@Test
public void shouldLimitPagedQueryWhenPageRequestExceedsUpperBoundary() {
repository.save(Arrays.asList(new Person("Bob-1", "Dylan"), new Person("Bob-2", "Dylan"), new Person("Bob-3",
"Dylan"), new Person("Bob-4", "Dylan"), new Person("Bob-5", "Dylan")));
Page<Person> result = repository.findTop3ByLastnameStartingWith("Dylan", new PageRequest(1, 2));
assertThat(result.getContent().size(), is(1));
}
/**
* @see DATAMONGO-950
*/
@Test
public void shouldReturnEmptyWhenPageRequestedPageIsTotallyOutOfScopeForLimit() {
repository.save(Arrays.asList(new Person("Bob-1", "Dylan"), new Person("Bob-2", "Dylan"), new Person("Bob-3",
"Dylan"), new Person("Bob-4", "Dylan"), new Person("Bob-5", "Dylan")));
Page<Person> result = repository.findTop3ByLastnameStartingWith("Dylan", new PageRequest(2, 2));
assertThat(result.getContent().size(), is(0));
}
}

View File

@@ -302,4 +302,15 @@ public interface PersonRepository extends MongoRepository<Person, String>, Query
*/
@Query("{lastname:?0, address.street:{$in:?1}}")
Page<Person> findByCustomQueryLastnameAndAddressStreetInList(String lastname, List<String> streetNames, Pageable page);
/**
* @see DATAMONGO-950
*/
List<Person> findTop3ByLastnameStartingWith(String lastname);
/**
* @see DATAMONGO-950
*/
Page<Person> findTop3ByLastnameStartingWith(String lastname, Pageable pageRequest);
}