Skip to content

Commit 491c211

Browse files
authored
feat: add arithmetic expressions (#2333)
* add rand and trunc expressions and documentation * fix trunc expression documentation and add tests for trunc and truncToPrecision * remove code sample in PipelineSnippets.java
1 parent 6371fd3 commit 491c211

File tree

2 files changed

+252
-0
lines changed

2 files changed

+252
-0
lines changed

google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/expressions/Expression.java

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3213,6 +3213,94 @@ public static Expression roundToPrecision(String numericField, Expression decima
32133213
return roundToPrecision(field(numericField), decimalPlace);
32143214
}
32153215

3216+
/**
3217+
* Creates an expression that returns a random double between 0.0 and 1.0 but not including 1.0.
3218+
*
3219+
* @return A new {@link Expression} representing a random double result from the rand operation.
3220+
*/
3221+
@BetaApi
3222+
public static Expression rand() {
3223+
return new FunctionExpression("rand", ImmutableList.of());
3224+
}
3225+
3226+
/**
3227+
* Creates an expression that truncates {@code numericExpr} to an integer.
3228+
*
3229+
* @param numericExpr An expression that returns number when evaluated.
3230+
* @return A new {@link Expression} representing the trunc operation.
3231+
*/
3232+
@BetaApi
3233+
public static Expression trunc(Expression numericExpr) {
3234+
return new FunctionExpression("trunc", ImmutableList.of(numericExpr));
3235+
}
3236+
3237+
/**
3238+
* Creates an expression that truncates {@code numericField} to an integer.
3239+
*
3240+
* @param numericField Name of field that returns number when evaluated.
3241+
* @return A new {@link Expression} representing the trunc operation.
3242+
*/
3243+
@BetaApi
3244+
public static Expression trunc(String numericField) {
3245+
return trunc(field(numericField));
3246+
}
3247+
3248+
/**
3249+
* Creates an expression that truncates {@code numericExpr} to {@code decimalPlace} decimal places
3250+
* if {@code decimalPlace} is positive, truncates digits to the left of the decimal point if
3251+
* {@code decimalPlace} is negative.
3252+
*
3253+
* @param numericExpr An expression that returns number when evaluated.
3254+
* @param decimalPlace The number of decimal places to truncate.
3255+
* @return A new {@link Expression} representing the trunc operation.
3256+
*/
3257+
@BetaApi
3258+
public static Expression truncToPrecision(Expression numericExpr, int decimalPlace) {
3259+
return new FunctionExpression("trunc", ImmutableList.of(numericExpr, constant(decimalPlace)));
3260+
}
3261+
3262+
/**
3263+
* Creates an expression that truncates {@code numericField} to {@code decimalPlace} decimal
3264+
* places if {@code decimalPlace} is positive, truncates digits to the left of the decimal point
3265+
* if {@code decimalPlace} is negative.
3266+
*
3267+
* @param numericField Name of field that returns number when evaluated.
3268+
* @param decimalPlace The number of decimal places to truncate.
3269+
* @return A new {@link Expression} representing the trunc operation.
3270+
*/
3271+
@BetaApi
3272+
public static Expression truncToPrecision(String numericField, int decimalPlace) {
3273+
return truncToPrecision(field(numericField), decimalPlace);
3274+
}
3275+
3276+
/**
3277+
* Creates an expression that truncates {@code numericExpr} to {@code decimalPlace} decimal places
3278+
* if {@code decimalPlace} is positive, truncates digits to the left of the decimal point if
3279+
* {@code decimalPlace} is negative.
3280+
*
3281+
* @param numericExpr An expression that returns number when evaluated.
3282+
* @param decimalPlace The number of decimal places to truncate.
3283+
* @return A new {@link Expression} representing the trunc operation.
3284+
*/
3285+
@BetaApi
3286+
public static Expression truncToPrecision(Expression numericExpr, Expression decimalPlace) {
3287+
return new FunctionExpression("trunc", ImmutableList.of(numericExpr, decimalPlace));
3288+
}
3289+
3290+
/**
3291+
* Creates an expression that truncates {@code numericField} to {@code decimalPlace} decimal
3292+
* places if {@code decimalPlace} is positive, truncates digits to the left of the decimal point
3293+
* if {@code decimalPlace} is negative.
3294+
*
3295+
* @param numericField Name of field that returns number when evaluated.
3296+
* @param decimalPlace The number of decimal places to truncate.
3297+
* @return A new {@link Expression} representing the trunc operation.
3298+
*/
3299+
@BetaApi
3300+
public static Expression truncToPrecision(String numericField, Expression decimalPlace) {
3301+
return truncToPrecision(field(numericField), decimalPlace);
3302+
}
3303+
32163304
/**
32173305
* Creates an expression that returns the smallest integer that isn't less than {@code
32183306
* numericExpr}.
@@ -3686,6 +3774,42 @@ public final Expression roundToPrecision(Expression decimalPlace) {
36863774
return roundToPrecision(this, decimalPlace);
36873775
}
36883776

3777+
/**
3778+
* Creates an expression that truncates this numeric expression to an integer.
3779+
*
3780+
* @return A new {@link Expression} representing the trunc operation.
3781+
*/
3782+
@BetaApi
3783+
public final Expression trunc() {
3784+
return trunc(this);
3785+
}
3786+
3787+
/**
3788+
* Creates an expression that truncates this numeric expression to {@code decimalPlace} decimal
3789+
* places if {@code decimalPlace} is positive, truncates digits to the left of the decimal point
3790+
* if {@code decimalPlace} is negative.
3791+
*
3792+
* @param decimalPlace The number of decimal places to truncate.
3793+
* @return A new {@link Expression} representing the trunc operation.
3794+
*/
3795+
@BetaApi
3796+
public final Expression truncToPrecision(int decimalPlace) {
3797+
return truncToPrecision(this, decimalPlace);
3798+
}
3799+
3800+
/**
3801+
* Creates an expression that truncates this numeric expression to {@code decimalPlace} decimal
3802+
* places if {@code decimalPlace} is positive, truncates digits to the left of the decimal point
3803+
* if {@code decimalPlace} is negative.
3804+
*
3805+
* @param decimalPlace The number of decimal places to truncate.
3806+
* @return A new {@link Expression} representing the trunc operation.
3807+
*/
3808+
@BetaApi
3809+
public final Expression truncToPrecision(Expression decimalPlace) {
3810+
return truncToPrecision(this, decimalPlace);
3811+
}
3812+
36893813
/**
36903814
* Creates an expression that returns the smallest integer that isn't less than this numeric
36913815
* expression.

google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
import static com.google.cloud.firestore.pipeline.expressions.Expression.nullValue;
5757
import static com.google.cloud.firestore.pipeline.expressions.Expression.or;
5858
import static com.google.cloud.firestore.pipeline.expressions.Expression.pow;
59+
import static com.google.cloud.firestore.pipeline.expressions.Expression.rand;
5960
import static com.google.cloud.firestore.pipeline.expressions.Expression.regexMatch;
6061
import static com.google.cloud.firestore.pipeline.expressions.Expression.round;
6162
import static com.google.cloud.firestore.pipeline.expressions.Expression.sqrt;
@@ -67,6 +68,8 @@
6768
import static com.google.cloud.firestore.pipeline.expressions.Expression.timestampToUnixMicros;
6869
import static com.google.cloud.firestore.pipeline.expressions.Expression.timestampToUnixMillis;
6970
import static com.google.cloud.firestore.pipeline.expressions.Expression.timestampToUnixSeconds;
71+
import static com.google.cloud.firestore.pipeline.expressions.Expression.trunc;
72+
import static com.google.cloud.firestore.pipeline.expressions.Expression.truncToPrecision;
7073
import static com.google.cloud.firestore.pipeline.expressions.Expression.unixMicrosToTimestamp;
7174
import static com.google.cloud.firestore.pipeline.expressions.Expression.unixMillisToTimestamp;
7275
import static com.google.cloud.firestore.pipeline.expressions.Expression.unixSecondsToTimestamp;
@@ -1552,6 +1555,131 @@ public void testAdvancedMathExpressions() throws Exception {
15521555
assertThat((Double) result.get("log10_rating")).isWithin(0.00001).of(0.67209);
15531556
}
15541557

1558+
@Test
1559+
public void testRand() throws Exception {
1560+
assumeFalse(
1561+
"Rand is not supported against the emulator.",
1562+
isRunningAgainstFirestoreEmulator(firestore));
1563+
1564+
List<PipelineResult> results =
1565+
firestore
1566+
.pipeline()
1567+
.createFrom(collection)
1568+
.select(rand().as("randomNumber"))
1569+
.limit(1)
1570+
.execute()
1571+
.get()
1572+
.getResults();
1573+
1574+
assertThat(results).hasSize(1);
1575+
Object randomNumber = results.get(0).getData().get("randomNumber");
1576+
assertThat(randomNumber).isInstanceOf(Double.class);
1577+
assertThat((Double) randomNumber).isAtLeast(0.0);
1578+
assertThat((Double) randomNumber).isLessThan(1.0);
1579+
}
1580+
1581+
@Test
1582+
public void testTrunc() throws Exception {
1583+
assumeFalse(
1584+
"Trunc is not supported against the emulator.",
1585+
isRunningAgainstFirestoreEmulator(firestore));
1586+
1587+
List<PipelineResult> results =
1588+
firestore
1589+
.pipeline()
1590+
.createFrom(collection)
1591+
.where(field("title").equal("Pride and Prejudice"))
1592+
.limit(1)
1593+
.select(trunc("rating").as("truncatedRating"))
1594+
.execute()
1595+
.get()
1596+
.getResults();
1597+
1598+
Map<String, Object> result = data(results).get(0);
1599+
assertThat(result.get("truncatedRating")).isEqualTo(4.0);
1600+
}
1601+
1602+
@Test
1603+
public void testTruncWithInstanceMethod() throws Exception {
1604+
assumeFalse(
1605+
"Trunc is not supported against the emulator.",
1606+
isRunningAgainstFirestoreEmulator(firestore));
1607+
1608+
List<PipelineResult> results =
1609+
firestore
1610+
.pipeline()
1611+
.createFrom(collection)
1612+
.where(field("title").equal("Pride and Prejudice"))
1613+
.limit(1)
1614+
.select(field("rating").trunc().as("truncatedRating"))
1615+
.execute()
1616+
.get()
1617+
.getResults();
1618+
1619+
Map<String, Object> result = data(results).get(0);
1620+
assertThat(result.get("truncatedRating")).isEqualTo(4.0);
1621+
}
1622+
1623+
@Test
1624+
public void testTruncToPrecision() throws Exception {
1625+
assumeFalse(
1626+
"Trunc is not supported against the emulator.",
1627+
isRunningAgainstFirestoreEmulator(firestore));
1628+
1629+
List<PipelineResult> results =
1630+
firestore
1631+
.pipeline()
1632+
.createFrom(collection)
1633+
.limit(1)
1634+
.select(
1635+
truncToPrecision(constant(4.123456), 0).as("p0"),
1636+
truncToPrecision(constant(4.123456), 1).as("p1"),
1637+
truncToPrecision(constant(4.123456), 2).as("p2"),
1638+
truncToPrecision(constant(4.123456), 4).as("p4"))
1639+
.execute()
1640+
.get()
1641+
.getResults();
1642+
1643+
assertThat(data(results))
1644+
.isEqualTo(
1645+
Lists.newArrayList(
1646+
map(
1647+
"p0", 4.0,
1648+
"p1", 4.1,
1649+
"p2", 4.12,
1650+
"p4", 4.1234)));
1651+
}
1652+
1653+
@Test
1654+
public void testTruncToPrecisionWithInstanceMethod() throws Exception {
1655+
assumeFalse(
1656+
"Trunc is not supported against the emulator.",
1657+
isRunningAgainstFirestoreEmulator(firestore));
1658+
1659+
List<PipelineResult> results =
1660+
firestore
1661+
.pipeline()
1662+
.createFrom(collection)
1663+
.limit(1)
1664+
.select(
1665+
constant(4.123456).truncToPrecision(0).as("p0"),
1666+
constant(4.123456).truncToPrecision(1).as("p1"),
1667+
constant(4.123456).truncToPrecision(constant(2)).as("p2"),
1668+
constant(4.123456).truncToPrecision(4).as("p4"))
1669+
.execute()
1670+
.get()
1671+
.getResults();
1672+
1673+
assertThat(data(results))
1674+
.isEqualTo(
1675+
Lists.newArrayList(
1676+
map(
1677+
"p0", 4.0,
1678+
"p1", 4.1,
1679+
"p2", 4.12,
1680+
"p4", 4.1234)));
1681+
}
1682+
15551683
@Test
15561684
public void testConcat() throws Exception {
15571685
// String concat

0 commit comments

Comments
 (0)