From bcbefa9264ffdb9504b912623070891ec8502790 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Mon, 24 Jan 2022 09:22:10 +0100 Subject: [PATCH] Support aggregation operators $first and $last via expression method reference. This commit registers the first(...) and last(...) methods for transformation via SpEL. Also update reference and java documentation and add issue reference to tests. Original Pull Request: #3866 --- .../core/aggregation/ArrayOperators.java | 20 +++++++++++++------ .../core/spel/MethodReferenceNode.java | 2 ++ .../aggregation/ArrayOperatorsUnitTests.java | 15 +++++++------- .../SpelExpressionTransformerUnitTests.java | 11 +++++++++- .../reference/aggregation-framework.adoc | 2 +- 5 files changed, 34 insertions(+), 16 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ArrayOperators.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ArrayOperators.java index bb69ebf5f..d50ef8afa 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ArrayOperators.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ArrayOperators.java @@ -35,6 +35,7 @@ import org.springframework.util.Assert; * @author Christoph Strobl * @author Mark Paluch * @author Shashank Sharma + * @author Divya Srivastava * @since 1.0 */ public class ArrayOperators { @@ -364,10 +365,11 @@ public class ArrayOperators { } /** - * Creates new {@link AggregationExpression} that return the first element in the given array. + * Creates new {@link AggregationExpression} that return the first element in the associated array. * NOTE: Requires MongoDB 4.4 or later. * * @return new instance of {@link First}. + * @since 3.4 */ public First first() { @@ -382,7 +384,8 @@ public class ArrayOperators { * Creates new {@link AggregationExpression} that return the last element in the given array. * NOTE: Requires MongoDB 4.4 or later. * - * @return new instance of {@link First}. + * @return new instance of {@link Last}. + * @since 3.4 */ public Last last() { @@ -1847,6 +1850,9 @@ public class ArrayOperators { * {@link AggregationExpression} for {@code $first} that returns the first element in an array.
* NOTE: Requires MongoDB 4.4 or later. * + * @author Divya Srivastava + * @author Christoph Strobl + * @since 3.4 */ public static class First extends AbstractAggregationExpression { @@ -1875,7 +1881,7 @@ public class ArrayOperators { } /** - * Returns the first element of the array of the given {@link AggregationExpression expression}. + * Returns the first element of the array computed by the given {@link AggregationExpression expression}. * * @param expression must not be {@literal null}. * @return new instance of {@link First}. @@ -1898,6 +1904,9 @@ public class ArrayOperators { * {@link AggregationExpression} for {@code $last} that returns the last element in an array.
* NOTE: Requires MongoDB 4.4 or later. * + * @author Divya Srivastava + * @author Christoph Strobl + * @since 3.4 */ public static class Last extends AbstractAggregationExpression { @@ -1906,7 +1915,7 @@ public class ArrayOperators { } /** - * Returns the first element in the given array. + * Returns the last element in the given array. * * @param array must not be {@literal null}. * @return new instance of {@link Last}. @@ -1926,7 +1935,7 @@ public class ArrayOperators { } /** - * Returns the last element of the array of the given {@link AggregationExpression expression}. + * Returns the last element of the array computed buy the given {@link AggregationExpression expression}. * * @param expression must not be {@literal null}. * @return new instance of {@link Last}. @@ -1944,5 +1953,4 @@ public class ArrayOperators { return "$last"; } } - } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/spel/MethodReferenceNode.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/spel/MethodReferenceNode.java index f5032868c..0e0145571 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/spel/MethodReferenceNode.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/spel/MethodReferenceNode.java @@ -137,7 +137,9 @@ public class MethodReferenceNode extends ExpressionNode { map.put("concatArrays", arrayArgRef().forOperator("$concatArrays")); map.put("filter", mapArgRef().forOperator("$filter") // .mappingParametersTo("input", "as", "cond")); + map.put("first", singleArgRef().forOperator("$first")); map.put("isArray", singleArgRef().forOperator("$isArray")); + map.put("last", singleArgRef().forOperator("$last")); map.put("size", singleArgRef().forOperator("$size")); map.put("slice", arrayArgRef().forOperator("$slice")); map.put("reverseArray", singleArgRef().forOperator("$reverseArray")); diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ArrayOperatorsUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ArrayOperatorsUnitTests.java index 56a7bf7ac..4e637918e 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ArrayOperatorsUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ArrayOperatorsUnitTests.java @@ -23,7 +23,6 @@ import java.util.List; import org.bson.Document; import org.junit.jupiter.api.Test; - import org.springframework.data.mongodb.core.aggregation.ArrayOperators.ArrayToObject; /** @@ -31,6 +30,7 @@ import org.springframework.data.mongodb.core.aggregation.ArrayOperators.ArrayToO * * @author Christoph Strobl * @author Shashank Sharma + * @author Divya Srivastava * @currentRead Royal Assassin - Robin Hobb */ public class ArrayOperatorsUnitTests { @@ -130,46 +130,45 @@ public class ArrayOperatorsUnitTests { .isEqualTo("{ \"$in\" : [\"$userName\", " + VALUE_LIST_STRING + "] }"); } - @Test + @Test // GH-3694 public void firstWithValueList() { assertThat(ArrayOperators.arrayOf(VALUE_LIST).first().toDocument(Aggregation.DEFAULT_CONTEXT)) .isEqualTo("{ \"$first\" : " + VALUE_LIST_STRING + "}"); } - @Test + @Test // GH-3694 public void firstWithExpression() { assertThat(ArrayOperators.arrayOf(EXPRESSION).first().toDocument(Aggregation.DEFAULT_CONTEXT)) .isEqualTo("{ \"$first\" : " + EXPRESSION_STRING + "}"); } - @Test + @Test // GH-3694 public void firstWithFieldReference() { assertThat(ArrayOperators.arrayOf("field").first().toDocument(Aggregation.DEFAULT_CONTEXT)) .isEqualTo("{ $first : \"$field\" }"); } - @Test + @Test // GH-3694 public void lastWithValueList() { assertThat(ArrayOperators.arrayOf(VALUE_LIST).last().toDocument(Aggregation.DEFAULT_CONTEXT)) .isEqualTo("{ \"$last\" : " + VALUE_LIST_STRING + "}"); } - @Test + @Test // GH-3694 public void lastWithExpression() { assertThat(ArrayOperators.arrayOf(EXPRESSION).last().toDocument(Aggregation.DEFAULT_CONTEXT)) .isEqualTo("{ \"$last\" : " + EXPRESSION_STRING + "}"); } - @Test + @Test // GH-3694 public void lastWithFieldReference() { assertThat(ArrayOperators.arrayOf("field").last().toDocument(Aggregation.DEFAULT_CONTEXT)) .isEqualTo("{ $last : \"$field\" }"); } - } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/SpelExpressionTransformerUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/SpelExpressionTransformerUnitTests.java index e308124eb..490322003 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/SpelExpressionTransformerUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/SpelExpressionTransformerUnitTests.java @@ -411,6 +411,16 @@ public class SpelExpressionTransformerUnitTests { assertThat(transform("arrayElemAt(a, 10)")).isEqualTo("{ \"$arrayElemAt\" : [ \"$a\" , 10]}"); } + @Test // GH-3694 + void shouldRenderMethodReferenceNodeFirst() { + assertThat(transform("first(a)")).isEqualTo("{ \"$first\" : \"$a\" }"); + } + + @Test // GH-3694 + void shouldRenderMethodReferenceNodeLast() { + assertThat(transform("last(a)")).isEqualTo("{ \"$last\" : \"$a\" }"); + } + @Test // DATAMONGO-1530 void shouldRenderMethodReferenceNodeConcatArrays() { assertThat(transform("concatArrays(a, b, c)")) @@ -879,7 +889,6 @@ public class SpelExpressionTransformerUnitTests { .isEqualTo("{ \"$replaceAll\" : {\"input\" : \"$field\" , \"find\" : \"bar\" , \"replacement\" : \"baz\"}}"); } - @Test // DATAMONGO-2077 void shouldRenderConvertWithoutOptionalParameters() { diff --git a/src/main/asciidoc/reference/aggregation-framework.adoc b/src/main/asciidoc/reference/aggregation-framework.adoc index c5db5f30a..3530ada88 100644 --- a/src/main/asciidoc/reference/aggregation-framework.adoc +++ b/src/main/asciidoc/reference/aggregation-framework.adoc @@ -94,7 +94,7 @@ At the time of this writing, we provide support for the following Aggregation Op | `eq` (+++*+++ via `is`), `gt`, `gte`, `lt`, `lte`, `ne` | Array Aggregation Operators -| `arrayElementAt`, `arrayToObject`, `concatArrays`, `filter`, `in`, `indexOfArray`, `isArray`, `range`, `reverseArray`, `reduce`, `size`, `slice`, `zip` +| `arrayElementAt`, `arrayToObject`, `concatArrays`, `filter`, `first`, `in`, `indexOfArray`, `isArray`, `last`, range`, `reverseArray`, `reduce`, `size`, `slice`, `zip` | Literal Operators | `literal`