Add support for $shift aggregation Operator.
Closes: #3727 Original pull request: #3741.
This commit is contained in:
committed by
Mark Paluch
parent
1a86761e2e
commit
510028a834
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.aggregation;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.bson.Document;
|
||||
|
||||
/**
|
||||
@@ -45,6 +47,26 @@ public class DocumentOperators {
|
||||
return new DenseRank();
|
||||
}
|
||||
|
||||
/**
|
||||
* Take the field referenced by given {@literal fieldReference}.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return new instance of {@link DocumentOperatorsFactory}.
|
||||
*/
|
||||
public static DocumentOperatorsFactory valueOf(String fieldReference) {
|
||||
return new DocumentOperatorsFactory(fieldReference);
|
||||
}
|
||||
|
||||
/**
|
||||
* Take the value resulting from the given {@link AggregationExpression}.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return new instance of {@link DocumentOperatorsFactory}.
|
||||
*/
|
||||
public static DocumentOperatorsFactory valueOf(AggregationExpression expression) {
|
||||
return new DocumentOperatorsFactory(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the current document position.
|
||||
*
|
||||
@@ -55,6 +77,35 @@ public class DocumentOperators {
|
||||
return new DocumentNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public static class DocumentOperatorsFactory {
|
||||
|
||||
private Object target;
|
||||
|
||||
public DocumentOperatorsFactory(Object target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that applies the expression to a document at specified position
|
||||
* relative to the current document.
|
||||
*
|
||||
* @param by the value to add to the current position.
|
||||
* @return new instance of {@link Shift}.
|
||||
*/
|
||||
public Shift shift(int by) {
|
||||
|
||||
Shift shift = usesExpression() ? Shift.shift((AggregationExpression) target) : Shift.shift(target.toString());
|
||||
return shift.by(by);
|
||||
}
|
||||
|
||||
private boolean usesExpression() {
|
||||
return target instanceof AggregationExpression;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Rank} resolves the current document position (the rank) relative to other documents. If multiple documents
|
||||
* occupy the same rank, {@literal $rank} places the document with the subsequent value at a rank with a gap.
|
||||
@@ -72,8 +123,8 @@ public class DocumentOperators {
|
||||
|
||||
/**
|
||||
* {@link DenseRank} resolves the current document position (the rank) relative to other documents. If multiple
|
||||
* documents occupy the same rank, {@literal $denseRank} places the document with the subsequent value at the next rank without
|
||||
* any gaps.
|
||||
* documents occupy the same rank, {@literal $denseRank} places the document with the subsequent value at the next
|
||||
* rank without any gaps.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 3.3
|
||||
@@ -99,4 +150,73 @@ public class DocumentOperators {
|
||||
return new Document("$documentNumber", new Document());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shift applies an expression to a document in a specified position relative to the current document.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 3.3
|
||||
*/
|
||||
public static class Shift extends AbstractAggregationExpression {
|
||||
|
||||
private Shift(Object value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the field to evaluate and return.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return new instance of {@link Shift}.
|
||||
*/
|
||||
public static Shift shift(String fieldReference) {
|
||||
return new Shift(Collections.singletonMap("output", Fields.field(fieldReference)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies the {@link AggregationExpression expression} to evaluate and return.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return new instance of {@link Shift}.
|
||||
*/
|
||||
public static Shift shift(AggregationExpression expression) {
|
||||
return new Shift(Collections.singletonMap("output", expression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Shift the document position relative to the current. Use a positive value for follow up documents (eg. 1 for the
|
||||
* next) or a negative value for the predecessor documents (eg. -1 for the previous).
|
||||
*
|
||||
* @param shiftBy value to add to the current position.
|
||||
* @return new instance of {@link Shift}.
|
||||
*/
|
||||
public Shift by(int shiftBy) {
|
||||
return new Shift(append("by", shiftBy));
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the default value if the target document is out of range.
|
||||
*
|
||||
* @param value must not be {@literal null}.
|
||||
* @return new instance of {@link Shift}.
|
||||
*/
|
||||
public Shift defaultTo(Object value) {
|
||||
return new Shift(append("default", value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the {@link AggregationExpression expression} to evaluate if the target document is out of range.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return new instance of {@link Shift}.
|
||||
*/
|
||||
public Shift defaultToValueOf(AggregationExpression expression) {
|
||||
return defaultTo(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$shift";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,6 +72,7 @@ public class MethodReferenceNode extends ExpressionNode {
|
||||
map.put("rank", emptyRef().forOperator("$rank"));
|
||||
map.put("denseRank", emptyRef().forOperator("$denseRank"));
|
||||
map.put("documentNumber", emptyRef().forOperator("$documentNumber"));
|
||||
map.put("shift", mapArgRef().forOperator("$shift").mappingParametersTo("output", "by", "default"));
|
||||
|
||||
// ARITHMETIC OPERATORS
|
||||
map.put("abs", singleArgRef().forOperator("$abs"));
|
||||
|
||||
@@ -39,6 +39,21 @@ class DocumentOperatorsUnitTests {
|
||||
|
||||
@Test // GH-3717
|
||||
void rendersDocumentNumber() {
|
||||
assertThat(documentNumber().toDocument(Aggregation.DEFAULT_CONTEXT)).isEqualTo(new Document("$documentNumber", new Document()));
|
||||
assertThat(documentNumber().toDocument(Aggregation.DEFAULT_CONTEXT))
|
||||
.isEqualTo(new Document("$documentNumber", new Document()));
|
||||
}
|
||||
|
||||
@Test // GH-3727
|
||||
void rendersShift() {
|
||||
|
||||
assertThat(valueOf("quantity").shift(1).toDocument(Aggregation.DEFAULT_CONTEXT))
|
||||
.isEqualTo(Document.parse("{ $shift: { output: \"$quantity\", by: 1 } }"));
|
||||
}
|
||||
|
||||
@Test // GH-3727
|
||||
void rendersShiftWithDefault() {
|
||||
|
||||
assertThat(valueOf("quantity").shift(1).defaultTo("Not available").toDocument(Aggregation.DEFAULT_CONTEXT))
|
||||
.isEqualTo(Document.parse("{ $shift: { output: \"$quantity\", by: 1, default: \"Not available\" } }"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -971,6 +971,20 @@ public class SpelExpressionTransformerUnitTests {
|
||||
assertThat(transform("documentNumber()")).isEqualTo(Document.parse("{ $documentNumber : {} }"));
|
||||
}
|
||||
|
||||
@Test // GH-3727
|
||||
void rendersShift() {
|
||||
|
||||
assertThat(transform("shift(quantity, 1)"))
|
||||
.isEqualTo(Document.parse("{ $shift: { output: \"$quantity\", by: 1 } }"));
|
||||
}
|
||||
|
||||
@Test // GH-3727
|
||||
void rendersShiftWithDefault() {
|
||||
|
||||
assertThat(transform("shift(quantity, 1, 'Not available')"))
|
||||
.isEqualTo(Document.parse("{ $shift: { output: \"$quantity\", by: 1, default: \"Not available\" } }"));
|
||||
}
|
||||
|
||||
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