Browse Source

Prevent key extraction if a keyset value is null.

Follow the changes in data commons that renamed scroll to window.
Also error when a certain scroll position does not allow creating a query out of it because of null values.

See: #4308
Original Pull Request: #4317
pull/4334/head
Christoph Strobl 3 years ago
parent
commit
9d0afc975a
No known key found for this signature in database
GPG Key ID: 8CC1AB53391458C8
  1. 27
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/EntityOperations.java
  2. 9
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ExecutableFindOperation.java
  3. 4
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ExecutableFindOperationSupport.java
  4. 20
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java
  5. 12
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java
  6. 4
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveFindOperation.java
  7. 4
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveFindOperationSupport.java
  8. 14
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoOperations.java
  9. 12
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java
  10. 21
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ScrollUtils.java
  11. 4
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/QuerydslMongoPredicateExecutor.java
  12. 4
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactiveQuerydslMongoPredicateExecutor.java
  13. 4
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactiveSpringDataMongodbQuery.java
  14. 4
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepository.java
  15. 4
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleReactiveMongoRepository.java
  16. 6
      spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SpringDataMongodbQuery.java
  17. 52
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateScrollTests.java
  18. 10
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateScrollTests.java
  19. 12
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/AbstractPersonRepositoryIntegrationTests.java
  20. 10
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/PersonRepository.java
  21. 18
      spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/ReactiveMongoRepositoryTests.java

27
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/EntityOperations.java

