From ed9173c384119167468e3864dcae5596d86e40a6 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Tue, 26 Feb 2019 10:35:04 +0100 Subject: [PATCH] DATAMONGO-1783 - Apply query limit and offset to CountOptions for MongoOperations.count. We now pass on the range defined by Query.skip and Query.limit to MongoDB. This allows to count documents within a certain range so that it is possible to find the number of matches within eg. the first 10,000 documents. Original pull request: #650. --- .../data/mongodb/core/MongoOperations.java | 17 ++- .../data/mongodb/core/MongoTemplate.java | 7 + .../mongodb/core/ReactiveMongoOperations.java | 17 ++- .../mongodb/core/ReactiveMongoTemplate.java | 7 + .../data/mongodb/core/query/Meta.java | 2 +- .../data/mongodb/core/query/Query.java | 54 ++++++++ .../repository/query/MongoQueryExecution.java | 3 +- .../QuerydslFetchableMongodbQuery.java | 2 +- .../support/SimpleMongoRepository.java | 6 +- .../data/mongodb/util/BsonUtils.java | 25 ++++ .../mongodb/core/MongoTemplateUnitTests.java | 22 +++ .../core/ReactiveMongoTemplateUnitTests.java | 24 ++++ .../data/mongodb/core/query/QueryTests.java | 128 ++++++++++++++++++ .../query/AbstractMongoQueryUnitTests.java | 4 +- src/main/asciidoc/new-features.adoc | 1 + 15 files changed, 307 insertions(+), 12 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java index 522b5bea5..11b44ee67 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoOperations.java @@ -1094,6 +1094,11 @@ public interface MongoOperations extends FluentMongoOperations { /** * Returns the number of documents for the given {@link Query} by querying the collection of the given entity class. + *
+ * NOTE: Query {@link Query#getSkip() offset} and {@link Query#getLimit() limit} can have direct + * influence on the resulting number of documents found as those values are passed on to the server and potentially + * limit the range and order within which the server performs the count operation. Use an {@literal unpaged} query to + * count all matches. * * @param query the {@link Query} class that specifies the criteria used to find documents. Must not be * {@literal null}. @@ -1105,7 +1110,11 @@ public interface MongoOperations extends FluentMongoOperations { /** * Returns the number of documents for the given {@link Query} querying the given collection. The given {@link Query} * must solely consist of document field references as we lack type information to map potential property references - * onto document fields. Use {@link #count(Query, Class, String)} to get full type specific support. + * onto document fields. Use {@link #count(Query, Class, String)} to get full type specific support.
+ * NOTE: Query {@link Query#getSkip() offset} and {@link Query#getLimit() limit} can have direct + * influence on the resulting number of documents found as those values are passed on to the server and potentially + * limit the range and order within which the server performs the count operation. Use an {@literal unpaged} query to + * count all matches. * * @param query the {@link Query} class that specifies the criteria used to find documents. * @param collectionName must not be {@literal null} or empty. @@ -1116,7 +1125,11 @@ public interface MongoOperations extends FluentMongoOperations { /** * Returns the number of documents for the given {@link Query} by querying the given collection using the given entity - * class to map the given {@link Query}. + * class to map the given {@link Query}.
+ * NOTE: Query {@link Query#getSkip() offset} and {@link Query#getLimit() limit} can have direct + * influence on the resulting number of documents found as those values are passed on to the server and potentially + * limit the range and order within which the server performs the count operation. Use an {@literal unpaged} query to + * count all matches. * * @param query the {@link Query} class that specifies the criteria used to find documents. Must not be * {@literal null}. diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java index 2dd2fb795..53e268777 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java @@ -1145,6 +1145,13 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, CountOptions options = new CountOptions(); query.getCollation().map(Collation::toMongoCollation).ifPresent(options::collation); + if (query.getLimit() > 0) { + options.limit(query.getLimit()); + } + if (query.getSkip() > 0) { + options.skip((int) query.getSkip()); + } + Document document = queryMapper.getMappedObject(query.getQueryObject(), Optional.ofNullable(entityClass).map(it -> mappingContext.getPersistentEntity(entityClass))); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoOperations.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoOperations.java index 8012e6455..3beb083ca 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoOperations.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoOperations.java @@ -880,6 +880,11 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { /** * Returns the number of documents for the given {@link Query} by querying the collection of the given entity class. + *
+ * NOTE: Query {@link Query#getSkip() offset} and {@link Query#getLimit() limit} can have direct + * influence on the resulting number of documents found as those values are passed on to the server and potentially + * limit the range and order within which the server performs the count operation. Use an {@literal unpaged} query to + * count all matches. * * @param query the {@link Query} class that specifies the criteria used to find documents. Must not be * {@literal null}. @@ -891,7 +896,11 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { /** * Returns the number of documents for the given {@link Query} querying the given collection. The given {@link Query} * must solely consist of document field references as we lack type information to map potential property references - * onto document fields. Use {@link #count(Query, Class, String)} to get full type specific support. + * onto document fields. Use {@link #count(Query, Class, String)} to get full type specific support.
+ * NOTE: Query {@link Query#getSkip() offset} and {@link Query#getLimit() limit} can have direct + * influence on the resulting number of documents found as those values are passed on to the server and potentially + * limit the range and order within which the server performs the count operation. Use an {@literal unpaged} query to + * count all matches. * * @param query the {@link Query} class that specifies the criteria used to find documents. * @param collectionName must not be {@literal null} or empty. @@ -902,7 +911,11 @@ public interface ReactiveMongoOperations extends ReactiveFluentMongoOperations { /** * Returns the number of documents for the given {@link Query} by querying the given collection using the given entity - * class to map the given {@link Query}. + * class to map the given {@link Query}.
+ * NOTE: Query {@link Query#getSkip() offset} and {@link Query#getLimit() limit} can have direct + * influence on the resulting number of documents found as those values are passed on to the server and potentially + * limit the range and order within which the server performs the count operation. Use an {@literal unpaged} query to + * count all matches. * * @param query the {@link Query} class that specifies the criteria used to find documents. Must not be * {@literal null}. diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java index deb9ef681..56fc38336 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/ReactiveMongoTemplate.java @@ -1171,6 +1171,13 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati CountOptions options = new CountOptions(); if (query != null) { query.getCollation().map(Collation::toMongoCollation).ifPresent(options::collation); + + if (query.getLimit() > 0) { + options.limit(query.getLimit()); + } + if (query.getSkip() > 0) { + options.skip((int) query.getSkip()); + } } if (LOGGER.isDebugEnabled()) { diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Meta.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Meta.java index 4d1147323..b794a3a85 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Meta.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Meta.java @@ -212,7 +212,7 @@ public class Meta { * @param key must not be {@literal null} or empty. * @param value */ - private void setValue(String key, @Nullable Object value) { + void setValue(String key, @Nullable Object value) { Assert.hasText(key, "Meta key must not be 'null' or blank."); diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java index 4a5add199..88e273522 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/query/Query.java @@ -34,6 +34,7 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Order; import org.springframework.data.mongodb.InvalidMongoDbApiUsageException; +import org.springframework.data.mongodb.util.BsonUtils; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -475,6 +476,59 @@ public class Query { return new ArrayList<>(this.criteria.values()); } + /** + * Create an independent copy of the given {@link Query}.
+ * The resulting {@link Query} will not be {@link Object#equals(Object) binary equal} to the given source but + * semantically equal in terms of creating the same result when executed. + * + * @param source The source {@link Query} to use a reference. Must not be {@literal null}. + * @return new {@link Query}. + * @since 2.2 + */ + public static Query of(Query source) { + + Assert.notNull(source, "Source must not be null!"); + + Document sourceFields = source.getFieldsObject(); + Document sourceSort = source.getSortObject(); + Document sourceQuery = source.getQueryObject(); + + Query target = new Query() { + + @Override + public Document getFieldsObject() { + return BsonUtils.merge(sourceFields, super.getFieldsObject()); + } + + @Override + public Document getSortObject() { + return BsonUtils.merge(sourceSort, super.getSortObject()); + } + + @Override + public Document getQueryObject() { + return BsonUtils.merge(sourceQuery, super.getQueryObject()); + } + }; + + target.criteria.putAll(source.criteria); + target.skip = source.skip; + target.limit = source.limit; + target.sort = Sort.unsorted().and(source.sort); + target.hint = source.hint; + target.collation = source.collation; + target.restrictedTypes.addAll(source.restrictedTypes); + + if (source.getMeta() != null && source.getMeta().hasValues()) { + + Meta meta = new Meta(); + source.getMeta().values().forEach(it -> meta.setValue(it.getKey(), it.getValue())); + target.setMeta(meta); + } + + return target; + } + /* * (non-Javadoc) * @see java.lang.Object#toString() diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryExecution.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryExecution.java index 98009cb7c..30ed87d7d 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryExecution.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/MongoQueryExecution.java @@ -92,6 +92,7 @@ interface MongoQueryExecution { * * @author Oliver Gierke * @author Mark Paluch + * @author Christoph Strobl */ @RequiredArgsConstructor final class PagedExecution implements MongoQueryExecution { @@ -120,7 +121,7 @@ interface MongoQueryExecution { return PageableExecutionUtils.getPage(matching.all(), pageable, () -> { - long count = matching.count(); + long count = operation.matching(Query.of(query).skip(-1).limit(-1)).count(); return overallLimit != 0 ? Math.min(count, overallLimit) : count; }); } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/QuerydslFetchableMongodbQuery.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/QuerydslFetchableMongodbQuery.java index a18709c5f..e4f821893 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/QuerydslFetchableMongodbQuery.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/support/QuerydslFetchableMongodbQuery.java @@ -147,7 +147,7 @@ abstract class QuerydslFetchableMongodbQuery implements MongoRepository { Assert.notNull(example, "Sample must not be null!"); Assert.notNull(pageable, "Pageable must not be null!"); - Query q = new Query(new Criteria().alike(example)).with(pageable); - List list = mongoOperations.find(q, example.getProbeType(), entityInformation.getCollectionName()); + Query query = new Query(new Criteria().alike(example)).with(pageable); + List list = mongoOperations.find(query, example.getProbeType(), entityInformation.getCollectionName()); return PageableExecutionUtils.getPage(list, pageable, - () -> mongoOperations.count(q, example.getProbeType(), entityInformation.getCollectionName())); + () -> mongoOperations.count(Query.of(query).limit(-1).skip(-1), example.getProbeType(), entityInformation.getCollectionName())); } /* diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/BsonUtils.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/BsonUtils.java index 1aa904f8c..56ea876f9 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/BsonUtils.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/BsonUtils.java @@ -15,6 +15,7 @@ */ package org.springframework.data.mongodb.util; +import java.util.Arrays; import java.util.Date; import java.util.Map; @@ -22,6 +23,7 @@ import org.bson.BsonValue; import org.bson.Document; import org.bson.conversions.Bson; import org.springframework.lang.Nullable; +import org.springframework.util.ObjectUtils; import com.mongodb.BasicDBObject; import com.mongodb.DBObject; @@ -104,4 +106,27 @@ public class BsonUtils { return value; } } + + /** + * Merge the given {@link Document documents} into on in the given order. Keys contained within multiple documents are + * overwritten by their follow ups. + * + * @param documents must not be {@literal null}. Can be empty. + * @return the document containing all key value pairs. + * @since 2.2 + */ + public static Document merge(Document... documents) { + + if (ObjectUtils.isEmpty(documents)) { + return new Document(); + } + + if (documents.length == 1) { + return documents[0]; + } + + Document target = new Document(); + Arrays.asList(documents).forEach(target::putAll); + return target; + } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java index 8e1d62a6c..819999da8 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/MongoTemplateUnitTests.java @@ -1035,6 +1035,28 @@ public class MongoTemplateUnitTests extends MongoOperationsUnitTests { is(equalTo(new Document("version", 11).append("_class", VersionedEntity.class.getName())))); } + @Test // DATAMONGO-1783 + public void usesQueryOffsetForCountOperation() { + + template.count(new BasicQuery("{}").skip(100), AutogenerateableId.class); + + ArgumentCaptor options = ArgumentCaptor.forClass(CountOptions.class); + verify(collection).count(any(), options.capture()); + + assertThat(options.getValue().getSkip(), is(equalTo(100))); + } + + @Test // DATAMONGO-1783 + public void usesQueryLimitForCountOperation() { + + template.count(new BasicQuery("{}").limit(10), AutogenerateableId.class); + + ArgumentCaptor options = ArgumentCaptor.forClass(CountOptions.class); + verify(collection).count(any(), options.capture()); + + assertThat(options.getValue().getLimit(), is(equalTo(10))); + } + @Test // DATAMONGO-2215 public void updateShouldApplyArrayFilters() { diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateUnitTests.java index cba7eadbb..974fdb6bc 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/ReactiveMongoTemplateUnitTests.java @@ -55,6 +55,7 @@ import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Update; import org.springframework.test.util.ReflectionTestUtils; +import com.mongodb.client.model.CountOptions; import com.mongodb.client.model.DeleteOptions; import com.mongodb.client.model.FindOneAndDeleteOptions; import com.mongodb.client.model.FindOneAndUpdateOptions; @@ -103,6 +104,7 @@ public class ReactiveMongoTemplateUnitTests { when(collection.find(any(Document.class), any(Class.class))).thenReturn(findPublisher); when(collection.aggregate(anyList())).thenReturn(aggregatePublisher); when(collection.aggregate(anyList(), any(Class.class))).thenReturn(aggregatePublisher); + when(collection.count(any(), any(CountOptions.class))).thenReturn(Mono.just(0L)); when(collection.updateOne(any(), any(), any(UpdateOptions.class))).thenReturn(updatePublisher); when(collection.findOneAndUpdate(any(), any(), any(FindOneAndUpdateOptions.class))).thenReturn(findAndUpdatePublisher); when(findPublisher.projection(any())).thenReturn(findPublisher); @@ -350,6 +352,28 @@ public class ReactiveMongoTemplateUnitTests { verify(findPublisher, never()).projection(any()); } + @Test // DATAMONGO-1783 + public void countShouldUseSkipFromQuery() { + + template.count(new Query().skip(10), Person.class, "star-wars").subscribe(); + + ArgumentCaptor options = ArgumentCaptor.forClass(CountOptions.class); + verify(collection).count(any(), options.capture()); + + assertThat(options.getValue().getSkip(), is(equalTo(10))); + } + + @Test // DATAMONGO-1783 + public void countShouldUseLimitFromQuery() { + + template.count(new Query().limit(100), Person.class, "star-wars").subscribe(); + + ArgumentCaptor options = ArgumentCaptor.forClass(CountOptions.class); + verify(collection).count(any(), options.capture()); + + assertThat(options.getValue().getLimit(), is(equalTo(100))); + } + @Test // DATAMONGO-2215 public void updateShouldApplyArrayFilters() { diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/QueryTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/QueryTests.java index bacd33c84..15ea7556b 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/QueryTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/query/QueryTests.java @@ -219,7 +219,135 @@ public class QueryTests { query.addCriteria(where("value").is(EnumType.VAL_2)); }).withMessageContaining("second 'value' criteria") .withMessageContaining("already contains '{ \"value\" : { \"$java\" : VAL_1 } }'"); + } + @Test // DATAMONGO-1783 + public void queryOfShouldCreateNewQueryWithEqualBehaviour() { + + Query source = new Query(); + source.addCriteria(where("This you must ken!").is(EnumType.VAL_1)); + + compareQueries(Query.of(source), source); + } + + @Test // DATAMONGO-1783 + public void clonedQueryShouldNotDependOnCriteriaFromSource() { + + Query source = new Query(); + source.addCriteria(where("From one make ten").is("and two let be.")); + Query target = Query.of(source); + + compareQueries(target, source); + source.addCriteria(where("Make even three").is("then rich you'll be.")); + + assertThat(target.getQueryObject()).isEqualTo(new Document("From one make ten", "and two let be.")) + .isNotEqualTo(source.getQueryObject()); + } + + @Test // DATAMONGO-1783 + public void clonedQueryShouldAppendCriteria() { + + Query source = new Query(); + source.addCriteria(where("Skip o'er the four!").is("From five and six")); + Query target = Query.of(source); + + compareQueries(target, source); + target.addCriteria(where("the Witch's tricks").is("make seven and eight")); + + assertThat(target.getQueryObject()).isEqualTo( + new Document("Skip o'er the four!", "From five and six").append("the Witch's tricks", "make seven and eight")); + } + + @Test // DATAMONGO-1783 + public void clonedQueryShouldNotDependOnCollationFromSource() { + + Query source = new Query().collation(Collation.simple()); + Query target = Query.of(source); + + compareQueries(target, source); + source.collation(Collation.of("Tis finished straight")); + + assertThat(target.getCollation()).contains(Collation.simple()).isNotEqualTo(source.getCollation()); + } + + @Test // DATAMONGO-1783 + public void clonedQueryShouldNotDependOnSortFromSource() { + + Query source = new Query().with(Sort.by("And nine is one")); + Query target = Query.of(source); + + compareQueries(target, source); + source.with(Sort.by("And ten is none")); + + assertThat(target.getSortObject()).isEqualTo(new Document("And nine is one", 1)) + .isNotEqualTo(source.getSortObject()); + } + + @Test // DATAMONGO-1783 + public void clonedQueryShouldNotDependOnFieldsFromSource() { + + Query source = new Query(); + source.fields().include("That is the witch's one-time-one!"); + Query target = Query.of(source); + + compareQueries(target, source); + source.fields().exclude("Goethe"); + + assertThat(target.getFieldsObject()).isEqualTo(new Document("That is the witch's one-time-one!", 1)) + .isNotEqualTo(source.getFieldsObject()); + } + + @Test // DATAMONGO-1783 + public void clonedQueryShouldNotDependOnMetaFromSource() { + + Query source = new Query().maxTimeMsec(100); + Query target = Query.of(source); + + compareQueries(target, source); + source.slaveOk(); + + Meta meta = new Meta(); + meta.setMaxTimeMsec(100); + assertThat(target.getMeta()).isEqualTo(meta).isNotEqualTo(source.getMeta()); + } + + @Test // DATAMONGO-1783 + public void clonedQueryShouldNotDependOnRestrictedTypesFromSource() { + + Query source = new Query(); + source.restrict(EnumType.class); + Query target = Query.of(source); + + compareQueries(target, source); + source.restrict(Query.class); + + assertThat(target.getRestrictedTypes()).containsExactly(EnumType.class).isNotEqualTo(source.getRestrictedTypes()); + } + + @Test // DATAMONGO-1783 + public void clonedQueryShouldApplyRestrictionsFromBasicQuery() { + + BasicQuery source = new BasicQuery("{ 'foo' : 'bar'}"); + Query target = Query.of(source); + + compareQueries(target, source); + + target.addCriteria(where("one").is("10")); + assertThat(target.getQueryObject()).isEqualTo(new Document("foo", "bar").append("one", "10")) + .isNotEqualTo(source.getQueryObject()); + } + + private void compareQueries(Query actual, Query expected) { + + assertThat(actual.getCollation()).isEqualTo(expected.getCollation()); + assertThat(actual.getSortObject()).isEqualTo(expected.getSortObject()); + assertThat(actual.getFieldsObject()).isEqualTo(expected.getFieldsObject()); + assertThat(actual.getQueryObject()).isEqualTo(expected.getQueryObject()); + assertThat(actual.getHint()).isEqualTo(expected.getHint()); + assertThat(actual.getLimit()).isEqualTo(expected.getLimit()); + assertThat(actual.getSkip()).isEqualTo(expected.getSkip()); + assertThat(actual.getMeta()).isEqualTo(expected.getMeta()); + assertThat(actual.getRestrictedTypes()).isEqualTo(expected.getRestrictedTypes()); } enum EnumType { diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/AbstractMongoQueryUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/AbstractMongoQueryUnitTests.java index efe0432e0..290103e4d 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/AbstractMongoQueryUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/AbstractMongoQueryUnitTests.java @@ -174,12 +174,12 @@ public class AbstractMongoQueryUnitTests { ArgumentCaptor captor = ArgumentCaptor.forClass(Query.class); verify(executableFind).as(Person.class); - verify(withQueryMock).matching(captor.capture()); + verify(withQueryMock, atLeast(1)).matching(captor.capture()); assertThat(captor.getValue().getMeta().getComment(), is("comment")); } - @Test // DATAMONGO-957 + @Test // DATAMONGO-957, DATAMONGO-1783 public void metadataShouldBeAddedToStringBasedQueryCorrectly() { MongoQueryFake query = createQueryForMethod("findByAnnotatedQuery", String.class, Pageable.class); diff --git a/src/main/asciidoc/new-features.adoc b/src/main/asciidoc/new-features.adoc index 96a1fafdd..fde5de85f 100644 --- a/src/main/asciidoc/new-features.adoc +++ b/src/main/asciidoc/new-features.adoc @@ -10,6 +10,7 @@ * Template API delete by entity considers the version property in delete queries. * Repository deletes now throw `OptimisticLockingFailureException` when a versioned entity cannot be deleted. * Support `Range` in repository between queries. +* Changed behavior of `Reactive/MongoOperations#count` now limiting the range to count matches within by passing on _offset_ & _limit_ to the server. * Kotlin extension methods accepting `KClass` are deprecated now in favor of `reified` methods. * Support of array filters in `Update` operations.