From 28acbff32bf36deb2b6e3becd9fb408bb49f1a3a Mon Sep 17 00:00:00 2001 From: Yvonne Pan <103622026+yvonnep165@users.noreply.github.com> Date: Mon, 2 Mar 2026 10:53:59 -0500 Subject: [PATCH 1/3] add rand and trunc expressions and documentation --- .../pipeline/expressions/Expression.java | 124 ++++++++++++++++++ .../cloud/firestore/it/ITPipelineTest.java | 74 +++++++++++ .../example/firestore/PipelineSnippets.java | 27 ++++ 3 files changed, 225 insertions(+) diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/expressions/Expression.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/expressions/Expression.java index 363046c39c..a8074beb85 100644 --- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/expressions/Expression.java +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/expressions/Expression.java @@ -3213,6 +3213,94 @@ public static Expression roundToPrecision(String numericField, Expression decima return roundToPrecision(field(numericField), decimalPlace); } + /** + * Creates an expression that returns a random double between 0.0 and 1.0 but not including 1.0. + * + * @return A new {@link Expression} representing a random double result from the rand operation. + */ + @BetaApi + public static Expression rand() { + return new FunctionExpression("rand", ImmutableList.of()); + } + + /** + * Creates an expression that truncates {@code numericExpr} to an integer. + * + * @param numericExpr An expression that returns number when evaluated. + * @return A new {@link Expression} representing an integer result from the trunc operation. + */ + @BetaApi + public static Expression trunc(Expression numericExpr) { + return new FunctionExpression("trunc", ImmutableList.of(numericExpr)); + } + + /** + * Creates an expression that truncates {@code numericField} to an integer. + * + * @param numericField Name of field that returns number when evaluated. + * @return A new {@link Expression} representing an integer result from the trunc operation. + */ + @BetaApi + public static Expression trunc(String numericField) { + return trunc(field(numericField)); + } + + /** + * Creates an expression that truncates {@code numericExpr} to {@code decimalPlace} decimal places + * if {@code decimalPlace} is positive, truncates digits to the left of the decimal point if + * {@code decimalPlace} is negative. + * + * @param numericExpr An expression that returns number when evaluated. + * @param decimalPlace The number of decimal places to truncate. + * @return A new {@link Expression} representing the trunc operation. + */ + @BetaApi + public static Expression truncToPrecision(Expression numericExpr, int decimalPlace) { + return new FunctionExpression("trunc", ImmutableList.of(numericExpr, constant(decimalPlace))); + } + + /** + * Creates an expression that truncates {@code numericField} to {@code decimalPlace} decimal + * places if {@code decimalPlace} is positive, truncates digits to the left of the decimal point + * if {@code decimalPlace} is negative. + * + * @param numericField Name of field that returns number when evaluated. + * @param decimalPlace The number of decimal places to truncate. + * @return A new {@link Expression} representing the trunc operation. + */ + @BetaApi + public static Expression truncToPrecision(String numericField, int decimalPlace) { + return truncToPrecision(field(numericField), decimalPlace); + } + + /** + * Creates an expression that truncates {@code numericExpr} to {@code decimalPlace} decimal places + * if {@code decimalPlace} is positive, truncates digits to the left of the decimal point if + * {@code decimalPlace} is negative. + * + * @param numericExpr An expression that returns number when evaluated. + * @param decimalPlace The number of decimal places to truncate. + * @return A new {@link Expression} representing the trunc operation. + */ + @BetaApi + public static Expression truncToPrecision(Expression numericExpr, Expression decimalPlace) { + return new FunctionExpression("trunc", ImmutableList.of(numericExpr, decimalPlace)); + } + + /** + * Creates an expression that truncates {@code numericField} to {@code decimalPlace} decimal + * places if {@code decimalPlace} is positive, truncates digits to the left of the decimal point + * if {@code decimalPlace} is negative. + * + * @param numericField Name of field that returns number when evaluated. + * @param decimalPlace The number of decimal places to truncate. + * @return A new {@link Expression} representing the trunc operation. + */ + @BetaApi + public static Expression truncToPrecision(String numericField, Expression decimalPlace) { + return truncToPrecision(field(numericField), decimalPlace); + } + /** * Creates an expression that returns the smallest integer that isn't less than {@code * numericExpr}. @@ -3686,6 +3774,42 @@ public final Expression roundToPrecision(Expression decimalPlace) { return roundToPrecision(this, decimalPlace); } + /** + * Creates an expression that truncates this numeric expression to an integer. + * + * @return A new {@link Expression} representing an integer result from the trunc operation. + */ + @BetaApi + public final Expression trunc() { + return trunc(this); + } + + /** + * Creates an expression that truncates this numeric expression to {@code decimalPlace} decimal + * places if {@code decimalPlace} is positive, truncates digits to the left of the decimal point + * if {@code decimalPlace} is negative. + * + * @param decimalPlace The number of decimal places to truncate. + * @return A new {@link Expression} representing the trunc operation. + */ + @BetaApi + public final Expression truncToPrecision(int decimalPlace) { + return truncToPrecision(this, decimalPlace); + } + + /** + * Creates an expression that truncates this numeric expression to {@code decimalPlace} decimal + * places if {@code decimalPlace} is positive, truncates digits to the left of the decimal point + * if {@code decimalPlace} is negative. + * + * @param decimalPlace The number of decimal places to truncate. + * @return A new {@link Expression} representing the trunc operation. + */ + @BetaApi + public final Expression truncToPrecision(Expression decimalPlace) { + return truncToPrecision(this, decimalPlace); + } + /** * Creates an expression that returns the smallest integer that isn't less than this numeric * expression. diff --git a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java index 5f810332f1..e4cd1cab64 100644 --- a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java +++ b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java @@ -56,6 +56,7 @@ import static com.google.cloud.firestore.pipeline.expressions.Expression.nullValue; import static com.google.cloud.firestore.pipeline.expressions.Expression.or; import static com.google.cloud.firestore.pipeline.expressions.Expression.pow; +import static com.google.cloud.firestore.pipeline.expressions.Expression.rand; import static com.google.cloud.firestore.pipeline.expressions.Expression.regexMatch; import static com.google.cloud.firestore.pipeline.expressions.Expression.round; import static com.google.cloud.firestore.pipeline.expressions.Expression.sqrt; @@ -67,6 +68,7 @@ import static com.google.cloud.firestore.pipeline.expressions.Expression.timestampToUnixMicros; import static com.google.cloud.firestore.pipeline.expressions.Expression.timestampToUnixMillis; import static com.google.cloud.firestore.pipeline.expressions.Expression.timestampToUnixSeconds; +import static com.google.cloud.firestore.pipeline.expressions.Expression.trunc; import static com.google.cloud.firestore.pipeline.expressions.Expression.unixMicrosToTimestamp; import static com.google.cloud.firestore.pipeline.expressions.Expression.unixMillisToTimestamp; import static com.google.cloud.firestore.pipeline.expressions.Expression.unixSecondsToTimestamp; @@ -1552,6 +1554,78 @@ public void testAdvancedMathExpressions() throws Exception { assertThat((Double) result.get("log10_rating")).isWithin(0.00001).of(0.67209); } + @Test + public void testRand() throws Exception { + assumeFalse( + "Rand is not supported against the emulator.", + isRunningAgainstFirestoreEmulator(firestore)); + + List results = + firestore + .pipeline() + .createFrom(collection) + .select(rand().as("randomNumber")) + .limit(1) + .execute() + .get() + .getResults(); + + assertThat(results).hasSize(1); + Object randomNumber = results.get(0).getData().get("randomNumber"); + assertThat(randomNumber).isInstanceOf(Double.class); + assertThat((Double) randomNumber).isAtLeast(0.0); + assertThat((Double) randomNumber).isLessThan(1.0); + } + + @Test + public void testTrunc() throws Exception { + assumeFalse( + "Trunc is not supported against the emulator.", + isRunningAgainstFirestoreEmulator(firestore)); + + List results = + firestore + .pipeline() + .createFrom(collection) + .where(field("title").equal("Pride and Prejudice")) + .limit(1) + .select(trunc("rating").as("truncatedRating")) + .execute() + .get() + .getResults(); + + Map result = data(results).get(0); + assertThat(result.get("truncatedRating")).isEqualTo(4); + } + + @Test + public void testTruncToPrecision() throws Exception { + assumeFalse( + "Trunc is not supported against the emulator.", + isRunningAgainstFirestoreEmulator(firestore)); + + List results = + firestore + .pipeline() + .createFrom(collection) + .limit(1) + .select( + constant(4.123456).truncToPrecision(1).as("p1"), + constant(4.123456).truncToPrecision(constant(2)).as("p2"), + constant(4.123456).truncToPrecision(4).as("p4")) + .execute() + .get() + .getResults(); + + assertThat(data(results)) + .isEqualTo( + Lists.newArrayList( + map( + "p1", 4.1, + "p2", 4.12, + "p4", 4.1234))); + } + @Test public void testConcat() throws Exception { // String concat diff --git a/samples/preview-snippets/src/main/java/com/example/firestore/PipelineSnippets.java b/samples/preview-snippets/src/main/java/com/example/firestore/PipelineSnippets.java index cf6efe72d1..ccc22a6a41 100644 --- a/samples/preview-snippets/src/main/java/com/example/firestore/PipelineSnippets.java +++ b/samples/preview-snippets/src/main/java/com/example/firestore/PipelineSnippets.java @@ -770,6 +770,33 @@ void roundFunction() throws ExecutionException, InterruptedException { System.out.println(result.getResults()); } + void truncFunction() throws ExecutionException, InterruptedException { + // [START trunc_function] + Pipeline.Snapshot result = + firestore + .pipeline() + .collection("books") + .select(trunc(divide(field("ratings"), field("soldBooks"))).as("avgRatingInt")) + .execute() + .get(); + // [END trunc_function] + System.out.println(result.getResults()); + } + + void randFunction() throws ExecutionException, InterruptedException { + // [START rand_function] + Pipeline.Snapshot result = + firestore + .pipeline() + .collection("books") + .addFields(rand().as("rand")) + .where(field("rand").lessThan(0.01)) + .execute() + .get(); + // [END rand_function] + System.out.println(result.getResults()); + } + void powFunction() throws ExecutionException, InterruptedException { // [START pow_function] double googleplexLat = 37.4221; From 994c273507e53b206b8cf5209a40ba330b895b0f Mon Sep 17 00:00:00 2001 From: Yvonne Pan <103622026+yvonnep165@users.noreply.github.com> Date: Mon, 2 Mar 2026 14:43:26 -0500 Subject: [PATCH 2/3] fix trunc expression documentation and add tests for trunc and truncToPrecision --- .../pipeline/expressions/Expression.java | 6 +- .../cloud/firestore/it/ITPipelineTest.java | 56 ++++++++++++++++++- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/expressions/Expression.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/expressions/Expression.java index 5f6e000456..372e0e39cb 100644 --- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/expressions/Expression.java +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/expressions/Expression.java @@ -3227,7 +3227,7 @@ public static Expression rand() { * Creates an expression that truncates {@code numericExpr} to an integer. * * @param numericExpr An expression that returns number when evaluated. - * @return A new {@link Expression} representing an integer result from the trunc operation. + * @return A new {@link Expression} representing the trunc operation. */ @BetaApi public static Expression trunc(Expression numericExpr) { @@ -3238,7 +3238,7 @@ public static Expression trunc(Expression numericExpr) { * Creates an expression that truncates {@code numericField} to an integer. * * @param numericField Name of field that returns number when evaluated. - * @return A new {@link Expression} representing an integer result from the trunc operation. + * @return A new {@link Expression} representing the trunc operation. */ @BetaApi public static Expression trunc(String numericField) { @@ -3777,7 +3777,7 @@ public final Expression roundToPrecision(Expression decimalPlace) { /** * Creates an expression that truncates this numeric expression to an integer. * - * @return A new {@link Expression} representing an integer result from the trunc operation. + * @return A new {@link Expression} representing the trunc operation. */ @BetaApi public final Expression trunc() { diff --git a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java index e4cd1cab64..1ecaf846a6 100644 --- a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java +++ b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java @@ -69,6 +69,7 @@ import static com.google.cloud.firestore.pipeline.expressions.Expression.timestampToUnixMillis; import static com.google.cloud.firestore.pipeline.expressions.Expression.timestampToUnixSeconds; import static com.google.cloud.firestore.pipeline.expressions.Expression.trunc; +import static com.google.cloud.firestore.pipeline.expressions.Expression.truncToPrecision; import static com.google.cloud.firestore.pipeline.expressions.Expression.unixMicrosToTimestamp; import static com.google.cloud.firestore.pipeline.expressions.Expression.unixMillisToTimestamp; import static com.google.cloud.firestore.pipeline.expressions.Expression.unixSecondsToTimestamp; @@ -1595,7 +1596,28 @@ public void testTrunc() throws Exception { .getResults(); Map result = data(results).get(0); - assertThat(result.get("truncatedRating")).isEqualTo(4); + assertThat(result.get("truncatedRating")).isEqualTo(4.0); + } + + @Test + public void testTruncWithInstanceMethod() throws Exception { + assumeFalse( + "Trunc is not supported against the emulator.", + isRunningAgainstFirestoreEmulator(firestore)); + + List results = + firestore + .pipeline() + .createFrom(collection) + .where(field("title").equal("Pride and Prejudice")) + .limit(1) + .select(field("rating").trunc().as("truncatedRating")) + .execute() + .get() + .getResults(); + + Map result = data(results).get(0); + assertThat(result.get("truncatedRating")).isEqualTo(4.0); } @Test @@ -1610,6 +1632,37 @@ public void testTruncToPrecision() throws Exception { .createFrom(collection) .limit(1) .select( + truncToPrecision(constant(4.123456), 0).as("p0"), + truncToPrecision(constant(4.123456), 1).as("p1"), + truncToPrecision(constant(4.123456), 2).as("p2"), + truncToPrecision(constant(4.123456), 4).as("p4")) + .execute() + .get() + .getResults(); + + assertThat(data(results)) + .isEqualTo( + Lists.newArrayList( + map( + "p0", 4.0, + "p1", 4.1, + "p2", 4.12, + "p4", 4.1234))); + } + + @Test + public void testTruncToPrecisionWithInstanceMethod() throws Exception { + assumeFalse( + "Trunc is not supported against the emulator.", + isRunningAgainstFirestoreEmulator(firestore)); + + List results = + firestore + .pipeline() + .createFrom(collection) + .limit(1) + .select( + constant(4.123456).truncToPrecision(0).as("p0"), constant(4.123456).truncToPrecision(1).as("p1"), constant(4.123456).truncToPrecision(constant(2)).as("p2"), constant(4.123456).truncToPrecision(4).as("p4")) @@ -1621,6 +1674,7 @@ public void testTruncToPrecision() throws Exception { .isEqualTo( Lists.newArrayList( map( + "p0", 4.0, "p1", 4.1, "p2", 4.12, "p4", 4.1234))); From a3cf0c4f5fcecef01265cde914b444d5b0e2658a Mon Sep 17 00:00:00 2001 From: Yvonne Pan <103622026+yvonnep165@users.noreply.github.com> Date: Tue, 3 Mar 2026 14:51:54 -0500 Subject: [PATCH 3/3] remove code sample in PipelineSnippets.java --- .../example/firestore/PipelineSnippets.java | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/samples/preview-snippets/src/main/java/com/example/firestore/PipelineSnippets.java b/samples/preview-snippets/src/main/java/com/example/firestore/PipelineSnippets.java index ccc22a6a41..cf6efe72d1 100644 --- a/samples/preview-snippets/src/main/java/com/example/firestore/PipelineSnippets.java +++ b/samples/preview-snippets/src/main/java/com/example/firestore/PipelineSnippets.java @@ -770,33 +770,6 @@ void roundFunction() throws ExecutionException, InterruptedException { System.out.println(result.getResults()); } - void truncFunction() throws ExecutionException, InterruptedException { - // [START trunc_function] - Pipeline.Snapshot result = - firestore - .pipeline() - .collection("books") - .select(trunc(divide(field("ratings"), field("soldBooks"))).as("avgRatingInt")) - .execute() - .get(); - // [END trunc_function] - System.out.println(result.getResults()); - } - - void randFunction() throws ExecutionException, InterruptedException { - // [START rand_function] - Pipeline.Snapshot result = - firestore - .pipeline() - .collection("books") - .addFields(rand().as("rand")) - .where(field("rand").lessThan(0.01)) - .execute() - .get(); - // [END rand_function] - System.out.println(result.getResults()); - } - void powFunction() throws ExecutionException, InterruptedException { // [START pow_function] double googleplexLat = 37.4221;