@ -21,6 +21,7 @@ import java.util.LinkedHashMap; @@ -21,6 +21,7 @@ import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
import org.bson.BsonNull;
import org.bson.Document;
import org.springframework.core.convert.ConversionService;
import org.springframework.dao.InvalidDataAccessApiUsageException;
@ -471,6 +472,7 @@ class EntityOperations { @@ -471,6 +472,7 @@ class EntityOperations {
* @param sortObject
* @return
* @since 3.1
* @throws IllegalStateException if a sort key yields {@literal null}.
*/
Map<String, Object> extractKeys(Document sortObject);
@ -600,7 +602,14 @@ class EntityOperations { @@ -600,7 +602,14 @@ class EntityOperations {
keyset.put(ID_FIELD, getId());
for (String key : sortObject.keySet()) {
keyset.put(key, BsonUtils.resolveValue(map, key));
Object value = BsonUtils.resolveValue(map, key);
if (value == null) {
throw new IllegalStateException(
String.format("Cannot extract value for key %s because its value is null", key));
}
keyset.put(key, value);
}
return keyset;
@ -756,14 +765,22 @@ class EntityOperations { @@ -756,14 +765,22 @@ class EntityOperations {
for (String key : sortObject.keySet()) {
Object value;
if (key.indexOf('.') != -1) {
// follow the path across nested levels.
// TODO: We should have a MongoDB-specific property path abstraction to allow diving into Document.
keyset.put(key, getNestedPropertyValue(key));
value = getNestedPropertyValue(key);
} else {
keyset.put(key, getPropertyValue(key));
value = getPropertyValue(key);
}
if (value == null) {
throw new IllegalStateException(
String.format("Cannot extract value for key %s because its value is null", key));
}
keyset.put(key, value);
}
return keyset;
@ -774,7 +791,7 @@ class EntityOperations { @@ -774,7 +791,7 @@ class EntityOperations {
String[] segments = key.split("\\.");
Entity<?> currentEntity = this;
Object currentValue = null;
Object currentValue = BsonNull.VALUE;
for (int i = 0; i < segments.length; i++) {
@ -786,7 +803,7 @@ class EntityOperations { @@ -786,7 +803,7 @@ class EntityOperations {
}
}
return currentValue;
return currentValue != null ? currentValue : BsonNull.VALUE;
}
}

9
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ExecutableFindOperation.java

@ -20,7 +20,7 @@ import java.util.Optional; @@ -20,7 +20,7 @@ import java.util.Optional;
import java.util.stream.Stream;
import org.springframework.dao.DataAccessException;
import org.springframework.data.domain.Scroll;
import org.springframework.data.domain.Window;
import org.springframework.data.domain.ScrollPosition;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.mongodb.core.query.CriteriaDefinition;
@ -126,16 +126,17 @@ public interface ExecutableFindOperation { @@ -126,16 +126,17 @@ public interface ExecutableFindOperation {
Stream<T> stream();
/**
* Return a scroll of elements either starting or resuming at
* Return a window of elements either starting or resuming at
* {@link org.springframework.data.domain.ScrollPosition}.
*
* @param scrollPosition the scroll position.
* @return a scroll of the resulting elements.
* @return a window of the resulting elements.
* @throws IllegalStateException if a potential {@literal KeysetScrollPosition} contains an invalid position.
* @since 4.1
* @see org.springframework.data.domain.OffsetScrollPosition
* @see org.springframework.data.domain.KeysetScrollPosition
*/
Scroll<T> scroll(ScrollPosition scrollPosition);
Window<T> scroll(ScrollPosition scrollPosition);
/**
* Get the number of matching elements. <br />

4
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ExecutableFindOperationSupport.java

@ -21,7 +21,7 @@ import java.util.stream.Stream; @@ -21,7 +21,7 @@ import java.util.stream.Stream;
import org.bson.Document;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.data.domain.Scroll;
import org.springframework.data.domain.Window;
import org.springframework.data.domain.ScrollPosition;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.Query;
@ -141,7 +141,7 @@ class ExecutableFindOperationSupport implements ExecutableFindOperation { @@ -141,7 +141,7 @@ class ExecutableFindOperationSupport implements ExecutableFindOperation {
}
@Override
public Scroll<T> scroll(ScrollPosition scrollPosition) {
public Window<T> scroll(ScrollPosition scrollPosition) {
return template.doScroll(query.with(scrollPosition), domainType, returnType, getCollectionName());
}

20
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java

@ -24,7 +24,7 @@ import java.util.stream.Stream; @@ -24,7 +24,7 @@ import java.util.stream.Stream;
import org.bson.Document;
import org.springframework.data.domain.KeysetScrollPosition;
import org.springframework.data.domain.Scroll;
import org.springframework.data.domain.Window;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.mongodb.core.BulkOperations.BulkMode;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
@ -807,7 +807,7 @@ public interface MongoOperations extends FluentMongoOperations { @@ -807,7 +807,7 @@ public interface MongoOperations extends FluentMongoOperations {
<T> List<T> find(Query query, Class<T> entityClass, String collectionName);
/**
* Query for a scroll window of objects of type T from the specified collection. <br />
* Query for a window window of objects of type T from the specified collection. <br />
* Make sure to either set {@link Query#skip(long)} or {@link Query#with(KeysetScrollPosition)} along with
* {@link Query#limit(int)} to limit large query results for efficient scrolling. <br />
* Result objects are converted from the MongoDB native representation using an instance of {@see MongoConverter}.
@ -817,16 +817,17 @@ public interface MongoOperations extends FluentMongoOperations { @@ -817,16 +817,17 @@ public interface MongoOperations extends FluentMongoOperations {
*
* @param query the query class that specifies the criteria used to find a record and also an optional fields
* specification. Must not be {@literal null}.
* @param entityType the parametrized type of the returned list.
* @return the converted scroll.
* @param entityType the parametrized type of the returned window.
* @return the converted window.
* @throws IllegalStateException if a potential {@link Query#getKeyset() KeysetScrollPosition} contains an invalid position.
* @since 4.1
* @see Query#with(org.springframework.data.domain.OffsetScrollPosition)
* @see Query#with(org.springframework.data.domain.KeysetScrollPosition)
*/
<T> Scroll<T> scroll(Query query, Class<T> entityType);
<T> Window<T> scroll(Query query, Class<T> entityType);
/**
* Query for a scroll of objects of type T from the specified collection. <br />
* Query for a window of objects of type T from the specified collection. <br />
* Make sure to either set {@link Query#skip(long)} or {@link Query#with(KeysetScrollPosition)} along with
* {@link Query#limit(int)} to limit large query results for efficient scrolling. <br />
* Result objects are converted from the MongoDB native representation using an instance of {@see MongoConverter}.
@ -836,14 +837,15 @@ public interface MongoOperations extends FluentMongoOperations { @@ -836,14 +837,15 @@ public interface MongoOperations extends FluentMongoOperations {
*
* @param query the query class that specifies the criteria used to find a record and also an optional fields
* specification. Must not be {@literal null}.
* @param entityType the parametrized type of the returned list.
* @param entityType the parametrized type of the returned window.
* @param collectionName name of the collection to retrieve the objects from.
* @return the converted scroll.
* @return the converted window.
* @throws IllegalStateException if a potential {@link Query#getKeyset() KeysetScrollPosition} contains an invalid position.
* @since 4.1
* @see Query#with(org.springframework.data.domain.OffsetScrollPosition)
* @see Query#with(org.springframework.data.domain.KeysetScrollPosition)
*/
<T> Scroll<T> scroll(Query query, Class<T> entityType, String collectionName);
<T> Window<T> scroll(Query query, Class<T> entityType, String collectionName);
/**
* Returns a document with the given id mapped onto the given class. The collection the query is ran against will be

12
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java

@ -45,7 +45,7 @@ import org.springframework.dao.OptimisticLockingFailureException; @@ -45,7 +45,7 @@ import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.convert.EntityReader;
import org.springframework.data.domain.OffsetScrollPosition;
import org.springframework.data.domain.Scroll;
import org.springframework.data.domain.Window;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoResult;
import org.springframework.data.geo.GeoResults;
@ -66,7 +66,7 @@ import org.springframework.data.mongodb.core.QueryOperations.DeleteContext; @@ -66,7 +66,7 @@ import org.springframework.data.mongodb.core.QueryOperations.DeleteContext;
import org.springframework.data.mongodb.core.QueryOperations.DistinctQueryContext;
import org.springframework.data.mongodb.core.QueryOperations.QueryContext;
import org.springframework.data.mongodb.core.QueryOperations.UpdateContext;
import org.springframework.data.mongodb.core.ScrollUtils.KeySetCursorQuery;
import org.springframework.data.mongodb.core.ScrollUtils.KeySetScrollQuery;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperationContext;
import org.springframework.data.mongodb.core.aggregation.AggregationOptions;
@ -851,7 +851,7 @@ public class MongoTemplate @@ -851,7 +851,7 @@ public class MongoTemplate
}
@Override
public <T> Scroll<T> scroll(Query query, Class<T> entityType) {
public <T> Window<T> scroll(Query query, Class<T> entityType) {
Assert.notNull(entityType, "Entity type must not be null");
@ -859,11 +859,11 @@ public class MongoTemplate @@ -859,11 +859,11 @@ public class MongoTemplate
}
@Override
public <T> Scroll<T> scroll(Query query, Class<T> entityType, String collectionName) {
public <T> Window<T> scroll(Query query, Class<T> entityType, String collectionName) {
return doScroll(query, entityType, entityType, collectionName);
}
<T> Scroll<T> doScroll(Query query, Class<?> sourceClass, Class<T> targetClass, String collectionName) {
<T> Window<T> doScroll(Query query, Class<?> sourceClass, Class<T> targetClass, String collectionName) {
Assert.notNull(query, "Query must not be null");
Assert.notNull(collectionName, "CollectionName must not be null");
@ -875,7 +875,7 @@ public class MongoTemplate @@ -875,7 +875,7 @@ public class MongoTemplate
if (query.hasKeyset()) {
KeySetCursorQuery keysetPaginationQuery = ScrollUtils.createKeysetPaginationQuery(query,
KeySetScrollQuery keysetPaginationQuery = ScrollUtils.createKeysetPaginationQuery(query,
operations.getIdPropertyName(sourceClass));
List<T> result = doFind(collectionName, createDelegate(query), keysetPaginationQuery.query(),

4
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveFindOperation.java

@ -18,7 +18,7 @@ package org.springframework.data.mongodb.core; @@ -18,7 +18,7 @@ package org.springframework.data.mongodb.core;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.data.domain.Scroll;
import org.springframework.data.domain.Window;
import org.springframework.data.domain.ScrollPosition;
import org.springframework.data.geo.GeoResult;
import org.springframework.data.mongodb.core.query.CriteriaDefinition;
@ -98,7 +98,7 @@ public interface ReactiveFindOperation { @@ -98,7 +98,7 @@ public interface ReactiveFindOperation {
* @see org.springframework.data.domain.OffsetScrollPosition
* @see org.springframework.data.domain.KeysetScrollPosition
*/
Mono<Scroll<T>> scroll(ScrollPosition scrollPosition);
Mono<Window<T>> scroll(ScrollPosition scrollPosition);
/**
* Get all matching elements using a {@link com.mongodb.CursorType#TailableAwait tailable cursor}. The stream will

4
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveFindOperationSupport.java

@ -20,7 +20,7 @@ import reactor.core.publisher.Mono; @@ -20,7 +20,7 @@ import reactor.core.publisher.Mono;
import org.bson.Document;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.data.domain.Scroll;
import org.springframework.data.domain.Window;
import org.springframework.data.domain.ScrollPosition;
import org.springframework.data.mongodb.core.CollectionPreparerSupport.ReactiveCollectionPreparerDelegate;
import org.springframework.data.mongodb.core.query.NearQuery;
@ -140,7 +140,7 @@ class ReactiveFindOperationSupport implements ReactiveFindOperation { @@ -140,7 +140,7 @@ class ReactiveFindOperationSupport implements ReactiveFindOperation {
}
@Override
public Mono<Scroll<T>> scroll(ScrollPosition scrollPosition) {
public Mono<Window<T>> scroll(ScrollPosition scrollPosition) {
return template.doScroll(query.with(scrollPosition), domainType, returnType, getCollectionName());
}

14
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoOperations.java

@ -26,7 +26,7 @@ import org.bson.Document; @@ -26,7 +26,7 @@ import org.bson.Document;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscription;
import org.springframework.data.domain.KeysetScrollPosition;
import org.springframework.data.domain.Scroll;
import org.springframework.data.domain.Window;
import org.springframework.data.geo.GeoResult;
import org.springframework.data.mongodb.ReactiveMongoDatabaseFactory;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
@ -477,15 +477,16 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { @@ -477,15 +477,16 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations {
* @param query the query class that specifies the criteria used to find a record and also an optional fields
* specification. Must not be {@literal null}.
* @param entityType the parametrized type of the returned list.
* @return {@link Mono} emitting the converted scroll.
* @return {@link Mono} emitting the converted window.
* @throws IllegalStateException if a potential {@link Query#getKeyset() KeysetScrollPosition} contains an invalid position.
* @since 4.1
* @see Query#with(org.springframework.data.domain.OffsetScrollPosition)
* @see Query#with(org.springframework.data.domain.KeysetScrollPosition)
*/
<T> Mono<Scroll<T>> scroll(Query query, Class<T> entityType);
<T> Mono<Window<T>> scroll(Query query, Class<T> entityType);
/**
* Query for a scroll of objects of type T from the specified collection. <br />
* Query for a window of objects of type T from the specified collection. <br />
* Make sure to either set {@link Query#skip(long)} or {@link Query#with(KeysetScrollPosition)} along with
* {@link Query#limit(int)} to limit large query results for efficient scrolling. <br />
* Result objects are converted from the MongoDB native representation using an instance of {@see MongoConverter}.
@ -497,12 +498,13 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { @@ -497,12 +498,13 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations {
* specification. Must not be {@literal null}.
* @param entityType the parametrized type of the returned list.
* @param collectionName name of the collection to retrieve the objects from.
* @return {@link Mono} emitting the converted scroll window.
* @return {@link Mono} emitting the converted window.
* @throws IllegalStateException if a potential {@link Query#getKeyset() KeysetScrollPosition} contains an invalid position.
* @since 4.1
* @see Query#with(org.springframework.data.domain.OffsetScrollPosition)
* @see Query#with(org.springframework.data.domain.KeysetScrollPosition)
*/
<T> Mono<Scroll<T>> scroll(Query query, Class<T> entityType, String collectionName);
<T> Mono<Window<T>> scroll(Query query, Class<T> entityType, String collectionName);
/**
* Returns a document with the given id mapped onto the given class. The collection the query is ran against will be

12
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java

@ -59,7 +59,7 @@ import org.springframework.dao.OptimisticLockingFailureException; @@ -59,7 +59,7 @@ import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.convert.EntityReader;
import org.springframework.data.domain.OffsetScrollPosition;
import org.springframework.data.domain.Scroll;
import org.springframework.data.domain.Window;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoResult;
import org.springframework.data.geo.Metric;
@ -80,7 +80,7 @@ import org.springframework.data.mongodb.core.QueryOperations.DeleteContext; @@ -80,7 +80,7 @@ import org.springframework.data.mongodb.core.QueryOperations.DeleteContext;
import org.springframework.data.mongodb.core.QueryOperations.DistinctQueryContext;
import org.springframework.data.mongodb.core.QueryOperations.QueryContext;
import org.springframework.data.mongodb.core.QueryOperations.UpdateContext;
import org.springframework.data.mongodb.core.ScrollUtils.KeySetCursorQuery;
import org.springframework.data.mongodb.core.ScrollUtils.KeySetScrollQuery;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperationContext;
import org.springframework.data.mongodb.core.aggregation.AggregationOptions;
@ -830,7 +830,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -830,7 +830,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
}
@Override
public <T> Mono<Scroll<T>> scroll(Query query, Class<T> entityType) {
public <T> Mono<Window<T>> scroll(Query query, Class<T> entityType) {
Assert.notNull(entityType, "Entity type must not be null");
@ -838,11 +838,11 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -838,11 +838,11 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
}
@Override
public <T> Mono<Scroll<T>> scroll(Query query, Class<T> entityType, String collectionName) {
public <T> Mono<Window<T>> scroll(Query query, Class<T> entityType, String collectionName) {
return doScroll(query, entityType, entityType, collectionName);
}
<T> Mono<Scroll<T>> doScroll(Query query, Class<?> sourceClass, Class<T> targetClass, String collectionName) {
<T> Mono<Window<T>> doScroll(Query query, Class<?> sourceClass, Class<T> targetClass, String collectionName) {
Assert.notNull(query, "Query must not be null");
Assert.notNull(collectionName, "CollectionName must not be null");
@ -853,7 +853,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati @@ -853,7 +853,7 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati
if (query.hasKeyset()) {
KeySetCursorQuery keysetPaginationQuery = ScrollUtils.createKeysetPaginationQuery(query,
KeySetScrollQuery keysetPaginationQuery = ScrollUtils.createKeysetPaginationQuery(query,
operations.getIdPropertyName(sourceClass));
Mono<List<T>> result = doFind(collectionName, ReactiveCollectionPreparerDelegate.of(query),

21
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ScrollUtils.java

@ -20,17 +20,19 @@ import java.util.List; @@ -20,17 +20,19 @@ import java.util.List;
import java.util.Map;
import java.util.function.IntFunction;
import org.bson.BsonNull;
import org.bson.Document;
import org.springframework.data.domain.KeysetScrollPosition;
import org.springframework.data.domain.Scroll;
import org.springframework.data.domain.ScrollPosition;
import org.springframework.data.domain.Window;
import org.springframework.data.mongodb.core.EntityOperations.Entity;
import org.springframework.data.mongodb.core.query.Query;
/**
* Utilities to run scroll queries and create {@link Scroll} results.
* Utilities to run scroll queries and create {@link Window} results.
*
* @author Mark Paluch
* @author Christoph Strobl
* @since 4.1
*/
class ScrollUtils {
@ -42,7 +44,7 @@ class ScrollUtils { @@ -42,7 +44,7 @@ class ScrollUtils {
* @param idPropertyName
* @return
*/
static KeySetCursorQuery createKeysetPaginationQuery(Query query, String idPropertyName) {
static KeySetScrollQuery createKeysetPaginationQuery(Query query, String idPropertyName) {
Document sortObject = query.isSorted() ? query.getSortObject() : new Document();
sortObject.put(idPropertyName, 1);
@ -84,6 +86,9 @@ class ScrollUtils { @@ -84,6 +86,9 @@ class ScrollUtils {
Object o = keysetValues.get(sortSegment);
if (j >= i) { // tail segment
if(o instanceof BsonNull) {
throw new IllegalStateException("Cannot resume from KeysetScrollPosition. Offending key: '%s' is 'null'".formatted(sortSegment));
}
sortConstraint.put(sortSegment, new Document(sortOrder == 1 ? "$gt" : "$lt", o));
break;
}
@ -104,10 +109,10 @@ class ScrollUtils { @@ -104,10 +109,10 @@ class ScrollUtils {
queryObject.put("$or", or);
}
return new KeySetCursorQuery(queryObject, fieldsObject, sortObject);
return new KeySetScrollQuery(queryObject, fieldsObject, sortObject);
}
static <T> Scroll<T> createWindow(Document sortObject, int limit, List<T> result, EntityOperations operations) {
static <T> Window<T> createWindow(Document sortObject, int limit, List<T> result, EntityOperations operations) {
IntFunction<KeysetScrollPosition> positionFunction = value -> {
@ -121,8 +126,8 @@ class ScrollUtils { @@ -121,8 +126,8 @@ class ScrollUtils {
return createWindow(result, limit, positionFunction);
}
static <T> Scroll<T> createWindow(List<T> result, int limit, IntFunction<? extends ScrollPosition> positionFunction) {
return Scroll.from(getSubList(result, limit), positionFunction, hasMoreElements(result, limit));
static <T> Window<T> createWindow(List<T> result, int limit, IntFunction<? extends ScrollPosition> positionFunction) {
return Window.from(getSubList(result, limit), positionFunction, hasMoreElements(result, limit));
}
static boolean hasMoreElements(List<?> result, int limit) {
@ -138,7 +143,7 @@ class ScrollUtils { @@ -138,7 +143,7 @@ class ScrollUtils {
return result;
}
record KeySetCursorQuery(Document query, Document fields, Document sort) {
record KeySetScrollQuery(Document query, Document fields, Document sort) {
}

4
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/QuerydslMongoPredicateExecutor.java

@ -25,7 +25,7 @@ import org.bson.Document; @@ -25,7 +25,7 @@ import org.bson.Document;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Scroll;
import org.springframework.data.domain.Window;
import org.springframework.data.domain.ScrollPosition;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoOperations;
@ -259,7 +259,7 @@ public class QuerydslMongoPredicateExecutor<T> extends QuerydslPredicateExecutor @@ -259,7 +259,7 @@ public class QuerydslMongoPredicateExecutor<T> extends QuerydslPredicateExecutor
}
@Override
public Scroll<T> scroll(ScrollPosition scrollPosition) {
public Window<T> scroll(ScrollPosition scrollPosition) {
return createQuery().scroll(scrollPosition);
}

4
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactiveQuerydslMongoPredicateExecutor.java

@ -26,7 +26,7 @@ import org.bson.Document; @@ -26,7 +26,7 @@ import org.bson.Document;
import org.reactivestreams.Publisher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Scroll;
import org.springframework.data.domain.Window;
import org.springframework.data.domain.ScrollPosition;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
@ -227,7 +227,7 @@ public class ReactiveQuerydslMongoPredicateExecutor<T> extends QuerydslPredicate @@ -227,7 +227,7 @@ public class ReactiveQuerydslMongoPredicateExecutor<T> extends QuerydslPredicate
}
@Override
public Mono<Scroll<T>> scroll(ScrollPosition scrollPosition) {
public Mono<Window<T>> scroll(ScrollPosition scrollPosition) {
return createQuery().scroll(scrollPosition);
}

4
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/ReactiveSpringDataMongodbQuery.java

@ -26,7 +26,7 @@ import java.util.function.Consumer; @@ -26,7 +26,7 @@ import java.util.function.Consumer;
import org.bson.Document;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Scroll;
import org.springframework.data.domain.Window;
import org.springframework.data.domain.ScrollPosition;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.ReactiveFindOperation;
@ -91,7 +91,7 @@ class ReactiveSpringDataMongodbQuery<K> extends SpringDataMongodbQuerySupport<Re @@ -91,7 +91,7 @@ class ReactiveSpringDataMongodbQuery<K> extends SpringDataMongodbQuerySupport<Re
return createQuery().flatMapMany(it -> find.matching(it).all());
}
Mono<Scroll<K>> scroll(ScrollPosition scrollPosition) {
Mono<Window<K>> scroll(ScrollPosition scrollPosition) {
return createQuery().flatMap(it -> find.matching(it).scroll(scrollPosition));
}

4
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleMongoRepository.java

@ -32,7 +32,7 @@ import org.springframework.data.domain.Example; @@ -32,7 +32,7 @@ import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Scroll;
import org.springframework.data.domain.Window;
import org.springframework.data.domain.ScrollPosition;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.ExecutableFindOperation;
@ -392,7 +392,7 @@ public class SimpleMongoRepository<T, ID> implements MongoRepository<T, ID> { @@ -392,7 +392,7 @@ public class SimpleMongoRepository<T, ID> implements MongoRepository<T, ID> {
}
@Override
public Scroll<T> scroll(ScrollPosition scrollPosition) {
public Window<T> scroll(ScrollPosition scrollPosition) {
return createQuery().scroll(scrollPosition);
}

4
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SimpleReactiveMongoRepository.java

@ -34,7 +34,7 @@ import org.springframework.dao.OptimisticLockingFailureException; @@ -34,7 +34,7 @@ import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Scroll;
import org.springframework.data.domain.Window;
import org.springframework.data.domain.ScrollPosition;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.ReactiveFindOperation;
@ -436,7 +436,7 @@ public class SimpleReactiveMongoRepository<T, ID extends Serializable> implement @@ -436,7 +436,7 @@ public class SimpleReactiveMongoRepository<T, ID extends Serializable> implement
}
@Override
public Mono<Scroll<T>> scroll(ScrollPosition scrollPosition) {
public Mono<Window<T>> scroll(ScrollPosition scrollPosition) {
return createQuery().scroll(scrollPosition);
}

6
spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/SpringDataMongodbQuery.java

@ -25,7 +25,7 @@ import org.bson.Document; @@ -25,7 +25,7 @@ import org.bson.Document;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Scroll;
import org.springframework.data.domain.Window;
import org.springframework.data.domain.ScrollPosition;
import org.springframework.data.mongodb.core.ExecutableFindOperation;
import org.springframework.data.mongodb.core.MongoOperations;
@ -133,12 +133,12 @@ public class SpringDataMongodbQuery<T> extends SpringDataMongodbQuerySupport<Spr @@ -133,12 +133,12 @@ public class SpringDataMongodbQuery<T> extends SpringDataMongodbQuerySupport<Spr
}
}
public Scroll<T> scroll(ScrollPosition scrollPosition) {
public Window<T> scroll(ScrollPosition scrollPosition) {
try {
return find.matching(createQuery()).scroll(scrollPosition);
} catch (RuntimeException e) {
return handleException(e, Scroll.from(Collections.emptyList(), value -> {
return handleException(e, Window.from(Collections.emptyList(), value -> {
throw new UnsupportedOperationException();
}));
}

52
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateScrollTests.java

@ -38,9 +38,9 @@ import org.springframework.data.annotation.PersistenceCreator; @@ -38,9 +38,9 @@ import org.springframework.data.annotation.PersistenceCreator;
import org.springframework.data.auditing.IsNewAwareAuditingHandler;
import org.springframework.data.domain.KeysetScrollPosition;
import org.springframework.data.domain.OffsetScrollPosition;
import org.springframework.data.domain.Scroll;
import org.springframework.data.domain.ScrollPosition;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Window;
import org.springframework.data.mapping.context.PersistentEntities;
import org.springframework.data.mongodb.core.MongoTemplateTests.PersonWithIdPropertyOfTypeUUIDListener;
import org.springframework.data.mongodb.core.query.Query;
@ -51,9 +51,10 @@ import org.springframework.data.mongodb.test.util.MongoTestTemplate; @@ -51,9 +51,10 @@ import org.springframework.data.mongodb.test.util.MongoTestTemplate;
import com.mongodb.client.MongoClient;
/**
* Integration tests for {@link Scroll} queries.
* Integration tests for {@link org.springframework.data.domain.Window} queries.
*
* @author Mark Paluch
* @author Christoph Strobl
*/
@ExtendWith(MongoClientExtension.class)
class MongoTemplateScrollTests {
@ -94,7 +95,7 @@ class MongoTemplateScrollTests { @@ -94,7 +95,7 @@ class MongoTemplateScrollTests {
template.remove(WithNestedDocument.class).all();
}
@Test
@Test // GH-4308
void shouldUseKeysetScrollingWithNestedSort() {
WithNestedDocument john20 = new WithNestedDocument(null, "John", 120, new WithNestedDocument("John", 20),
@ -110,20 +111,55 @@ class MongoTemplateScrollTests { @@ -110,20 +111,55 @@ class MongoTemplateScrollTests {
.limit(2);
q.with(KeysetScrollPosition.initial());
Scroll<WithNestedDocument> scroll = template.scroll(q, WithNestedDocument.class);
Window<WithNestedDocument> scroll = template.scroll(q, WithNestedDocument.class);
assertThat(scroll.hasNext()).isTrue();
assertThat(scroll.isLast()).isFalse();
assertThat(scroll).hasSize(2);
assertThat(scroll).containsOnly(john20, john40);
scroll = template.scroll(q.with(scroll.lastPosition()), WithNestedDocument.class);
scroll = template.scroll(q.with(scroll.positionAt(scroll.size()-1)), WithNestedDocument.class);
assertThat(scroll.hasNext()).isFalse();
assertThat(scroll.isLast()).isTrue();
assertThat(scroll).hasSize(1);
assertThat(scroll).containsOnly(john41);
}
@Test // GH-4308
void shouldErrorOnNullValueForQuery() {
WithNestedDocument john20 = new WithNestedDocument(null, "John", 120, new WithNestedDocument("John", 20),
new Document("name", "bar"));
WithNestedDocument john40 = new WithNestedDocument(null, "John", 140, new WithNestedDocument("John", 41),
new Document());
WithNestedDocument john41 = new WithNestedDocument(null, "John", 140, new WithNestedDocument("John", 41),
new Document());
WithNestedDocument john42 = new WithNestedDocument(null, "John", 140, new WithNestedDocument("John", 41),
new Document());
WithNestedDocument john43 = new WithNestedDocument(null, "John", 140, new WithNestedDocument("John", 41),
new Document());
WithNestedDocument john44 = new WithNestedDocument(null, "John", 141, new WithNestedDocument("John", 41),
new Document("name", "foo"));
template.insertAll(Arrays.asList(john20, john40, john41, john42, john43, john44));
Query q = new Query(where("name").regex("J.*")).with(Sort.by("nested.name", "nested.age", "document.name"))
.limit(2);
q.with(KeysetScrollPosition.initial());
Window<WithNestedDocument> scroll = template.scroll(q, WithNestedDocument.class);
assertThat(scroll.hasNext()).isTrue();
assertThat(scroll.isLast()).isFalse();
assertThat(scroll).hasSize(2);
assertThat(scroll).containsOnly(john20, john40);
ScrollPosition startAfter = scroll.positionAt(scroll.size()-1);
assertThatExceptionOfType(IllegalStateException.class)
.isThrownBy(() -> template.scroll(q.with(startAfter), WithNestedDocument.class))
.withMessageContaining("document.name");
}
@ParameterizedTest // GH-4308
@ -142,14 +178,14 @@ class MongoTemplateScrollTests { @@ -142,14 +178,14 @@ class MongoTemplateScrollTests {
Query q = new Query(where("firstName").regex("J.*")).with(Sort.by("firstName", "age")).limit(2);
q.with(scrollPosition);
Scroll<T> scroll = template.scroll(q, resultType, "person");
Window<T> scroll = template.scroll(q, resultType, "person");
assertThat(scroll.hasNext()).isTrue();
assertThat(scroll.isLast()).isFalse();
assertThat(scroll).hasSize(2);
assertThat(scroll).containsOnly(assertionConverter.apply(jane_20), assertionConverter.apply(jane_40));
scroll = template.scroll(q.with(scroll.lastPosition()).limit(3), resultType, "person");
scroll = template.scroll(q.with(scroll.positionAt(scroll.size()-1)).limit(3), resultType, "person");
assertThat(scroll.hasNext()).isTrue();
assertThat(scroll.isLast()).isFalse();
@ -157,7 +193,7 @@ class MongoTemplateScrollTests { @@ -157,7 +193,7 @@ class MongoTemplateScrollTests {
assertThat(scroll).contains(assertionConverter.apply(jane_42), assertionConverter.apply(john20));
assertThat(scroll).containsAnyOf(assertionConverter.apply(john40_1), assertionConverter.apply(john40_2));
scroll = template.scroll(q.with(scroll.lastPosition()).limit(1), resultType, "person");
scroll = template.scroll(q.with(scroll.positionAt(scroll.size()-1)).limit(1), resultType, "person");
assertThat(scroll.hasNext()).isFalse();
assertThat(scroll.isLast()).isTrue();

10
spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateScrollTests.java

@ -35,7 +35,7 @@ import org.springframework.context.ConfigurableApplicationContext; @@ -35,7 +35,7 @@ import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.data.domain.KeysetScrollPosition;
import org.springframework.data.domain.OffsetScrollPosition;
import org.springframework.data.domain.Scroll;
import org.springframework.data.domain.Window;
import org.springframework.data.domain.ScrollPosition;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Query;
@ -46,7 +46,7 @@ import org.springframework.data.mongodb.test.util.ReactiveMongoTestTemplate; @@ -46,7 +46,7 @@ import org.springframework.data.mongodb.test.util.ReactiveMongoTestTemplate;
import com.mongodb.reactivestreams.client.MongoClient;
/**
* Integration tests for {@link Scroll} queries.
* Integration tests for {@link Window} queries.
*
* @author Mark Paluch
*/
@ -100,14 +100,14 @@ class ReactiveMongoTemplateScrollTests { @@ -100,14 +100,14 @@ class ReactiveMongoTemplateScrollTests {
Query q = new Query(where("firstName").regex("J.*")).with(Sort.by("firstName", "age")).limit(2);
q.with(scrollPosition);
Scroll<T> scroll = template.scroll(q, resultType, "person").block(Duration.ofSeconds(10));
Window<T> scroll = template.scroll(q, resultType, "person").block(Duration.ofSeconds(10));
assertThat(scroll.hasNext()).isTrue();
assertThat(scroll.isLast()).isFalse();
assertThat(scroll).hasSize(2);
assertThat(scroll).containsOnly(assertionConverter.apply(jane_20), assertionConverter.apply(jane_40));
scroll = template.scroll(q.limit(3).with(scroll.lastPosition()), resultType, "person")
scroll = template.scroll(q.limit(3).with(scroll.positionAt(scroll.size() - 1)), resultType, "person")
.block(Duration.ofSeconds(10));
assertThat(scroll.hasNext()).isTrue();
@ -116,7 +116,7 @@ class ReactiveMongoTemplateScrollTests { @@ -116,7 +116,7 @@ class ReactiveMongoTemplateScrollTests {
assertThat(scroll).contains(assertionConverter.apply(jane_42), assertionConverter.apply(john20));
assertThat(scroll).containsAnyOf(assertionConverter.apply(john40_1), assertionConverter.apply(john40_2));
scroll = template.scroll(q.limit(1).with(scroll.lastPosition()), resultType, "person")
scroll = template.scroll(q.limit(1).with(scroll.positionAt(scroll.size() - 1)), resultType, "person")
.block(Duration.ofSeconds(10));
assertThat(scroll.hasNext()).isFalse();

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

@ -205,7 +205,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests implements Dirtie @@ -205,7 +205,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests implements Dirtie
@Test // GH-4308
void appliesScrollPositionCorrectly() {
Scroll<Person> page = repository.findTop2ByLastnameLikeOrderByLastnameAscFirstnameAsc("*a*",
Window<Person> page = repository.findTop2ByLastnameLikeOrderByLastnameAscFirstnameAsc("*a*",
KeysetScrollPosition.initial());
assertThat(page.isLast()).isFalse();
@ -216,7 +216,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests implements Dirtie @@ -216,7 +216,7 @@ public abstract class AbstractPersonRepositoryIntegrationTests implements Dirtie
@Test // GH-4308
void appliesScrollPositionWithProjectionCorrectly() {
Scroll<PersonSummaryDto> page = repository.findCursorProjectionByLastnameLike("*a*",
Window<PersonSummaryDto> page = repository.findCursorProjectionByLastnameLike("*a*",
PageRequest.of(0, 2, Sort.by(Direction.ASC, "lastname", "firstname")));
assertThat(page.isLast()).isFalse();
@ -956,12 +956,12 @@ public abstract class AbstractPersonRepositoryIntegrationTests implements Dirtie @@ -956,12 +956,12 @@ public abstract class AbstractPersonRepositoryIntegrationTests implements Dirtie
@Test // DATAMONGO-969
void shouldScrollPersonsWhenUsingQueryDslPerdicatedOnIdProperty() {
Scroll<Person> scroll = repository.findBy(person.id.in(asList(dave.id, carter.id, boyd.id)), //
Window<Person> scroll = repository.findBy(person.id.in(asList(dave.id, carter.id, boyd.id)), //
q -> q.limit(2).sortBy(Sort.by("firstname")).scroll(KeysetScrollPosition.initial()));
assertThat(scroll).containsExactly(boyd, carter);
ScrollPosition resumeFrom = scroll.lastPosition();
ScrollPosition resumeFrom = scroll.positionAt(scroll.size() - 1);
scroll = repository.findBy(person.id.in(asList(dave.id, carter.id, boyd.id)), //
q -> q.limit(2).sortBy(Sort.by("firstname")).scroll(resumeFrom));
@ -1185,14 +1185,14 @@ public abstract class AbstractPersonRepositoryIntegrationTests implements Dirtie @@ -1185,14 +1185,14 @@ public abstract class AbstractPersonRepositoryIntegrationTests implements Dirtie
ReflectionTestUtils.setField(sample, "createdAt", null);
ReflectionTestUtils.setField(sample, "email", null);
Scroll<Person> result = repository.findBy(
Window<Person> result = repository.findBy(
Example.of(sample, ExampleMatcher.matching().withMatcher("lastname", GenericPropertyMatcher::startsWith)),
q -> q.limit(2).sortBy(Sort.by("firstname")).scroll(KeysetScrollPosition.initial()));
assertThat(result).containsOnly(dave, leroi);
assertThat(result.hasNext()).isTrue();
ScrollPosition position = result.lastPosition();
ScrollPosition position = result.positionAt(result.size() - 1);
result = repository.findBy(
Example.of(sample, ExampleMatcher.matching().withMatcher("lastname", GenericPropertyMatcher::startsWith)),
q -> q.limit(2).sortBy(Sort.by("firstname")).scroll(position));

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

@ -23,11 +23,11 @@ import java.util.UUID; @@ -23,11 +23,11 @@ import java.util.UUID;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import org.springframework.data.domain.KeysetScrollPosition;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Range;
import org.springframework.data.domain.Scroll;
import org.springframework.data.domain.Window;
import org.springframework.data.domain.ScrollPosition;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.Sort;
import org.springframework.data.geo.Box;
@ -123,8 +123,8 @@ public interface PersonRepository extends MongoRepository<Person, String>, Query @@ -123,8 +123,8 @@ public interface PersonRepository extends MongoRepository<Person, String>, Query
* @param scrollPosition
* @return
*/
Scroll<Person> findTop2ByLastnameLikeOrderByLastnameAscFirstnameAsc(String lastname,
KeysetScrollPosition scrollPosition);
Window<Person> findTop2ByLastnameLikeOrderByLastnameAscFirstnameAsc(String lastname,
ScrollPosition scrollPosition);
/**
* Returns a scroll of {@link Person}s applying projections with a lastname matching the given one (*-wildcards
@ -134,7 +134,7 @@ public interface PersonRepository extends MongoRepository<Person, String>, Query @@ -134,7 +134,7 @@ public interface PersonRepository extends MongoRepository<Person, String>, Query
* @param pageable
* @return
*/
Scroll<PersonSummaryDto> findCursorProjectionByLastnameLike(String lastname, Pageable pageable);
Window<PersonSummaryDto> findCursorProjectionByLastnameLike(String lastname, Pageable pageable);
/**
* Returns a page of {@link Person}s with a lastname matching the given one (*-wildcards supported).

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

@ -50,10 +50,10 @@ import org.springframework.dao.IncorrectResultSizeDataAccessException; @@ -50,10 +50,10 @@ import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.data.domain.KeysetScrollPosition;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Scroll;
import org.springframework.data.domain.ScrollPosition;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Window;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoResult;
@ -293,15 +293,15 @@ class ReactiveMongoRepositoryTests implements DirtiesStateExtension.StateFunctio @@ -293,15 +293,15 @@ class ReactiveMongoRepositoryTests implements DirtiesStateExtension.StateFunctio
@Test // GH-4308
void appliesScrollingCorrectly() {
Scroll<Person> scroll = repository
Window<Person> scroll = repository
.findTop2ByLastnameLikeOrderByFirstnameAscLastnameAsc("*", KeysetScrollPosition.initial()).block();
assertThat(scroll).hasSize(2);
assertThat(scroll).containsSequence(alicia, boyd);
assertThat(scroll.isLast()).isFalse();
Scroll<Person> nextScroll = repository
.findTop2ByLastnameLikeOrderByFirstnameAscLastnameAsc("*", scroll.lastPosition()).block();
Window<Person> nextScroll = repository
.findTop2ByLastnameLikeOrderByFirstnameAscLastnameAsc("*", scroll.positionAt(scroll.size() - 1)).block();
assertThat(nextScroll).hasSize(2);
assertThat(nextScroll).containsSequence(carter, dave);
@ -474,7 +474,7 @@ class ReactiveMongoRepositoryTests implements DirtiesStateExtension.StateFunctio @@ -474,7 +474,7 @@ class ReactiveMongoRepositoryTests implements DirtiesStateExtension.StateFunctio
@Test // GH-4308
void shouldScrollWithId() {
List<Scroll<Person>> capture = new ArrayList<>();
List<Window<Person>> capture = new ArrayList<>();
repository.findBy(person.id.in(Arrays.asList(dave.id, carter.id, boyd.id)), //
q -> q.limit(2).sortBy(Sort.by("firstname")).scroll(KeysetScrollPosition.initial())) //
.as(StepVerifier::create) //
@ -482,10 +482,10 @@ class ReactiveMongoRepositoryTests implements DirtiesStateExtension.StateFunctio @@ -482,10 +482,10 @@ class ReactiveMongoRepositoryTests implements DirtiesStateExtension.StateFunctio
assertThat(actual).hasSize(2).containsExactly(boyd, carter);
}).verifyComplete();
Scroll<Person> scroll = capture.get(0);
Window<Person> scroll = capture.get(0);
repository.findBy(person.id.in(Arrays.asList(dave.id, carter.id, boyd.id)), //
q -> q.limit(2).sortBy(Sort.by("firstname")).scroll(scroll.lastPosition())) //
q -> q.limit(2).sortBy(Sort.by("firstname")).scroll(scroll.positionAt(scroll.size() - 1))) //
.as(StepVerifier::create) //
.recordWith(() -> capture).assertNext(actual -> {
assertThat(actual).containsOnly(dave);
@ -768,10 +768,10 @@ class ReactiveMongoRepositoryTests implements DirtiesStateExtension.StateFunctio @@ -768,10 +768,10 @@ class ReactiveMongoRepositoryTests implements DirtiesStateExtension.StateFunctio
@Query("{ lastname: { $in: ?0 }, age: { $gt : ?1 } }")
Flux<Person> findStringQuery(Flux<String> lastname, Mono<Integer> age);
Mono<Scroll<Person>> findTop2ByLastnameLikeOrderByFirstnameAscLastnameAsc(String lastname,
Mono<Window<Person>> findTop2ByLastnameLikeOrderByFirstnameAscLastnameAsc(String lastname,
ScrollPosition scrollPosition);
Mono<Scroll<PersonSummaryDto>> findCursorProjectionByLastnameLike(String lastname, Pageable pageable);
Mono<Window<PersonSummaryDto>> findCursorProjectionByLastnameLike(String lastname, Pageable pageable);
Flux<Person> findByLocationWithin(Circle circle);

Loading…
Cancel
Save