Skip to content

Commit db12c4b

Browse files
christophstroblmp911de
authored andcommitted
Add support for $dateSubtract aggregation operator.
See #4139 Original pull request: #4182.
1 parent 5bbe481 commit db12c4b

File tree

4 files changed

+209
-0
lines changed

4 files changed

+209
-0
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/DateOperators.java

+186
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,95 @@ public DateAdd add(Object value, TemporalUnit unit) {
449449
timezone);
450450
}
451451

452+
/**
453+
* Creates new {@link AggregationExpression} that subtracts the value of the given {@link AggregationExpression
454+
* expression} (in {@literal units}).
455+
*
456+
* @param expression must not be {@literal null}.
457+
* @param unit the unit of measure. Must not be {@literal null}.
458+
* @return new instance of {@link DateSubtract}.
459+
* @since 4.0
460+
*/
461+
public DateSubtract subtractValueOf(AggregationExpression expression, String unit) {
462+
return applyTimezone(DateSubtract.subtractValueOf(expression, unit).fromDate(dateReference()), timezone);
463+
}
464+
465+
/**
466+
* Creates new {@link AggregationExpression} that subtracts the value of the given {@link AggregationExpression
467+
* expression} (in {@literal units}).
468+
*
469+
* @param expression must not be {@literal null}.
470+
* @param unit the unit of measure. Must not be {@literal null}.
471+
* @return new instance of {@link DateSubtract}.
472+
* @since 4.0
473+
*/
474+
public DateSubtract subtractValueOf(AggregationExpression expression, TemporalUnit unit) {
475+
476+
Assert.notNull(unit, "TemporalUnit must not be null");
477+
return applyTimezone(
478+
DateSubtract.subtractValueOf(expression, unit.name().toLowerCase(Locale.ROOT)).fromDate(dateReference()),
479+
timezone);
480+
}
481+
482+
/**
483+
* Creates new {@link AggregationExpression} that subtracts the value stored at the given {@literal field} (in
484+
* {@literal units}).
485+
*
486+
* @param fieldReference must not be {@literal null}.
487+
* @param unit the unit of measure. Must not be {@literal null}.
488+
* @return new instance of {@link DateSubtract}.
489+
* @since 4.0
490+
*/
491+
public DateSubtract subtractValueOf(String fieldReference, String unit) {
492+
return applyTimezone(DateSubtract.subtractValueOf(fieldReference, unit).fromDate(dateReference()), timezone);
493+
}
494+
495+
/**
496+
* Creates new {@link AggregationExpression} that subtracts the value stored at the given {@literal field} (in
497+
* {@literal units}).
498+
*
499+
* @param fieldReference must not be {@literal null}.
500+
* @param unit the unit of measure. Must not be {@literal null}.
501+
* @return new instance of {@link DateSubtract}.
502+
* @since 4.0
503+
*/
504+
public DateSubtract subtractValueOf(String fieldReference, TemporalUnit unit) {
505+
506+
Assert.notNull(unit, "TemporalUnit must not be null");
507+
508+
return applyTimezone(
509+
DateSubtract.subtractValueOf(fieldReference, unit.name().toLowerCase(Locale.ROOT)).fromDate(dateReference()),
510+
timezone);
511+
}
512+
513+
/**
514+
* Creates new {@link AggregationExpression} that subtracts the given value (in {@literal units}).
515+
*
516+
* @param value must not be {@literal null}.
517+
* @param unit the unit of measure. Must not be {@literal null}.
518+
* @return new instance of {@link DateSubtract}.
519+
* @since 4.0
520+
*/
521+
public DateSubtract subtract(Object value, String unit) {
522+
return applyTimezone(DateSubtract.subtractValue(value, unit).fromDate(dateReference()), timezone);
523+
}
524+
525+
/**
526+
* Creates new {@link AggregationExpression} that subtracts the given value (in {@literal units}).
527+
*
528+
* @param value must not be {@literal null}.
529+
* @param unit the unit of measure. Must not be {@literal null}.
530+
* @return new instance of {@link DateSubtract}.
531+
* @since 4.0
532+
*/
533+
public DateSubtract subtract(Object value, TemporalUnit unit) {
534+
535+
Assert.notNull(unit, "TemporalUnit must not be null");
536+
537+
return applyTimezone(
538+
DateSubtract.subtractValue(value, unit.name().toLowerCase(Locale.ROOT)).fromDate(dateReference()), timezone);
539+
}
540+
452541
/**
453542
* Creates new {@link AggregationExpression} that returns the day of the year for a date as a number between 1 and
454543
* 366.
@@ -2733,6 +2822,103 @@ protected String getMongoMethod() {
27332822
}
27342823
}
27352824

2825+
/**
2826+
* {@link AggregationExpression} for {@code $dateSubtract}.<br />
2827+
* <strong>NOTE:</strong> Requires MongoDB 5.0 or later.
2828+
*
2829+
* @author Christoph Strobl
2830+
* @since 4.0
2831+
*/
2832+
public static class DateSubtract extends TimezonedDateAggregationExpression {
2833+
2834+
private DateSubtract(Object value) {
2835+
super(value);
2836+
}
2837+
2838+
/**
2839+
* Subtract the number of {@literal units} of the result of the given {@link AggregationExpression expression} from
2840+
* a {@link #fromDate(Object) start date}.
2841+
*
2842+
* @param expression must not be {@literal null}.
2843+
* @param unit must not be {@literal null}.
2844+
* @return new instance of {@link DateSubtract}.
2845+
*/
2846+
public static DateSubtract subtractValueOf(AggregationExpression expression, String unit) {
2847+
return subtractValue(expression, unit);
2848+
}
2849+
2850+
/**
2851+
* Subtract the number of {@literal units} from a {@literal field} from a {@link #fromDate(Object) start date}.
2852+
*
2853+
* @param fieldReference must not be {@literal null}.
2854+
* @param unit must not be {@literal null}.
2855+
* @return new instance of {@link DateSubtract}.
2856+
*/
2857+
public static DateSubtract subtractValueOf(String fieldReference, String unit) {
2858+
return subtractValue(Fields.field(fieldReference), unit);
2859+
}
2860+
2861+
/**
2862+
* Subtract the number of {@literal units} from a {@link #fromDate(Object) start date}.
2863+
*
2864+
* @param value must not be {@literal null}.
2865+
* @param unit must not be {@literal null}.
2866+
* @return new instance of {@link DateSubtract}.
2867+
*/
2868+
public static DateSubtract subtractValue(Object value, String unit) {
2869+
2870+
Map<String, Object> args = new HashMap<>();
2871+
args.put("unit", unit);
2872+
args.put("amount", value);
2873+
return new DateSubtract(args);
2874+
}
2875+
2876+
/**
2877+
* Define the start date, in UTC, for the subtraction operation.
2878+
*
2879+
* @param expression must not be {@literal null}.
2880+
* @return new instance of {@link DateSubtract}.
2881+
*/
2882+
public DateSubtract fromDateOf(AggregationExpression expression) {
2883+
return fromDate(expression);
2884+
}
2885+
2886+
/**
2887+
* Define the start date, in UTC, for the subtraction operation.
2888+
*
2889+
* @param fieldReference must not be {@literal null}.
2890+
* @return new instance of {@link DateSubtract}.
2891+
*/
2892+
public DateSubtract fromDateOf(String fieldReference) {
2893+
return fromDate(Fields.field(fieldReference));
2894+
}
2895+
2896+
/**
2897+
* Define the start date, in UTC, for the subtraction operation.
2898+
*
2899+
* @param dateExpression anything that evaluates to a valid date. Must not be {@literal null}.
2900+
* @return new instance of {@link DateSubtract}.
2901+
*/
2902+
public DateSubtract fromDate(Object dateExpression) {
2903+
return new DateSubtract(append("startDate", dateExpression));
2904+
}
2905+
2906+
/**
2907+
* Optionally set the {@link Timezone} to use. If not specified {@literal UTC} is used.
2908+
*
2909+
* @param timezone must not be {@literal null}. Consider {@link Timezone#none()} instead.
2910+
* @return new instance of {@link DateSubtract}.
2911+
*/
2912+
public DateSubtract withTimezone(Timezone timezone) {
2913+
return new DateSubtract(appendTimezone(argumentMap(), timezone));
2914+
}
2915+
2916+
@Override
2917+
protected String getMongoMethod() {
2918+
return "$dateSubtract";
2919+
}
2920+
}
2921+
27362922
/**
27372923
* {@link AggregationExpression} for {@code $dateDiff}.<br />
27382924
* <strong>NOTE:</strong> Requires MongoDB 5.0 or later.

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/spel/MethodReferenceNode.java

+2
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ public class MethodReferenceNode extends ExpressionNode {
161161
// DATE OPERATORS
162162
map.put("dateAdd",
163163
mapArgRef().forOperator("$dateAdd").mappingParametersTo("startDate", "unit", "amount", "timezone"));
164+
map.put("dateSubtract",
165+
mapArgRef().forOperator("$dateSubtract").mappingParametersTo("startDate", "unit", "amount", "timezone"));
164166
map.put("dateDiff", mapArgRef().forOperator("$dateDiff").mappingParametersTo("startDate", "endDate", "unit",
165167
"timezone", "startOfWeek"));
166168
map.put("dayOfYear", singleArgRef().forOperator("$dayOfYear"));

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/DateOperatorsUnitTests.java

+15
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,21 @@ void rendersDateAddWithTimezone() {
4949
"{ $dateAdd: { startDate: \"$purchaseDate\", unit: \"day\", amount: 3, timezone : \"America/Chicago\" } }");
5050
}
5151

52+
@Test // GH-4139
53+
void rendersDateSubtract() {
54+
55+
assertThat(DateOperators.dateOf("purchaseDate").subtract(3, "day").toDocument(Aggregation.DEFAULT_CONTEXT))
56+
.isEqualTo("{ $dateSubtract: { startDate: \"$purchaseDate\", unit: \"day\", amount: 3 } }");
57+
}
58+
59+
@Test // GH-4139
60+
void rendersDateSubtractWithTimezone() {
61+
62+
assertThat(DateOperators.zonedDateOf("purchaseDate", Timezone.valueOf("America/Chicago")).subtract(3, "day")
63+
.toDocument(Aggregation.DEFAULT_CONTEXT)).isEqualTo(
64+
"{ $dateSubtract: { startDate: \"$purchaseDate\", unit: \"day\", amount: 3, timezone : \"America/Chicago\" } }");
65+
}
66+
5267
@Test // GH-3713
5368
void rendersDateDiff() {
5469

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/SpelExpressionTransformerUnitTests.java

+6
Original file line numberDiff line numberDiff line change
@@ -1163,6 +1163,12 @@ void shouldRenderDateAdd() {
11631163
.isEqualTo("{ $dateAdd: { startDate: \"$purchaseDate\", unit: \"day\", amount: 3 } }");
11641164
}
11651165

1166+
@Test // GH-4139
1167+
void shouldRenderDateSubtract() {
1168+
assertThat(transform("dateSubtract(purchaseDate, 'day', 3)"))
1169+
.isEqualTo("{ $dateSubtract: { startDate: \"$purchaseDate\", unit: \"day\", amount: 3 } }");
1170+
}
1171+
11661172
@Test // GH-3713
11671173
void shouldRenderDateDiff() {
11681174
assertThat(transform("dateDiff(purchaseDate, delivered, 'day')"))

0 commit comments

Comments
 (0)