diff --git a/pom.xml b/pom.xml
index 4556c2de22..333a75e424 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.springframework.dataspring-data-mongodb-parent
- 2.3.0.BUILD-SNAPSHOT
+ 3.0.0.DATAMONGO-2370-SNAPSHOTpomSpring Data MongoDB
diff --git a/spring-data-mongodb-benchmarks/pom.xml b/spring-data-mongodb-benchmarks/pom.xml
index c4766040c1..720a116e23 100644
--- a/spring-data-mongodb-benchmarks/pom.xml
+++ b/spring-data-mongodb-benchmarks/pom.xml
@@ -7,7 +7,7 @@
org.springframework.dataspring-data-mongodb-parent
- 2.3.0.BUILD-SNAPSHOT
+ 3.0.0.DATAMONGO-2370-SNAPSHOT../pom.xml
diff --git a/spring-data-mongodb-distribution/pom.xml b/spring-data-mongodb-distribution/pom.xml
index ed39c63e76..2922c1e76d 100644
--- a/spring-data-mongodb-distribution/pom.xml
+++ b/spring-data-mongodb-distribution/pom.xml
@@ -14,7 +14,7 @@
org.springframework.dataspring-data-mongodb-parent
- 2.3.0.BUILD-SNAPSHOT
+ 3.0.0.DATAMONGO-2370-SNAPSHOT../pom.xml
diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml
index 25cf02b5d5..c560eff01a 100644
--- a/spring-data-mongodb/pom.xml
+++ b/spring-data-mongodb/pom.xml
@@ -11,7 +11,7 @@
org.springframework.dataspring-data-mongodb-parent
- 2.3.0.BUILD-SNAPSHOT
+ 3.0.0.DATAMONGO-2370-SNAPSHOT../pom.xml
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ArithmeticOperators.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ArithmeticOperators.java
index 10785623e3..40f28d94ce 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ArithmeticOperators.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ArithmeticOperators.java
@@ -511,6 +511,27 @@ public StdDevSamp stdDevSamp() {
: 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 static Trunc truncValueOf(Number value) {
return new Trunc(value);
}
}
+
+ /**
+ * {@link Round} rounds a number to a whole integer or to a specified decimal place.
+ *
+ *
If {@link Round#place(int)} resolves to a positive integer, {@code $round} rounds to the given decimal
+ * places.
+ *
If {@link Round#place(int)} resolves to a negative integer, {@code $round} rounds to the left of the
+ * decimal.
+ *
If {@link Round#place(int)} resolves to a zero, {@code $round} rounds using the first digit to the right of the
+ * decimal.
+ *
+ *
+ * @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";
+ }
+ }
}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/spel/MethodReferenceNode.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/spel/MethodReferenceNode.java
index fd00c39a4f..dcc351fa0f 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/spel/MethodReferenceNode.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/spel/MethodReferenceNode.java
@@ -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"));
diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ArithmeticOperatorsUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ArithmeticOperatorsUnitTests.java
new file mode 100644
index 0000000000..4fd7a226a4
--- /dev/null
+++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ArithmeticOperatorsUnitTests.java
@@ -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"))));
+ }
+}
diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/SpelExpressionTransformerUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/SpelExpressionTransformerUnitTests.java
index ac16820de3..f0f1922525 100644
--- a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/SpelExpressionTransformerUnitTests.java
+++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/SpelExpressionTransformerUnitTests.java
@@ -20,10 +20,9 @@
import java.util.Arrays;
import org.bson.Document;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
import org.springframework.data.mongodb.core.Person;
/**
@@ -39,8 +38,8 @@ public class SpelExpressionTransformerUnitTests {
Data data;
- @Before
- public void setup() {
+ @BeforeEach
+ public void beforeEach() {
this.data = new Data();
this.data.primitiveLongValue = 42;
@@ -109,7 +108,7 @@ public void shouldRenderNestedFieldReference() {
}
@Test // DATAMONGO-774
- @Ignore
+ @Disabled
public void shouldRenderNestedIndexedFieldReference() {
// TODO add support for rendering nested indexed field references
@@ -162,23 +161,25 @@ public void shouldRenderParameterExpressionResults() {
}
@Test // DATAMONGO-774
- @Ignore("TODO: mongo3 renders this a bit strange")
public void shouldRenderNestedParameterExpressionResults() {
assertThat(
((Document) transform("[0].primitiveLongValue + [0].primitiveDoubleValue + [0].doubleValue.longValue()", data))
- .toJson()).isEqualTo(Document.parse("{ \"$add\" : [ 42 , 1.2345 , 23]}").toJson());
+ .toJson())
+ .isEqualTo(Document
+ .parse("{ \"$add\" : [ { $numberLong : \"42\"} , 1.2345 , { $numberLong : \"23\" } ]}").toJson());
}
@Test // DATAMONGO-774
- @Ignore("TODO: mongo3 renders this a bit strange")
public void shouldRenderNestedParameterExpressionResultsInNestedExpressions() {
assertThat(
((Document) transform("((1 + [0].primitiveLongValue) + [0].primitiveDoubleValue) * [0].doubleValue.longValue()",
- data)).toJson()).isEqualTo(
- new Document("$multiply", Arrays.asList(new Document("$add", Arrays.asList(1, 42L, 1.2345D, 23L))))
- .toJson());
+ data)).toJson())
+ .isEqualTo(new Document("$multiply",
+ Arrays.