diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractReactiveMongoQuery.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractReactiveMongoQuery.java index e38168cbc..e653f1b39 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractReactiveMongoQuery.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/AbstractReactiveMongoQuery.java @@ -17,7 +17,6 @@ package org.springframework.data.mongodb.repository.query; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import reactor.util.function.Tuple2; import java.util.ArrayList; import java.util.List; @@ -25,6 +24,7 @@ import java.util.List; import org.bson.Document; import org.bson.codecs.configuration.CodecRegistry; import org.reactivestreams.Publisher; + import org.springframework.core.convert.converter.Converter; import org.springframework.data.mapping.model.EntityInstantiators; import org.springframework.data.mapping.model.SpELExpressionEvaluator; @@ -231,7 +231,6 @@ public abstract class AbstractReactiveMongoQuery implements RepositoryQuery { return method.getTailableAnnotation() != null; } - Query applyQueryMetaAttributesWhenPresent(Query query) { if (method.hasQueryMetaAttributes()) { @@ -290,7 +289,8 @@ public abstract class AbstractReactiveMongoQuery implements RepositoryQuery { } /** - * If present apply the {@link com.mongodb.ReadPreference} from the {@link org.springframework.data.mongodb.repository.ReadPreference} annotation. + * If present apply the {@link com.mongodb.ReadPreference} from the + * {@link org.springframework.data.mongodb.repository.ReadPreference} annotation. * * @param query must not be {@literal null}. * @return never {@literal null}. @@ -339,8 +339,8 @@ public abstract class AbstractReactiveMongoQuery implements RepositoryQuery { String updateJson = updateSource.update(); return getParameterBindingCodec() // - .flatMap(codec -> expressionEvaluator(updateJson, accessor, codec)) // - .map(it -> decode(it.getT1(), updateJson, accessor, it.getT2())) // + .flatMap(codec -> expressionEvaluator(updateJson, accessor, codec) // + .map(evaluator -> decode(evaluator, updateJson, accessor, codec))) // .map(BasicUpdate::fromDocument); } if (!ObjectUtils.isEmpty(updateSource.pipeline())) { @@ -376,16 +376,17 @@ public abstract class AbstractReactiveMongoQuery implements RepositoryQuery { private Mono computePipelineStage(String source, MongoParameterAccessor accessor, ParameterBindingDocumentCodec codec) { - return expressionEvaluator(source, accessor, codec).map( - it -> new StringAggregationOperation(source, AbstractReactiveMongoQuery.this.getQueryMethod().getDomainClass(), bsonString -> AbstractReactiveMongoQuery.this.decode(it.getT1(), bsonString, accessor, it.getT2()))); + return expressionEvaluator(source, accessor, codec).map(evaluator -> new StringAggregationOperation(source, + AbstractReactiveMongoQuery.this.getQueryMethod().getDomainClass(), + bsonString -> AbstractReactiveMongoQuery.this.decode(evaluator, bsonString, accessor, codec))); } - private Mono> expressionEvaluator(String source, - MongoParameterAccessor accessor, ParameterBindingDocumentCodec codec) { + private Mono expressionEvaluator(String source, MongoParameterAccessor accessor, + ParameterBindingDocumentCodec codec) { ExpressionDependencies dependencies = codec.captureExpressionDependencies(source, accessor::getBindableValue, expressionParser); - return getSpelEvaluatorFor(dependencies, accessor).zipWith(Mono.just(codec)); + return getSpelEvaluatorFor(dependencies, accessor); } private Document decode(SpELExpressionEvaluator expressionEvaluator, String source, MongoParameterAccessor accessor, diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/StringAggregationOperation.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/StringAggregationOperation.java index 45f66f972..a9cd28ab5 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/StringAggregationOperation.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/repository/query/StringAggregationOperation.java @@ -22,9 +22,13 @@ import java.util.regex.Pattern; import org.bson.Document; import org.springframework.data.mongodb.core.aggregation.AggregationOperation; import org.springframework.data.mongodb.core.aggregation.AggregationOperationContext; +import org.springframework.lang.Nullable; /** + * String-based aggregation operation for a repository query method. + * * @author Christoph Strobl + * @since 4.3.1 */ class StringAggregationOperation implements AggregationOperation { @@ -33,12 +37,16 @@ class StringAggregationOperation implements AggregationOperation { private final String source; private final Class domainType; private final Function bindFunction; + private final @Nullable String operator; StringAggregationOperation(String source, Class domainType, Function bindFunction) { this.source = source; this.domainType = domainType; this.bindFunction = bindFunction; + + Matcher matcher = OPERATOR_PATTERN.matcher(source); + this.operator = matcher.find() ? matcher.group() : null; } @Override @@ -48,11 +56,6 @@ class StringAggregationOperation implements AggregationOperation { @Override public String getOperator() { - - Matcher matcher = OPERATOR_PATTERN.matcher(source); - if (matcher.find()) { - return matcher.group(); - } - return AggregationOperation.super.getOperator(); + return operator != null ? operator : AggregationOperation.super.getOperator(); } } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/StringBasedAggregationOperationUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/StringBasedAggregationOperationUnitTests.java index 61da17624..58abf5168 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/StringBasedAggregationOperationUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/repository/query/StringBasedAggregationOperationUnitTests.java @@ -15,7 +15,7 @@ */ package org.springframework.data.mongodb.repository.query; -import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.*; import org.assertj.core.api.Assertions; import org.bson.Document; @@ -24,27 +24,28 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; /** + * Unit tests for {@link StringBasedAggregation}. + * * @author Christoph Strobl */ public class StringBasedAggregationOperationUnitTests { - @ParameterizedTest // GH-4712 - @ValueSource(strings = { "$project", "'$project'", "\"$project\"" }) - void extractsAggregationOperatorFromAggregationStringWithoutBindingParameters(String operator) { + @ParameterizedTest // GH-4712 + @ValueSource(strings = { "$project", "'$project'", "\"$project\"" }) + void extractsAggregationOperatorFromAggregationStringWithoutBindingParameters(String operator) { - StringAggregationOperation agg = new StringAggregationOperation("{ %s : { 'fn' : 1 } }".formatted(operator), - Object.class, (it) -> Assertions.fail("o_O Parameter binding")); + StringAggregationOperation agg = new StringAggregationOperation("{ %s : { 'fn' : 1 } }".formatted(operator), + Object.class, (it) -> Assertions.fail("o_O Parameter binding")); - assertThat(agg.getOperator()).isEqualTo("$project"); - } + assertThat(agg.getOperator()).isEqualTo("$project"); + } - @Test - // GH-4712 - void fallbackToParameterBindingIfAggregationOperatorCannotBeExtractedFromAggregationStringWithoutBindingParameters() { + @Test // GH-4712 + void fallbackToParameterBindingIfAggregationOperatorCannotBeExtractedFromAggregationStringWithoutBindingParameters() { - StringAggregationOperation agg = new StringAggregationOperation("{ happy-madison : { 'fn' : 1 } }", Object.class, - (it) -> new Document("$project", "")); + StringAggregationOperation agg = new StringAggregationOperation("{ happy-madison : { 'fn' : 1 } }", Object.class, + (it) -> new Document("$project", "")); - assertThat(agg.getOperator()).isEqualTo("$project"); - } + assertThat(agg.getOperator()).isEqualTo("$project"); + } }