Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,19 @@ replacements:
)
from google.cloud.firestore_v1.pipeline_source import PipelineSource
from google.cloud.firestore_v1.pipeline_types import (
DocumentWindowFrame,
FindNearestOptions,
Ordering,
PipelineDataType,
RangeWindowFrame,
SampleOptions,
SearchOptions,
TimeGranularity,
TimePart,
TimeUnit,
UnnestOptions,
WindowBound,
WindowSpec,
)
from google.cloud.firestore_v1.query import CollectionGroup, Query
from google.cloud.firestore_v1.query_profile import (
Expand Down Expand Up @@ -198,6 +202,7 @@ replacements:
"DocumentReference",
"DocumentSnapshot",
"DocumentTransform",
"DocumentWindowFrame",
"ExistsOption",
"ExplainOptions",
"FieldFilter",
Expand All @@ -217,6 +222,7 @@ replacements:
"PipelineSource",
"PipelineStream",
"Query",
"RangeWindowFrame",
"ReadAfterWriteError",
"SERVER_TIMESTAMP",
"SampleOptions",
Expand All @@ -230,6 +236,8 @@ replacements:
"types",
"UnnestOptions",
"Watch",
"WindowBound",
"WindowSpec",
"WriteBatch",
"WriteOption",
]
Expand Down Expand Up @@ -278,6 +286,7 @@ replacements:
DocumentReference,
DocumentSnapshot,
DocumentTransform,
DocumentWindowFrame,
ExistsOption,
ExplainOptions,
FieldFilter,
Expand All @@ -297,6 +306,7 @@ replacements:
PipelineSource,
PipelineStream,
Query,
RangeWindowFrame,
ReadAfterWriteError,
SampleOptions,
SearchOptions,
Expand All @@ -307,6 +317,8 @@ replacements:
Transaction,
UnnestOptions,
Watch,
WindowBound,
WindowSpec,
WriteBatch,
WriteOption,
async_transactional,
Expand Down Expand Up @@ -345,6 +357,7 @@ replacements:
"DocumentReference",
"DocumentSnapshot",
"DocumentTransform",
"DocumentWindowFrame",
"ExistsOption",
"ExplainOptions",
"FieldFilter",
Expand All @@ -364,6 +377,7 @@ replacements:
"PipelineSource",
"PipelineStream",
"Query",
"RangeWindowFrame",
"ReadAfterWriteError",
"SERVER_TIMESTAMP",
"SampleOptions",
Expand All @@ -377,6 +391,8 @@ replacements:
"types",
"UnnestOptions",
"Watch",
"WindowBound",
"WindowSpec",
"WriteBatch",
"WriteOption",
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
DocumentReference,
DocumentSnapshot,
DocumentTransform,
DocumentWindowFrame,
ExistsOption,
ExplainOptions,
FieldFilter,
Expand All @@ -70,6 +71,7 @@
PipelineSource,
PipelineStream,
Query,
RangeWindowFrame,
ReadAfterWriteError,
SampleOptions,
SearchOptions,
Expand All @@ -80,6 +82,8 @@
Transaction,
UnnestOptions,
Watch,
WindowBound,
WindowSpec,
WriteBatch,
WriteOption,
async_transactional,
Expand Down Expand Up @@ -118,6 +122,7 @@
"DocumentReference",
"DocumentSnapshot",
"DocumentTransform",
"DocumentWindowFrame",
"ExistsOption",
"ExplainOptions",
"FieldFilter",
Expand All @@ -137,6 +142,7 @@
"PipelineSource",
"PipelineStream",
"Query",
"RangeWindowFrame",
"ReadAfterWriteError",
"SERVER_TIMESTAMP",
"SampleOptions",
Expand All @@ -150,6 +156,8 @@
"types",
"UnnestOptions",
"Watch",
"WindowBound",
"WindowSpec",
"WriteBatch",
"WriteOption",
]
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,19 @@
)
from google.cloud.firestore_v1.pipeline_source import PipelineSource
from google.cloud.firestore_v1.pipeline_types import (
DocumentWindowFrame,
FindNearestOptions,
Ordering,
PipelineDataType,
RangeWindowFrame,
SampleOptions,
SearchOptions,
TimeGranularity,
TimePart,
TimeUnit,
UnnestOptions,
WindowBound,
WindowSpec,
)
from google.cloud.firestore_v1.query import CollectionGroup, Query
from google.cloud.firestore_v1.query_profile import (
Expand Down Expand Up @@ -175,6 +179,7 @@
"DocumentReference",
"DocumentSnapshot",
"DocumentTransform",
"DocumentWindowFrame",
"ExistsOption",
"ExplainOptions",
"FieldFilter",
Expand All @@ -194,6 +199,7 @@
"PipelineSource",
"PipelineStream",
"Query",
"RangeWindowFrame",
"ReadAfterWriteError",
"SERVER_TIMESTAMP",
"SampleOptions",
Expand All @@ -207,6 +213,8 @@
"types",
"UnnestOptions",
"Watch",
"WindowBound",
"WindowSpec",
"WriteBatch",
"WriteOption",
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
Field,
FunctionExpression,
Selectable,
WindowFunction,
_PipelineValueExpression,
)
from google.cloud.firestore_v1.types.pipeline import (
Expand Down Expand Up @@ -176,6 +177,41 @@ def add_fields(self, *fields: Selectable) -> "_BasePipeline":
"""
return self._append(stages.AddFields(*fields))

def add_window_fields(
self,
*fields: AliasedExpression[AggregateFunction | WindowFunction],
window: types.WindowSpec | None = None,
) -> "_BasePipeline":
"""
Adds new fields computed by window functions over a window of documents.

.. note::
This feature is currently in beta and is subject to change.

Example:
>>> from google.cloud.firestore_v1.pipeline_expressions import Field, Rank
>>> from google.cloud.firestore_v1.pipeline_types import WindowSpec
>>> pipeline = client.pipeline().collection("books")
>>> pipeline = pipeline.add_window_fields(
... Rank().as_("genre_rank"),
... Field.of("price").sum().as_("genre_total_price"),
... window=WindowSpec(
... partition=["genre"],
... sort=[Field.of("rating").descending()],
... ),
... )

Args:
*fields: Aliased `AggregateFunction` or `WindowFunction` expressions defining
the window calculations and their output field aliases.
window: Optional `WindowSpec` specifying the baseline window configuration
for this stage.

Returns:
A new Pipeline object with this stage appended to the stage list.
"""
return self._append(stages.AddWindowFields(*fields, window=window))

def remove_fields(self, *fields: Field | str) -> "_BasePipeline":
"""
Removes fields from outputs of previous stages.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
TimeGranularity,
TimePart,
TimeUnit,
WindowSpec,
)
from google.cloud.firestore_v1.types.document import Pipeline as Pipeline_pb
from google.cloud.firestore_v1.types.document import Value
Expand Down Expand Up @@ -2574,6 +2575,21 @@ def is_type(
"is_type", [self, self._cast_to_expr_or_convert_to_constant(type_val)]
)

