DATAMONGO-2370 - Add support for $round aggregation operator.
Original pull request: #803.
This commit is contained in:
committed by
Mark Paluch
parent
588ed2b0e2
commit
7abf69e575
@@ -511,6 +511,27 @@ public class ArithmeticOperators {
|
||||
: AccumulatorOperators.StdDevSamp.stdDevSampOf(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that rounds a number to a whole integer or to a specified decimal
|
||||
* place.
|
||||
*
|
||||
* @return new instance of {@link Round}.
|
||||
* @since 3.0
|
||||
*/
|
||||
public Round round() {
|
||||
return usesFieldRef() ? Round.roundValueOf(fieldReference) : Round.roundValueOf(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new {@link AggregationExpression} that rounds a number to a specified decimal place.
|
||||
*
|
||||
* @return new instance of {@link Round}.
|
||||
* @since 3.0
|
||||
*/
|
||||
public Round roundToPlace(int place) {
|
||||
return round().place(place);
|
||||
}
|
||||
|
||||
private boolean usesFieldRef() {
|
||||
return fieldReference != null;
|
||||
}
|
||||
@@ -1422,4 +1443,100 @@ public class ArithmeticOperators {
|
||||
return new Trunc(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Round} rounds a number to a whole integer or to a specified decimal place. <br />
|
||||
* <ul>
|
||||
* <li>If {@link Round#place(int)} resolves to a positive integer, {@code $round} rounds to the given decimal
|
||||
* places.</li>
|
||||
* <li>If {@link Round#place(int)} resolves to a negative integer, {@code $round} rounds to the left of the
|
||||
* decimal.</li>
|
||||
* <li>If {@link Round#place(int)} resolves to a zero, {@code $round} rounds using the first digit to the right of the
|
||||
* decimal.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
public static class Round extends AbstractAggregationExpression {
|
||||
|
||||
private Round(Object value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Round the value of the field that resolves to an integer, double, decimal, or long.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return new instance of {@link Round}.
|
||||
*/
|
||||
public static Round roundValueOf(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "FieldReference must not be null!");
|
||||
return new Round(Collections.singletonList(Fields.field(fieldReference)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Round the outcome of the given expression hat resolves to an integer, double, decimal, or long.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return new instance of {@link Round}.
|
||||
*/
|
||||
public static Round roundValueOf(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Round(Collections.singletonList(expression));
|
||||
}
|
||||
|
||||
/**
|
||||
* Round the given numeric (integer, double, decimal, or long) value.
|
||||
*
|
||||
* @param value must not be {@literal null}.
|
||||
* @return new instance of {@link Round}.
|
||||
*/
|
||||
public static Round round(Number value) {
|
||||
|
||||
Assert.notNull(value, "Value must not be null!");
|
||||
return new Round(Collections.singletonList(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* The place to round to. Can be between -20 and 100, exclusive.
|
||||
*
|
||||
* @param place
|
||||
* @return new instance of {@link Round}.
|
||||
*/
|
||||
public Round place(int place) {
|
||||
return new Round(append(place));
|
||||
}
|
||||
|
||||
/**
|
||||
* The place to round to defined by an expression that resolves to an integer between -20 and 100, exclusive.
|
||||
*
|
||||
* @param expression must not be {@literal null}.
|
||||
* @return new instance of {@link Round}.
|
||||
*/
|
||||
public Round placeOf(AggregationExpression expression) {
|
||||
|
||||
Assert.notNull(expression, "Expression must not be null!");
|
||||
return new Round(append(expression));
|
||||
}
|
||||
|
||||
/**
|
||||
* The place to round to defined by via a field reference that resolves to an integer between -20 and 100,
|
||||
* exclusive.
|
||||
*
|
||||
* @param fieldReference must not be {@literal null}.
|
||||
* @return new instance of {@link Round}.
|
||||
*/
|
||||
public Round placeOf(String fieldReference) {
|
||||
|
||||
Assert.notNull(fieldReference, "fieldReference must not be null!");
|
||||
return new Round(append(Fields.field(fieldReference)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMongoMethod() {
|
||||
return "$round";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +84,7 @@ public class MethodReferenceNode extends ExpressionNode {
|
||||
map.put("sqrt", singleArgRef().forOperator("$sqrt"));
|
||||
map.put("subtract", arrayArgRef().forOperator("$subtract"));
|
||||
map.put("trunc", singleArgRef().forOperator("$trunc"));
|
||||
map.put("round", arrayArgRef().forOperator("$round"));
|
||||
|
||||
// STRING OPERATORS
|
||||
map.put("concat", arrayArgRef().forOperator("$concat"));
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2019 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.ArithmeticOperators.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
|
||||
public class ArithmeticOperatorsUnitTests {
|
||||
|
||||
@Test // DATAMONGO-2370
|
||||
void roundShouldWithoutPlace() {
|
||||
|
||||
assertThat(valueOf("field").round().toDocument(Aggregation.DEFAULT_CONTEXT))
|
||||
.isEqualTo(new Document("$round", Collections.singletonList("$field")));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2370
|
||||
void roundShouldWithPlace() {
|
||||
|
||||
assertThat(valueOf("field").roundToPlace(3).toDocument(Aggregation.DEFAULT_CONTEXT))
|
||||
.isEqualTo(new Document("$round", Arrays.asList("$field", Integer.valueOf(3))));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2370
|
||||
void roundShouldWithPlaceFromField() {
|
||||
|
||||
assertThat(valueOf("field").round().placeOf("my-field").toDocument(Aggregation.DEFAULT_CONTEXT))
|
||||
.isEqualTo(new Document("$round", Arrays.asList("$field", "$my-field")));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2370
|
||||
void roundShouldWithPlaceFromExpression() {
|
||||
|
||||
assertThat(valueOf("field").round().placeOf((ctx -> new Document("$first", "$source")))
|
||||
.toDocument(Aggregation.DEFAULT_CONTEXT))
|
||||
.isEqualTo(new Document("$round", Arrays.asList("$field", new Document("$first", "$source"))));
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,6 @@ import org.bson.Document;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.data.mongodb.core.Person;
|
||||
|
||||
/**
|
||||
@@ -935,6 +934,16 @@ public class SpelExpressionTransformerUnitTests {
|
||||
assertThat(transform("range(0, 10, 2)")).isEqualTo(Document.parse("{ \"$range\" : [0, 10, 2 ]}"));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2370
|
||||
public void shouldRenderRound() {
|
||||
assertThat(transform("round(field)")).isEqualTo(Document.parse("{ \"$round\" : [\"$field\"]}"));
|
||||
}
|
||||
|
||||
@Test // DATAMONGO-2370
|
||||
public void shouldRenderRoundWithPlace() {
|
||||
assertThat(transform("round(field, 2)")).isEqualTo(Document.parse("{ \"$round\" : [\"$field\", 2]}"));
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -2516,7 +2516,7 @@ At the time of this writing, we provide support for the following Aggregation Op
|
||||
| `addToSet`, `first`, `last`, `max`, `min`, `avg`, `push`, `sum`, `(*count)`, `stdDevPop`, `stdDevSamp`
|
||||
|
||||
| Arithmetic Aggregation Operators
|
||||
| `abs`, `add` (*via `plus`), `ceil`, `divide`, `exp`, `floor`, `ln`, `log`, `log10`, `mod`, `multiply`, `pow`, `sqrt`, `subtract` (*via `minus`), `trunc`
|
||||
| `abs`, `add` (*via `plus`), `ceil`, `divide`, `exp`, `floor`, `ln`, `log`, `log10`, `mod`, `multiply`, `pow`, `sqrt`, `subtract` (*via `minus`), `trunc`, `round`
|
||||
|
||||
| String Aggregation Operators
|
||||
| `concat`, `substr`, `toLower`, `toUpper`, `stcasecmp`, `indexOfBytes`, `indexOfCP`, `split`, `strLenBytes`, `strLenCP`, `substrCP`, `trim`, `ltrim`, `rtim`
|
||||
|
||||
Reference in New Issue
Block a user