Skip to content

Commit 9de9d42

Browse files
committed
refactored how repr strings are handled
1 parent 19fc296 commit 9de9d42

File tree

2 files changed

+114
-37
lines changed

2 files changed

+114
-37
lines changed

packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_expressions.py

Lines changed: 102 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from typing import (
2626
TYPE_CHECKING,
2727
Any,
28+
Callable,
2829
Generic,
2930
Sequence,
3031
TypeVar,
@@ -569,7 +570,7 @@ def logical_maximum(self, *others: Expression | CONSTANT_TYPE) -> "Expression":
569570
return FunctionExpression(
570571
"maximum",
571572
[self] + [self._cast_to_expr_or_convert_to_constant(o) for o in others],
572-
infix_name_override="logical_maximum",
573+
repr_function=FunctionExpression._build_infix_repr("logical_maximum"),
573574
)
574575

575576
@expose_as_static
@@ -595,7 +596,7 @@ def logical_minimum(self, *others: Expression | CONSTANT_TYPE) -> "Expression":
595596
return FunctionExpression(
596597
"minimum",
597598
[self] + [self._cast_to_expr_or_convert_to_constant(o) for o in others],
598-
infix_name_override="logical_minimum",
599+
repr_function=FunctionExpression._build_infix_repr("logical_minimum"),
599600
)
600601

601602
@expose_as_static
@@ -955,7 +956,10 @@ def array_filter(
955956
args.append(self._cast_to_expr_or_convert_to_constant(index_alias))
956957
args.append(filter_expr)
957958

958-
return FunctionExpression("array_filter", args)
959+
repr_func = (
960+
lambda expr: f"{expr.params[0]!r}.{expr.name}({expr.params[-1]!r}, {expr.params[1]!r}{', ' + repr(expr.params[2]) if len(expr.params) == 4 else ''})"
961+
)
962+
return FunctionExpression("array_filter", args, repr_function=repr_func)
959963

960964
@expose_as_static
961965
def array_transform(
@@ -987,7 +991,10 @@ def array_transform(
987991
args.append(self._cast_to_expr_or_convert_to_constant(index_alias))
988992
args.append(transform_expr)
989993

990-
return FunctionExpression("array_transform", args)
994+
repr_func = (
995+
lambda expr: f"{expr.params[0]!r}.{expr.name}({expr.params[-1]!r}, {expr.params[1]!r}{', ' + repr(expr.params[2]) if len(expr.params) == 4 else ''})"
996+
)
997+
return FunctionExpression("array_transform", args, repr_function=repr_func)
991998

992999
@expose_as_static
9931000
def array_concat(
@@ -2154,7 +2161,9 @@ def array_maximum(self) -> "Expression":
21542161
A new `Expression` representing the maximum element of the array.
21552162
"""
21562163
return FunctionExpression(
2157-
"maximum", [self], infix_name_override="array_maximum"
2164+
"maximum",
2165+
[self],
2166+
repr_function=FunctionExpression._build_infix_repr("array_maximum"),
21582167
)
21592168

21602169
@expose_as_static
@@ -2169,7 +2178,9 @@ def array_minimum(self) -> "Expression":
21692178
A new `Expression` representing the minimum element of the array.
21702179
"""
21712180
return FunctionExpression(
2172-
"minimum", [self], infix_name_override="array_minimum"
2181+
"minimum",
2182+
[self],
2183+
repr_function=FunctionExpression._build_infix_repr("array_minimum"),
21732184
)
21742185

21752186
@expose_as_static
@@ -2191,7 +2202,7 @@ def array_maximum_n(self, n: int | "Expression") -> "Expression":
21912202
return FunctionExpression(
21922203
"maximum_n",
21932204
[self, self._cast_to_expr_or_convert_to_constant(n)],
2194-
infix_name_override="array_maximum_n",
2205+
repr_function=FunctionExpression._build_infix_repr("array_maximum_n"),
21952206
)
21962207

21972208
@expose_as_static
@@ -2213,7 +2224,7 @@ def array_minimum_n(self, n: int | "Expression") -> "Expression":
22132224
return FunctionExpression(
22142225
"minimum_n",
22152226
[self, self._cast_to_expr_or_convert_to_constant(n)],
2216-
infix_name_override="array_minimum_n",
2227+
repr_function=FunctionExpression._build_infix_repr("array_minimum_n"),
22172228
)
22182229

22192230
@expose_as_static
@@ -2683,36 +2694,66 @@ def __init__(
26832694
name: str,
26842695
params: Sequence[Expression],
26852696
*,
2686-
use_infix_repr: bool = True,
2687-
infix_name_override: str | None = None,
2697+
repr_function: Callable[["FunctionExpression"], str] | None = None,
26882698
):
26892699
self.name = name
26902700
self.params = list(params)
2691-
self._use_infix_repr = use_infix_repr
2692-
self._infix_name_override = infix_name_override
2701+
self._repr_function = repr_function or self._build_infix_repr()
26932702

26942703
def __repr__(self):
26952704
"""
26962705
Most FunctionExpressions can be triggered infix. Eg: Field.of('age').greater_than(18).
26972706
26982707
Display them this way in the repr string where possible
26992708
"""
2700-
if self._use_infix_repr:
2701-
infix_name = self._infix_name_override or self.name
2702-
if len(self.params) == 1:
2703-
return f"{self.params[0]!r}.{infix_name}()"
2704-
elif len(self.params) == 2:
2705-
return f"{self.params[0]!r}.{infix_name}({self.params[1]!r})"
2706-
else:
2707-
return f"{self.params[0]!r}.{infix_name}({', '.join([repr(p) for p in self.params[1:]])})"
2708-
return f"{self.__class__.__name__}({', '.join([repr(p) for p in self.params])})"
2709+
return self._repr_function(self)
27092710

27102711
def __eq__(self, other):
27112712
if not isinstance(other, FunctionExpression):
27122713
return False
27132714
else:
27142715
return other.name == self.name and other.params == self.params
27152716

2717+
@staticmethod
2718+
def _build_infix_repr(
2719+
name_override: str | None = None,
2720+
) -> Callable[["FunctionExpression"], str]:
2721+
"""Creates a repr_function that displays a FunctionExpression using infix notation.
2722+
2723+
Example:
2724+
`value.greater_than(18)`
2725+
"""
2726+
2727+
def build_repr(expr):
2728+
final_name = name_override or expr.name
2729+
args = expr.params
2730+
if len(args) == 0:
2731+
return f"{final_name}()"
2732+
elif len(args) == 1:
2733+
return f"{args[0]!r}.{final_name}()"
2734+
elif len(args) == 2:
2735+
return f"{args[0]!r}.{final_name}({args[1]!r})"
2736+
else:
2737+
return f"{args[0]!r}.{final_name}({', '.join([repr(a) for a in args[1:]])})"
2738+
2739+
return build_repr
2740+
2741+
@staticmethod
2742+
def _build_standalone_repr(
2743+
name_override: str | None = None,
2744+
) -> Callable[["FunctionExpression"], str]:
2745+
"""Creates a repr_function that displays a FunctionExpression using standalone function notation.
2746+
2747+
Example:
2748+
`GreaterThan(value, 18)`
2749+
"""
2750+
2751+
def build_repr(expr):
2752+
final_name = name_override or expr.__class__.__name__
2753+
return f"{final_name}({', '.join([repr(a) for a in expr.params])})"
2754+
2755+
return build_repr
2756+
27162757
def _to_pb(self):
27172758
return Value(
27182759
function_value={
@@ -2966,7 +3007,9 @@ class And(BooleanExpression):
29663007
"""
29673008

29683009
def __init__(self, *conditions: "BooleanExpression"):
2969-
super().__init__("and", conditions, use_infix_repr=False)
3010+
super().__init__(
3011+
"and", conditions, repr_function=FunctionExpression._build_standalone_repr()
3012+
)
29703013

29713014

29723015
class Not(BooleanExpression):
@@ -2982,7 +3025,11 @@ class Not(BooleanExpression):
29823025
"""
29833026

29843027
def __init__(self, condition: BooleanExpression):
2985-
super().__init__("not", [condition], use_infix_repr=False)
3028+
super().__init__(
3029+
"not",
3030+
[condition],
3031+
repr_function=FunctionExpression._build_standalone_repr(),
3032+
)
29863033

29873034

29883035
class Or(BooleanExpression):
@@ -2999,7 +3046,9 @@ class Or(BooleanExpression):
29993046
"""
30003047

30013048
def __init__(self, *conditions: "BooleanExpression"):
3002-
super().__init__("or", conditions, use_infix_repr=False)
3049+
super().__init__(
3050+
"or", conditions, repr_function=FunctionExpression._build_standalone_repr()
3051+
)
30033052

30043053

30053054
class Nor(BooleanExpression):
@@ -3015,7 +3064,9 @@ class Nor(BooleanExpression):
30153064
"""
30163065

30173066
def __init__(self, *conditions: "BooleanExpression"):
3018-
super().__init__("nor", conditions, use_infix_repr=False)
3067+
super().__init__(
3068+
"nor", conditions, repr_function=FunctionExpression._build_standalone_repr()
3069+
)
30193070

30203071

30213072
class Xor(BooleanExpression):
@@ -3032,7 +3083,9 @@ class Xor(BooleanExpression):
30323083
"""
30333084

30343085
def __init__(self, conditions: Sequence["BooleanExpression"]):
3035-
super().__init__("xor", conditions, use_infix_repr=False)
3086+
super().__init__(
3087+
"xor", conditions, repr_function=FunctionExpression._build_standalone_repr()
3088+
)
30363089

30373090

30383091
class Conditional(BooleanExpression):
@@ -3054,7 +3107,9 @@ def __init__(
30543107
self, condition: BooleanExpression, then_expr: Expression, else_expr: Expression
30553108
):
30563109
super().__init__(
3057-
"conditional", [condition, then_expr, else_expr], use_infix_repr=False
3110+
"conditional",
3111+
[condition, then_expr, else_expr],
3112+
repr_function=FunctionExpression._build_standalone_repr(),
30583113
)
30593114

30603115

@@ -3075,7 +3130,13 @@ class Count(AggregateFunction):
30753130

30763131
def __init__(self, expression: Expression | None = None):
30773132
expression_list = [expression] if expression else []
3078-
super().__init__("count", expression_list, use_infix_repr=bool(expression_list))
3133+
super().__init__(
3134+
"count",
3135+
expression_list,
3136+
repr_function=FunctionExpression._build_infix_repr()
3137+
if expression_list
3138+
else FunctionExpression._build_standalone_repr(),
3139+
)
30793140

30803141

30813142
class CurrentTimestamp(FunctionExpression):
@@ -3086,7 +3147,11 @@ class CurrentTimestamp(FunctionExpression):
30863147
"""
30873148

30883149
def __init__(self):
3089-
super().__init__("current_timestamp", [], use_infix_repr=False)
3150+
super().__init__(
3151+
"current_timestamp",
3152+
[],
3153+
repr_function=FunctionExpression._build_standalone_repr(),
3154+
)
30903155

30913156

30923157
class Rand(FunctionExpression):
@@ -3098,7 +3163,9 @@ class Rand(FunctionExpression):
30983163
"""
30993164

31003165
def __init__(self):
3101-
super().__init__("rand", [], use_infix_repr=False)
3166+
super().__init__(
3167+
"rand", [], repr_function=FunctionExpression._build_standalone_repr()
3168+
)
31023169

31033170

31043171
class Variable(Expression):
@@ -3137,4 +3204,8 @@ class CurrentDocument(FunctionExpression):
31373204
"""
31383205

31393206
def __init__(self):
3140-
super().__init__("current_document", [])
3207+
super().__init__(
3208+
"current_document",
3209+
[],
3210+
repr_function=FunctionExpression._build_standalone_repr(),
3211+
)

packages/google-cloud-firestore/tests/unit/v1/test_pipeline_expressions.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1669,7 +1669,7 @@ def test_array_reverse(self):
16691669

16701670
def test_array_filter(self):
16711671
arr = self._make_arg("ArrayField")
1672-
filter_expr = self._make_arg("FilterExpr", expr_type=BooleanExpression)
1672+
filter_expr = self._make_arg("FilterExpr")
16731673
elm_alias = "element_alias"
16741674
instance = Expression.array_filter(arr, filter_expr, elm_alias)
16751675
assert instance.name == "array_filter"
@@ -1682,7 +1682,9 @@ def test_array_filter(self):
16821682
assert infix_instance == instance
16831683

16841684
idx_alias = "index_alias"
1685-
instance_with_idx = Expression.array_filter(arr, filter_expr, elm_alias, idx_alias)
1685+
instance_with_idx = Expression.array_filter(
1686+
arr, filter_expr, elm_alias, idx_alias
1687+
)
16861688
assert instance_with_idx.name == "array_filter"
16871689
assert instance_with_idx.params == [
16881690
arr,
@@ -1692,7 +1694,7 @@ def test_array_filter(self):
16921694
]
16931695
assert (
16941696
repr(instance_with_idx)
1695-
== "ArrayField.array_filter(FilterExpr, Constant.of('element_alias'), Constant.of('index_alias'), None)"
1697+
== "ArrayField.array_filter(FilterExpr, Constant.of('element_alias'), Constant.of('index_alias'))"
16961698
)
16971699
infix_instance_with_idx = arr.array_filter(filter_expr, elm_alias, idx_alias)
16981700
assert infix_instance_with_idx == instance_with_idx
@@ -1706,13 +1708,15 @@ def test_array_transform(self):
17061708
assert instance.params == [arr, Constant.of(elm_alias), transform_expr]
17071709
assert (
17081710
repr(instance)
1709-
== "ArrayField.array_transform(TransformExpr, Constant.of('element_alias'), None)"
1711+
== "ArrayField.array_transform(TransformExpr, Constant.of('element_alias'))"
17101712
)
17111713
infix_instance = arr.array_transform(transform_expr, elm_alias)
17121714
assert infix_instance == instance
17131715

17141716
idx_alias = "index_alias"
1715-
instance_with_idx = Expression.array_transform(arr, transform_expr, elm_alias, idx_alias)
1717+
instance_with_idx = Expression.array_transform(
1718+
arr, transform_expr, elm_alias, idx_alias
1719+
)
17161720
assert instance_with_idx.name == "array_transform"
17171721
assert instance_with_idx.params == [
17181722
arr,
@@ -1724,7 +1728,9 @@ def test_array_transform(self):
17241728
repr(instance_with_idx)
17251729
== "ArrayField.array_transform(TransformExpr, Constant.of('element_alias'), Constant.of('index_alias'))"
17261730
)
1727-
infix_instance_with_idx = arr.array_transform(transform_expr, elm_alias, idx_alias)
1731+
infix_instance_with_idx = arr.array_transform(
1732+
transform_expr, elm_alias, idx_alias
1733+
)
17281734
assert infix_instance_with_idx == instance_with_idx
17291735

17301736
def test_array_concat(self):

0 commit comments

Comments
 (0)