diff --git a/google/cloud/firestore_v1/_pipeline_stages.py b/google/cloud/firestore_v1/_pipeline_stages.py index caba9926a..7cd0efed4 100644 --- a/google/cloud/firestore_v1/_pipeline_stages.py +++ b/google/cloud/firestore_v1/_pipeline_stages.py @@ -23,11 +23,12 @@ from google.cloud.firestore_v1.vector import Vector from google.cloud.firestore_v1.base_vector_query import DistanceMeasure from google.cloud.firestore_v1.pipeline_expressions import ( - Accumulator, + AggregateFunction, Expr, - ExprWithAlias, + AliasedAggregate, + AliasedExpr, Field, - FilterCondition, + BooleanExpr, Selectable, Ordering, ) @@ -164,8 +165,8 @@ class Aggregate(Stage): def __init__( self, - *args: ExprWithAlias[Accumulator], - accumulators: Sequence[ExprWithAlias[Accumulator]] = (), + *args: AliasedExpr[AggregateFunction], + accumulators: Sequence[AliasedAggregate] = (), groups: Sequence[str | Selectable] = (), ): super().__init__() @@ -459,7 +460,7 @@ def _pb_options(self): class Where(Stage): """Filters documents based on a specified condition.""" - def __init__(self, condition: FilterCondition): + def __init__(self, condition: BooleanExpr): super().__init__() self.condition = condition diff --git a/google/cloud/firestore_v1/base_pipeline.py b/google/cloud/firestore_v1/base_pipeline.py index 26bdda2e8..5cf341e58 100644 --- a/google/cloud/firestore_v1/base_pipeline.py +++ b/google/cloud/firestore_v1/base_pipeline.py @@ -23,11 +23,9 @@ from google.cloud.firestore_v1.types.firestore import ExecutePipelineRequest from google.cloud.firestore_v1.pipeline_result import PipelineResult from google.cloud.firestore_v1.pipeline_expressions import ( - Accumulator, Expr, - ExprWithAlias, Field, - FilterCondition, + BooleanExpr, Selectable, ) from google.cloud.firestore_v1 import _helpers @@ -220,14 +218,14 @@ def select(self, *selections: str | Selectable) -> "_BasePipeline": """ return self._append(stages.Select(*selections)) - def where(self, condition: FilterCondition) -> "_BasePipeline": + def where(self, condition: BooleanExpr) -> "_BasePipeline": """ Filters the documents from previous stages to only include those matching - the specified `FilterCondition`. + the specified `BooleanExpr`. This stage allows you to apply conditions to the data, similar to a "WHERE" clause in SQL. You can filter documents based on their field values, using - implementations of `FilterCondition`, typically including but not limited to: + implementations of `BooleanExpr`, typically including but not limited to: - field comparators: `eq`, `lt` (less than), `gt` (greater than), etc. - logical operators: `And`, `Or`, `Not`, etc. - advanced functions: `regex_matches`, `array_contains`, etc. @@ -252,7 +250,7 @@ def where(self, condition: FilterCondition) -> "_BasePipeline": Args: - condition: The `FilterCondition` to apply. + condition: The `BooleanExpr` to apply. Returns: A new Pipeline object with this stage appended to the stage list @@ -579,7 +577,7 @@ def limit(self, limit: int) -> "_BasePipeline": def aggregate( self, - *accumulators: ExprWithAlias[Accumulator], + *accumulators: AliasedAggregate, groups: Sequence[str | Selectable] = (), ) -> "_BasePipeline": """ @@ -589,7 +587,7 @@ def aggregate( This stage allows you to calculate aggregate values (like sum, average, count, min, max) over a set of documents. - - **Accumulators:** Define the aggregation calculations using `Accumulator` + - **AggregateFunctions:** Define the aggregation calculations using `AggregateFunction` expressions (e.g., `sum()`, `avg()`, `count()`, `min()`, `max()`) combined with `as_()` to name the result field. - **Groups:** Optionally specify fields (by name or `Selectable`) to group @@ -617,7 +615,7 @@ def aggregate( Args: - *accumulators: One or more `ExprWithAlias[Accumulator]` expressions defining + *accumulators: One or more `AliasedAggregate` expressions defining the aggregations to perform and their output names. groups: An optional sequence of field names (str) or `Selectable` expressions to group by before aggregating. diff --git a/google/cloud/firestore_v1/pipeline_expressions.py b/google/cloud/firestore_v1/pipeline_expressions.py index 1129ea999..5cef1c225 100644 --- a/google/cloud/firestore_v1/pipeline_expressions.py +++ b/google/cloud/firestore_v1/pipeline_expressions.py @@ -116,7 +116,7 @@ def _to_pb(self) -> Value: def _cast_to_expr_or_convert_to_constant(o: Any) -> "Expr": return o if isinstance(o, Expr) else Constant(o) - def add(self, other: Expr | float) -> "Add": + def add(self, other: Expr | float) -> "Expr": """Creates an expression that adds this expression to another expression or constant. Example: @@ -133,7 +133,7 @@ def add(self, other: Expr | float) -> "Add": """ return Add(self, self._cast_to_expr_or_convert_to_constant(other)) - def subtract(self, other: Expr | float) -> "Subtract": + def subtract(self, other: Expr | float) -> "Expr": """Creates an expression that subtracts another expression or constant from this expression. Example: @@ -150,7 +150,7 @@ def subtract(self, other: Expr | float) -> "Subtract": """ return Subtract(self, self._cast_to_expr_or_convert_to_constant(other)) - def multiply(self, other: Expr | float) -> "Multiply": + def multiply(self, other: Expr | float) -> "Expr": """Creates an expression that multiplies this expression by another expression or constant. Example: @@ -167,7 +167,7 @@ def multiply(self, other: Expr | float) -> "Multiply": """ return Multiply(self, self._cast_to_expr_or_convert_to_constant(other)) - def divide(self, other: Expr | float) -> "Divide": + def divide(self, other: Expr | float) -> "Expr": """Creates an expression that divides this expression by another expression or constant. Example: @@ -184,7 +184,7 @@ def divide(self, other: Expr | float) -> "Divide": """ return Divide(self, self._cast_to_expr_or_convert_to_constant(other)) - def mod(self, other: Expr | float) -> "Mod": + def mod(self, other: Expr | float) -> "Expr": """Creates an expression that calculates the modulo (remainder) to another expression or constant. Example: @@ -201,7 +201,7 @@ def mod(self, other: Expr | float) -> "Mod": """ return Mod(self, self._cast_to_expr_or_convert_to_constant(other)) - def logical_max(self, other: Expr | CONSTANT_TYPE) -> "LogicalMax": + def logical_maximum(self, other: Expr | CONSTANT_TYPE) -> "Expr": """Creates an expression that returns the larger value between this expression and another expression or constant, based on Firestore's value type ordering. @@ -210,19 +210,19 @@ def logical_max(self, other: Expr | CONSTANT_TYPE) -> "LogicalMax": Example: >>> # Returns the larger value between the 'discount' field and the 'cap' field. - >>> Field.of("discount").logical_max(Field.of("cap")) + >>> Field.of("discount").logical_maximum(Field.of("cap")) >>> # Returns the larger value between the 'value' field and 10. - >>> Field.of("value").logical_max(10) + >>> Field.of("value").logical_maximum(10) Args: other: The other expression or constant value to compare with. Returns: - A new `Expr` representing the logical max operation. + A new `Expr` representing the logical maximum operation. """ - return LogicalMax(self, self._cast_to_expr_or_convert_to_constant(other)) + return LogicalMaximum(self, self._cast_to_expr_or_convert_to_constant(other)) - def logical_min(self, other: Expr | CONSTANT_TYPE) -> "LogicalMin": + def logical_minimum(self, other: Expr | CONSTANT_TYPE) -> "Expr": """Creates an expression that returns the smaller value between this expression and another expression or constant, based on Firestore's value type ordering. @@ -231,27 +231,27 @@ def logical_min(self, other: Expr | CONSTANT_TYPE) -> "LogicalMin": Example: >>> # Returns the smaller value between the 'discount' field and the 'floor' field. - >>> Field.of("discount").logical_min(Field.of("floor")) + >>> Field.of("discount").logical_minimum(Field.of("floor")) >>> # Returns the smaller value between the 'value' field and 10. - >>> Field.of("value").logical_min(10) + >>> Field.of("value").logical_minimum(10) Args: other: The other expression or constant value to compare with. Returns: - A new `Expr` representing the logical min operation. + A new `Expr` representing the logical minimum operation. """ - return LogicalMin(self, self._cast_to_expr_or_convert_to_constant(other)) + return LogicalMinimum(self, self._cast_to_expr_or_convert_to_constant(other)) - def eq(self, other: Expr | CONSTANT_TYPE) -> "Eq": + def equal(self, other: Expr | CONSTANT_TYPE) -> "BooleanExpr": """Creates an expression that checks if this expression is equal to another expression or constant value. Example: >>> # Check if the 'age' field is equal to 21 - >>> Field.of("age").eq(21) + >>> Field.of("age").equal(21) >>> # Check if the 'city' field is equal to "London" - >>> Field.of("city").eq("London") + >>> Field.of("city").equal("London") Args: other: The expression or constant value to compare for equality. @@ -259,17 +259,17 @@ def eq(self, other: Expr | CONSTANT_TYPE) -> "Eq": Returns: A new `Expr` representing the equality comparison. """ - return Eq(self, self._cast_to_expr_or_convert_to_constant(other)) + return Equal(self, self._cast_to_expr_or_convert_to_constant(other)) - def neq(self, other: Expr | CONSTANT_TYPE) -> "Neq": + def not_equal(self, other: Expr | CONSTANT_TYPE) -> "BooleanExpr": """Creates an expression that checks if this expression is not equal to another expression or constant value. Example: >>> # Check if the 'status' field is not equal to "completed" - >>> Field.of("status").neq("completed") + >>> Field.of("status").not_equal("completed") >>> # Check if the 'country' field is not equal to "USA" - >>> Field.of("country").neq("USA") + >>> Field.of("country").not_equal("USA") Args: other: The expression or constant value to compare for inequality. @@ -277,17 +277,17 @@ def neq(self, other: Expr | CONSTANT_TYPE) -> "Neq": Returns: A new `Expr` representing the inequality comparison. """ - return Neq(self, self._cast_to_expr_or_convert_to_constant(other)) + return NotEqual(self, self._cast_to_expr_or_convert_to_constant(other)) - def gt(self, other: Expr | CONSTANT_TYPE) -> "Gt": + def greater_than(self, other: Expr | CONSTANT_TYPE) -> "BooleanExpr": """Creates an expression that checks if this expression is greater than another expression or constant value. Example: >>> # Check if the 'age' field is greater than the 'limit' field - >>> Field.of("age").gt(Field.of("limit")) + >>> Field.of("age").greater_than(Field.of("limit")) >>> # Check if the 'price' field is greater than 100 - >>> Field.of("price").gt(100) + >>> Field.of("price").greater_than(100) Args: other: The expression or constant value to compare for greater than. @@ -295,17 +295,17 @@ def gt(self, other: Expr | CONSTANT_TYPE) -> "Gt": Returns: A new `Expr` representing the greater than comparison. """ - return Gt(self, self._cast_to_expr_or_convert_to_constant(other)) + return GreaterThan(self, self._cast_to_expr_or_convert_to_constant(other)) - def gte(self, other: Expr | CONSTANT_TYPE) -> "Gte": + def greater_than_or_equal(self, other: Expr | CONSTANT_TYPE) -> "BooleanExpr": """Creates an expression that checks if this expression is greater than or equal to another expression or constant value. Example: >>> # Check if the 'quantity' field is greater than or equal to field 'requirement' plus 1 - >>> Field.of("quantity").gte(Field.of('requirement').add(1)) + >>> Field.of("quantity").greater_than_or_equal(Field.of('requirement').add(1)) >>> # Check if the 'score' field is greater than or equal to 80 - >>> Field.of("score").gte(80) + >>> Field.of("score").greater_than_or_equal(80) Args: other: The expression or constant value to compare for greater than or equal to. @@ -313,17 +313,17 @@ def gte(self, other: Expr | CONSTANT_TYPE) -> "Gte": Returns: A new `Expr` representing the greater than or equal to comparison. """ - return Gte(self, self._cast_to_expr_or_convert_to_constant(other)) + return GreaterThanOrEqual(self, self._cast_to_expr_or_convert_to_constant(other)) - def lt(self, other: Expr | CONSTANT_TYPE) -> "Lt": + def less_than(self, other: Expr | CONSTANT_TYPE) -> "BooleanExpr": """Creates an expression that checks if this expression is less than another expression or constant value. Example: >>> # Check if the 'age' field is less than 'limit' - >>> Field.of("age").lt(Field.of('limit')) + >>> Field.of("age").less_than(Field.of('limit')) >>> # Check if the 'price' field is less than 50 - >>> Field.of("price").lt(50) + >>> Field.of("price").less_than(50) Args: other: The expression or constant value to compare for less than. @@ -331,17 +331,17 @@ def lt(self, other: Expr | CONSTANT_TYPE) -> "Lt": Returns: A new `Expr` representing the less than comparison. """ - return Lt(self, self._cast_to_expr_or_convert_to_constant(other)) + return LessThan(self, self._cast_to_expr_or_convert_to_constant(other)) - def lte(self, other: Expr | CONSTANT_TYPE) -> "Lte": + def less_than_or_equal(self, other: Expr | CONSTANT_TYPE) -> "BooleanExpr": """Creates an expression that checks if this expression is less than or equal to another expression or constant value. Example: >>> # Check if the 'quantity' field is less than or equal to 20 - >>> Field.of("quantity").lte(Constant.of(20)) + >>> Field.of("quantity").less_than_or_equal(Constant.of(20)) >>> # Check if the 'score' field is less than or equal to 70 - >>> Field.of("score").lte(70) + >>> Field.of("score").less_than_or_equal(70) Args: other: The expression or constant value to compare for less than or equal to. @@ -349,9 +349,9 @@ def lte(self, other: Expr | CONSTANT_TYPE) -> "Lte": Returns: A new `Expr` representing the less than or equal to comparison. """ - return Lte(self, self._cast_to_expr_or_convert_to_constant(other)) + return LessThanOrEqual(self, self._cast_to_expr_or_convert_to_constant(other)) - def in_any(self, array: Sequence[Expr | CONSTANT_TYPE]) -> "In": + def in_any(self, array: Sequence[Expr | CONSTANT_TYPE]) -> "BooleanExpr": """Creates an expression that checks if this expression is equal to any of the provided values or expressions. @@ -367,7 +367,7 @@ def in_any(self, array: Sequence[Expr | CONSTANT_TYPE]) -> "In": """ return In(self, [self._cast_to_expr_or_convert_to_constant(v) for v in array]) - def not_in_any(self, array: Sequence[Expr | CONSTANT_TYPE]) -> "Not": + def not_in_any(self, array: Sequence[Expr | CONSTANT_TYPE]) -> "BooleanExpr": """Creates an expression that checks if this expression is not equal to any of the provided values or expressions. @@ -383,7 +383,7 @@ def not_in_any(self, array: Sequence[Expr | CONSTANT_TYPE]) -> "Not": """ return Not(self.in_any(array)) - def array_concat(self, array: List[Expr | CONSTANT_TYPE]) -> "ArrayConcat": + def array_concat(self, array: List[Expr | CONSTANT_TYPE]) -> "Expr": """Creates an expression that concatenates an array expression with another array. Example: @@ -400,7 +400,7 @@ def array_concat(self, array: List[Expr | CONSTANT_TYPE]) -> "ArrayConcat": self, [self._cast_to_expr_or_convert_to_constant(o) for o in array] ) - def array_contains(self, element: Expr | CONSTANT_TYPE) -> "ArrayContains": + def array_contains(self, element: Expr | CONSTANT_TYPE) -> "BooleanExpr": """Creates an expression that checks if an array contains a specific element or value. Example: @@ -419,7 +419,7 @@ def array_contains(self, element: Expr | CONSTANT_TYPE) -> "ArrayContains": def array_contains_all( self, elements: Sequence[Expr | CONSTANT_TYPE] - ) -> "ArrayContainsAll": + ) -> "BooleanExpr": """Creates an expression that checks if an array contains all the specified elements. Example: @@ -440,7 +440,7 @@ def array_contains_all( def array_contains_any( self, elements: Sequence[Expr | CONSTANT_TYPE] - ) -> "ArrayContainsAny": + ) -> "BooleanExpr": """Creates an expression that checks if an array contains any of the specified elements. Example: @@ -460,7 +460,7 @@ def array_contains_any( self, [self._cast_to_expr_or_convert_to_constant(e) for e in elements] ) - def array_length(self) -> "ArrayLength": + def array_length(self) -> "Expr": """Creates an expression that calculates the length of an array. Example: @@ -472,7 +472,7 @@ def array_length(self) -> "ArrayLength": """ return ArrayLength(self) - def array_reverse(self) -> "ArrayReverse": + def array_reverse(self) -> "Expr": """Creates an expression that returns the reversed content of an array. Example: @@ -484,7 +484,7 @@ def array_reverse(self) -> "ArrayReverse": """ return ArrayReverse(self) - def is_nan(self) -> "IsNaN": + def is_nan(self) -> "BooleanExpr": """Creates an expression that checks if this expression evaluates to 'NaN' (Not a Number). Example: @@ -496,7 +496,7 @@ def is_nan(self) -> "IsNaN": """ return IsNaN(self) - def exists(self) -> "Exists": + def exists(self) -> "BooleanExpr": """Creates an expression that checks if a field exists in the document. Example: @@ -508,7 +508,7 @@ def exists(self) -> "Exists": """ return Exists(self) - def sum(self) -> "Sum": + def sum(self) -> "Expr": """Creates an aggregation that calculates the sum of a numeric field across multiple stage inputs. Example: @@ -516,24 +516,24 @@ def sum(self) -> "Sum": >>> Field.of("orderAmount").sum().as_("totalRevenue") Returns: - A new `Accumulator` representing the 'sum' aggregation. + A new `AggregateFunction` representing the 'sum' aggregation. """ return Sum(self) - def avg(self) -> "Avg": + def average(self) -> "Expr": """Creates an aggregation that calculates the average (mean) of a numeric field across multiple stage inputs. Example: >>> # Calculate the average age of users - >>> Field.of("age").avg().as_("averageAge") + >>> Field.of("age").average().as_("averageAge") Returns: - A new `Accumulator` representing the 'avg' aggregation. + A new `AggregateFunction` representing the 'avg' aggregation. """ - return Avg(self) + return Average(self) - def count(self) -> "Count": + def count(self) -> "Expr": """Creates an aggregation that counts the number of stage inputs with valid evaluations of the expression or field. @@ -542,35 +542,35 @@ def count(self) -> "Count": >>> Field.of("productId").count().as_("totalProducts") Returns: - A new `Accumulator` representing the 'count' aggregation. + A new `AggregateFunction` representing the 'count' aggregation. """ return Count(self) - def min(self) -> "Min": + def minimum(self) -> "Expr": """Creates an aggregation that finds the minimum value of a field across multiple stage inputs. Example: >>> # Find the lowest price of all products - >>> Field.of("price").min().as_("lowestPrice") + >>> Field.of("price").minimum().as_("lowestPrice") Returns: - A new `Accumulator` representing the 'min' aggregation. + A new `AggregateFunction` representing the 'minimum' aggregation. """ return Min(self) - def max(self) -> "Max": + def maxiumum(self) -> "Expr": """Creates an aggregation that finds the maximum value of a field across multiple stage inputs. Example: >>> # Find the highest score in a leaderboard - >>> Field.of("score").max().as_("highestScore") + >>> Field.of("score").maxiumum().as_("highestScore") Returns: - A new `Accumulator` representing the 'max' aggregation. + A new `AggregateFunction` representing the 'max' aggregation. """ return Max(self) - def char_length(self) -> "CharLength": + def char_length(self) -> "Expr": """Creates an expression that calculates the character length of a string. Example: @@ -582,7 +582,7 @@ def char_length(self) -> "CharLength": """ return CharLength(self) - def byte_length(self) -> "ByteLength": + def byte_length(self) -> "Expr": """Creates an expression that calculates the byte length of a string in its UTF-8 form. Example: @@ -594,7 +594,7 @@ def byte_length(self) -> "ByteLength": """ return ByteLength(self) - def like(self, pattern: Expr | str) -> "Like": + def like(self, pattern: Expr | str) -> "BooleanExpr": """Creates an expression that performs a case-sensitive string comparison. Example: @@ -611,7 +611,7 @@ def like(self, pattern: Expr | str) -> "Like": """ return Like(self, self._cast_to_expr_or_convert_to_constant(pattern)) - def regex_contains(self, regex: Expr | str) -> "RegexContains": + def regex_contains(self, regex: Expr | str) -> "BooleanExpr": """Creates an expression that checks if a string contains a specified regular expression as a substring. @@ -629,7 +629,7 @@ def regex_contains(self, regex: Expr | str) -> "RegexContains": """ return RegexContains(self, self._cast_to_expr_or_convert_to_constant(regex)) - def regex_matches(self, regex: Expr | str) -> "RegexMatch": + def regex_matches(self, regex: Expr | str) -> "BooleanExpr": """Creates an expression that checks if a string matches a specified regular expression. Example: @@ -646,14 +646,14 @@ def regex_matches(self, regex: Expr | str) -> "RegexMatch": """ return RegexMatch(self, self._cast_to_expr_or_convert_to_constant(regex)) - def str_contains(self, substring: Expr | str) -> "StrContains": + def string_contains(self, substring: Expr | str) -> "BooleanExpr": """Creates an expression that checks if this string expression contains a specified substring. Example: >>> # Check if the 'description' field contains "example". - >>> Field.of("description").str_contains("example") + >>> Field.of("description").string_contains("example") >>> # Check if the 'description' field contains the value of the 'keyword' field. - >>> Field.of("description").str_contains(Field.of("keyword")) + >>> Field.of("description").string_contains(Field.of("keyword")) Args: substring: The substring (string or expression) to use for the search. @@ -661,9 +661,9 @@ def str_contains(self, substring: Expr | str) -> "StrContains": Returns: A new `Expr` representing the 'contains' comparison. """ - return StrContains(self, self._cast_to_expr_or_convert_to_constant(substring)) + return StringContains(self, self._cast_to_expr_or_convert_to_constant(substring)) - def starts_with(self, prefix: Expr | str) -> "StartsWith": + def starts_with(self, prefix: Expr | str) -> "BooleanExpr": """Creates an expression that checks if a string starts with a given prefix. Example: @@ -680,7 +680,7 @@ def starts_with(self, prefix: Expr | str) -> "StartsWith": """ return StartsWith(self, self._cast_to_expr_or_convert_to_constant(prefix)) - def ends_with(self, postfix: Expr | str) -> "EndsWith": + def ends_with(self, postfix: Expr | str) -> "BooleanExpr": """Creates an expression that checks if a string ends with a given postfix. Example: @@ -697,12 +697,12 @@ def ends_with(self, postfix: Expr | str) -> "EndsWith": """ return EndsWith(self, self._cast_to_expr_or_convert_to_constant(postfix)) - def str_concat(self, *elements: Expr | CONSTANT_TYPE) -> "StrConcat": + def string_concat(self, *elements: Expr | CONSTANT_TYPE) -> "Expr": """Creates an expression that concatenates string expressions, fields or constants together. Example: >>> # Combine the 'firstName', " ", and 'lastName' fields into a single string - >>> Field.of("firstName").str_concat(" ", Field.of("lastName")) + >>> Field.of("firstName").string_concat(" ", Field.of("lastName")) Args: *elements: The expressions or constants (typically strings) to concatenate. @@ -710,11 +710,11 @@ def str_concat(self, *elements: Expr | CONSTANT_TYPE) -> "StrConcat": Returns: A new `Expr` representing the concatenated string. """ - return StrConcat( + return StringConcat( self, *[self._cast_to_expr_or_convert_to_constant(el) for el in elements] ) - def to_lower(self) -> "ToLower": + def to_lower(self) -> "Expr": """Creates an expression that converts a string to lowercase. Example: @@ -726,7 +726,7 @@ def to_lower(self) -> "ToLower": """ return ToLower(self) - def to_upper(self) -> "ToUpper": + def to_upper(self) -> "Expr": """Creates an expression that converts a string to uppercase. Example: @@ -738,7 +738,7 @@ def to_upper(self) -> "ToUpper": """ return ToUpper(self) - def trim(self) -> "Trim": + def trim(self) -> "Expr": """Creates an expression that removes leading and trailing whitespace from a string. Example: @@ -750,7 +750,7 @@ def trim(self) -> "Trim": """ return Trim(self) - def reverse(self) -> "Reverse": + def reverse(self) -> "Expr": """Creates an expression that reverses a string. Example: @@ -762,7 +762,7 @@ def reverse(self) -> "Reverse": """ return Reverse(self) - def replace_first(self, find: Expr | str, replace: Expr | str) -> "ReplaceFirst": + def replace_first(self, find: Expr | str, replace: Expr | str) -> "Expr": """Creates an expression that replaces the first occurrence of a substring within a string with another substring. @@ -785,7 +785,7 @@ def replace_first(self, find: Expr | str, replace: Expr | str) -> "ReplaceFirst" self._cast_to_expr_or_convert_to_constant(replace), ) - def replace_all(self, find: Expr | str, replace: Expr | str) -> "ReplaceAll": + def replace_all(self, find: Expr | str, replace: Expr | str) -> "Expr": """Creates an expression that replaces all occurrences of a substring within a string with another substring. @@ -808,7 +808,7 @@ def replace_all(self, find: Expr | str, replace: Expr | str) -> "ReplaceAll": self._cast_to_expr_or_convert_to_constant(replace), ) - def map_get(self, key: str) -> "MapGet": + def map_get(self, key: str) -> "Expr": """Accesses a value from a map (object) field using the provided key. Example: @@ -824,7 +824,7 @@ def map_get(self, key: str) -> "MapGet": """ return MapGet(self, Constant.of(key)) - def cosine_distance(self, other: Expr | list[float] | Vector) -> "CosineDistance": + def cosine_distance(self, other: Expr | list[float] | Vector) -> "Expr": """Calculates the cosine distance between two vectors. Example: @@ -843,7 +843,7 @@ def cosine_distance(self, other: Expr | list[float] | Vector) -> "CosineDistance def euclidean_distance( self, other: Expr | list[float] | Vector - ) -> "EuclideanDistance": + ) -> "Expr": """Calculates the Euclidean distance between two vectors. Example: @@ -860,7 +860,7 @@ def euclidean_distance( """ return EuclideanDistance(self, self._cast_to_expr_or_convert_to_constant(other)) - def dot_product(self, other: Expr | list[float] | Vector) -> "DotProduct": + def dot_product(self, other: Expr | list[float] | Vector) -> "Expr": """Calculates the dot product between two vectors. Example: @@ -877,7 +877,7 @@ def dot_product(self, other: Expr | list[float] | Vector) -> "DotProduct": """ return DotProduct(self, self._cast_to_expr_or_convert_to_constant(other)) - def vector_length(self) -> "VectorLength": + def vector_length(self) -> "Expr": """Creates an expression that calculates the length (dimension) of a Firestore Vector. Example: @@ -889,7 +889,7 @@ def vector_length(self) -> "VectorLength": """ return VectorLength(self) - def timestamp_to_unix_micros(self) -> "TimestampToUnixMicros": + def timestamp_to_unix_micros(self) -> "Expr": """Creates an expression that converts a timestamp to the number of microseconds since the epoch (1970-01-01 00:00:00 UTC). @@ -904,7 +904,7 @@ def timestamp_to_unix_micros(self) -> "TimestampToUnixMicros": """ return TimestampToUnixMicros(self) - def unix_micros_to_timestamp(self) -> "UnixMicrosToTimestamp": + def unix_micros_to_timestamp(self) -> "Expr": """Creates an expression that converts a number of microseconds since the epoch (1970-01-01 00:00:00 UTC) to a timestamp. @@ -917,7 +917,7 @@ def unix_micros_to_timestamp(self) -> "UnixMicrosToTimestamp": """ return UnixMicrosToTimestamp(self) - def timestamp_to_unix_millis(self) -> "TimestampToUnixMillis": + def timestamp_to_unix_millis(self) -> "Expr": """Creates an expression that converts a timestamp to the number of milliseconds since the epoch (1970-01-01 00:00:00 UTC). @@ -932,7 +932,7 @@ def timestamp_to_unix_millis(self) -> "TimestampToUnixMillis": """ return TimestampToUnixMillis(self) - def unix_millis_to_timestamp(self) -> "UnixMillisToTimestamp": + def unix_millis_to_timestamp(self) -> "Expr": """Creates an expression that converts a number of milliseconds since the epoch (1970-01-01 00:00:00 UTC) to a timestamp. @@ -945,7 +945,7 @@ def unix_millis_to_timestamp(self) -> "UnixMillisToTimestamp": """ return UnixMillisToTimestamp(self) - def timestamp_to_unix_seconds(self) -> "TimestampToUnixSeconds": + def timestamp_to_unix_seconds(self) -> "Expr": """Creates an expression that converts a timestamp to the number of seconds since the epoch (1970-01-01 00:00:00 UTC). @@ -960,7 +960,7 @@ def timestamp_to_unix_seconds(self) -> "TimestampToUnixSeconds": """ return TimestampToUnixSeconds(self) - def unix_seconds_to_timestamp(self) -> "UnixSecondsToTimestamp": + def unix_seconds_to_timestamp(self) -> "Expr": """Creates an expression that converts a number of seconds since the epoch (1970-01-01 00:00:00 UTC) to a timestamp. @@ -973,7 +973,7 @@ def unix_seconds_to_timestamp(self) -> "UnixSecondsToTimestamp": """ return UnixSecondsToTimestamp(self) - def timestamp_add(self, unit: Expr | str, amount: Expr | float) -> "TimestampAdd": + def timestamp_add(self, unit: Expr | str, amount: Expr | float) -> "Expr": """Creates an expression that adds a specified amount of time to this timestamp expression. Example: @@ -996,14 +996,14 @@ def timestamp_add(self, unit: Expr | str, amount: Expr | float) -> "TimestampAdd self._cast_to_expr_or_convert_to_constant(amount), ) - def timestamp_sub(self, unit: Expr | str, amount: Expr | float) -> "TimestampSub": + def timestamp_subtract(self, unit: Expr | str, amount: Expr | float) -> "Expr": """Creates an expression that subtracts a specified amount of time from this timestamp expression. Example: >>> # Subtract a duration specified by the 'unit' and 'amount' fields from the 'timestamp' field. - >>> Field.of("timestamp").timestamp_sub(Field.of("unit"), Field.of("amount")) + >>> Field.of("timestamp").timestamp_subtract(Field.of("unit"), Field.of("amount")) >>> # Subtract 2.5 hours from the 'timestamp' field. - >>> Field.of("timestamp").timestamp_sub("hour", 2.5) + >>> Field.of("timestamp").timestamp_subtract("hour", 2.5) Args: unit: The expression or string evaluating to the unit of time to subtract, must be one of @@ -1013,7 +1013,7 @@ def timestamp_sub(self, unit: Expr | str, amount: Expr | float) -> "TimestampSub Returns: A new `Expr` representing the resulting timestamp. """ - return TimestampSub( + return TimestampSubtract( self, self._cast_to_expr_or_convert_to_constant(unit), self._cast_to_expr_or_convert_to_constant(amount), @@ -1043,7 +1043,7 @@ def descending(self) -> Ordering: """ return Ordering(self, Ordering.Direction.DESCENDING) - def as_(self, alias: str) -> "ExprWithAlias": + def as_(self, alias: str) -> "AliasedExpr": """Assigns an alias to this expression. Aliases are useful for renaming fields in the output of a stage or for giving meaningful @@ -1059,10 +1059,10 @@ def as_(self, alias: str) -> "ExprWithAlias": alias: The alias to assign to this expression. Returns: - A new `Selectable` (typically an `ExprWithAlias`) that wraps this + A new `Selectable` (typically an `AliasedExpr`) that wraps this expression and associates it with the provided alias. """ - return ExprWithAlias(self, alias) + return AliasedExpr(self, alias) class Constant(Expr, Generic[CONSTANT_TYPE]): @@ -1132,7 +1132,7 @@ def _to_pb(self): } ) - def add(left: Expr | str, right: Expr | float) -> "Add": + def add(left: Expr | str, right: Expr | float) -> "Expr": """Creates an expression that adds two expressions together. Example: @@ -1149,7 +1149,7 @@ def add(left: Expr | str, right: Expr | float) -> "Add": left_expr = Field.of(left) if isinstance(left, str) else left return Expr.add(left_expr, right) - def subtract(left: Expr | str, right: Expr | float) -> "Subtract": + def subtract(left: Expr | str, right: Expr | float) -> "Expr": """Creates an expression that subtracts another expression or constant from this expression. Example: @@ -1166,7 +1166,7 @@ def subtract(left: Expr | str, right: Expr | float) -> "Subtract": left_expr = Field.of(left) if isinstance(left, str) else left return Expr.subtract(left_expr, right) - def multiply(left: Expr | str, right: Expr | float) -> "Multiply": + def multiply(left: Expr | str, right: Expr | float) -> "Expr": """Creates an expression that multiplies this expression by another expression or constant. Example: @@ -1183,7 +1183,7 @@ def multiply(left: Expr | str, right: Expr | float) -> "Multiply": left_expr = Field.of(left) if isinstance(left, str) else left return Expr.multiply(left_expr, right) - def divide(left: Expr | str, right: Expr | float) -> "Divide": + def divide(left: Expr | str, right: Expr | float) -> "Expr": """Creates an expression that divides this expression by another expression or constant. Example: @@ -1200,7 +1200,7 @@ def divide(left: Expr | str, right: Expr | float) -> "Divide": left_expr = Field.of(left) if isinstance(left, str) else left return Expr.divide(left_expr, right) - def mod(left: Expr | str, right: Expr | float) -> "Mod": + def mod(left: Expr | str, right: Expr | float) -> "Expr": """Creates an expression that calculates the modulo (remainder) to another expression or constant. Example: @@ -1217,7 +1217,7 @@ def mod(left: Expr | str, right: Expr | float) -> "Mod": left_expr = Field.of(left) if isinstance(left, str) else left return Expr.mod(left_expr, right) - def logical_max(left: Expr | str, right: Expr | CONSTANT_TYPE) -> "LogicalMax": + def logical_maximum(left: Expr | str, right: Expr | CONSTANT_TYPE) -> "Expr": """Creates an expression that returns the larger value between this expression and another expression or constant, based on Firestore's value type ordering. @@ -1225,8 +1225,8 @@ def logical_max(left: Expr | str, right: Expr | CONSTANT_TYPE) -> "LogicalMax": https://cloud.google.com/firestore/docs/concepts/data-types#value_type_ordering Example: - >>> Function.logical_max("value", 10) - >>> Function.logical_max(Field.of("discount"), Field.of("cap")) + >>> Function.logical_maximum("value", 10) + >>> Function.logical_maximum(Field.of("discount"), Field.of("cap")) Args: left: The expression or field path to compare. @@ -1236,9 +1236,9 @@ def logical_max(left: Expr | str, right: Expr | CONSTANT_TYPE) -> "LogicalMax": A new `Expr` representing the logical max operation. """ left_expr = Field.of(left) if isinstance(left, str) else left - return Expr.logical_max(left_expr, right) + return Expr.logical_maximum(left_expr, right) - def logical_min(left: Expr | str, right: Expr | CONSTANT_TYPE) -> "LogicalMin": + def logical_minimum(left: Expr | str, right: Expr | CONSTANT_TYPE) -> "Expr": """Creates an expression that returns the smaller value between this expression and another expression or constant, based on Firestore's value type ordering. @@ -1246,26 +1246,26 @@ def logical_min(left: Expr | str, right: Expr | CONSTANT_TYPE) -> "LogicalMin": https://cloud.google.com/firestore/docs/concepts/data-types#value_type_ordering Example: - >>> Function.logical_min("value", 10) - >>> Function.logical_min(Field.of("discount"), Field.of("floor")) + >>> Function.logical_minimum("value", 10) + >>> Function.logical_minimum(Field.of("discount"), Field.of("floor")) Args: left: The expression or field path to compare. right: The other expression or constant value to compare with. Returns: - A new `Expr` representing the logical min operation. + A new `Expr` representing the logical minimum operation. """ left_expr = Field.of(left) if isinstance(left, str) else left - return Expr.logical_min(left_expr, right) + return Expr.logical_minimum(left_expr, right) - def eq(left: Expr | str, right: Expr | CONSTANT_TYPE) -> "Eq": + def equal(left: Expr | str, right: Expr | CONSTANT_TYPE) -> "BooleanExpr": """Creates an expression that checks if this expression is equal to another expression or constant value. Example: - >>> Function.eq("city", "London") - >>> Function.eq(Field.of("age"), 21) + >>> Function.equal("city", "London") + >>> Function.equal(Field.of("age"), 21) Args: left: The expression or field path to compare. @@ -1275,15 +1275,15 @@ def eq(left: Expr | str, right: Expr | CONSTANT_TYPE) -> "Eq": A new `Expr` representing the equality comparison. """ left_expr = Field.of(left) if isinstance(left, str) else left - return Expr.eq(left_expr, right) + return Expr.equal(left_expr, right) - def neq(left: Expr | str, right: Expr | CONSTANT_TYPE) -> "Neq": + def not_equal(left: Expr | str, right: Expr | CONSTANT_TYPE) -> "BooleanExpr": """Creates an expression that checks if this expression is not equal to another expression or constant value. Example: - >>> Function.neq("country", "USA") - >>> Function.neq(Field.of("status"), "completed") + >>> Function.not_equal("country", "USA") + >>> Function.not_equal(Field.of("status"), "completed") Args: left: The expression or field path to compare. @@ -1293,15 +1293,15 @@ def neq(left: Expr | str, right: Expr | CONSTANT_TYPE) -> "Neq": A new `Expr` representing the inequality comparison. """ left_expr = Field.of(left) if isinstance(left, str) else left - return Expr.neq(left_expr, right) + return Expr.not_equal(left_expr, right) - def gt(left: Expr | str, right: Expr | CONSTANT_TYPE) -> "Gt": + def greater_than(left: Expr | str, right: Expr | CONSTANT_TYPE) -> "BooleanExpr": """Creates an expression that checks if this expression is greater than another expression or constant value. Example: - >>> Function.gt("price", 100) - >>> Function.gt(Field.of("age"), Field.of("limit")) + >>> Function.greater_than("price", 100) + >>> Function.greater_than(Field.of("age"), Field.of("limit")) Args: left: The expression or field path to compare. @@ -1311,15 +1311,15 @@ def gt(left: Expr | str, right: Expr | CONSTANT_TYPE) -> "Gt": A new `Expr` representing the greater than comparison. """ left_expr = Field.of(left) if isinstance(left, str) else left - return Expr.gt(left_expr, right) + return Expr.greater_than(left_expr, right) - def gte(left: Expr | str, right: Expr | CONSTANT_TYPE) -> "Gte": + def greater_than_or_equal(left: Expr | str, right: Expr | CONSTANT_TYPE) -> "BooleanExpr": """Creates an expression that checks if this expression is greater than or equal to another expression or constant value. Example: - >>> Function.gte("score", 80) - >>> Function.gte(Field.of("quantity"), Field.of('requirement').add(1)) + >>> Function.greater_than_or_equal("score", 80) + >>> Function.greater_than_or_equal(Field.of("quantity"), Field.of('requirement').add(1)) Args: left: The expression or field path to compare. @@ -1329,15 +1329,15 @@ def gte(left: Expr | str, right: Expr | CONSTANT_TYPE) -> "Gte": A new `Expr` representing the greater than or equal to comparison. """ left_expr = Field.of(left) if isinstance(left, str) else left - return Expr.gte(left_expr, right) + return Expr.greater_than_or_equal(left_expr, right) - def lt(left: Expr | str, right: Expr | CONSTANT_TYPE) -> "Lt": + def less_than(left: Expr | str, right: Expr | CONSTANT_TYPE) -> "BooleanExpr": """Creates an expression that checks if this expression is less than another expression or constant value. Example: - >>> Function.lt("price", 50) - >>> Function.lt(Field.of("age"), Field.of('limit')) + >>> Function.less_than("price", 50) + >>> Function.less_than(Field.of("age"), Field.of('limit')) Args: left: The expression or field path to compare. @@ -1347,15 +1347,15 @@ def lt(left: Expr | str, right: Expr | CONSTANT_TYPE) -> "Lt": A new `Expr` representing the less than comparison. """ left_expr = Field.of(left) if isinstance(left, str) else left - return Expr.lt(left_expr, right) + return Expr.less_than(left_expr, right) - def lte(left: Expr | str, right: Expr | CONSTANT_TYPE) -> "Lte": + def less_than_or_equal(left: Expr | str, right: Expr | CONSTANT_TYPE) -> "BooleanExpr": """Creates an expression that checks if this expression is less than or equal to another expression or constant value. Example: - >>> Function.lte("score", 70) - >>> Function.lte(Field.of("quantity"), Constant.of(20)) + >>> Function.less_than_or_equal("score", 70) + >>> Function.less_than_or_equal(Field.of("quantity"), Constant.of(20)) Args: left: The expression or field path to compare. @@ -1365,9 +1365,9 @@ def lte(left: Expr | str, right: Expr | CONSTANT_TYPE) -> "Lte": A new `Expr` representing the less than or equal to comparison. """ left_expr = Field.of(left) if isinstance(left, str) else left - return Expr.lte(left_expr, right) + return Expr.less_than_or_equal(left_expr, right) - def in_any(left: Expr | str, array: List[Expr | CONSTANT_TYPE]) -> "In": + def in_any(left: Expr | str, array: List[Expr | CONSTANT_TYPE]) -> "BooleanExpr": """Creates an expression that checks if this expression is equal to any of the provided values or expressions. @@ -1385,7 +1385,7 @@ def in_any(left: Expr | str, array: List[Expr | CONSTANT_TYPE]) -> "In": left_expr = Field.of(left) if isinstance(left, str) else left return Expr.in_any(left_expr, array) - def not_in_any(left: Expr | str, array: List[Expr | CONSTANT_TYPE]) -> "Not": + def not_in_any(left: Expr | str, array: List[Expr | CONSTANT_TYPE]) -> "BooleanExpr": """Creates an expression that checks if this expression is not equal to any of the provided values or expressions. @@ -1404,7 +1404,7 @@ def not_in_any(left: Expr | str, array: List[Expr | CONSTANT_TYPE]) -> "Not": def array_contains( array: Expr | str, element: Expr | CONSTANT_TYPE - ) -> "ArrayContains": + ) -> "BooleanExpr": """Creates an expression that checks if an array contains a specific element or value. Example: @@ -1423,7 +1423,7 @@ def array_contains( def array_contains_all( array: Expr | str, elements: List[Expr | CONSTANT_TYPE] - ) -> "ArrayContainsAll": + ) -> "BooleanExpr": """Creates an expression that checks if an array contains all the specified elements. Example: @@ -1442,7 +1442,7 @@ def array_contains_all( def array_contains_any( array: Expr | str, elements: List[Expr | CONSTANT_TYPE] - ) -> "ArrayContainsAny": + ) -> "BooleanExpr": """Creates an expression that checks if an array contains any of the specified elements. Example: @@ -1459,7 +1459,7 @@ def array_contains_any( array_expr = Field.of(array) if isinstance(array, str) else array return Expr.array_contains_any(array_expr, elements) - def array_length(array: Expr | str) -> "ArrayLength": + def array_length(array: Expr | str) -> "Expr": """Creates an expression that calculates the length of an array. Example: @@ -1471,7 +1471,7 @@ def array_length(array: Expr | str) -> "ArrayLength": array_expr = Field.of(array) if isinstance(array, str) else array return Expr.array_length(array_expr) - def array_reverse(array: Expr | str) -> "ArrayReverse": + def array_reverse(array: Expr | str) -> "Expr": """Creates an expression that returns the reversed content of an array. Example: @@ -1483,7 +1483,7 @@ def array_reverse(array: Expr | str) -> "ArrayReverse": array_expr = Field.of(array) if isinstance(array, str) else array return Expr.array_reverse(array_expr) - def is_nan(expr: Expr | str) -> "IsNaN": + def is_nan(expr: Expr | str) -> "BooleanExpr": """Creates an expression that checks if this expression evaluates to 'NaN' (Not a Number). Example: @@ -1495,7 +1495,7 @@ def is_nan(expr: Expr | str) -> "IsNaN": expr_val = Field.of(expr) if isinstance(expr, str) else expr return Expr.is_nan(expr_val) - def exists(expr: Expr | str) -> "Exists": + def exists(expr: Expr | str) -> "BooleanExpr": """Creates an expression that checks if a field exists in the document. Example: @@ -1507,32 +1507,32 @@ def exists(expr: Expr | str) -> "Exists": expr_val = Field.of(expr) if isinstance(expr, str) else expr return Expr.exists(expr_val) - def sum(expr: Expr | str) -> "Sum": + def sum(expr: Expr | str) -> "Expr": """Creates an aggregation that calculates the sum of a numeric field across multiple stage inputs. Example: >>> Function.sum("orderAmount") Returns: - A new `Accumulator` representing the 'sum' aggregation. + A new `AggregateFunction` representing the 'sum' aggregation. """ expr_val = Field.of(expr) if isinstance(expr, str) else expr return Expr.sum(expr_val) - def avg(expr: Expr | str) -> "Avg": + def average(expr: Expr | str) -> "Expr": """Creates an aggregation that calculates the average (mean) of a numeric field across multiple stage inputs. Example: - >>> Function.avg("age") + >>> Function.average("age") Returns: - A new `Accumulator` representing the 'avg' aggregation. + A new `AggregateFunction` representing the 'average' aggregation. """ expr_val = Field.of(expr) if isinstance(expr, str) else expr - return Expr.avg(expr_val) + return Expr.average(expr_val) - def count(expr: Expr | str | None = None) -> "Count": + def count(expr: Expr | str | None = None) -> "Expr": """Creates an aggregation that counts the number of stage inputs with valid evaluations of the expression or field. If no expression is provided, it counts all inputs. @@ -1541,38 +1541,38 @@ def count(expr: Expr | str | None = None) -> "Count": >>> Function.count() Returns: - A new `Accumulator` representing the 'count' aggregation. + A new `AggregateFunction` representing the 'count' aggregation. """ if expr is None: return Count() expr_val = Field.of(expr) if isinstance(expr, str) else expr return Expr.count(expr_val) - def min(expr: Expr | str) -> "Min": + def minimum(expr: Expr | str) -> "Expr": """Creates an aggregation that finds the minimum value of a field across multiple stage inputs. Example: - >>> Function.min("price") + >>> Function.minimum("price") Returns: - A new `Accumulator` representing the 'min' aggregation. + A new `AggregateFunction` representing the 'minimum' aggregation. """ expr_val = Field.of(expr) if isinstance(expr, str) else expr - return Expr.min(expr_val) + return Expr.minimum(expr_val) - def max(expr: Expr | str) -> "Max": + def maxiumum(expr: Expr | str) -> "Expr": """Creates an aggregation that finds the maximum value of a field across multiple stage inputs. Example: - >>> Function.max("score") + >>> Function.maxiumum("score") Returns: - A new `Accumulator` representing the 'max' aggregation. + A new `AggregateFunction` representing the 'maximum' aggregation. """ expr_val = Field.of(expr) if isinstance(expr, str) else expr - return Expr.max(expr_val) + return Expr.maxiumum(expr_val) - def char_length(expr: Expr | str) -> "CharLength": + def char_length(expr: Expr | str) -> "Expr": """Creates an expression that calculates the character length of a string. Example: @@ -1584,7 +1584,7 @@ def char_length(expr: Expr | str) -> "CharLength": expr_val = Field.of(expr) if isinstance(expr, str) else expr return Expr.char_length(expr_val) - def byte_length(expr: Expr | str) -> "ByteLength": + def byte_length(expr: Expr | str) -> "Expr": """Creates an expression that calculates the byte length of a string in its UTF-8 form. Example: @@ -1596,7 +1596,7 @@ def byte_length(expr: Expr | str) -> "ByteLength": expr_val = Field.of(expr) if isinstance(expr, str) else expr return Expr.byte_length(expr_val) - def like(expr: Expr | str, pattern: Expr | str) -> "Like": + def like(expr: Expr | str, pattern: Expr | str) -> "BooleanExpr": """Creates an expression that performs a case-sensitive string comparison. Example: @@ -1613,7 +1613,7 @@ def like(expr: Expr | str, pattern: Expr | str) -> "Like": expr_val = Field.of(expr) if isinstance(expr, str) else expr return Expr.like(expr_val, pattern) - def regex_contains(expr: Expr | str, regex: Expr | str) -> "RegexContains": + def regex_contains(expr: Expr | str, regex: Expr | str) -> "BooleanExpr": """Creates an expression that checks if a string contains a specified regular expression as a substring. @@ -1631,7 +1631,7 @@ def regex_contains(expr: Expr | str, regex: Expr | str) -> "RegexContains": expr_val = Field.of(expr) if isinstance(expr, str) else expr return Expr.regex_contains(expr_val, regex) - def regex_matches(expr: Expr | str, regex: Expr | str) -> "RegexMatch": + def regex_matches(expr: Expr | str, regex: Expr | str) -> "BooleanExpr": """Creates an expression that checks if a string matches a specified regular expression. Example: @@ -1649,12 +1649,12 @@ def regex_matches(expr: Expr | str, regex: Expr | str) -> "RegexMatch": expr_val = Field.of(expr) if isinstance(expr, str) else expr return Expr.regex_matches(expr_val, regex) - def str_contains(expr: Expr | str, substring: Expr | str) -> "StrContains": + def string_contains(expr: Expr | str, substring: Expr | str) -> "BooleanExpr": """Creates an expression that checks if this string expression contains a specified substring. Example: - >>> Function.str_contains("description", "example") - >>> Function.str_contains(Field.of("description"), Field.of("keyword")) + >>> Function.string_contains("description", "example") + >>> Function.string_contains(Field.of("description"), Field.of("keyword")) Args: expr: The expression or field path to perform the comparison on. @@ -1664,9 +1664,9 @@ def str_contains(expr: Expr | str, substring: Expr | str) -> "StrContains": A new `Expr` representing the 'contains' comparison. """ expr_val = Field.of(expr) if isinstance(expr, str) else expr - return Expr.str_contains(expr_val, substring) + return Expr.string_contains(expr_val, substring) - def starts_with(expr: Expr | str, prefix: Expr | str) -> "StartsWith": + def starts_with(expr: Expr | str, prefix: Expr | str) -> "BooleanExpr": """Creates an expression that checks if a string starts with a given prefix. Example: @@ -1683,7 +1683,7 @@ def starts_with(expr: Expr | str, prefix: Expr | str) -> "StartsWith": expr_val = Field.of(expr) if isinstance(expr, str) else expr return Expr.starts_with(expr_val, prefix) - def ends_with(expr: Expr | str, postfix: Expr | str) -> "EndsWith": + def ends_with(expr: Expr | str, postfix: Expr | str) -> "BooleanExpr": """Creates an expression that checks if a string ends with a given postfix. Example: @@ -1700,11 +1700,11 @@ def ends_with(expr: Expr | str, postfix: Expr | str) -> "EndsWith": expr_val = Field.of(expr) if isinstance(expr, str) else expr return Expr.ends_with(expr_val, postfix) - def str_concat(first: Expr | str, *elements: Expr | CONSTANT_TYPE) -> "StrConcat": + def string_concat(first: Expr | str, *elements: Expr | CONSTANT_TYPE) -> "Expr": """Creates an expression that concatenates string expressions, fields or constants together. Example: - >>> Function.str_concat("firstName", " ", Field.of("lastName")) + >>> Function.string_concat("firstName", " ", Field.of("lastName")) Args: first: The first expression or field path to concatenate. @@ -1714,9 +1714,9 @@ def str_concat(first: Expr | str, *elements: Expr | CONSTANT_TYPE) -> "StrConcat A new `Expr` representing the concatenated string. """ first_expr = Field.of(first) if isinstance(first, str) else first - return Expr.str_concat(first_expr, *elements) + return Expr.string_concat(first_expr, *elements) - def map_get(map_expr: Expr | str, key: str) -> "MapGet": + def map_get(map_expr: Expr | str, key: str) -> "Expr": """Accesses a value from a map (object) field using the provided key. Example: @@ -1732,7 +1732,7 @@ def map_get(map_expr: Expr | str, key: str) -> "MapGet": map_val = Field.of(map_expr) if isinstance(map_expr, str) else map_expr return Expr.map_get(map_val, key) - def vector_length(vector_expr: Expr | str) -> "VectorLength": + def vector_length(vector_expr: Expr | str) -> "Expr": """Creates an expression that calculates the length (dimension) of a Firestore Vector. Example: @@ -1746,7 +1746,7 @@ def vector_length(vector_expr: Expr | str) -> "VectorLength": ) return Expr.vector_length(vector_val) - def timestamp_to_unix_micros(timestamp_expr: Expr | str) -> "TimestampToUnixMicros": + def timestamp_to_unix_micros(timestamp_expr: Expr | str) -> "Expr": """Creates an expression that converts a timestamp to the number of microseconds since the epoch (1970-01-01 00:00:00 UTC). @@ -1765,7 +1765,7 @@ def timestamp_to_unix_micros(timestamp_expr: Expr | str) -> "TimestampToUnixMicr ) return Expr.timestamp_to_unix_micros(timestamp_val) - def unix_micros_to_timestamp(micros_expr: Expr | str) -> "UnixMicrosToTimestamp": + def unix_micros_to_timestamp(micros_expr: Expr | str) -> "Expr": """Creates an expression that converts a number of microseconds since the epoch (1970-01-01 00:00:00 UTC) to a timestamp. @@ -1780,7 +1780,7 @@ def unix_micros_to_timestamp(micros_expr: Expr | str) -> "UnixMicrosToTimestamp" ) return Expr.unix_micros_to_timestamp(micros_val) - def timestamp_to_unix_millis(timestamp_expr: Expr | str) -> "TimestampToUnixMillis": + def timestamp_to_unix_millis(timestamp_expr: Expr | str) -> "Expr": """Creates an expression that converts a timestamp to the number of milliseconds since the epoch (1970-01-01 00:00:00 UTC). @@ -1799,7 +1799,7 @@ def timestamp_to_unix_millis(timestamp_expr: Expr | str) -> "TimestampToUnixMill ) return Expr.timestamp_to_unix_millis(timestamp_val) - def unix_millis_to_timestamp(millis_expr: Expr | str) -> "UnixMillisToTimestamp": + def unix_millis_to_timestamp(millis_expr: Expr | str) -> "Expr": """Creates an expression that converts a number of milliseconds since the epoch (1970-01-01 00:00:00 UTC) to a timestamp. @@ -1816,7 +1816,7 @@ def unix_millis_to_timestamp(millis_expr: Expr | str) -> "UnixMillisToTimestamp" def timestamp_to_unix_seconds( timestamp_expr: Expr | str, - ) -> "TimestampToUnixSeconds": + ) -> "Expr": """Creates an expression that converts a timestamp to the number of seconds since the epoch (1970-01-01 00:00:00 UTC). @@ -1835,7 +1835,7 @@ def timestamp_to_unix_seconds( ) return Expr.timestamp_to_unix_seconds(timestamp_val) - def unix_seconds_to_timestamp(seconds_expr: Expr | str) -> "UnixSecondsToTimestamp": + def unix_seconds_to_timestamp(seconds_expr: Expr | str) -> "Expr": """Creates an expression that converts a number of seconds since the epoch (1970-01-01 00:00:00 UTC) to a timestamp. @@ -1852,7 +1852,7 @@ def unix_seconds_to_timestamp(seconds_expr: Expr | str) -> "UnixSecondsToTimesta def timestamp_add( timestamp: Expr | str, unit: Expr | str, amount: Expr | float - ) -> "TimestampAdd": + ) -> "Expr": """Creates an expression that adds a specified amount of time to this timestamp expression. Example: @@ -1875,7 +1875,7 @@ def timestamp_add( def timestamp_sub( timestamp: Expr | str, unit: Expr | str, amount: Expr | float - ) -> "TimestampSub": + ) -> "Expr": """Creates an expression that subtracts a specified amount of time from this timestamp expression. Example: @@ -1918,14 +1918,14 @@ def __init__(self, vector1: Expr, vector2: Expr): super().__init__("euclidean_distance", [vector1, vector2]) -class LogicalMax(Function): +class LogicalMaximum(Function): """Represents the logical maximum function based on Firestore type ordering.""" def __init__(self, left: Expr, right: Expr): super().__init__("logical_maximum", [left, right]) -class LogicalMin(Function): +class LogicalMinimum(Function): """Represents the logical minimum function based on Firestore type ordering.""" def __init__(self, left: Expr, right: Expr): @@ -1981,11 +1981,11 @@ def __init__(self, expr: Expr): super().__init__("reverse", [expr]) -class StrConcat(Function): +class StringConcat(Function): """Represents concatenating multiple strings.""" def __init__(self, *exprs: Expr): - super().__init__("str_concat", exprs) + super().__init__("string_concat", exprs) class Subtract(Function): @@ -2002,11 +2002,11 @@ def __init__(self, timestamp: Expr, unit: Expr, amount: Expr): super().__init__("timestamp_add", [timestamp, unit, amount]) -class TimestampSub(Function): +class TimestampSubtract(Function): """Represents subtracting a duration from a timestamp.""" def __init__(self, timestamp: Expr, unit: Expr, amount: Expr): - super().__init__("timestamp_sub", [timestamp, unit, amount]) + super().__init__("timestamp_subtract", [timestamp, unit, amount]) class TimestampToUnixMicros(Function): @@ -2103,7 +2103,7 @@ def __init__(self): class ArrayFilter(Function): """Represents filtering elements from an array based on a condition.""" - def __init__(self, array: Expr, filter: "FilterCondition"): + def __init__(self, array: Expr, filter: "BooleanExpr"): super().__init__("array_filter", [array, filter]) @@ -2156,39 +2156,54 @@ def __init__(self, vector1: Expr, vector2: Expr): super().__init__("cosine_distance", [vector1, vector2]) -class Accumulator(Function): +class AggregateFunction(Function): """A base class for aggregation functions that operate across multiple inputs.""" + def as_(self, alias: str) -> "AliasedAggregate": + """Assigns an alias to this expression. -class Max(Accumulator): + Aliases are useful for renaming fields in the output of a stage or for giving meaningful + names to calculated values. + + Args: + alias: The alias to assign to this expression. + + Returns: A new AliasedAggregate that wraps this expression and associates it with the + provided alias. + """ + return AliasedAggregate(self, alias) + + + +class Max(AggregateFunction): """Represents the maximum aggregation function.""" def __init__(self, value: Expr): super().__init__("maximum", [value]) -class Min(Accumulator): +class Min(AggregateFunction): """Represents the minimum aggregation function.""" def __init__(self, value: Expr): super().__init__("minimum", [value]) -class Sum(Accumulator): +class Sum(AggregateFunction): """Represents the sum aggregation function.""" def __init__(self, value: Expr): super().__init__("sum", [value]) -class Avg(Accumulator): +class Average(AggregateFunction): """Represents the average aggregation function.""" def __init__(self, value: Expr): super().__init__("avg", [value]) -class Count(Accumulator): +class Count(AggregateFunction): """Represents an aggregation that counts the total number of inputs.""" def __init__(self, value: Expr | None = None): @@ -2234,7 +2249,7 @@ def _to_value(field_list: Sequence[Selectable]) -> Value: T = TypeVar("T", bound=Expr) -class ExprWithAlias(Selectable, Generic[T]): +class AliasedExpr(Selectable, Generic[T]): """Wraps an expression with an alias.""" def __init__(self, expr: T, alias: str): @@ -2251,6 +2266,23 @@ def _to_pb(self): return Value(map_value={"fields": {self.alias: self.expr._to_pb()}}) +class AliasedAggregate: + """Wraps an aggregate with an alias""" + + def __init__(self, expr: AggregateFunction, alias: str): + self.expr = expr + self.alias = alias + + def _to_map(self): + return self.alias, self.expr._to_pb() + + def __repr__(self): + return f"{self.expr}.as_('{self.alias}')" + + def _to_pb(self): + return Value(map_value={"fields": {self.alias: self.expr._to_pb()}}) + + class Field(Selectable): """Represents a reference to a field within a document.""" @@ -2288,7 +2320,7 @@ def _to_pb(self): return Value(field_reference_value=self.path) -class FilterCondition(Function): +class BooleanExpr(Function): """Filters the given data in some way.""" def __init__( @@ -2304,7 +2336,7 @@ def __init__( def __repr__(self): """ - Most FilterConditions can be triggered infix. Eg: Field.of('age').gte(18). + Most BooleanExprs can be triggered infix. Eg: Field.of('age').gte(18). Display them this way in the repr string where possible """ @@ -2320,7 +2352,7 @@ def __repr__(self): def _from_query_filter_pb(filter_pb, client): if isinstance(filter_pb, Query_pb.CompositeFilter): sub_filters = [ - FilterCondition._from_query_filter_pb(f, client) + BooleanExpr._from_query_filter_pb(f, client) for f in filter_pb.filters ] if filter_pb.op == Query_pb.CompositeFilter.Operator.OR: @@ -2375,82 +2407,82 @@ def _from_query_filter_pb(filter_pb, client): or filter_pb.field_filter or filter_pb.unary_filter ) - return FilterCondition._from_query_filter_pb(f, client) + return BooleanExpr._from_query_filter_pb(f, client) else: raise TypeError(f"Unexpected filter type: {type(filter_pb)}") -class And(FilterCondition): - def __init__(self, *conditions: "FilterCondition"): +class And(BooleanExpr): + def __init__(self, *conditions: "BooleanExpr"): super().__init__("and", conditions, use_infix_repr=False) -class ArrayContains(FilterCondition): +class ArrayContains(BooleanExpr): def __init__(self, array: Expr, element: Expr): super().__init__( "array_contains", [array, element] ) -class ArrayContainsAll(FilterCondition): +class ArrayContainsAll(BooleanExpr): """Represents checking if an array contains all specified elements.""" def __init__(self, array: Expr, elements: Sequence[Expr]): super().__init__("array_contains_all", [array, ListOfExprs(elements)]) -class ArrayContainsAny(FilterCondition): +class ArrayContainsAny(BooleanExpr): """Represents checking if an array contains any of the specified elements.""" def __init__(self, array: Expr, elements: Sequence[Expr]): super().__init__("array_contains_any", [array, ListOfExprs(elements)]) -class EndsWith(FilterCondition): +class EndsWith(BooleanExpr): """Represents checking if a string ends with a specific postfix.""" def __init__(self, expr: Expr, postfix: Expr): super().__init__("ends_with", [expr, postfix]) -class Eq(FilterCondition): +class Equal(BooleanExpr): """Represents the equality comparison.""" def __init__(self, left: Expr, right: Expr): super().__init__("eq", [left, right]) -class Exists(FilterCondition): +class Exists(BooleanExpr): """Represents checking if a field exists.""" def __init__(self, expr: Expr): super().__init__("exists", [expr]) -class Gt(FilterCondition): +class GreaterThan(BooleanExpr): """Represents the greater than comparison.""" def __init__(self, left: Expr, right: Expr): - super().__init__("gt", [left, right]) + super().__init__("greater_than", [left, right]) -class Gte(FilterCondition): +class GreaterThanOrEqual(BooleanExpr): """Represents the greater than or equal to comparison.""" def __init__(self, left: Expr, right: Expr): - super().__init__("gte", [left, right]) + super().__init__("greater_than_or_equal", [left, right]) -class If(FilterCondition): +class If(BooleanExpr): """Represents a conditional expression (if-then-else).""" - def __init__(self, condition: "FilterCondition", true_expr: Expr, false_expr: Expr): + def __init__(self, condition: "BooleanExpr", true_expr: Expr, false_expr: Expr): super().__init__( "if", [condition, true_expr, false_expr] ) -class In(FilterCondition): +class In(BooleanExpr): """Represents checking if an expression's value is within a list of values.""" def __init__(self, left: Expr, others: Sequence[Expr]): @@ -2459,85 +2491,85 @@ def __init__(self, left: Expr, others: Sequence[Expr]): ) -class IsNaN(FilterCondition): +class IsNaN(BooleanExpr): """Represents checking if a numeric value is NaN.""" def __init__(self, value: Expr): super().__init__("is_nan", [value]) -class Like(FilterCondition): +class Like(BooleanExpr): """Represents a case-sensitive wildcard string comparison.""" def __init__(self, expr: Expr, pattern: Expr): super().__init__("like", [expr, pattern]) -class Lt(FilterCondition): +class LessThan(BooleanExpr): """Represents the less than comparison.""" def __init__(self, left: Expr, right: Expr): - super().__init__("lt", [left, right]) + super().__init__("less_than", [left, right]) -class Lte(FilterCondition): +class LessThanOrEqual(BooleanExpr): """Represents the less than or equal to comparison.""" def __init__(self, left: Expr, right: Expr): - super().__init__("lte", [left, right]) + super().__init__("less_than_or_equal", [left, right]) -class Neq(FilterCondition): +class NotEqual(BooleanExpr): """Represents the inequality comparison.""" def __init__(self, left: Expr, right: Expr): - super().__init__("neq", [left, right]) + super().__init__("not_equal", [left, right]) -class Not(FilterCondition): +class Not(BooleanExpr): """Represents the logical NOT of a filter condition.""" def __init__(self, condition: Expr): super().__init__("not", [condition], use_infix_repr=False) -class Or(FilterCondition): +class Or(BooleanExpr): """Represents the logical OR of multiple filter conditions.""" - def __init__(self, *conditions: "FilterCondition"): + def __init__(self, *conditions: "BooleanExpr"): super().__init__("or", conditions) -class RegexContains(FilterCondition): +class RegexContains(BooleanExpr): """Represents checking if a string contains a substring matching a regex.""" def __init__(self, expr: Expr, regex: Expr): super().__init__("regex_contains", [expr, regex]) -class RegexMatch(FilterCondition): +class RegexMatch(BooleanExpr): """Represents checking if a string fully matches a regex.""" def __init__(self, expr: Expr, regex: Expr): super().__init__("regex_match", [expr, regex]) -class StartsWith(FilterCondition): +class StartsWith(BooleanExpr): """Represents checking if a string starts with a specific prefix.""" def __init__(self, expr: Expr, prefix: Expr): super().__init__("starts_with", [expr, prefix]) -class StrContains(FilterCondition): +class StringContains(BooleanExpr): """Represents checking if a string contains a specific substring.""" def __init__(self, expr: Expr, substring: Expr): - super().__init__("str_contains", [expr, substring]) + super().__init__("string_contains", [expr, substring]) -class Xor(FilterCondition): +class Xor(BooleanExpr): """Represents the logical XOR of multiple filter conditions.""" - def __init__(self, conditions: Sequence["FilterCondition"]): + def __init__(self, conditions: Sequence["BooleanExpr"]): super().__init__("xor", conditions, use_infix_repr=False) diff --git a/tests/unit/v1/test_pipeline_expressions.py b/tests/unit/v1/test_pipeline_expressions.py index 66d05f3db..9f7e4a48f 100644 --- a/tests/unit/v1/test_pipeline_expressions.py +++ b/tests/unit/v1/test_pipeline_expressions.py @@ -22,7 +22,7 @@ from google.cloud.firestore_v1.types.document import Value from google.cloud.firestore_v1.vector import Vector from google.cloud.firestore_v1._helpers import GeoPoint -from google.cloud.firestore_v1.pipeline_expressions import FilterCondition, ListOfExprs +from google.cloud.firestore_v1.pipeline_expressions import BooleanExpr, ListOfExprs import google.cloud.firestore_v1.pipeline_expressions as expr @@ -143,13 +143,13 @@ def test_ctor(self): ("timestamp_sub", ("hour", 2.5), expr.TimestampSub), ("ascending", (), expr.Ordering), ("descending", (), expr.Ordering), - ("as_", ("alias",), expr.ExprWithAlias), + ("as_", ("alias",), expr.AliasedExpr), ], ) @pytest.mark.parametrize("base_instance", [expr.Constant(1), expr.Function.add("1", 1), expr.Field.of("test"), expr.Constant(1).as_("one")]) def test_infix_call(self, method, args, result_cls, base_instance): """ - many FilterCondition expressions support infix execution, and are exposed as methods on Expr. Test calling them + many BooleanExpr expressions support infix execution, and are exposed as methods on Expr. Test calling them """ method_ptr = getattr(base_instance, method) @@ -363,7 +363,7 @@ def test_to_map(self): assert result[0] == "field1" assert result[1] == Value(field_reference_value="field1") - class TestExprWithAlias: + class TestAliasedExpr: def test_repr(self): instance = expr.Field.of("field1").as_("alias1") assert repr(instance) == "Field.of('field1').as_('alias1')" @@ -371,14 +371,14 @@ def test_repr(self): def test_ctor(self): arg = expr.Field.of("field1") alias = "alias1" - instance = expr.ExprWithAlias(arg, alias) + instance = expr.AliasedExpr(arg, alias) assert instance.expr == arg assert instance.alias == alias def test_to_pb(self): arg = expr.Field.of("field1") alias = "alias1" - instance = expr.ExprWithAlias(arg, alias) + instance = expr.AliasedExpr(arg, alias) result = instance._to_pb() assert result.map_value.fields.get("alias1") == arg._to_pb() @@ -389,7 +389,7 @@ def test_to_map(self): assert result[1] == Value(field_reference_value="field1") -class TestFilterCondition: +class TestBooleanExpr: def test__from_query_filter_pb_composite_filter_or(self, mock_client): """ test composite OR filters @@ -417,7 +417,7 @@ def test__from_query_filter_pb_composite_filter_or(self, mock_client): composite_filter=composite_pb ) - result = FilterCondition._from_query_filter_pb(wrapped_filter_pb, mock_client) + result = BooleanExpr._from_query_filter_pb(wrapped_filter_pb, mock_client) # should include existance checks expected_cond1 = expr.And( @@ -460,7 +460,7 @@ def test__from_query_filter_pb_composite_filter_and(self, mock_client): composite_filter=composite_pb ) - result = FilterCondition._from_query_filter_pb(wrapped_filter_pb, mock_client) + result = BooleanExpr._from_query_filter_pb(wrapped_filter_pb, mock_client) # should include existance checks expected_cond1 = expr.And( @@ -511,7 +511,7 @@ def test__from_query_filter_pb_composite_filter_nested(self, mock_client): composite_filter=outer_or_pb ) - result = FilterCondition._from_query_filter_pb(wrapped_filter_pb, mock_client) + result = BooleanExpr._from_query_filter_pb(wrapped_filter_pb, mock_client) expected_cond1 = expr.And( expr.Exists(expr.Field.of("field1")), @@ -548,7 +548,7 @@ def test__from_query_filter_pb_composite_filter_unknown_op(self, mock_client): ) with pytest.raises(TypeError, match="Unexpected CompositeFilter operator type"): - FilterCondition._from_query_filter_pb(wrapped_filter_pb, mock_client) + BooleanExpr._from_query_filter_pb(wrapped_filter_pb, mock_client) @pytest.mark.parametrize( "op_enum, expected_expr_func", @@ -581,7 +581,7 @@ def test__from_query_filter_pb_unary_filter( ) wrapped_filter_pb = query_pb.StructuredQuery.Filter(unary_filter=filter_pb) - result = FilterCondition._from_query_filter_pb(wrapped_filter_pb, mock_client) + result = BooleanExpr._from_query_filter_pb(wrapped_filter_pb, mock_client) field_expr_inst = expr.Field.of(field_path) expected_condition = expected_expr_func(field_expr_inst) @@ -602,7 +602,7 @@ def test__from_query_filter_pb_unary_filter_unknown_op(self, mock_client): wrapped_filter_pb = query_pb.StructuredQuery.Filter(unary_filter=filter_pb) with pytest.raises(TypeError, match="Unexpected UnaryFilter operator type"): - FilterCondition._from_query_filter_pb(wrapped_filter_pb, mock_client) + BooleanExpr._from_query_filter_pb(wrapped_filter_pb, mock_client) @pytest.mark.parametrize( "op_enum, value, expected_expr_func", @@ -654,7 +654,7 @@ def test__from_query_filter_pb_field_filter( ) wrapped_filter_pb = query_pb.StructuredQuery.Filter(field_filter=filter_pb) - result = FilterCondition._from_query_filter_pb(wrapped_filter_pb, mock_client) + result = BooleanExpr._from_query_filter_pb(wrapped_filter_pb, mock_client) field_expr = expr.Field.of(field_path) # convert values into constants @@ -683,7 +683,7 @@ def test__from_query_filter_pb_field_filter_unknown_op(self, mock_client): wrapped_filter_pb = query_pb.StructuredQuery.Filter(field_filter=filter_pb) with pytest.raises(TypeError, match="Unexpected FieldFilter operator type"): - FilterCondition._from_query_filter_pb(wrapped_filter_pb, mock_client) + BooleanExpr._from_query_filter_pb(wrapped_filter_pb, mock_client) def test__from_query_filter_pb_unknown_filter_type(self, mock_client): """ @@ -691,12 +691,12 @@ def test__from_query_filter_pb_unknown_filter_type(self, mock_client): """ # Test with an unexpected protobuf type with pytest.raises(TypeError, match="Unexpected filter type"): - FilterCondition._from_query_filter_pb(document_pb.Value(), mock_client) + BooleanExpr._from_query_filter_pb(document_pb.Value(), mock_client) -class TestFilterConditionClasses: +class TestBooleanExprClasses: """ - contains test methods for each Expr class that derives from FilterCondition + contains test methods for each Expr class that derives from BooleanExpr """ def _make_arg(self, name="Mock"):