From 6963f9e07a8a47dcba5972b6b71d9235ff307f40 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 4 Mar 2014 17:27:31 +0100 Subject: [PATCH] DATAMONGO-870 - Added support for sliced query execution. Added support for Slice as return type for query methods. The execution will expand the requested page size by one to read one more element than actually requested. If that additional element is returned, it will considered to be an indicator for whether a next slice is available. Related issues: DATACMNS-397. --- .../repository/query/AbstractMongoQuery.java | 40 +++++++++++++++++++ ...tractPersonRepositoryIntegrationTests.java | 30 +++++++++----- .../mongodb/repository/PersonRepository.java | 7 +++- 3 files changed, 67 insertions(+), 10 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractMongoQuery.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractMongoQuery.java index 190c83b82..7feffa28c 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractMongoQuery.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractMongoQuery.java @@ -20,7 +20,10 @@ import java.util.List; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.data.domain.SliceImpl; import org.springframework.data.mongodb.core.MongoOperations; import org.springframework.data.mongodb.core.geo.Distance; import org.springframework.data.mongodb.core.geo.GeoPage; @@ -87,6 +90,8 @@ public abstract class AbstractMongoQuery implements RepositoryQuery { return new GeoNearExecution(accessor).execute(query, countQuery); } else if (method.isGeoNearQuery()) { return new GeoNearExecution(accessor).execute(query); + } else if (method.isSliceQuery()) { + return new SlicedExecution(accessor.getPageable()).execute(query); } else if (method.isCollectionQuery()) { return new CollectionExecution(accessor.getPageable()).execute(query); } else if (method.isPageQuery()) { @@ -171,6 +176,41 @@ public abstract class AbstractMongoQuery implements RepositoryQuery { } } + /** + * {@link Execution} for {@link Slice} query methods. + * + * @author Oliver Gierke + * @since 1.5 + */ + + final class SlicedExecution extends Execution { + + private final Pageable pageable; + + SlicedExecution(Pageable pageable) { + this.pageable = pageable; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.mongodb.repository.query.AbstractMongoQuery.Execution#execute(org.springframework.data.mongodb.core.query.Query) + */ + @Override + @SuppressWarnings({ "unchecked", "rawtypes" }) + Object execute(Query query) { + + MongoEntityMetadata metadata = method.getEntityInformation(); + int pageSize = pageable.getPageSize(); + Pageable slicePageable = new PageRequest(pageable.getPageNumber(), pageSize + 1, pageable.getSort()); + + List result = operations.find(query.with(slicePageable), metadata.getJavaType(), metadata.getCollectionName()); + + boolean hasNext = result.size() > pageSize; + + return new SliceImpl(hasNext ? result.subList(0, pageSize) : result, pageable, hasNext); + } + } + /** * {@link Execution} for pagination queries. * diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java index a3ffd2dc7..32af2d790 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2013 the original author or authors. + * Copyright 2011-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DuplicateKeyException; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Slice; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; import org.springframework.data.mongodb.core.MongoOperations; @@ -155,8 +156,8 @@ public abstract class AbstractPersonRepositoryIntegrationTests { public void findsPagedPersons() throws Exception { Page result = repository.findAll(new PageRequest(1, 2, Direction.ASC, "lastname", "firstname")); - assertThat(result.isFirstPage(), is(false)); - assertThat(result.isLastPage(), is(false)); + assertThat(result.isFirst(), is(false)); + assertThat(result.isLast(), is(false)); assertThat(result, hasItems(dave, stefan)); } @@ -165,8 +166,8 @@ public abstract class AbstractPersonRepositoryIntegrationTests { Page page = repository.findByLastnameLike("*a*", new PageRequest(0, 2, Direction.ASC, "lastname", "firstname")); - assertThat(page.isFirstPage(), is(true)); - assertThat(page.isLastPage(), is(false)); + assertThat(page.isFirst(), is(true)); + assertThat(page.isLast(), is(false)); assertThat(page.getNumberOfElements(), is(2)); assertThat(page, hasItems(carter, stefan)); } @@ -176,8 +177,8 @@ public abstract class AbstractPersonRepositoryIntegrationTests { Page page = repository.findByLastnameLikeWithPageable(".*a.*", new PageRequest(0, 2, Direction.ASC, "lastname", "firstname")); - assertThat(page.isFirstPage(), is(true)); - assertThat(page.isLastPage(), is(false)); + assertThat(page.isFirst(), is(true)); + assertThat(page.isLast(), is(false)); assertThat(page.getNumberOfElements(), is(2)); assertThat(page, hasItems(carter, stefan)); } @@ -301,8 +302,8 @@ public abstract class AbstractPersonRepositoryIntegrationTests { Page page = repository.findAll(person.lastname.contains("a"), new PageRequest(0, 2, Direction.ASC, "lastname")); - assertThat(page.isFirstPage(), is(true)); - assertThat(page.isLastPage(), is(false)); + assertThat(page.isFirst(), is(true)); + assertThat(page.isLast(), is(false)); assertThat(page.getNumberOfElements(), is(2)); assertThat(page, hasItems(carter, stefan)); } @@ -738,4 +739,15 @@ public abstract class AbstractPersonRepositoryIntegrationTests { assertThat(result.size(), is(1)); assertThat(result.get(0), is(dave)); } + + /** + * @see DATAMONGO-870 + */ + @Test + public void findsSliceOfPersons() { + + Slice result = repository.findByAgeGreaterThan(40, new PageRequest(0, 2, Direction.DESC, "firstname")); + + assertThat(result.hasNext(), is(true)); + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepository.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepository.java index 52285f763..2d639e32f 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepository.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepository.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2013 the original author or authors. + * Copyright 2010-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ import java.util.List; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; import org.springframework.data.domain.Sort; import org.springframework.data.mongodb.core.geo.Box; import org.springframework.data.mongodb.core.geo.Circle; @@ -245,4 +246,8 @@ public interface PersonRepository extends MongoRepository, Query */ List findByFirstnameContainingIgnoreCase(String firstName); + /** + * @see DATAMONGO-870 + */ + Slice findByAgeGreaterThan(int age, Pageable pageable); }