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 b479e911f..65815b641 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 @@ -1818,7 +1818,7 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, if (query.getLimit() > 0 && mapReduceOptions != null && mapReduceOptions.getLimit() == null) { mapReduce = mapReduce.limit(query.getLimit()); } - if (query.getMeta().getMaxTimeMsec() != null) { + if (query.getMeta().hasMaxTime()) { mapReduce = mapReduce.maxTime(query.getMeta().getMaxTimeMsec(), TimeUnit.MILLISECONDS); } @@ -3159,12 +3159,12 @@ public class MongoTemplate implements MongoOperations, ApplicationContextAware, if (meta.hasValues()) { - if (StringUtils.hasText(meta.getComment())) { - cursorToUse = cursorToUse.comment(meta.getComment()); + if (meta.hasComment()) { + cursorToUse = cursorToUse.comment(meta.getRequiredComment()); } - if (meta.getMaxTimeMsec() != null) { - cursorToUse = cursorToUse.maxTime(meta.getMaxTimeMsec(), TimeUnit.MILLISECONDS); + if (meta.hasMaxTime()) { + cursorToUse = cursorToUse.maxTime(meta.getRequiredMaxTimeMsec(), TimeUnit.MILLISECONDS); } if (meta.getCursorBatchSize() != null) { diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryOperations.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryOperations.java index c3acbd994..36876e18f 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryOperations.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/QueryOperations.java @@ -53,6 +53,7 @@ import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty; import org.springframework.data.mongodb.core.mapping.ShardKey; import org.springframework.data.mongodb.core.query.BasicQuery; import org.springframework.data.mongodb.core.query.Collation; +import org.springframework.data.mongodb.core.query.Meta; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.UpdateDefinition; import org.springframework.data.mongodb.core.query.UpdateDefinition.ArrayFilter; @@ -67,7 +68,6 @@ import com.mongodb.client.model.CountOptions; import com.mongodb.client.model.DeleteOptions; import com.mongodb.client.model.ReplaceOptions; import com.mongodb.client.model.UpdateOptions; -import org.springframework.util.StringUtils; /** * {@link QueryOperations} centralizes common operations required before an operation is actually ready to be executed. @@ -390,7 +390,7 @@ class QueryOperations { for (Entry entry : fields.entrySet()) { - if (entry.getValue() instanceof MongoExpression) { + if (entry.getValue()instanceof MongoExpression) { AggregationOperationContext ctx = entity == null ? Aggregation.DEFAULT_CONTEXT : new RelaxedTypeBasedAggregationOperationContext(entity.getType(), mappingContext, queryMapper); @@ -566,16 +566,20 @@ class QueryOperations { if (query.getLimit() > 0) { options.limit(query.getLimit()); } + if (query.getSkip() > 0) { options.skip((int) query.getSkip()); } - if(query.getMeta().hasValues()) { - if(query.getMeta().getMaxTimeMsec() != null && query.getMeta().getMaxTimeMsec() > 0) { - options.maxTime(query.getMeta().getMaxTimeMsec(), TimeUnit.MILLISECONDS); + Meta meta = query.getMeta(); + if (meta.hasValues()) { + + if (meta.hasMaxTime()) { + options.maxTime(meta.getRequiredMaxTimeMsec(), TimeUnit.MILLISECONDS); } - if(StringUtils.hasText(query.getMeta().getComment())) { - options.comment(query.getMeta().getComment()); + + if (meta.hasComment()) { + options.comment(meta.getComment()); } } 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 dfdb8dfeb..723372bc9 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 @@ -1971,8 +1971,9 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati publisher.sort(mappedSort); } - if (filterQuery.getMeta().getMaxTimeMsec() != null) { - publisher.maxTime(filterQuery.getMeta().getMaxTimeMsec(), TimeUnit.MILLISECONDS); + Meta meta = filterQuery.getMeta(); + if (meta.hasMaxTime()) { + publisher.maxTime(meta.getRequiredMaxTimeMsec(), TimeUnit.MILLISECONDS); } if (filterQuery.getLimit() > 0 || (options.getLimit() != null)) { @@ -3062,12 +3063,12 @@ public class ReactiveMongoTemplate implements ReactiveMongoOperations, Applicati if (meta.hasValues()) { - if (StringUtils.hasText(meta.getComment())) { - findPublisherToUse = findPublisherToUse.comment(meta.getComment()); + if (meta.hasComment()) { + findPublisherToUse = findPublisherToUse.comment(meta.getRequiredComment()); } - if (meta.getMaxTimeMsec() != null) { - findPublisherToUse = findPublisherToUse.maxTime(meta.getMaxTimeMsec(), TimeUnit.MILLISECONDS); + if (meta.hasMaxTime()) { + findPublisherToUse = findPublisherToUse.maxTime(meta.getRequiredMaxTimeMsec(), TimeUnit.MILLISECONDS); } if (meta.getCursorBatchSize() != null) { 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 7733690fe..0ef9590ad 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 @@ -69,6 +69,19 @@ public class Meta { this.allowDiskUse = source.allowDiskUse; } + /** + * Return whether the maximum time limit for processing operations is set. + * + * @return {@code true} if set; {@code false} otherwise. + * @since 4.0.6 + */ + public boolean hasMaxTime() { + + Long maxTimeMsec = getMaxTimeMsec(); + + return maxTimeMsec != null && maxTimeMsec > 0; + } + /** * @return {@literal null} if not set. */ @@ -77,6 +90,26 @@ public class Meta { return getValue(MetaKey.MAX_TIME_MS.key); } + /** + * Returns the required maximum time limit in milliseconds or throws {@link IllegalStateException} if the maximum time + * limit is not set. + * + * @return the maximum time limit in milliseconds for processing operations. + * @throws IllegalStateException if the maximum time limit is not set + * @see #hasMaxTime() + * @since 4.0.6 + */ + public Long getRequiredMaxTimeMsec() { + + Long maxTimeMsec = getMaxTimeMsec(); + + if (maxTimeMsec == null) { + throw new IllegalStateException("Maximum time limit in milliseconds not set"); + } + + return maxTimeMsec; + } + /** * Set the maximum time limit in milliseconds for processing operations. * @@ -99,12 +132,13 @@ public class Meta { } /** - * Add a comment to the query that is propagated to the profile log. + * Return whether the comment is set. * - * @param comment + * @return {@code true} if set; {@code false} otherwise. + * @since 4.0.6 */ - public void setComment(String comment) { - setValue(MetaKey.COMMENT.key, comment); + public boolean hasComment() { + return StringUtils.hasText(getComment()); } /** @@ -115,6 +149,34 @@ public class Meta { return getValue(MetaKey.COMMENT.key); } + /** + * Returns the required comment or throws {@link IllegalStateException} if the comment is not set. + * + * @return the comment. + * @throws IllegalStateException if the comment is not set + * @see #hasComment() + * @since 4.0.6 + */ + public String getRequiredComment() { + + String comment = getComment(); + + if (comment == null) { + throw new IllegalStateException("Comment not set"); + } + + return comment; + } + + /** + * Add a comment to the query that is propagated to the profile log. + * + * @param comment + */ + public void setComment(String comment) { + setValue(MetaKey.COMMENT.key, comment); + } + /** * @return {@literal null} if not set. * @since 2.1 diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AggregationUtils.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AggregationUtils.java index 4df4f6383..f185245bb 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AggregationUtils.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AggregationUtils.java @@ -16,7 +16,6 @@ package org.springframework.data.mongodb.repository.query; import java.time.Duration; -import java.util.List; import java.util.Map; import java.util.function.IntUnaryOperator; import java.util.function.LongUnaryOperator; @@ -25,7 +24,6 @@ import org.bson.Document; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort.Order; import org.springframework.data.mongodb.core.aggregation.Aggregation; -import org.springframework.data.mongodb.core.aggregation.AggregationOperation; import org.springframework.data.mongodb.core.aggregation.AggregationOptions; import org.springframework.data.mongodb.core.aggregation.AggregationPipeline; import org.springframework.data.mongodb.core.convert.MongoConverter; @@ -37,7 +35,6 @@ import org.springframework.expression.ExpressionParser; import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; -import org.springframework.util.StringUtils; /** * Internal utility class to help avoid duplicate code required in both the reactive and the sync {@link Aggregation} @@ -84,7 +81,7 @@ abstract class AggregationUtils { Meta meta = queryMethod.getQueryMetaAttributes(); - if (StringUtils.hasText(meta.getComment())) { + if (meta.hasComment()) { builder.comment(meta.getComment()); } @@ -92,8 +89,8 @@ abstract class AggregationUtils { builder.cursorBatchSize(meta.getCursorBatchSize()); } - if (meta.getMaxTimeMsec() != null && meta.getMaxTimeMsec() > 0) { - builder.maxTime(Duration.ofMillis(meta.getMaxTimeMsec())); + if (meta.hasMaxTime()) { + builder.maxTime(Duration.ofMillis(meta.getRequiredMaxTimeMsec())); } if (meta.getAllowDiskUse() != null) { diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryMethodUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryMethodUnitTests.java index 8eb7ac65b..c0517eafb 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryMethodUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/MongoQueryMethodUnitTests.java @@ -274,7 +274,8 @@ public class MongoQueryMethodUnitTests { void queryCreationForUpdateMethodFailsOnInvalidReturnType() throws Exception { assertThatExceptionOfType(IllegalStateException.class) // - .isThrownBy(() -> queryMethod(InvalidUpdateMethodRepo.class, "findAndIncrementVisitsByFirstname", String.class).verify()) // + .isThrownBy(() -> queryMethod(InvalidUpdateMethodRepo.class, "findAndIncrementVisitsByFirstname", String.class) + .verify()) // .withMessageContaining("Update") // .withMessageContaining("numeric") // .withMessageContaining("findAndIncrementVisitsByFirstname"); @@ -283,7 +284,8 @@ public class MongoQueryMethodUnitTests { @Test // GH-3002 void readsCollationFromAtCollationAnnotation() throws Exception { - MongoQueryMethod method = queryMethod(PersonRepository.class, "findWithCollationFromAtCollationByFirstname", String.class); + MongoQueryMethod method = queryMethod(PersonRepository.class, "findWithCollationFromAtCollationByFirstname", + String.class); assertThat(method.hasAnnotatedCollation()).isTrue(); assertThat(method.getAnnotatedCollation()).isEqualTo("en_US"); @@ -292,7 +294,8 @@ public class MongoQueryMethodUnitTests { @Test // GH-3002 void readsCollationFromAtQueryAnnotation() throws Exception { - MongoQueryMethod method = queryMethod(PersonRepository.class, "findWithCollationFromAtQueryByFirstname", String.class); + MongoQueryMethod method = queryMethod(PersonRepository.class, "findWithCollationFromAtQueryByFirstname", + String.class); assertThat(method.hasAnnotatedCollation()).isTrue(); assertThat(method.getAnnotatedCollation()).isEqualTo("en_US"); @@ -301,7 +304,8 @@ public class MongoQueryMethodUnitTests { @Test // GH-3002 void annotatedCollationClashSelectsAtCollationAnnotationValue() throws Exception { - MongoQueryMethod method = queryMethod(PersonRepository.class, "findWithMultipleCollationsFromAtQueryAndAtCollationByFirstname", String.class); + MongoQueryMethod method = queryMethod(PersonRepository.class, + "findWithMultipleCollationsFromAtQueryAndAtCollationByFirstname", String.class); assertThat(method.hasAnnotatedCollation()).isTrue(); assertThat(method.getAnnotatedCollation()).isEqualTo("de_AT");