From 2a8213cf5ff647529960c84c528bbddd2677ccae Mon Sep 17 00:00:00 2001 From: Linchin Date: Thu, 5 Mar 2026 00:26:49 +0000 Subject: [PATCH 1/9] feat: literals pipeline stage --- .../cloud/firestore_v1/base_pipeline.py | 65 +++++++++++++++++++ .../cloud/firestore_v1/pipeline_stages.py | 17 +++++ .../tests/system/pipeline_e2e/general.yaml | 21 +++++- .../tests/unit/v1/test_pipeline.py | 1 + .../tests/unit/v1/test_pipeline_stages.py | 29 +++++++++ 5 files changed, 132 insertions(+), 1 deletion(-) diff --git a/packages/google-cloud-firestore/google/cloud/firestore_v1/base_pipeline.py b/packages/google-cloud-firestore/google/cloud/firestore_v1/base_pipeline.py index fac7f8bc4bce..fe42785a9aad 100644 --- a/packages/google-cloud-firestore/google/cloud/firestore_v1/base_pipeline.py +++ b/packages/google-cloud-firestore/google/cloud/firestore_v1/base_pipeline.py @@ -275,6 +275,71 @@ def find_nearest( stages.FindNearest(field, vector, distance_measure, options) ) + def literals(self, *documents: str | Selectable) -> "_BasePipeline": + """ + Returns documents from a fixed set of predefined document objects. + + This stage is commonly used for testing other stages in isolation, + though it can also be used as inputs to join conditions. + + Example: + >>> from google.cloud.firestore_v1.pipeline_expressions import Constant + >>> documents = [ + ... {"name": "joe", "age": 10}, + ... {"name": "bob", "age": 30}, + ... {"name": "alice", "age": 40} + ... ] + >>> pipeline = client.pipeline() + ... .literals(Constant.of(documents)) + ... .where(field("age").lessThan(35)) + + Output documents: + ```json + [ + {"name": "joe", "age": 10}, + {"name": "bob", "age": 30} + ] + ``` + + Behavior: + The `literals(...)` stage can only be used as the first stage in a pipeline (or + sub-pipeline). The order of documents returned from the `literals` matches the + order in which they are defined. + + While literal values are the most common, it is also possible to pass in + expressions, which will be evaluated and returned, making it possible to test + out different query / expression behavior without first needing to create some + test data. + + For example, the following shows how to quickly test out the `length(...)` + function on some constant test sets: + + Example: + >>> from google.cloud.firestore_v1.pipeline_expressions import Constant + >>> documents = [ + ... {"x": Constant.of("foo-bar-baz").char_length()}, + ... {"x": Constant.of("bar").char_length()} + ... ] + >>> pipeline = client.pipeline().literals(Constant.of(documents)) + + Output documents: + ```json + [ + {"x": 11}, + {"x": 3} + ] + ``` + + Args: + documents: A `str` or `Selectable` expression. If a `str`, it's + treated as a field path to an array of documents. + If a `Selectable`, it's usually a `Constant` + containing an array of documents (as dictionaries). + Returns: + A new Pipeline object with this stage appended to the stage list. + """ + return self._append(stages.Literals(*documents)) + def replace_with( self, field: Selectable, diff --git a/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_stages.py b/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_stages.py index b00d923c673c..cd48960da1de 100644 --- a/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_stages.py +++ b/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_stages.py @@ -342,6 +342,23 @@ def _pb_args(self): return [Value(integer_value=self.limit)] +class Literals(Stage): + """Returns documents from a fixed set of predefined document objects.""" + + def __init__(self, *documents: str | Selectable): + super().__init__("literals") + self.documents = documents + + def _pb_args(self): + args = [] + for doc in self.documents: + if hasattr(doc, "_to_pb"): + args.append(doc._to_pb()) + else: + args.append(encode_value(doc)) + return args + + class Offset(Stage): """Skips a specified number of documents.""" diff --git a/packages/google-cloud-firestore/tests/system/pipeline_e2e/general.yaml b/packages/google-cloud-firestore/tests/system/pipeline_e2e/general.yaml index 46a10cd4d1af..bcd81916be84 100644 --- a/packages/google-cloud-firestore/tests/system/pipeline_e2e/general.yaml +++ b/packages/google-cloud-firestore/tests/system/pipeline_e2e/general.yaml @@ -684,4 +684,23 @@ tests: - args: - fieldReferenceValue: awards - stringValue: full_replace - name: replace_with \ No newline at end of file + name: replace_with + - description: literals + pipeline: + - Literals: + - title: "The Hitchhiker's Guide to the Galaxy" + author: "Douglas Adams" + assert_results: + - title: "The Hitchhiker's Guide to the Galaxy" + author: "Douglas Adams" + assert_proto: + pipeline: + stages: + - args: + - mapValue: + fields: + author: + stringValue: "Douglas Adams" + title: + stringValue: "The Hitchhiker's Guide to the Galaxy" + name: literals \ No newline at end of file diff --git a/packages/google-cloud-firestore/tests/unit/v1/test_pipeline.py b/packages/google-cloud-firestore/tests/unit/v1/test_pipeline.py index 5953398709a3..d264f714ddaa 100644 --- a/packages/google-cloud-firestore/tests/unit/v1/test_pipeline.py +++ b/packages/google-cloud-firestore/tests/unit/v1/test_pipeline.py @@ -417,6 +417,7 @@ def test_pipeline_execute_stream_equivalence(): ("aggregate", (Field.of("n").as_("alias"),), stages.Aggregate), ("distinct", ("field_name",), stages.Distinct), ("distinct", (Field.of("n"), "second"), stages.Distinct), + ("literals", (Field.of("a"),), stages.Literals), ], ) def test_pipeline_methods(method, args, result_cls): diff --git a/packages/google-cloud-firestore/tests/unit/v1/test_pipeline_stages.py b/packages/google-cloud-firestore/tests/unit/v1/test_pipeline_stages.py index b32a6e5d3f13..e3693c8415d6 100644 --- a/packages/google-cloud-firestore/tests/unit/v1/test_pipeline_stages.py +++ b/packages/google-cloud-firestore/tests/unit/v1/test_pipeline_stages.py @@ -517,6 +517,35 @@ def test_to_pb(self): assert len(result.options) == 0 +class TestLiterals: + def _make_one(self, *args, **kwargs): + return stages.Literals(*args, **kwargs) + + def test_ctor(self): + val1 = Constant.of({"a": 1}) + val2 = Constant.of({"b": 2}) + instance = self._make_one(val1, val2) + assert instance.documents == (val1, val2) + assert instance.name == "literals" + + def test_repr(self): + val1 = Constant.of({"a": 1}) + instance = self._make_one(val1) + repr_str = repr(instance) + assert repr_str == "Literals(documents=(Constant.of({'a': 1}),))" + + def test_to_pb(self): + val1 = Constant.of({"a": 1}) + val2 = Constant.of({"b": 2}) + instance = self._make_one(val1, val2) + result = instance._to_pb() + assert result.name == "literals" + assert len(result.args) == 2 + assert result.args[0].map_value.fields["a"].integer_value == 1 + assert result.args[1].map_value.fields["b"].integer_value == 2 + assert len(result.options) == 0 + + class TestOffset: def _make_one(self, *args, **kwargs): return stages.Offset(*args, **kwargs) From 28acee915967602e06f179e164242c6aa5cdf7df Mon Sep 17 00:00:00 2001 From: Linchin Date: Fri, 6 Mar 2026 21:37:01 +0000 Subject: [PATCH 2/9] add dict as supported type and update docstring --- .../google/cloud/firestore_v1/base_pipeline.py | 2 +- .../google/cloud/firestore_v1/pipeline_stages.py | 2 +- .../tests/unit/v1/test_pipeline_stages.py | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/google-cloud-firestore/google/cloud/firestore_v1/base_pipeline.py b/packages/google-cloud-firestore/google/cloud/firestore_v1/base_pipeline.py index fe42785a9aad..02e2ceecaa52 100644 --- a/packages/google-cloud-firestore/google/cloud/firestore_v1/base_pipeline.py +++ b/packages/google-cloud-firestore/google/cloud/firestore_v1/base_pipeline.py @@ -275,7 +275,7 @@ def find_nearest( stages.FindNearest(field, vector, distance_measure, options) ) - def literals(self, *documents: str | Selectable) -> "_BasePipeline": + def literals(self, *documents: Selectable | dict) -> "_BasePipeline": """ Returns documents from a fixed set of predefined document objects. diff --git a/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_stages.py b/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_stages.py index cd48960da1de..9ccb1d5aaa69 100644 --- a/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_stages.py +++ b/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_stages.py @@ -345,7 +345,7 @@ def _pb_args(self): class Literals(Stage): """Returns documents from a fixed set of predefined document objects.""" - def __init__(self, *documents: str | Selectable): + def __init__(self, *documents: Selectable | dict): super().__init__("literals") self.documents = documents diff --git a/packages/google-cloud-firestore/tests/unit/v1/test_pipeline_stages.py b/packages/google-cloud-firestore/tests/unit/v1/test_pipeline_stages.py index e3693c8415d6..82fe3e1881b2 100644 --- a/packages/google-cloud-firestore/tests/unit/v1/test_pipeline_stages.py +++ b/packages/google-cloud-firestore/tests/unit/v1/test_pipeline_stages.py @@ -523,20 +523,20 @@ def _make_one(self, *args, **kwargs): def test_ctor(self): val1 = Constant.of({"a": 1}) - val2 = Constant.of({"b": 2}) + val2 = {"b": 2} instance = self._make_one(val1, val2) assert instance.documents == (val1, val2) assert instance.name == "literals" def test_repr(self): val1 = Constant.of({"a": 1}) - instance = self._make_one(val1) + instance = self._make_one(val1, {"b": 2}) repr_str = repr(instance) - assert repr_str == "Literals(documents=(Constant.of({'a': 1}),))" + assert repr_str == "Literals(documents=(Constant.of({'a': 1}), {'b': 2}))" def test_to_pb(self): val1 = Constant.of({"a": 1}) - val2 = Constant.of({"b": 2}) + val2 = {"b": 2} instance = self._make_one(val1, val2) result = instance._to_pb() assert result.name == "literals" From a2e11ed359427538ee8a2027c846cbba7006c940 Mon Sep 17 00:00:00 2001 From: Linchin Date: Mon, 9 Mar 2026 19:13:40 +0000 Subject: [PATCH 3/9] correct docstring and type annotation --- .../google/cloud/firestore_v1/base_pipeline.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/google-cloud-firestore/google/cloud/firestore_v1/base_pipeline.py b/packages/google-cloud-firestore/google/cloud/firestore_v1/base_pipeline.py index 02e2ceecaa52..4db636fe9d41 100644 --- a/packages/google-cloud-firestore/google/cloud/firestore_v1/base_pipeline.py +++ b/packages/google-cloud-firestore/google/cloud/firestore_v1/base_pipeline.py @@ -275,7 +275,7 @@ def find_nearest( stages.FindNearest(field, vector, distance_measure, options) ) - def literals(self, *documents: Selectable | dict) -> "_BasePipeline": + def literals(self, *documents: Expression | dict) -> "_BasePipeline": """ Returns documents from a fixed set of predefined document objects. @@ -290,7 +290,7 @@ def literals(self, *documents: Selectable | dict) -> "_BasePipeline": ... {"name": "alice", "age": 40} ... ] >>> pipeline = client.pipeline() - ... .literals(Constant.of(documents)) + ... .literals(documents) ... .where(field("age").lessThan(35)) Output documents: @@ -320,7 +320,7 @@ def literals(self, *documents: Selectable | dict) -> "_BasePipeline": ... {"x": Constant.of("foo-bar-baz").char_length()}, ... {"x": Constant.of("bar").char_length()} ... ] - >>> pipeline = client.pipeline().literals(Constant.of(documents)) + >>> pipeline = client.pipeline().literals(documents) Output documents: ```json @@ -331,10 +331,8 @@ def literals(self, *documents: Selectable | dict) -> "_BasePipeline": ``` Args: - documents: A `str` or `Selectable` expression. If a `str`, it's - treated as a field path to an array of documents. - If a `Selectable`, it's usually a `Constant` - containing an array of documents (as dictionaries). + documents: One or more documents to be returned by this stage. Each can be a `dict` + or an `Expression`. Returns: A new Pipeline object with this stage appended to the stage list. """ From a97cb134040b0e429b83bfd60d6ae79b5c9dd57c Mon Sep 17 00:00:00 2001 From: Linchin Date: Mon, 9 Mar 2026 19:14:55 +0000 Subject: [PATCH 4/9] type annotation --- .../google/cloud/firestore_v1/pipeline_stages.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_stages.py b/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_stages.py index 9ccb1d5aaa69..30d2fd8e936a 100644 --- a/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_stages.py +++ b/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_stages.py @@ -345,7 +345,7 @@ def _pb_args(self): class Literals(Stage): """Returns documents from a fixed set of predefined document objects.""" - def __init__(self, *documents: Selectable | dict): + def __init__(self, *documents: Expression | dict): super().__init__("literals") self.documents = documents From cc1b737571cdc660ed6cdee9e407814900d91b81 Mon Sep 17 00:00:00 2001 From: Linchin Date: Mon, 9 Mar 2026 20:33:45 +0000 Subject: [PATCH 5/9] add more unit tests --- packages/google-cloud-firestore/tests/unit/v1/test_pipeline.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/google-cloud-firestore/tests/unit/v1/test_pipeline.py b/packages/google-cloud-firestore/tests/unit/v1/test_pipeline.py index d264f714ddaa..5ec2e9ac1123 100644 --- a/packages/google-cloud-firestore/tests/unit/v1/test_pipeline.py +++ b/packages/google-cloud-firestore/tests/unit/v1/test_pipeline.py @@ -418,6 +418,8 @@ def test_pipeline_execute_stream_equivalence(): ("distinct", ("field_name",), stages.Distinct), ("distinct", (Field.of("n"), "second"), stages.Distinct), ("literals", (Field.of("a"),), stages.Literals), + ("literals", ({"name": "joe"}, {"name": "bob"}), stages.Literals), + ("literals", (Field.of("a"), {"name": "joe"}), stages.Literals), ], ) def test_pipeline_methods(method, args, result_cls): From 386122314ff9b244be18f81a7a4a482ec0540762 Mon Sep 17 00:00:00 2001 From: Linchin Date: Mon, 9 Mar 2026 20:35:46 +0000 Subject: [PATCH 6/9] correct docstring --- .../google/cloud/firestore_v1/base_pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/google-cloud-firestore/google/cloud/firestore_v1/base_pipeline.py b/packages/google-cloud-firestore/google/cloud/firestore_v1/base_pipeline.py index 4db636fe9d41..5b7f234f7d0f 100644 --- a/packages/google-cloud-firestore/google/cloud/firestore_v1/base_pipeline.py +++ b/packages/google-cloud-firestore/google/cloud/firestore_v1/base_pipeline.py @@ -331,7 +331,7 @@ def literals(self, *documents: Expression | dict) -> "_BasePipeline": ``` Args: - documents: One or more documents to be returned by this stage. Each can be a `dict` + *documents: One or more documents to be returned by this stage. Each can be a `dict` or an `Expression`. Returns: A new Pipeline object with this stage appended to the stage list. From 7bad13cbf5b8636a422565accc6054911a5cc6fc Mon Sep 17 00:00:00 2001 From: Linchin Date: Mon, 9 Mar 2026 21:11:38 +0000 Subject: [PATCH 7/9] add cases to system test --- .../tests/system/pipeline_e2e/general.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/google-cloud-firestore/tests/system/pipeline_e2e/general.yaml b/packages/google-cloud-firestore/tests/system/pipeline_e2e/general.yaml index bcd81916be84..37fbbdd54dc6 100644 --- a/packages/google-cloud-firestore/tests/system/pipeline_e2e/general.yaml +++ b/packages/google-cloud-firestore/tests/system/pipeline_e2e/general.yaml @@ -690,6 +690,10 @@ tests: - Literals: - title: "The Hitchhiker's Guide to the Galaxy" author: "Douglas Adams" + - Constant: + value: + genre: "Science Fiction" + year: 1979 assert_results: - title: "The Hitchhiker's Guide to the Galaxy" author: "Douglas Adams" @@ -703,4 +707,10 @@ tests: stringValue: "Douglas Adams" title: stringValue: "The Hitchhiker's Guide to the Galaxy" + - mapValue: + fields: + genre: + stringValue: "Science Fiction" + year: + integerValue: '1979' name: literals \ No newline at end of file From 36e45bf5e8ff95d7477d7636727658d78b8566d9 Mon Sep 17 00:00:00 2001 From: Linchin Date: Tue, 10 Mar 2026 21:08:08 +0000 Subject: [PATCH 8/9] fix system test --- .../tests/system/pipeline_e2e/general.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/google-cloud-firestore/tests/system/pipeline_e2e/general.yaml b/packages/google-cloud-firestore/tests/system/pipeline_e2e/general.yaml index 37fbbdd54dc6..d4aa80ba8d7b 100644 --- a/packages/google-cloud-firestore/tests/system/pipeline_e2e/general.yaml +++ b/packages/google-cloud-firestore/tests/system/pipeline_e2e/general.yaml @@ -697,6 +697,8 @@ tests: assert_results: - title: "The Hitchhiker's Guide to the Galaxy" author: "Douglas Adams" + - genre: "Science Fiction" + year: 1979 assert_proto: pipeline: stages: From 816498e3a1278624af166812e273646d196068ad Mon Sep 17 00:00:00 2001 From: Linchin Date: Wed, 11 Mar 2026 20:36:14 +0000 Subject: [PATCH 9/9] move literals to pipeline_source.py --- .../cloud/firestore_v1/base_pipeline.py | 62 ------------------ .../cloud/firestore_v1/pipeline_source.py | 64 +++++++++++++++++++ .../tests/unit/v1/test_pipeline.py | 3 - .../tests/unit/v1/test_pipeline_source.py | 11 ++++ 4 files changed, 75 insertions(+), 65 deletions(-) diff --git a/packages/google-cloud-firestore/google/cloud/firestore_v1/base_pipeline.py b/packages/google-cloud-firestore/google/cloud/firestore_v1/base_pipeline.py index 5b7f234f7d0f..fb7bbdbbc81e 100644 --- a/packages/google-cloud-firestore/google/cloud/firestore_v1/base_pipeline.py +++ b/packages/google-cloud-firestore/google/cloud/firestore_v1/base_pipeline.py @@ -275,68 +275,6 @@ def find_nearest( stages.FindNearest(field, vector, distance_measure, options) ) - def literals(self, *documents: Expression | dict) -> "_BasePipeline": - """ - Returns documents from a fixed set of predefined document objects. - - This stage is commonly used for testing other stages in isolation, - though it can also be used as inputs to join conditions. - - Example: - >>> from google.cloud.firestore_v1.pipeline_expressions import Constant - >>> documents = [ - ... {"name": "joe", "age": 10}, - ... {"name": "bob", "age": 30}, - ... {"name": "alice", "age": 40} - ... ] - >>> pipeline = client.pipeline() - ... .literals(documents) - ... .where(field("age").lessThan(35)) - - Output documents: - ```json - [ - {"name": "joe", "age": 10}, - {"name": "bob", "age": 30} - ] - ``` - - Behavior: - The `literals(...)` stage can only be used as the first stage in a pipeline (or - sub-pipeline). The order of documents returned from the `literals` matches the - order in which they are defined. - - While literal values are the most common, it is also possible to pass in - expressions, which will be evaluated and returned, making it possible to test - out different query / expression behavior without first needing to create some - test data. - - For example, the following shows how to quickly test out the `length(...)` - function on some constant test sets: - - Example: - >>> from google.cloud.firestore_v1.pipeline_expressions import Constant - >>> documents = [ - ... {"x": Constant.of("foo-bar-baz").char_length()}, - ... {"x": Constant.of("bar").char_length()} - ... ] - >>> pipeline = client.pipeline().literals(documents) - - Output documents: - ```json - [ - {"x": 11}, - {"x": 3} - ] - ``` - - Args: - *documents: One or more documents to be returned by this stage. Each can be a `dict` - or an `Expression`. - Returns: - A new Pipeline object with this stage appended to the stage list. - """ - return self._append(stages.Literals(*documents)) def replace_with( self, diff --git a/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_source.py b/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_source.py index 0a7c6e7fbdab..d647f7985c9e 100644 --- a/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_source.py +++ b/packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_source.py @@ -32,6 +32,7 @@ from google.cloud.firestore_v1.base_document import BaseDocumentReference from google.cloud.firestore_v1.base_query import BaseQuery from google.cloud.firestore_v1.client import Client + from google.cloud.firestore_v1.pipeline_expressions import Expression PipelineType = TypeVar("PipelineType", bound=_BasePipeline) @@ -108,3 +109,66 @@ def documents(self, *docs: "BaseDocumentReference") -> PipelineType: a new pipeline instance targeting the specified documents """ return self._create_pipeline(stages.Documents.of(*docs)) + + def literals(self, *documents: "Expression" | dict) -> PipelineType: + """ + Returns documents from a fixed set of predefined document objects. + + This stage is commonly used for testing other stages in isolation, + though it can also be used as inputs to join conditions. + + Example: + >>> from google.cloud.firestore_v1.pipeline_expressions import Constant + >>> documents = [ + ... {"name": "joe", "age": 10}, + ... {"name": "bob", "age": 30}, + ... {"name": "alice", "age": 40} + ... ] + >>> pipeline = client.pipeline() + ... .literals(documents) + ... .where(field("age").lessThan(35)) + + Output documents: + ```json + [ + {"name": "joe", "age": 10}, + {"name": "bob", "age": 30} + ] + ``` + + Behavior: + The `literals(...)` stage can only be used as the first stage in a pipeline (or + sub-pipeline). The order of documents returned from the `literals` matches the + order in which they are defined. + + While literal values are the most common, it is also possible to pass in + expressions, which will be evaluated and returned, making it possible to test + out different query / expression behavior without first needing to create some + test data. + + For example, the following shows how to quickly test out the `length(...)` + function on some constant test sets: + + Example: + >>> from google.cloud.firestore_v1.pipeline_expressions import Constant + >>> documents = [ + ... {"x": Constant.of("foo-bar-baz").char_length()}, + ... {"x": Constant.of("bar").char_length()} + ... ] + >>> pipeline = client.pipeline().literals(documents) + + Output documents: + ```json + [ + {"x": 11}, + {"x": 3} + ] + ``` + + Args: + *documents: One or more documents to be returned by this stage. Each can be a `dict` + or an `Expression`. + Returns: + A new Pipeline object with this stage appended to the stage list. + """ + return self._create_pipeline(stages.Literals(*documents)) diff --git a/packages/google-cloud-firestore/tests/unit/v1/test_pipeline.py b/packages/google-cloud-firestore/tests/unit/v1/test_pipeline.py index 5ec2e9ac1123..5953398709a3 100644 --- a/packages/google-cloud-firestore/tests/unit/v1/test_pipeline.py +++ b/packages/google-cloud-firestore/tests/unit/v1/test_pipeline.py @@ -417,9 +417,6 @@ def test_pipeline_execute_stream_equivalence(): ("aggregate", (Field.of("n").as_("alias"),), stages.Aggregate), ("distinct", ("field_name",), stages.Distinct), ("distinct", (Field.of("n"), "second"), stages.Distinct), - ("literals", (Field.of("a"),), stages.Literals), - ("literals", ({"name": "joe"}, {"name": "bob"}), stages.Literals), - ("literals", (Field.of("a"), {"name": "joe"}), stages.Literals), ], ) def test_pipeline_methods(method, args, result_cls): diff --git a/packages/google-cloud-firestore/tests/unit/v1/test_pipeline_source.py b/packages/google-cloud-firestore/tests/unit/v1/test_pipeline_source.py index de31d47f70eb..94da65a61690 100644 --- a/packages/google-cloud-firestore/tests/unit/v1/test_pipeline_source.py +++ b/packages/google-cloud-firestore/tests/unit/v1/test_pipeline_source.py @@ -110,6 +110,17 @@ def test_documents(self): assert first_stage.paths[1] == "/a/2" assert first_stage.paths[2] == "/a/3" + def test_literals(self): + from google.cloud.firestore_v1.pipeline_expressions import Field + + instance = self._make_client().pipeline() + documents = (Field.of("a"), {"name": "joe"}) + ppl = instance.literals(*documents) + assert isinstance(ppl, self._expected_pipeline_type) + assert len(ppl.stages) == 1 + first_stage = ppl.stages[0] + assert isinstance(first_stage, stages.Literals) + class TestPipelineSourceWithAsyncClient(TestPipelineSource): """