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 159c6bbea..db328338e 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 @@ -31,6 +31,7 @@ import org.springframework.data.mongodb.core.aggregation.SetWindowFieldsOperatio import org.springframework.data.mongodb.core.aggregation.SetWindowFieldsOperation.WindowUnits; import org.springframework.lang.Nullable; import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; /** @@ -676,6 +677,48 @@ public class ArithmeticOperators { return round().place(place); } + /** + * Creates new {@link AggregationExpression} that calculates the sine of a numeric value given in {@link AngularDimension#RADIANS radians}. + * + * @return new instance of {@link Sin}. + * @since 3.3 + */ + public Sin sin() { + return sin(AngularDimension.RADIANS); + } + + /** + * Creates new {@link AggregationExpression} that calculates the sine of a numeric value in the given {@link AngularDimension unit}. + * + * @param unit the unit of measure. + * @return new instance of {@link Sin}. + * @since 3.3 + */ + public Sin sin(AngularDimension unit) { + return usesFieldRef() ? Sin.sinOf(fieldReference, unit) : Sin.sinOf(expression, unit); + } + + /** + * Creates new {@link AggregationExpression} that calculates the sine of a numeric value given in {@link AngularDimension#RADIANS radians}. + * + * @return new instance of {@link Sin}. + * @since 3.3 + */ + public Sinh sinh() { + return sinh(AngularDimension.RADIANS); + } + + /** + * Creates new {@link AggregationExpression} that calculates the sine of a numeric value. + * + * @param unit the unit of measure. + * @return new instance of {@link Sin}. + * @since 3.3 + */ + public Sinh sinh(AngularDimension unit) { + return usesFieldRef() ? Sinh.sinhOf(fieldReference, unit) : Sinh.sinhOf(expression, unit); + } + private boolean usesFieldRef() { return fieldReference != null; } @@ -1907,4 +1950,207 @@ public class ArithmeticOperators { return "$integral"; } } + + /** + * The unit of measure for computations that operate upon angles. + * + * @author Christoph Strobl + * @since 3.3 + */ + public enum AngularDimension { + RADIANS, DEGREES + } + + /** + * An {@link AggregationExpression expression} that calculates the sine of a value that is measured in radians. + * + * @author Christoph Strobl + * @since 3.3 + */ + public static class Sin extends AbstractAggregationExpression { + + private Sin(Object value) { + super(value); + } + + /** + * Creates a new {@link AggregationExpression} that calculates the sine of a value that is measured in + * {@link AngularDimension#RADIANS radians}. + *
+ * Use {@code sinhOf("angle", DEGREES)} as shortcut for{ $sinh : { $degreesToRadians : "$angle" } }.
+ *
+ * @param fieldReference the name of the {@link Field field} that resolves to a numeric value.
+ * @return new instance of {@link Sin}.
+ */
+ public static Sin sinOf(String fieldReference) {
+ return sinOf(fieldReference, AngularDimension.RADIANS);
+ }
+
+ /**
+ * Creates a new {@link AggregationExpression} that calculates the sine of a value that is measured in the given
+ * {@link AngularDimension unit}.
+ *
+ * @param fieldReference the name of the {@link Field field} that resolves to a numeric value.
+ * @param unit the unit of measure used by the value of the given field.
+ * @return new instance of {@link Sin}.
+ */
+ public static Sin sinOf(String fieldReference, AngularDimension unit) {
+ return sin(Fields.field(fieldReference), unit);
+ }
+
+ /**
+ * Creates a new {@link AggregationExpression} that calculates the sine of a value that is measured in
+ * {@link AngularDimension#RADIANS}.
+ *
+ * @param expression the {@link AggregationExpression expression} that resolves to a numeric value.
+ * @return new instance of {@link Sin}.
+ */
+ public static Sin sinOf(AggregationExpression expression) {
+ return sinOf(expression, AngularDimension.RADIANS);
+ }
+
+ /**
+ * Creates a new {@link AggregationExpression} that calculates the sine of a value that is measured in the given
+ * {@link AngularDimension unit}.
+ *
+ * @param expression the {@link AggregationExpression expression} that resolves to a numeric value.
+ * @param unit the unit of measure used by the value of the given field.
+ * @return new instance of {@link Sin}.
+ */
+ public static Sin sinOf(AggregationExpression expression, AngularDimension unit) {
+ return sin(expression, unit);
+ }
+
+ /**
+ * Creates a new {@link AggregationExpression} that calculates the sine of a value that is measured in
+ * {@link AngularDimension#RADIANS}.
+ *
+ * @param value anything ({@link Field field}, {@link AggregationExpression expression}, ...) that resolves to a
+ * numeric value
+ * @return new instance of {@link Sin}.
+ */
+ public static Sin sin(Object value) {
+ return sin(value, AngularDimension.RADIANS);
+ }
+
+ /**
+ * Creates a new {@link AggregationExpression} that calculates the sine of a value that is measured in the given
+ * {@link AngularDimension unit}.
+ *
+ * @param value anything ({@link Field field}, {@link AggregationExpression expression}, ...) that resolves to a
+ * numeric value.
+ * @param unit the unit of measure used by the value of the given field.
+ * @return new instance of {@link Sin}.
+ */
+ public static Sin sin(Object value, AngularDimension unit) {
+
+ if (ObjectUtils.nullSafeEquals(AngularDimension.DEGREES, unit)) {
+ return new Sin(ConvertOperators.DegreesToRadians.degreesToRadians(value));
+ }
+ return new Sin(value);
+ }
+
+ @Override
+ protected String getMongoMethod() {
+ return "$sin";
+ }
+ }
+
+ /**
+ * An {@link AggregationExpression expression} that calculates the hyperbolic sine of a value that is measured in
+ * {@link AngularDimension#RADIANS}.
+ *
+ * @author Christoph Strobl
+ * @since 3.3
+ */
+ public static class Sinh extends AbstractAggregationExpression {
+
+ private Sinh(Object value) {
+ super(value);
+ }
+
+ /**
+ * Creates a new {@link AggregationExpression} that calculates the hyperbolic sine of a value that is measured in
+ * {@link AngularDimension#RADIANS}.
+ *
+ * @param fieldReference the name of the {@link Field field} that resolves to a numeric value.
+ * @return new instance of {@link Sin}.
+ */
+ public static Sinh sinhOf(String fieldReference) {
+ return sinhOf(fieldReference, AngularDimension.RADIANS);
+ }
+
+ /**
+ * Creates a new {@link AggregationExpression} that calculates the hyperbolic sine of a value that is measured in
+ * the given {@link AngularDimension unit}.
+ *
+ * Use {@code sinhOf("angle", DEGREES)} as shortcut for { $sinh : { $degreesToRadians : "$angle" } }.
+ *
+ * @param fieldReference the name of the {@link Field field} that resolves to a numeric value.
+ * @param unit the unit of measure used by the value of the given field.
+ * @return new instance of {@link Sin}.
+ */
+ public static Sinh sinhOf(String fieldReference, AngularDimension unit) {
+ return sinh(Fields.field(fieldReference), unit);
+ }
+
+ /**
+ * Creates a new {@link AggregationExpression} that calculates the hyperbolic sine of a value that is measured in
+ * {@link AngularDimension#RADIANS}.
+ *
+ * Use {@code sinhOf("angle", DEGREES)} as shortcut for eg. {@code sinhOf(ConvertOperators.valueOf("angle").degreesToRadians())}.
+ *
+ * @param expression the {@link AggregationExpression expression} that resolves to a numeric value.
+ * @return new instance of {@link Sin}.
+ */
+ public static Sinh sinhOf(AggregationExpression expression) {
+ return sinhOf(expression, AngularDimension.RADIANS);
+ }
+
+ /**
+ * Creates a new {@link AggregationExpression} that calculates the hyperbolic sine of a value that is measured in
+ * the given {@link AngularDimension unit}.
+ *
+ * @param expression the {@link AggregationExpression expression} that resolves to a numeric value.
+ * @param unit the unit of measure used by the value of the given field.
+ * @return new instance of {@link Sin}.
+ */
+ public static Sinh sinhOf(AggregationExpression expression, AngularDimension unit) {
+ return sinh(expression, unit);
+ }
+
+ /**
+ * Creates a new {@link AggregationExpression} that calculates the hyperbolic sine of a value that is measured in
+ * {@link AngularDimension#RADIANS}.
+ *
+ * @param value anything ({@link Field field}, {@link AggregationExpression expression}, ...) that resolves to a
+ * numeric value.
+ * @return new instance of {@link Sin}.
+ */
+ public static Sinh sinh(Object value) {
+ return sinh(value, AngularDimension.RADIANS);
+ }
+
+ /**
+ * Creates a new {@link AggregationExpression} that calculates the hyperbolic sine of a value that is measured in
+ * the given {@link AngularDimension unit}.
+ *
+ * @param value anything ({@link Field field}, {@link AggregationExpression expression}, ...) that resolves to a
+ * numeric value
+ * @param unit the unit of measure used by the value of the given field.
+ * @return new instance of {@link Sin}.
+ */
+ public static Sinh sinh(Object value, AngularDimension unit) {
+
+ if (ObjectUtils.nullSafeEquals(AngularDimension.DEGREES, unit)) {
+ return new Sinh(ConvertOperators.DegreesToRadians.degreesToRadians(value));
+ }
+ return new Sinh(value);
+ }
+
+ @Override
+ protected String getMongoMethod() {
+ return "$sinh";
+ }
+ }
}
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 f0799a1af..9ee12be1e 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
@@ -93,6 +93,8 @@ public class MethodReferenceNode extends ExpressionNode {
map.put("round", arrayArgRef().forOperator("$round"));
map.put("derivative", mapArgRef().forOperator("$derivative").mappingParametersTo("input", "unit"));
map.put("integral", mapArgRef().forOperator("$integral").mappingParametersTo("input", "unit"));
+ map.put("sin", singleArgRef().forOperator("$sin"));
+ map.put("sinh", singleArgRef().forOperator("$sinh"));
// 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
index d57363d91..cc32a9432 100644
--- 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
@@ -81,4 +81,32 @@ class ArithmeticOperatorsUnitTests {
.toDocument(Aggregation.DEFAULT_CONTEXT))
.isEqualTo("{ $integral : { input : \"$kilowatts\", unit : \"hour\" } }");
}
+
+ @Test // GH-3728
+ void rendersSin() {
+
+ assertThat(valueOf("angle").sin().toDocument(Aggregation.DEFAULT_CONTEXT))
+ .isEqualTo(Document.parse("{ $sin : \"$angle\" }"));
+ }
+
+ @Test // GH-3728
+ void rendersSinWithValueInDegrees() {
+
+ assertThat(valueOf("angle").sin(AngularDimension.DEGREES).toDocument(Aggregation.DEFAULT_CONTEXT))
+ .isEqualTo(Document.parse("{ $sin : { $degreesToRadians : \"$angle\" } }"));
+ }
+
+ @Test // GH-3728
+ void rendersSinh() {
+
+ assertThat(valueOf("angle").sinh().toDocument(Aggregation.DEFAULT_CONTEXT))
+ .isEqualTo(Document.parse("{ $sinh : \"$angle\" }"));
+ }
+
+ @Test // GH-3728
+ void rendersSinhWithValueInDegrees() {
+
+ assertThat(valueOf("angle").sinh(AngularDimension.DEGREES).toDocument(Aggregation.DEFAULT_CONTEXT))
+ .isEqualTo(Document.parse("{ $sinh : { $degreesToRadians : \"$angle\" } }"));
+ }
}
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 9cad6cbb1..e25024155 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
@@ -1004,6 +1004,16 @@ public class SpelExpressionTransformerUnitTests {
.isEqualTo(Document.parse("{ \"$integral\" : { \"input\" : \"$field\", \"unit\" : \"hour\" }}"));
}
+ @Test // GH-3728
+ void shouldRenderSin() {
+ assertThat(transform("sin(angle)")).isEqualTo(Document.parse("{ \"$sin\" : \"$angle\"}"));
+ }
+
+ @Test // GH-3728
+ void shouldRenderSinh() {
+ assertThat(transform("sinh(angle)")).isEqualTo(Document.parse("{ \"$sinh\" : \"$angle\"}"));
+ }
+
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);