Add support for $locf aggregation operator.

See #4139
Original pull request: #4182.
This commit is contained in:
Christoph Strobl
2022-09-26 10:02:08 +02:00
committed by Mark Paluch
parent 8d223abd05
commit 9217821472
4 changed files with 67 additions and 1 deletions

View File

@@ -16,7 +16,6 @@
package org.springframework.data.mongodb.core.aggregation; package org.springframework.data.mongodb.core.aggregation;
import org.bson.Document; import org.bson.Document;
import org.springframework.data.mongodb.core.query.CriteriaDefinition; import org.springframework.data.mongodb.core.query.CriteriaDefinition;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@@ -24,6 +23,7 @@ import org.springframework.util.Assert;
* Gateway to {@literal evaluation operators} such as {@literal $expr}. * Gateway to {@literal evaluation operators} such as {@literal $expr}.
* *
* @author Divya Srivastava * @author Divya Srivastava
* @author Christoph Strobl
* @since 3.3 * @since 3.3
*/ */
public class EvaluationOperators { public class EvaluationOperators {
@@ -86,6 +86,15 @@ public class EvaluationOperators {
return usesFieldRef() ? Expr.valueOf(fieldReference) : Expr.valueOf(expression); return usesFieldRef() ? Expr.valueOf(fieldReference) : Expr.valueOf(expression);
} }
/**
* Creates new {@link AggregationExpression} that is a valid aggregation expression.
*
* @return new instance of {@link Expr}.
*/
public LastObservationCarriedForward locf() {
return usesFieldRef() ? LastObservationCarriedForward.locfValueOf(fieldReference) : LastObservationCarriedForward.locfValueOf(expression);
}
/** /**
* Allows the use of aggregation expressions within the query language. * Allows the use of aggregation expressions within the query language.
*/ */
@@ -152,4 +161,45 @@ public class EvaluationOperators {
} }
} }
/**
* Sets {@literal null} and missing values to the last non-null value.
*
* @since 4.0
*/
public static class LastObservationCarriedForward extends AbstractAggregationExpression {
private LastObservationCarriedForward(Object value) {
super(value);
}
@Override
protected String getMongoMethod() {
return "$locf";
}
/**
* Creates new {@link EvaluationOperatorFactory.Expr}.
*
* @param fieldReference must not be {@literal null}.
* @return new instance of {@link EvaluationOperatorFactory.Expr}.
*/
public static LastObservationCarriedForward locfValueOf(String fieldReference) {
Assert.notNull(fieldReference, "FieldReference must not be null");
return new LastObservationCarriedForward(Fields.field(fieldReference));
}
/**
* Creates new {@link LastObservationCarriedForward}.
*
* @param expression must not be {@literal null}.
* @return new instance of {@link LastObservationCarriedForward}.
*/
public static LastObservationCarriedForward locfValueOf(AggregationExpression expression) {
Assert.notNull(expression, "Expression must not be null");
return new LastObservationCarriedForward(expression);
}
}
} }

View File

@@ -251,6 +251,9 @@ public class MethodReferenceNode extends ExpressionNode {
map.put("toString", singleArgRef().forOperator("$toString")); map.put("toString", singleArgRef().forOperator("$toString"));
map.put("degreesToRadians", singleArgRef().forOperator("$degreesToRadians")); map.put("degreesToRadians", singleArgRef().forOperator("$degreesToRadians"));
// expression operators
map.put("locf", singleArgRef().forOperator("$locf"));
FUNCTIONS = Collections.unmodifiableMap(map); FUNCTIONS = Collections.unmodifiableMap(map);
} }

View File

@@ -23,6 +23,7 @@ import org.junit.jupiter.api.Test;
* Unit tests for {@link EvaluationOperators}. * Unit tests for {@link EvaluationOperators}.
* *
* @author Mark Paluch * @author Mark Paluch
* @author Christoph Strobl
*/ */
class EvaluationOperatorsUnitTests { class EvaluationOperatorsUnitTests {
@@ -32,4 +33,11 @@ class EvaluationOperatorsUnitTests {
assertThat(EvaluationOperators.valueOf("foo").expr().toDocument(Aggregation.DEFAULT_CONTEXT)) assertThat(EvaluationOperators.valueOf("foo").expr().toDocument(Aggregation.DEFAULT_CONTEXT))
.isEqualTo("{ $expr: \"$foo\" }"); .isEqualTo("{ $expr: \"$foo\" }");
} }
@Test // GH-4139
void shouldRenderLocfCorrectly() {
assertThat(EvaluationOperators.valueOf("foo").locf().toDocument(Aggregation.DEFAULT_CONTEXT))
.isEqualTo("{ $locf: \"$foo\" }");
}
} }

View File

@@ -1250,6 +1250,11 @@ public class SpelExpressionTransformerUnitTests {
void shouldTsSecond() { void shouldTsSecond() {
assertThat(transform("tsSecond(saleTimestamp)")).isEqualTo("{ $tsSecond: \"$saleTimestamp\" }"); assertThat(transform("tsSecond(saleTimestamp)")).isEqualTo("{ $tsSecond: \"$saleTimestamp\" }");
} }
@Test // GH-4139
void shouldRenderLocf() {
assertThat(transform("locf(price)")).isEqualTo("{ $locf: \"$price\" }");
}
private Document transform(String expression, Object... params) { private Document transform(String expression, Object... params) {
return (Document) transformer.transform(expression, Aggregation.DEFAULT_CONTEXT, params); return (Document) transformer.transform(expression, Aggregation.DEFAULT_CONTEXT, params);