Add support for $dateAdd aggregation operator.
Closes: #3713 Original pull request: #3748.
This commit is contained in:
committed by
Mark Paluch
parent
869b88702d
commit
afef243634
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -156,7 +157,7 @@ public class DateOperators {
|
||||
* representing an Olson Timezone Identifier or UTC Offset.
|
||||
*
|
||||
* @param value the plain timezone {@link String}, a {@link Field} holding the timezone or an
|
||||
* {@link AggregationExpression} resulting in the timezone.
|
||||
* {@link AggregationExpression} resulting in the timezone.
|
||||
* @return new instance of {@link Timezone}.
|
||||
*/
|
||||
public static Timezone valueOf(Object value) {
|
||||
@@ -274,6 +275,41 @@ public class DateOperators {
|
||||
return new DateOperatorFactory(fieldReference, expression, dateValue, timezone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that adds the value of the given {@link AggregationExpression
|
||||
* expression} (in {@literal units). @param expression must not be {@literal null}.
|
||||
*
|
||||
* @param unit the unit of measure. Must not be {@literal null}.
|
||||
* @return new instance of {@link DateAdd}.
|
||||
* @since 3.3
|
||||
*/
|
||||
public DateAdd addValueOf(AggregationExpression expression, String unit) {
|
||||
return applyTimezone(DateAdd.addValueOf(expression, unit).toDate(dateReference()), timezone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that adds the value stored at the given {@literal field} (in
|
||||
* {@literal units). @param fieldReference must not be {@literal null}.
|
||||
*
|
||||
* @param unit the unit of measure. Must not be {@literal null}.
|
||||
* @return new instance of {@link DateAdd}.
|
||||
* @since 3.3
|
||||
*/
|
||||
public DateAdd addValueOf(String fieldReference, String unit) {
|
||||
return applyTimezone(DateAdd.addValueOf(fieldReference, unit).toDate(dateReference()), timezone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that adds the given value (in {@literal units). @param value must not
|
||||
* be {@literal null}. @param unit the unit of measure. Must not be {@literal null}.
|
||||
*
|
||||
* @return
|
||||
* @since 3.3 new instance of {@link DateAdd}.
|
||||
*/
|
||||
public DateAdd add(Object value, String unit) {
|
||||
return applyTimezone(DateAdd.addValue(value, unit).toDate(dateReference()), timezone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that returns the day of the year for a date as a number between 1 and
|
||||
* 366.
|
||||
@@ -1480,7 +1516,6 @@ public class DateOperators {
|
||||
} else {
|
||||
clone.put("timezone", ((Timezone) value).value);
|
||||
}
|
||||
|
||||
} else {
|
||||
clone.put(key, value);
|
||||
}
|
||||
@@ -1911,7 +1946,7 @@ public class DateOperators {
|
||||
* @author Matt Morrissette
|
||||
* @author Christoph Strobl
|
||||
* @see <a href=
|
||||
* "https://docs.mongodb.com/manual/reference/operator/aggregation/dateFromParts/">https://docs.mongodb.com/manual/reference/operator/aggregation/dateFromParts/</a>
|
||||
* "https://docs.mongodb.com/manual/reference/operator/aggregation/dateFromParts/">https://docs.mongodb.com/manual/reference/operator/aggregation/dateFromParts/</a>
|
||||
* @since 2.1
|
||||
*/
|
||||
public static class DateFromParts extends TimezonedDateAggregationExpression implements DateParts<DateFromParts> {
|
||||
@@ -2086,7 +2121,7 @@ public class DateOperators {
|
||||
* @author Matt Morrissette
|
||||
* @author Christoph Strobl
|
||||
* @see <a href=
|
||||
* "https://docs.mongodb.com/manual/reference/operator/aggregation/dateFromParts/">https://docs.mongodb.com/manual/reference/operator/aggregation/dateFromParts/</a>
|
||||
* "https://docs.mongodb.com/manual/reference/operator/aggregation/dateFromParts/">https://docs.mongodb.com/manual/reference/operator/aggregation/dateFromParts/</a>
|
||||
* @since 2.1
|
||||
*/
|
||||
public static class IsoDateFromParts extends TimezonedDateAggregationExpression
|
||||
@@ -2262,7 +2297,7 @@ public class DateOperators {
|
||||
* @author Matt Morrissette
|
||||
* @author Christoph Strobl
|
||||
* @see <a href=
|
||||
* "https://docs.mongodb.com/manual/reference/operator/aggregation/dateToParts/">https://docs.mongodb.com/manual/reference/operator/aggregation/dateToParts/</a>
|
||||
* "https://docs.mongodb.com/manual/reference/operator/aggregation/dateToParts/">https://docs.mongodb.com/manual/reference/operator/aggregation/dateToParts/</a>
|
||||
* @since 2.1
|
||||
*/
|
||||
public static class DateToParts extends TimezonedDateAggregationExpression {
|
||||
@@ -2343,7 +2378,7 @@ public class DateOperators {
|
||||
* @author Matt Morrissette
|
||||
* @author Christoph Strobl
|
||||
* @see <a href=
|
||||
* "https://docs.mongodb.com/manual/reference/operator/aggregation/dateFromString/">https://docs.mongodb.com/manual/reference/operator/aggregation/dateFromString/</a>
|
||||
* "https://docs.mongodb.com/manual/reference/operator/aggregation/dateFromString/">https://docs.mongodb.com/manual/reference/operator/aggregation/dateFromString/</a>
|
||||
* @since 2.1
|
||||
*/
|
||||
public static class DateFromString extends TimezonedDateAggregationExpression {
|
||||
@@ -2418,6 +2453,103 @@ public class DateOperators {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link AggregationExpression} for {@code $dateAdd}.<br />
|
||||
* <strong>NOTE:</strong> Requires MongoDB 5.0 or later.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 3.3
|
||||
*/
|
||||
public static class DateAdd extends TimezonedDateAggregationExpression {
|
||||
|
||||
private DateAdd(Object value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the number of {@literal units} of the result of the given {@link AggregationExpression expression} to a
|
||||
* {@link #toDate(Object) start date}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @param unit must not be {@literal null}.
|
||||
* @return new instance of {@link DateAdd}.
|
||||
*/
|
||||
public static DateAdd addValueOf(AggregationExpression expression, String unit) {
|
||||
return addValue(expression, unit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the number of {@literal units} from a {@literal field} to a {@link #toDate(Object) start date}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @param unit must not be {@literal null}.
|
||||
* @return new instance of {@link DateAdd}.
|
||||
*/
|
||||
public static DateAdd addValueOf(String fieldReference, String unit) {
|
||||
return addValue(Fields.field(fieldReference), unit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the number of {@literal units} to a {@link #toDate(Object) start date}.
|
||||
*
|
||||
* @param value must not be {@literal null}.
|
||||
* @param unit must not be {@literal null}.
|
||||
* @return new instance of {@link DateAdd}.
|
||||
*/
|
||||
public static DateAdd addValue(Object value, String unit) {
|
||||
|
||||
Map<String, Object> args = new HashMap<>();
|
||||
args.put("unit", unit);
|
||||
args.put("amount", value);
|
||||
return new DateAdd(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the start date, in UTC, for the addition operation.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return new instance of {@link DateAdd}.
|
||||
*/
|
||||
public DateAdd toDateOf(AggregationExpression expression) {
|
||||
return toDate(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the start date, in UTC, for the addition operation.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return new instance of {@link DateAdd}.
|
||||
*/
|
||||
public DateAdd toDateOf(String fieldReference) {
|
||||
return toDate(Fields.field(fieldReference));
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the start date, in UTC, for the addition operation.
|
||||
*
|
||||
* @param dateExpression anything that evaluates to a valid date. Must not be {@literal null}.
|
||||
* @return new instance of {@link DateAdd}.
|
||||
*/
|
||||
public DateAdd toDate(Object dateExpression) {
|
||||
return new DateAdd(append("startDate", dateExpression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Optionally set the {@link Timezone} to use. If not specified {@literal UTC} is used.
|
||||
*
|
||||
* @param timezone must not be {@literal null}. Consider {@link Timezone#none()} instead.
|
||||
* @return new instance of {@link DateAdd}.
|
||||
*/
|
||||
public DateAdd withTimezone(Timezone timezone) {
|
||||
return new DateAdd(appendTimezone(argumentMap(), timezone));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$dateAdd";
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T extends TimezonedDateAggregationExpression> T applyTimezone(T instance, Timezone timezone) {
|
||||
return !ObjectUtils.nullSafeEquals(Timezone.none(), timezone) && !instance.hasTimezone()
|
||||
|
||||
@@ -144,6 +144,7 @@ public class MethodReferenceNode extends ExpressionNode {
|
||||
map.put("literal", singleArgRef().forOperator("$literal"));
|
||||
|
||||
// DATE OPERATORS
|
||||
map.put("dateAdd", mapArgRef().forOperator("$dateAdd").mappingParametersTo("startDate", "unit", "amount", "timezone"));
|
||||
map.put("dayOfYear", singleArgRef().forOperator("$dayOfYear"));
|
||||
map.put("dayOfMonth", singleArgRef().forOperator("$dayOfMonth"));
|
||||
map.put("dayOfWeek", singleArgRef().forOperator("$dayOfWeek"));
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2021. the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.data.mongodb.core.aggregation.DateOperators.Timezone;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
class DateOperatorsUnitTests {
|
||||
|
||||
@Test // GH-3713
|
||||
void rendersDateAdd() {
|
||||
|
||||
assertThat(DateOperators.dateOf("purchaseDate").add(3, "day").toDocument(Aggregation.DEFAULT_CONTEXT))
|
||||
.isEqualTo(Document.parse("{ $dateAdd: { startDate: \"$purchaseDate\", unit: \"day\", amount: 3 } }"));
|
||||
}
|
||||
|
||||
@Test // GH-3713
|
||||
void rendersDateAddWithTimezone() {
|
||||
|
||||
assertThat(DateOperators.dateOf("purchaseDate").withTimezone(Timezone.valueOf("America/Chicago")).add(3, "day")
|
||||
.toDocument(Aggregation.DEFAULT_CONTEXT)).isEqualTo(Document.parse(
|
||||
"{ $dateAdd: { startDate: \"$purchaseDate\", unit: \"day\", amount: 3, timezone : \"America/Chicago\" } }"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1039,6 +1039,12 @@ public class SpelExpressionTransformerUnitTests {
|
||||
}
|
||||
|
||||
private Object transformValue(String expression, Object... params) {
|
||||
@Test // GH-3713
|
||||
void shouldRenderDateAdd() {
|
||||
assertThat(transform("dateAdd(purchaseDate, 'day', 3)")).isEqualTo(Document.parse("{ $dateAdd: { startDate: \"$purchaseDate\", unit: \"day\", amount: 3 } }"));
|
||||
}
|
||||
|
||||
private Object transform(String expression, Object... params) {
|
||||
Object result = transformer.transform(expression, Aggregation.DEFAULT_CONTEXT, params);
|
||||
return result == null ? null : (!(result instanceof org.bson.Document) ? result.toString() : result);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user