From 8d223abd05a2a9f6ef74106a10d31b2424b86fd7 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Mon, 26 Sep 2022 09:48:47 +0200 Subject: [PATCH] Add support for $tsSecond aggregation operator. See #4139 Original pull request: #4182. --- .../core/aggregation/DateOperators.java | 72 +++++++++++++++++++ .../core/spel/MethodReferenceNode.java | 1 + .../aggregation/DateOperatorsUnitTests.java | 14 ++++ .../SpelExpressionTransformerUnitTests.java | 5 ++ 4 files changed, 92 insertions(+) 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 e380802fc..c3644432f 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 @@ -833,6 +833,21 @@ public class DateOperators { return TsIncrement.tsIncrement(dateReference()); } + /** + * Creates new {@link AggregationExpression} that returns the seconds from a timestamp. + * + * @return new instance of {@link TsIncrement}. + * @since 4.0 + */ + public TsSecond tsSecond() { + + if(timezone != null && !Timezone.none().equals(timezone)) { + throw new IllegalArgumentException("$tsSecond does not support timezones"); + } + + return TsSecond.tsSecond(dateReference()); + } + private Object dateReference() { if (usesFieldRef()) { @@ -3254,6 +3269,63 @@ public class DateOperators { } } + /** + * {@link AggregationExpression} for {@code $tsSecond}. + * + * @author Christoph Strobl + * @since 4.0 + */ + public static class TsSecond extends AbstractAggregationExpression { + + private TsSecond(Object value) { + super(value); + } + + /** + * Creates new {@link TsSecond} that returns the incrementing ordinal from a timestamp. + * + * @param value must not be {@literal null}. + * @return new instance of {@link TsSecond}. + * @throws IllegalArgumentException if given {@literal value} is {@literal null}. + */ + public static TsSecond tsSecond(Object value) { + + Assert.notNull(value, "Value must not be null"); + return new TsSecond(value); + } + + /** + * Creates new {@link TsSecond} that returns the incrementing ordinal from a timestamp. + * + * @param fieldReference must not be {@literal null}. + * @return new instance of {@link TsSecond}. + * @throws IllegalArgumentException if given {@literal fieldReference} is {@literal null}. + */ + public static TsSecond tsSecondValueOf(String fieldReference) { + + Assert.notNull(fieldReference, "FieldReference must not be null"); + return tsSecond(Fields.field(fieldReference)); + } + + /** + * Creates new {@link TsSecond}. + * + * @param expression must not be {@literal null}. + * @return new instance of {@link TsSecond}. + * @throws IllegalArgumentException if given {@literal expression} is {@literal null}. + */ + public static TsSecond tsSecondValueOf(AggregationExpression expression) { + + Assert.notNull(expression, "Expression must not be null"); + return tsSecond(expression); + } + + @Override + protected String getMongoMethod() { + return "$tsSecond"; + } + } + /** * 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 0a22d7f1d..cc572ab5d 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 @@ -192,6 +192,7 @@ public class MethodReferenceNode extends ExpressionNode { map.put("isoWeek", singleArgRef().forOperator("$isoWeek")); map.put("isoWeekYear", singleArgRef().forOperator("$isoWeekYear")); map.put("tsIncrement", singleArgRef().forOperator("$tsIncrement")); + map.put("tsSecond", singleArgRef().forOperator("$tsSecond")); // 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 313086718..da5b354b2 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 @@ -130,4 +130,18 @@ class DateOperatorsUnitTests { assertThatExceptionOfType(IllegalArgumentException.class) .isThrownBy(() -> DateOperators.zonedDateOf("purchaseDate", Timezone.valueOf("America/Chicago")).tsIncrement()); } + + @Test // GH-4139 + void rendersTsSecond() { + + assertThat(DateOperators.dateOf("saleTimestamp").tsSecond().toDocument(Aggregation.DEFAULT_CONTEXT)).isEqualTo( + "{ $tsSecond: \"$saleTimestamp\" }"); + } + + @Test // GH-4139 + void tsSecondErrorsOnTimezone() { + + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> DateOperators.zonedDateOf("purchaseDate", Timezone.valueOf("America/Chicago")).tsSecond()); + } } 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 06f2715e8..94b9cf935 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 @@ -1245,6 +1245,11 @@ public class SpelExpressionTransformerUnitTests { void shouldTsIncrement() { assertThat(transform("tsIncrement(saleTimestamp)")).isEqualTo("{ $tsIncrement: \"$saleTimestamp\" }"); } + + @Test // GH-4139 + void shouldTsSecond() { + assertThat(transform("tsSecond(saleTimestamp)")).isEqualTo("{ $tsSecond: \"$saleTimestamp\" }"); + } private Document transform(String expression, Object... params) { return (Document) transformer.transform(expression, Aggregation.DEFAULT_CONTEXT, params);