@expose_as_static
def over(
self,
window: WindowSpec,
) -> "WindowFunction":
"""Configures a window over which this function is evaluated.

Args:
window: A `WindowSpec` specifying the window override for this function.

Returns:
A `WindowFunction` with the specified window override.
"""
return WindowFunction("over", [self, window]) # type: ignore[list-item]


class Constant(Expression, Generic[CONSTANT_TYPE]):
"""Represents a constant literal value in an expression."""
Expand Down Expand Up @@ -2685,6 +2701,14 @@ def _to_pb(self):
class AggregateFunction(FunctionExpression):
"""A base class for aggregation functions that operate across multiple inputs."""

pass


class WindowFunction(FunctionExpression):
"""A base class for window functions that operate over a window of documents."""

pass


class Selectable(Expression):
"""Base class for expressions that can be selected or aliased in projection stages."""
Expand Down Expand Up @@ -3197,3 +3221,28 @@ def __init__(self):
[],
repr_function=FunctionExpression._build_standalone_repr(),
)


class Rank(WindowFunction):
"""Creates a window function that computes the rank of each document within a window.

Documents with equal sort values receive the same rank, with gaps in the subsequent
ranking numbers.

Example:
>>> # Rank documents by price descending within each category
>>> db.pipeline().collection("products").add_window_fields(
... Rank().as_("price_rank"),
... window=WindowSpec(
... partition=["category"],
... sort=[Field.of("price").descending()],
... ),
... )
"""

def __init__(self):
super().__init__(
"rank",
[],
repr_function=FunctionExpression._build_standalone_repr(),
)
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
Expression,
Field,
Selectable,
WindowFunction,
)
from google.cloud.firestore_v1.types.document import Pipeline as Pipeline_pb
from google.cloud.firestore_v1.types.document import Value
Expand All @@ -42,6 +43,7 @@
SampleOptions,
SearchOptions,
UnnestOptions,
WindowSpec,
)


Expand Down Expand Up @@ -86,6 +88,30 @@ def _pb_args(self):
return [Selectable._to_value(self.fields)]


class AddWindowFields(Stage):
"""Adds new fields computed by window functions over a window of documents."""

def __init__(
self,
*args: AliasedExpression[AggregateFunction | WindowFunction],
fields: Sequence[AliasedExpression[AggregateFunction | WindowFunction]] = (),
window: WindowSpec | None = None,
):
super().__init__("add_window_fields")
if args and fields:
raise ValueError(
"AddWindowFields stage contains both positional and keyword fields"
)
self.fields = list(args or fields)
self.window: WindowSpec = window if window is not None else WindowSpec()

def _pb_args(self) -> list[Value]:
return [
self.window._to_pb(),
Selectable._to_value(self.fields),
]


class Aggregate(Stage):
"""Performs aggregation operations, optionally grouped."""

Expand Down
Loading
Loading