From 6a973b245f3c56b9c3b3fb0e1195f4631184b9e6 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Mon, 26 Sep 2022 09:44:02 +0200 Subject: [PATCH] Add support for $tsIncrement aggregation operator. See #4139 Original pull request: #4182. --- .../core/aggregation/DateOperators.java | 72 +++++++++++++++++++ .../core/spel/MethodReferenceNode.java | 1 + .../aggregation/DateOperatorsUnitTests.java | 16 ++++- .../SpelExpressionTransformerUnitTests.java | 5 ++ 4 files changed, 92 insertions(+), 2 deletions(-) diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/DateOperators.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/DateOperators.java index 0a0ac44ba0..e380802fc2 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/DateOperators.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/DateOperators.java @@ -818,6 +818,21 @@ public DateFromString fromString() { return applyTimezone(DateFromString.fromString(dateReference()), timezone); } + /** + * Creates new {@link AggregationExpression} that returns the incrementing ordinal from a timestamp. + * + * @return new instance of {@link TsIncrement}. + * @since 4.0 + */ + public TsIncrement tsIncrement() { + + if(timezone != null && !Timezone.none().equals(timezone)) { + throw new IllegalArgumentException("$tsIncrement does not support timezones"); + } + + return TsIncrement.tsIncrement(dateReference()); + } + private Object dateReference() { if (usesFieldRef()) { @@ -3182,6 +3197,63 @@ protected String getMongoMethod() { } } + /** + * {@link AggregationExpression} for {@code $tsIncrement}. + * + * @author Christoph Strobl + * @since 4.0 + */ + public static class TsIncrement extends AbstractAggregationExpression { + + private TsIncrement(Object value) { + super(value); + } + + /** + * Creates new {@link TsIncrement} that returns the incrementing ordinal from a timestamp. + * + * @param value must not be {@literal null}. + * @return new instance of {@link TsIncrement}. + * @throws IllegalArgumentException if given {@literal value} is {@literal null}. + */ + public static TsIncrement tsIncrement(Object value) { + + Assert.notNull(value, "Value must not be null"); + return new TsIncrement(value); + } + + /** + * Creates new {@link TsIncrement} that returns the incrementing ordinal from a timestamp. + * + * @param fieldReference must not be {@literal null}. + * @return new instance of {@link TsIncrement}. + * @throws IllegalArgumentException if given {@literal fieldReference} is {@literal null}. + */ + public static TsIncrement tsIncrementValueOf(String fieldReference) { + + Assert.notNull(fieldReference, "FieldReference must not be null"); + return tsIncrement(Fields.field(fieldReference)); + } + + /** + * Creates new {@link TsIncrement}. + * + * @param expression must not be {@literal null}. + * @return new instance of {@link TsIncrement}. + * @throws IllegalArgumentException if given {@literal expression} is {@literal null}. + */ + public static TsIncrement tsIncrementValueOf(AggregationExpression expression) { + + Assert.notNull(expression, "Expression must not be null"); + return tsIncrement(expression); + } + + @Override + protected String getMongoMethod() { + return "$tsIncrement"; + } + } + /** * Interface defining a temporal unit for date operators. * 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 4347adba15..0a22d7f1d1 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 @@ -191,6 +191,7 @@ public class MethodReferenceNode extends ExpressionNode { map.put("isoDayOfWeek", singleArgRef().forOperator("$isoDayOfWeek")); map.put("isoWeek", singleArgRef().forOperator("$isoWeek")); map.put("isoWeekYear", singleArgRef().forOperator("$isoWeekYear")); + map.put("tsIncrement", singleArgRef().forOperator("$tsIncrement")); // CONDITIONAL OPERATORS map.put("cond", mapArgRef().forOperator("$cond") // diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/DateOperatorsUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/DateOperatorsUnitTests.java index f0830acd1c..313086718f 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/DateOperatorsUnitTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/DateOperatorsUnitTests.java @@ -24,8 +24,6 @@ import java.util.TimeZone; import org.junit.jupiter.api.Test; - -import org.springframework.data.mongodb.core.aggregation.DateOperators.TemporalUnit; import org.springframework.data.mongodb.core.aggregation.DateOperators.Timezone; /** @@ -118,4 +116,18 @@ void rendersDateTruncWithTimezone() { assertThat(DateOperators.zonedDateOf("purchaseDate", Timezone.valueOf("America/Chicago")).truncate("week").binSize(2).startOfWeek(DayOfWeek.MONDAY).toDocument(Aggregation.DEFAULT_CONTEXT)) .isEqualTo("{ $dateTrunc: { date: \"$purchaseDate\", unit: \"week\", binSize: 2, startOfWeek : \"monday\", timezone : \"America/Chicago\" } }"); } + + @Test // GH-4139 + void rendersTsIncrement() { + + assertThat(DateOperators.dateOf("saleTimestamp").tsIncrement().toDocument(Aggregation.DEFAULT_CONTEXT)).isEqualTo( + "{ $tsIncrement: \"$saleTimestamp\" }"); + } + + @Test // GH-4139 + void tsIncrementErrorsOnTimezone() { + + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> DateOperators.zonedDateOf("purchaseDate", Timezone.valueOf("America/Chicago")).tsIncrement()); + } } 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 ebf944020b..06f2715e88 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 @@ -1240,6 +1240,11 @@ void shouldRenderSortArray() { assertThat(transform( "sortArray(team, new org.bson.Document(\"name\" , 1))")).isEqualTo("{ $sortArray : { input : \"$team\", sortBy : {\"name\" : 1 } }}"); } + + @Test // GH-4139 + void shouldTsIncrement() { + assertThat(transform("tsIncrement(saleTimestamp)")).isEqualTo("{ $tsIncrement: \"$saleTimestamp\" }"); + } private Document transform(String expression, Object... params) { return (Document) transformer.transform(expression, Aggregation.DEFAULT_CONTEXT, params);