From 11bdbccb9befaa871ee2f9f902fa279c86c4c250 Mon Sep 17 00:00:00 2001 From: Linchin Date: Thu, 5 Mar 2026 22:22:11 +0000 Subject: [PATCH 1/6] feat: Add `Rand` expression --- .../firestore_v1/pipeline_expressions.py | 11 +++++ .../tests/system/pipeline_e2e/math.yaml | 45 +++++++++++++++++++ .../unit/v1/test_pipeline_expressions.py | 6 +++ 3 files changed, 62 insertions(+) diff --git a/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_expressions.py b/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_expressions.py index 376d785901fc..277fe18a83d3 100644 --- a/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_expressions.py +++ b/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_expressions.py @@ -2029,3 +2029,14 @@ class CurrentTimestamp(FunctionExpression): def __init__(self): super().__init__("current_timestamp", [], use_infix_repr=False) + + +class Rand(FunctionExpression): + """Creates an expression that returns a pseudorandom float between 0.0 (inclusive) and 1.0 (exclusive). + + Returns: + A new `Expression` representing the random value. + """ + + def __init__(self): + super().__init__("rand", [], use_infix_repr=False) diff --git a/packages/google-cloud-firestore/tests/system/pipeline_e2e/math.yaml b/packages/google-cloud-firestore/tests/system/pipeline_e2e/math.yaml index 4d35f746d3f4..0ef0a1f427d6 100644 --- a/packages/google-cloud-firestore/tests/system/pipeline_e2e/math.yaml +++ b/packages/google-cloud-firestore/tests/system/pipeline_e2e/math.yaml @@ -306,4 +306,49 @@ tests: - fieldReferenceValue: rating - integerValue: '2' name: mod + name: select + - description: testRand + pipeline: + - Collection: books + - Limit: 1 + - Select: + - AliasedExpression: + - And: + - FunctionExpression.greater_than_or_equal: + - Rand: [] + - Constant: 0.0 + - FunctionExpression.less_than: + - Rand: [] + - Constant: 1.0 + - "is_valid_rand" + assert_results: + - is_valid_rand: true + assert_proto: + pipeline: + stages: + - args: + - referenceValue: /books + name: collection + - args: + - integerValue: '1' + name: limit + - args: + - mapValue: + fields: + is_valid_rand: + functionValue: + name: and + args: + - functionValue: + name: greater_than_or_equal + args: + - functionValue: + name: rand + - doubleValue: 0.0 + - functionValue: + name: less_than + args: + - functionValue: + name: rand + - doubleValue: 1.0 name: select \ No newline at end of file diff --git a/packages/google-cloud-firestore/tests/unit/v1/test_pipeline_expressions.py b/packages/google-cloud-firestore/tests/unit/v1/test_pipeline_expressions.py index fe7beb460502..7b73de12099f 100644 --- a/packages/google-cloud-firestore/tests/unit/v1/test_pipeline_expressions.py +++ b/packages/google-cloud-firestore/tests/unit/v1/test_pipeline_expressions.py @@ -1583,3 +1583,9 @@ def test_maximum(self): assert repr(instance) == "Value.maximum()" infix_instance = arg1.maximum() assert infix_instance == instance + + def test_rand(self): + instance = expr.Rand() + assert instance.name == "rand" + assert instance.params == [] + assert repr(instance) == "Rand()" From 40a490b15450ebf6dda52a78677d2db937e4128e Mon Sep 17 00:00:00 2001 From: Linchin Date: Thu, 5 Mar 2026 22:33:20 +0000 Subject: [PATCH 2/6] feat: add trunc function expression --- .../firestore_v1/pipeline_expressions.py | 13 ++++ .../tests/system/pipeline_e2e/math.yaml | 63 +++++++++++++++++++ .../unit/v1/test_pipeline_expressions.py | 9 +++ 3 files changed, 85 insertions(+) diff --git a/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_expressions.py b/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_expressions.py index 277fe18a83d3..7f4dda095de8 100644 --- a/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_expressions.py +++ b/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_expressions.py @@ -405,6 +405,19 @@ def sqrt(self) -> "Expression": """ return FunctionExpression("sqrt", [self]) + @expose_as_static + def trunc(self) -> "Expression": + """Creates an expression that truncates this expression towards zero. + + Example: + >>> # Truncate the 'value' field. + >>> Field.of("value").trunc() + + Returns: + A new `Expression` representing the truncated value. + """ + return FunctionExpression("trunc", [self]) + @expose_as_static def logical_maximum(self, *others: Expression | CONSTANT_TYPE) -> "Expression": """Creates an expression that returns the larger value between this expression diff --git a/packages/google-cloud-firestore/tests/system/pipeline_e2e/math.yaml b/packages/google-cloud-firestore/tests/system/pipeline_e2e/math.yaml index 0ef0a1f427d6..ca190a62d8e3 100644 --- a/packages/google-cloud-firestore/tests/system/pipeline_e2e/math.yaml +++ b/packages/google-cloud-firestore/tests/system/pipeline_e2e/math.yaml @@ -134,6 +134,69 @@ tests: - fieldReferenceValue: rating name: sqrt name: select + - description: testTrunc + pipeline: + - Collection: books + - Where: + - FunctionExpression.equal_any: + - Field: title + - - Constant: "To Kill a Mockingbird" # rating 4.2 + - Constant: "Pride and Prejudice" # rating 4.5 + - Constant: "The Lord of the Rings" # rating 4.7 + - Select: + - title + - AliasedExpression: + - FunctionExpression.trunc: + - Field: rating + - "trunc_rating" + - Sort: + - Ordering: + - Field: title + - ASCENDING + assert_results: + - title: "Pride and Prejudice" + trunc_rating: 4.0 + - title: "The Lord of the Rings" + trunc_rating: 4.0 + - title: "To Kill a Mockingbird" + trunc_rating: 4.0 + assert_proto: + pipeline: + stages: + - args: + - referenceValue: /books + name: collection + - args: + - functionValue: + args: + - fieldReferenceValue: title + - functionValue: + args: + - stringValue: "To Kill a Mockingbird" + - stringValue: "Pride and Prejudice" + - stringValue: "The Lord of the Rings" + name: array + name: equal_any + name: where + - args: + - mapValue: + fields: + title: + fieldReferenceValue: title + trunc_rating: + functionValue: + args: + - fieldReferenceValue: rating + name: trunc + name: select + - args: + - mapValue: + fields: + direction: + stringValue: ascending + expression: + fieldReferenceValue: title + name: sort - description: testRoundFunctionExpressionessions pipeline: - Collection: books diff --git a/packages/google-cloud-firestore/tests/unit/v1/test_pipeline_expressions.py b/packages/google-cloud-firestore/tests/unit/v1/test_pipeline_expressions.py index 7b73de12099f..3084fac965b1 100644 --- a/packages/google-cloud-firestore/tests/unit/v1/test_pipeline_expressions.py +++ b/packages/google-cloud-firestore/tests/unit/v1/test_pipeline_expressions.py @@ -1418,6 +1418,15 @@ def test_sqrt(self): infix_instance = arg1.sqrt() assert infix_instance == instance + def test_trunc(self): + arg1 = self._make_arg("Value") + instance = Expression.trunc(arg1) + assert instance.name == "trunc" + assert instance.params == [arg1] + assert repr(instance) == "Value.trunc()" + infix_instance = arg1.trunc() + assert infix_instance == instance + def test_array_length(self): arg1 = self._make_arg("Array") instance = Expression.array_length(arg1) From bc888161eef964e0382a4f2a712db316ae4e098b Mon Sep 17 00:00:00 2001 From: Linchin Date: Fri, 6 Mar 2026 18:43:22 +0000 Subject: [PATCH 3/6] update trunc docstring --- .../google/cloud/firestore_v1/pipeline_expressions.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_expressions.py b/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_expressions.py index 7f4dda095de8..9311d6d145fa 100644 --- a/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_expressions.py +++ b/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_expressions.py @@ -407,11 +407,12 @@ def sqrt(self) -> "Expression": @expose_as_static def trunc(self) -> "Expression": - """Creates an expression that truncates this expression towards zero. + """Creates an expression that truncates a numeric value to the specified + number of decimal places. Example: - >>> # Truncate the 'value' field. - >>> Field.of("value").trunc() + >>> # Truncate the 'value' field to 2 decimal places. + >>> Field.of("value").trunc(2) Returns: A new `Expression` representing the truncated value. @@ -2045,10 +2046,10 @@ def __init__(self): class Rand(FunctionExpression): - """Creates an expression that returns a pseudorandom float between 0.0 (inclusive) and 1.0 (exclusive). + """Creates an expression that generates a random number between 0.0 and 1.0 but not including 1.0. Returns: - A new `Expression` representing the random value. + A new `Expression` representing the rand operation. """ def __init__(self): From 4e122d81985f59be1dfd9b92f443ca27823556e4 Mon Sep 17 00:00:00 2001 From: Linchin Date: Wed, 11 Mar 2026 21:18:35 +0000 Subject: [PATCH 4/6] update docstring --- .../google/cloud/firestore_v1/pipeline_expressions.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_expressions.py b/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_expressions.py index 9311d6d145fa..b2b1bbeb9e05 100644 --- a/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_expressions.py +++ b/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_expressions.py @@ -407,8 +407,7 @@ def sqrt(self) -> "Expression": @expose_as_static def trunc(self) -> "Expression": - """Creates an expression that truncates a numeric value to the specified - number of decimal places. + """Function to truncate a numeric expression to the nearest whole number towards zero. Example: >>> # Truncate the 'value' field to 2 decimal places. From fb9c57c02179a312114e196e90aa56f2c4033b11 Mon Sep 17 00:00:00 2001 From: Linchin Date: Wed, 11 Mar 2026 21:58:52 +0000 Subject: [PATCH 5/6] add parameter for trunc --- .../cloud/firestore_v1/pipeline_expressions.py | 7 ++++--- .../tests/system/pipeline_e2e/math.yaml | 14 ++++++++++++++ .../tests/unit/v1/test_pipeline_expressions.py | 8 ++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_expressions.py b/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_expressions.py index b2b1bbeb9e05..0cff309433a1 100644 --- a/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_expressions.py +++ b/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_expressions.py @@ -406,17 +406,18 @@ def sqrt(self) -> "Expression": return FunctionExpression("sqrt", [self]) @expose_as_static - def trunc(self) -> "Expression": + def trunc(self, places: "Expression" | None = None) -> "Expression": """Function to truncate a numeric expression to the nearest whole number towards zero. Example: >>> # Truncate the 'value' field to 2 decimal places. - >>> Field.of("value").trunc(2) + >>> Field.of("value").trunc(PipelineSource.literals(2)) Returns: A new `Expression` representing the truncated value. """ - return FunctionExpression("trunc", [self]) + params = [self, places] if places is not None else [self] + return FunctionExpression("trunc", params) @expose_as_static def logical_maximum(self, *others: Expression | CONSTANT_TYPE) -> "Expression": diff --git a/packages/google-cloud-firestore/tests/system/pipeline_e2e/math.yaml b/packages/google-cloud-firestore/tests/system/pipeline_e2e/math.yaml index ca190a62d8e3..5b05c24aeb71 100644 --- a/packages/google-cloud-firestore/tests/system/pipeline_e2e/math.yaml +++ b/packages/google-cloud-firestore/tests/system/pipeline_e2e/math.yaml @@ -149,6 +149,11 @@ tests: - FunctionExpression.trunc: - Field: rating - "trunc_rating" + - AliasedExpression: + - FunctionExpression.trunc: + - Field: rating + - Constant: 1 + - "trunc_rating_with_places" - Sort: - Ordering: - Field: title @@ -156,10 +161,13 @@ tests: assert_results: - title: "Pride and Prejudice" trunc_rating: 4.0 + trunc_rating_with_places: 4.5 - title: "The Lord of the Rings" trunc_rating: 4.0 + trunc_rating_with_places: 4.7 - title: "To Kill a Mockingbird" trunc_rating: 4.0 + trunc_rating_with_places: 4.2 assert_proto: pipeline: stages: @@ -188,6 +196,12 @@ tests: args: - fieldReferenceValue: rating name: trunc + trunc_rating_with_places: + functionValue: + args: + - fieldReferenceValue: rating + - integerValue: '1' + name: trunc name: select - args: - mapValue: diff --git a/packages/google-cloud-firestore/tests/unit/v1/test_pipeline_expressions.py b/packages/google-cloud-firestore/tests/unit/v1/test_pipeline_expressions.py index 3084fac965b1..eff8512346ca 100644 --- a/packages/google-cloud-firestore/tests/unit/v1/test_pipeline_expressions.py +++ b/packages/google-cloud-firestore/tests/unit/v1/test_pipeline_expressions.py @@ -1427,6 +1427,14 @@ def test_trunc(self): infix_instance = arg1.trunc() assert infix_instance == instance + places = self._make_arg("Places") + instance_with_places = Expression.trunc(arg1, places) + assert instance_with_places.name == "trunc" + assert instance_with_places.params == [arg1, places] + assert repr(instance_with_places) == "Value.trunc(Places)" + infix_instance_with_places = arg1.trunc(places) + assert infix_instance_with_places == instance_with_places + def test_array_length(self): arg1 = self._make_arg("Array") instance = Expression.array_length(arg1) From 920fb15c31ea2631627c44917c8f2de9e66ce0e4 Mon Sep 17 00:00:00 2001 From: Linchin Date: Wed, 11 Mar 2026 22:00:31 +0000 Subject: [PATCH 6/6] docstring --- .../google/cloud/firestore_v1/pipeline_expressions.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_expressions.py b/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_expressions.py index 0cff309433a1..f54c9059aa51 100644 --- a/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_expressions.py +++ b/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_expressions.py @@ -2046,7 +2046,8 @@ def __init__(self): class Rand(FunctionExpression): - """Creates an expression that generates a random number between 0.0 and 1.0 but not including 1.0. + """Creates an expression that generates a random number between 0.0 and 1.0 but not + including 1.0. Returns: A new `Expression` representing the rand operation.