Add support for $rank and $denseRank aggregation operators.
Closes: #3715 Original pull request: #3741.
This commit is contained in:
committed by
Mark Paluch
parent
a977b8a790
commit
30da62181f
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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 org.bson.Document;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @since 3.3
|
||||
*/
|
||||
public class DocumentOperators {
|
||||
|
||||
/**
|
||||
* Obtain the document position (including gaps) relative to others (rank).
|
||||
*
|
||||
* @return new instance of {@link Rank}.
|
||||
* @since 3.3
|
||||
*/
|
||||
public static Rank rank() {
|
||||
return new Rank();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the document position (without gaps) relative to others (rank).
|
||||
*
|
||||
* @return new instance of {@link DenseRank}.
|
||||
* @since 3.3
|
||||
*/
|
||||
public static DenseRank denseRank() {
|
||||
return new DenseRank();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 3.3
|
||||
*/
|
||||
public static class Rank implements AggregationExpression {
|
||||
|
||||
@Override
|
||||
public Document toDocument(AggregationOperationContext context) {
|
||||
return new Document("$rank", new Document());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 3.3
|
||||
*/
|
||||
public static class DenseRank implements AggregationExpression {
|
||||
|
||||
@Override
|
||||
public Document toDocument(AggregationOperationContext context) {
|
||||
return new Document("$denseRank", new Document());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -500,7 +500,10 @@ class SpelExpressionTransformer implements AggregationExpressionTransformer {
|
||||
dbo.put(methodReference.getArgumentMap()[i++], transform(child, context));
|
||||
}
|
||||
args = dbo;
|
||||
} else {
|
||||
} else if (ObjectUtils.nullSafeEquals(methodReference.getArgumentType(), ArgumentType.EMPTY_DOCUMENT)) {
|
||||
args = new Document();
|
||||
}
|
||||
else {
|
||||
|
||||
List<Object> argList = new ArrayList<Object>();
|
||||
|
||||
|
||||
@@ -68,6 +68,10 @@ public class MethodReferenceNode extends ExpressionNode {
|
||||
map.put("lte", arrayArgRef().forOperator("$lte"));
|
||||
map.put("ne", arrayArgRef().forOperator("$ne"));
|
||||
|
||||
// DOCUMENT OPERATORS
|
||||
map.put("rank", emptyRef().forOperator("$rank"));
|
||||
map.put("denseRank", emptyRef().forOperator("$denseRank"));
|
||||
|
||||
// ARITHMETIC OPERATORS
|
||||
map.put("abs", singleArgRef().forOperator("$abs"));
|
||||
map.put("add", arrayArgRef().forOperator("$add"));
|
||||
@@ -307,6 +311,16 @@ public class MethodReferenceNode extends ExpressionNode {
|
||||
return new AggregationMethodReference(null, ArgumentType.MAP, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link AggregationMethodReference} for a {@link ArgumentType#EMPTY_DOCUMENT} argument.
|
||||
*
|
||||
* @return never {@literal null}.
|
||||
* @since 3.3
|
||||
*/
|
||||
static AggregationMethodReference emptyRef() {
|
||||
return new AggregationMethodReference(null, ArgumentType.EMPTY_DOCUMENT, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link AggregationMethodReference} for a given {@literal aggregationExpressionOperator} reusing
|
||||
* previously set arguments.
|
||||
@@ -342,7 +356,7 @@ public class MethodReferenceNode extends ExpressionNode {
|
||||
* @since 1.10
|
||||
*/
|
||||
public enum ArgumentType {
|
||||
SINGLE, ARRAY, MAP
|
||||
SINGLE, ARRAY, MAP, EMPTY_DOCUMENT
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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 static org.springframework.data.mongodb.core.aggregation.DocumentOperators.*;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
class DocumentOperatorsUnitTests {
|
||||
|
||||
@Test // GH-3715
|
||||
void rendersRank() {
|
||||
assertThat(rank().toDocument(Aggregation.DEFAULT_CONTEXT)).isEqualTo(new Document("$rank", new Document()));
|
||||
}
|
||||
|
||||
@Test // GH-3715
|
||||
void rendersDenseRank() {
|
||||
assertThat(denseRank().toDocument(Aggregation.DEFAULT_CONTEXT))
|
||||
.isEqualTo(new Document("$denseRank", new Document()));
|
||||
}
|
||||
}
|
||||
@@ -956,6 +956,16 @@ public class SpelExpressionTransformerUnitTests {
|
||||
assertThat(transform("covarianceSamp(field1, field2)")).isEqualTo(Document.parse("{ \"$covarianceSamp\" : [\"$field1\", \"$field2\"]}"));
|
||||
}
|
||||
|
||||
@Test // GH-3715
|
||||
void shouldRenderRank() {
|
||||
assertThat(transform("rank()")).isEqualTo(Document.parse("{ $rank : {} }"));
|
||||
}
|
||||
|
||||
@Test // GH-3715
|
||||
void shouldRenderDenseRank() {
|
||||
assertThat(transform("denseRank()")).isEqualTo(Document.parse("{ $denseRank : {} }"));
|
||||
}
|
||||
|
||||
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