Skip to content

Commit 8b0ee6c

Browse files
committed
Merge branch 'main' into pipeline_cursors
2 parents 7632b85 + 3b27042 commit 8b0ee6c

36 files changed

+441
-487
lines changed

.librarian/state.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
image: us-central1-docker.pkg.dev/cloud-sdk-librarian-prod/images-prod/python-librarian-generator@sha256:b8058df4c45e9a6e07f6b4d65b458d0d059241dd34c814f151c8bf6b89211209
22
libraries:
33
- id: google-cloud-firestore
4-
version: 2.22.0
4+
version: 2.23.0
55
last_generated_commit: 1a9d00bed77e6db82ff67764ffe14e3b5209f5cd
66
apis:
77
- path: google/firestore/v1

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,18 @@
44

55
[1]: https://pypi.org/project/google-cloud-firestore/#history
66

7+
## [2.23.0](https://github.com/googleapis/python-firestore/compare/v2.22.0...v2.23.0) (2026-01-14)
8+
9+
10+
### Features
11+
12+
* pipelines preview (#1156) ([9462d106dcda516e24a518dbd32a3ee5a39e40ca](https://github.com/googleapis/python-firestore/commit/9462d106dcda516e24a518dbd32a3ee5a39e40ca))
13+
14+
15+
### Bug Fixes
16+
17+
* stream generator type (#1148) ([165d367c342cb4205f13cf6d4fcd001419f9e2da](https://github.com/googleapis/python-firestore/commit/165d367c342cb4205f13cf6d4fcd001419f9e2da))
18+
719
## [2.22.0](https://github.com/googleapis/python-firestore/compare/v2.21.0...v2.22.0) (2025-12-16)
820

921

google/cloud/firestore/gapic_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
#
16-
__version__ = "2.22.0" # {x-release-please-version}
16+
__version__ = "2.23.0" # {x-release-please-version}

google/cloud/firestore_admin_v1/gapic_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
#
16-
__version__ = "2.22.0" # {x-release-please-version}
16+
__version__ = "2.23.0" # {x-release-please-version}

google/cloud/firestore_bundle/gapic_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
#
16-
__version__ = "2.22.0" # {x-release-please-version}
16+
__version__ = "2.23.0" # {x-release-please-version}

google/cloud/firestore_v1/async_pipeline.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14+
"""
15+
.. warning::
16+
**Preview API**: Firestore Pipelines is currently in preview and is
17+
subject to potential breaking changes in future releases
18+
"""
1419

1520
from __future__ import annotations
1621
from typing import TYPE_CHECKING
@@ -50,6 +55,10 @@ class AsyncPipeline(_BasePipeline):
5055
... print(result)
5156
5257
Use `client.pipeline()` to create instances of this class.
58+
59+
.. warning::
60+
**Preview API**: Firestore Pipelines is currently in preview and is
61+
subject to potential breaking changes in future releases
5362
"""
5463

5564
def __init__(self, client: AsyncClient, *stages: stages.Stage):
@@ -68,7 +77,6 @@ async def execute(
6877
transaction: "AsyncTransaction" | None = None,
6978
read_time: datetime.datetime | None = None,
7079
explain_options: PipelineExplainOptions | None = None,
71-
index_mode: str | None = None,
7280
additional_options: dict[str, Value | Constant] = {},
7381
) -> PipelineSnapshot[PipelineResult]:
7482
"""
@@ -87,10 +95,8 @@ async def execute(
8795
explain_options (Optional[:class:`~google.cloud.firestore_v1.query_profile.PipelineExplainOptions`]):
8896
Options to enable query profiling for this query. When set,
8997
explain_metrics will be available on the returned list.
90-
index_mode (Optional[str]): Configures the pipeline to require a certain type of indexes to be present.
91-
Firestore will reject the request if there is not appropiate indexes to serve the query.
9298
additional_options (Optional[dict[str, Value | Constant]]): Additional options to pass to the query.
93-
These options will take precedence over method argument if there is a conflict (e.g. explain_options, index_mode)
99+
These options will take precedence over method argument if there is a conflict (e.g. explain_options)
94100
"""
95101
kwargs = {k: v for k, v in locals().items() if k != "self"}
96102
stream = AsyncPipelineStream(PipelineResult, self, **kwargs)
@@ -103,7 +109,6 @@ def stream(
103109
read_time: datetime.datetime | None = None,
104110
transaction: "AsyncTransaction" | None = None,
105111
explain_options: PipelineExplainOptions | None = None,
106-
index_mode: str | None = None,
107112
additional_options: dict[str, Value | Constant] = {},
108113
) -> AsyncPipelineStream[PipelineResult]:
109114
"""
@@ -122,10 +127,8 @@ def stream(
122127
explain_options (Optional[:class:`~google.cloud.firestore_v1.query_profile.PipelineExplainOptions`]):
123128
Options to enable query profiling for this query. When set,
124129
explain_metrics will be available on the returned generator.
125-
index_mode (Optional[str]): Configures the pipeline to require a certain type of indexes to be present.
126-
Firestore will reject the request if there is not appropiate indexes to serve the query.
127130
additional_options (Optional[dict[str, Value | Constant]]): Additional options to pass to the query.
128-
These options will take precedence over method argument if there is a conflict (e.g. explain_options, index_mode)
131+
These options will take precedence over method argument if there is a conflict (e.g. explain_options)
129132
"""
130133
kwargs = {k: v for k, v in locals().items() if k != "self"}
131134
return AsyncPipelineStream(PipelineResult, self, **kwargs)

google/cloud/firestore_v1/base_aggregation.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,8 +361,12 @@ def _build_pipeline(self, source: "PipelineSource"):
361361
"""
362362
Convert this query into a Pipeline
363363
364+
Queries containing a `cursor` or `limit_to_last` are not currently supported
365+
364366
Args:
365367
source: the PipelineSource to build the pipeline off of
368+
Raises:
369+
- NotImplementedError: raised if the query contains a `cursor` or `limit_to_last`
366370
Returns:
367371
a Pipeline representing the query
368372
"""

google/cloud/firestore_v1/base_collection.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,8 +608,12 @@ def _build_pipeline(self, source: "PipelineSource"):
608608
"""
609609
Convert this query into a Pipeline
610610
611+
Queries containing a `cursor` or `limit_to_last` are not currently supported
612+
611613
Args:
612614
source: the PipelineSource to build the pipeline off o
615+
Raises:
616+
- NotImplementedError: raised if the query contains a `cursor` or `limit_to_last`
613617
Returns:
614618
a Pipeline representing the query
615619
"""

google/cloud/firestore_v1/base_query.py

Lines changed: 18 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,8 +1134,12 @@ def _build_pipeline(self, source: "PipelineSource"):
11341134
"""
11351135
Convert this query into a Pipeline
11361136
1137+
Queries containing a `cursor` or `limit_to_last` are not currently supported
1138+
11371139
Args:
11381140
source: the PipelineSource to build the pipeline off of
1141+
Raises:
1142+
- NotImplementedError: raised if the query contains a `cursor` or `limit_to_last`
11391143
Returns:
11401144
a Pipeline representing the query
11411145
"""
@@ -1158,10 +1162,9 @@ def _build_pipeline(self, source: "PipelineSource"):
11581162

11591163
# Orders
11601164
orders = self._normalize_orders()
1161-
1162-
exists = []
1163-
orderings = []
11641165
if orders:
1166+
exists = []
1167+
orderings = []
11651168
for order in orders:
11661169
field = pipeline_expressions.Field.of(order.field.field_path)
11671170
exists.append(field.exists())
@@ -1175,59 +1178,23 @@ def _build_pipeline(self, source: "PipelineSource"):
11751178
# Add exists filters to match Query's implicit orderby semantics.
11761179
if len(exists) == 1:
11771180
ppl = ppl.where(exists[0])
1178-
elif len(exists) > 1:
1181+
else:
11791182
ppl = ppl.where(pipeline_expressions.And(*exists))
11801183

1181-
if orderings:
1182-
# Normalize cursors to get the raw values corresponding to the orders
1183-
start_at_val = None
1184-
if self._start_at:
1185-
start_at_val = self._normalize_cursor(self._start_at, orders)
1186-
1187-
end_at_val = None
1188-
if self._end_at:
1189-
end_at_val = self._normalize_cursor(self._end_at, orders)
1190-
1191-
# If limit_to_last is set, we need to reverse the orderings to find the
1192-
# "last" N documents (which effectively become the "first" N in reverse order).
1193-
if self._limit_to_last:
1194-
actual_orderings = _reverse_orderings(orderings)
1195-
ppl = ppl.sort(*actual_orderings)
1196-
1197-
# Apply cursor conditions.
1198-
# Cursors are translated into filter conditions (e.g., field > value)
1199-
# based on the orderings.
1200-
if start_at_val:
1201-
ppl = ppl.where(
1202-
_where_conditions_from_cursor(
1203-
start_at_val, orderings, is_start_cursor=True
1204-
)
1205-
)
1206-
1207-
if end_at_val:
1208-
ppl = ppl.where(
1209-
_where_conditions_from_cursor(
1210-
end_at_val, orderings, is_start_cursor=False
1211-
)
1212-
)
1184+
# Add sort orderings
1185+
ppl = ppl.sort(*orderings)
12131186

1214-
if not self._limit_to_last:
1215-
ppl = ppl.sort(*orderings)
1216-
1217-
if self._limit is not None:
1187+
# Cursors, Limit and Offset
1188+
if self._start_at or self._end_at or self._limit_to_last:
1189+
raise NotImplementedError(
1190+
"Query to Pipeline conversion: cursors and limit_to_last is not supported yet."
1191+
)
1192+
else: # Limit & Offset without cursors
1193+
if self._offset:
1194+
ppl = ppl.offset(self._offset)
1195+
if self._limit:
12181196
ppl = ppl.limit(self._limit)
12191197

1220-
# If we reversed the orderings for limit_to_last, we must now re-sort
1221-
# using the original orderings to return the results in the user-requested order.
1222-
if self._limit_to_last:
1223-
ppl = ppl.sort(*orderings)
1224-
elif self._limit is not None and not self._limit_to_last:
1225-
ppl = ppl.limit(self._limit)
1226-
1227-
# Offset
1228-
if self._offset:
1229-
ppl = ppl.offset(self._offset)
1230-
12311198
return ppl
12321199

12331200
def _comparator(self, doc1, doc2) -> int:

google/cloud/firestore_v1/gapic_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
#
16-
__version__ = "2.22.0" # {x-release-please-version}
16+
__version__ = "2.23.0" # {x-release-please-version}

0 commit comments

Comments
 (0)