Skip to content

Commit 3235485

Browse files
Add support for $sin & $sinh aggregation operators.
Cloes: #3728
1 parent a57964c commit 3235485

File tree

4 files changed

+286
-0
lines changed

4 files changed

+286
-0
lines changed

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/aggregation/ArithmeticOperators.java

+246
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.springframework.data.mongodb.core.aggregation.AccumulatorOperators.StdDevSamp;
2626
import org.springframework.data.mongodb.core.aggregation.AccumulatorOperators.Sum;
2727
import org.springframework.util.Assert;
28+
import org.springframework.util.ObjectUtils;
2829

2930
/**
3031
* Gateway to {@literal Arithmetic} aggregation operations that perform math operations on numbers.
@@ -532,6 +533,48 @@ public Round roundToPlace(int place) {
532533
return round().place(place);
533534
}
534535

536+
/**
537+
* Creates new {@link AggregationExpression} that calculates the sine of a numeric value given in {@link AngularDimension#RADIANS radians}.
538+
*
539+
* @return new instance of {@link Sin}.
540+
* @since 3.3
541+
*/
542+
public Sin sin() {
543+
return sin(AngularDimension.RADIANS);
544+
}
545+
546+
/**
547+
* Creates new {@link AggregationExpression} that calculates the sine of a numeric value in the given {@link AngularDimension unit}.
548+
*
549+
* @param unit the unit of measure.
550+
* @return new instance of {@link Sin}.
551+
* @since 3.3
552+
*/
553+
public Sin sin(AngularDimension unit) {
554+
return usesFieldRef() ? Sin.sinOf(fieldReference, unit) : Sin.sinOf(expression, unit);
555+
}
556+
557+
/**
558+
* Creates new {@link AggregationExpression} that calculates the sine of a numeric value given in {@link AngularDimension#RADIANS radians}.
559+
*
560+
* @return new instance of {@link Sin}.
561+
* @since 3.3
562+
*/
563+
public Sinh sinh() {
564+
return sinh(AngularDimension.RADIANS);
565+
}
566+
567+
/**
568+
* Creates new {@link AggregationExpression} that calculates the sine of a numeric value.
569+
*
570+
* @param unit the unit of measure.
571+
* @return new instance of {@link Sin}.
572+
* @since 3.3
573+
*/
574+
public Sinh sinh(AngularDimension unit) {
575+
return usesFieldRef() ? Sinh.sinhOf(fieldReference, unit) : Sinh.sinhOf(expression, unit);
576+
}
577+
535578
private boolean usesFieldRef() {
536579
return fieldReference != null;
537580
}
@@ -1665,4 +1708,207 @@ protected String getMongoMethod() {
16651708
return "$round";
16661709
}
16671710
}
1711+
1712+
/**
1713+
* The unit of measure for computations that operate upon angles.
1714+
*
1715+
* @author Christoph Strobl
1716+
* @since 3.3
1717+
*/
1718+
public enum AngularDimension {
1719+
RADIANS, DEGREES
1720+
}
1721+
1722+
/**
1723+
* An {@link AggregationExpression expression} that calculates the sine of a value that is measured in radians.
1724+
*
1725+
* @author Christoph Strobl
1726+
* @since 3.3
1727+
*/
1728+
public static class Sin extends AbstractAggregationExpression {
1729+
1730+
private Sin(Object value) {
1731+
super(value);
1732+
}
1733+
1734+
/**
1735+
* Creates a new {@link AggregationExpression} that calculates the sine of a value that is measured in
1736+
* {@link AngularDimension#RADIANS radians}.
1737+
* <p />
1738+
* Use {@code sinhOf("angle", DEGREES)} as shortcut for <pre>{ $sinh : { $degreesToRadians : "$angle" } }</pre>.
1739+
*
1740+
* @param fieldReference the name of the {@link Field field} that resolves to a numeric value.
1741+
* @return new instance of {@link Sin}.
1742+
*/
1743+
public static Sin sinOf(String fieldReference) {
1744+
return sinOf(fieldReference, AngularDimension.RADIANS);
1745+
}
1746+
1747+
/**
1748+
* Creates a new {@link AggregationExpression} that calculates the sine of a value that is measured in the given
1749+
* {@link AngularDimension unit}.
1750+
*
1751+
* @param fieldReference the name of the {@link Field field} that resolves to a numeric value.
1752+
* @param unit the unit of measure used by the value of the given field.
1753+
* @return new instance of {@link Sin}.
1754+
*/
1755+
public static Sin sinOf(String fieldReference, AngularDimension unit) {
1756+
return sin(Fields.field(fieldReference), unit);
1757+
}
1758+
1759+
/**
1760+
* Creates a new {@link AggregationExpression} that calculates the sine of a value that is measured in
1761+
* {@link AngularDimension#RADIANS}.
1762+
*
1763+
* @param expression the {@link AggregationExpression expression} that resolves to a numeric value.
1764+
* @return new instance of {@link Sin}.
1765+
*/
1766+
public static Sin sinOf(AggregationExpression expression) {
1767+
return sinOf(expression, AngularDimension.RADIANS);
1768+
}
1769+
1770+
/**
1771+
* Creates a new {@link AggregationExpression} that calculates the sine of a value that is measured in the given
1772+
* {@link AngularDimension unit}.
1773+
*
1774+
* @param expression the {@link AggregationExpression expression} that resolves to a numeric value.
1775+
* @param unit the unit of measure used by the value of the given field.
1776+
* @return new instance of {@link Sin}.
1777+
*/
1778+
public static Sin sinOf(AggregationExpression expression, AngularDimension unit) {
1779+
return sin(expression, unit);
1780+
}
1781+
1782+
/**
1783+
* Creates a new {@link AggregationExpression} that calculates the sine of a value that is measured in
1784+
* {@link AngularDimension#RADIANS}.
1785+
*
1786+
* @param value anything ({@link Field field}, {@link AggregationExpression expression}, ...) that resolves to a
1787+
* numeric value
1788+
* @return new instance of {@link Sin}.
1789+
*/
1790+
public static Sin sin(Object value) {
1791+
return sin(value, AngularDimension.RADIANS);
1792+
}
1793+
1794+
/**
1795+
* Creates a new {@link AggregationExpression} that calculates the sine of a value that is measured in the given
1796+
* {@link AngularDimension unit}.
1797+
*
1798+
* @param value anything ({@link Field field}, {@link AggregationExpression expression}, ...) that resolves to a
1799+
* numeric value.
1800+
* @param unit the unit of measure used by the value of the given field.
1801+
* @return new instance of {@link Sin}.
1802+
*/
1803+
public static Sin sin(Object value, AngularDimension unit) {
1804+
1805+
if (ObjectUtils.nullSafeEquals(AngularDimension.DEGREES, unit)) {
1806+
return new Sin(ConvertOperators.DegreesToRadians.degreesToRadians(value));
1807+
}
1808+
return new Sin(value);
1809+
}
1810+
1811+
@Override
1812+
protected String getMongoMethod() {
1813+
return "$sin";
1814+
}
1815+
}
1816+
1817+
/**
1818+
* An {@link AggregationExpression expression} that calculates the hyperbolic sine of a value that is measured in
1819+
* {@link AngularDimension#RADIANS}.
1820+
*
1821+
* @author Christoph Strobl
1822+
* @since 3.3
1823+
*/
1824+
public static class Sinh extends AbstractAggregationExpression {
1825+
1826+
private Sinh(Object value) {
1827+
super(value);
1828+
}
1829+
1830+
/**
1831+
* Creates a new {@link AggregationExpression} that calculates the hyperbolic sine of a value that is measured in
1832+
* {@link AngularDimension#RADIANS}.
1833+
*
1834+
* @param fieldReference the name of the {@link Field field} that resolves to a numeric value.
1835+
* @return new instance of {@link Sin}.
1836+
*/
1837+
public static Sinh sinhOf(String fieldReference) {
1838+
return sinhOf(fieldReference, AngularDimension.RADIANS);
1839+
}
1840+
1841+
/**
1842+
* Creates a new {@link AggregationExpression} that calculates the hyperbolic sine of a value that is measured in
1843+
* the given {@link AngularDimension unit}.
1844+
* <p />
1845+
* Use {@code sinhOf("angle", DEGREES)} as shortcut for <pre>{ $sinh : { $degreesToRadians : "$angle" } }</pre>.
1846+
*
1847+
* @param fieldReference the name of the {@link Field field} that resolves to a numeric value.
1848+
* @param unit the unit of measure used by the value of the given field.
1849+
* @return new instance of {@link Sin}.
1850+
*/
1851+
public static Sinh sinhOf(String fieldReference, AngularDimension unit) {
1852+
return sinh(Fields.field(fieldReference), unit);
1853+
}
1854+
1855+
/**
1856+
* Creates a new {@link AggregationExpression} that calculates the hyperbolic sine of a value that is measured in
1857+
* {@link AngularDimension#RADIANS}.
1858+
* <p />
1859+
* Use {@code sinhOf("angle", DEGREES)} as shortcut for eg. {@code sinhOf(ConvertOperators.valueOf("angle").degreesToRadians())}.
1860+
*
1861+
* @param expression the {@link AggregationExpression expression} that resolves to a numeric value.
1862+
* @return new instance of {@link Sin}.
1863+
*/
1864+
public static Sinh sinhOf(AggregationExpression expression) {
1865+
return sinhOf(expression, AngularDimension.RADIANS);
1866+
}
1867+
1868+
/**
1869+
* Creates a new {@link AggregationExpression} that calculates the hyperbolic sine of a value that is measured in
1870+
* the given {@link AngularDimension unit}.
1871+
*
1872+
* @param expression the {@link AggregationExpression expression} that resolves to a numeric value.
1873+
* @param unit the unit of measure used by the value of the given field.
1874+
* @return new instance of {@link Sin}.
1875+
*/
1876+
public static Sinh sinhOf(AggregationExpression expression, AngularDimension unit) {
1877+
return sinh(expression, unit);
1878+
}
1879+
1880+
/**
1881+
* Creates a new {@link AggregationExpression} that calculates the hyperbolic sine of a value that is measured in
1882+
* {@link AngularDimension#RADIANS}.
1883+
*
1884+
* @param value anything ({@link Field field}, {@link AggregationExpression expression}, ...) that resolves to a
1885+
* numeric value.
1886+
* @return new instance of {@link Sin}.
1887+
*/
1888+
public static Sinh sinh(Object value) {
1889+
return sinh(value, AngularDimension.RADIANS);
1890+
}
1891+
1892+
/**
1893+
* Creates a new {@link AggregationExpression} that calculates the hyperbolic sine of a value that is measured in
1894+
* the given {@link AngularDimension unit}.
1895+
*
1896+
* @param value anything ({@link Field field}, {@link AggregationExpression expression}, ...) that resolves to a
1897+
* numeric value
1898+
* @param unit the unit of measure used by the value of the given field.
1899+
* @return new instance of {@link Sin}.
1900+
*/
1901+
public static Sinh sinh(Object value, AngularDimension unit) {
1902+
1903+
if (ObjectUtils.nullSafeEquals(AngularDimension.DEGREES, unit)) {
1904+
return new Sinh(ConvertOperators.DegreesToRadians.degreesToRadians(value));
1905+
}
1906+
return new Sinh(value);
1907+
}
1908+
1909+
@Override
1910+
protected String getMongoMethod() {
1911+
return "$sinh";
1912+
}
1913+
}
16681914
}

spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/spel/MethodReferenceNode.java

+2
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ public class MethodReferenceNode extends ExpressionNode {
8585
map.put("subtract", arrayArgRef().forOperator("$subtract"));
8686
map.put("trunc", singleArgRef().forOperator("$trunc"));
8787
map.put("round", arrayArgRef().forOperator("$round"));
88+
map.put("sin", singleArgRef().forOperator("$sin"));
89+
map.put("sinh", singleArgRef().forOperator("$sinh"));
8890

8991
// STRING OPERATORS
9092
map.put("concat", arrayArgRef().forOperator("$concat"));

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/ArithmeticOperatorsUnitTests.java

+28
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,32 @@ void roundShouldWithPlaceFromExpression() {
5959
.toDocument(Aggregation.DEFAULT_CONTEXT))
6060
.isEqualTo(new Document("$round", Arrays.asList("$field", new Document("$first", "$source"))));
6161
}
62+
63+
@Test // GH-3728
64+
void rendersSin() {
65+
66+
assertThat(valueOf("angle").sin().toDocument(Aggregation.DEFAULT_CONTEXT))
67+
.isEqualTo(Document.parse("{ $sin : \"$angle\" }"));
68+
}
69+
70+
@Test // GH-3728
71+
void rendersSinWithValueInDegrees() {
72+
73+
assertThat(valueOf("angle").sin(AngularDimension.DEGREES).toDocument(Aggregation.DEFAULT_CONTEXT))
74+
.isEqualTo(Document.parse("{ $sin : { $degreesToRadians : \"$angle\" } }"));
75+
}
76+
77+
@Test // GH-3728
78+
void rendersSinh() {
79+
80+
assertThat(valueOf("angle").sinh().toDocument(Aggregation.DEFAULT_CONTEXT))
81+
.isEqualTo(Document.parse("{ $sinh : \"$angle\" }"));
82+
}
83+
84+
@Test // GH-3728
85+
void rendersSinhWithValueInDegrees() {
86+
87+
assertThat(valueOf("angle").sinh(AngularDimension.DEGREES).toDocument(Aggregation.DEFAULT_CONTEXT))
88+
.isEqualTo(Document.parse("{ $sinh : { $degreesToRadians : \"$angle\" } }"));
89+
}
6290
}

spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/aggregation/SpelExpressionTransformerUnitTests.java

+10
Original file line numberDiff line numberDiff line change
@@ -951,6 +951,16 @@ void shouldRenderDegreesToRadians() {
951951
assertThat(transform("degreesToRadians(angle_a)")).isEqualTo(Document.parse("{ \"$degreesToRadians\" : \"$angle_a\"}"));
952952
}
953953

954+
@Test // GH-3728
955+
void shouldRenderSin() {
956+
assertThat(transform("sin(angle)")).isEqualTo(Document.parse("{ \"$sin\" : \"$angle\"}"));
957+
}
958+
959+
@Test // GH-3728
960+
void shouldRenderSinh() {
961+
assertThat(transform("sinh(angle)")).isEqualTo(Document.parse("{ \"$sinh\" : \"$angle\"}"));
962+
}
963+
954964
private Object transform(String expression, Object... params) {
955965
Object result = transformer.transform(expression, Aggregation.DEFAULT_CONTEXT, params);
956966
return result == null ? null : (!(result instanceof org.bson.Document) ? result.toString() : result);

0 commit comments

Comments
 (0)