Skip to content

Commit c4cd995

Browse files
committed
added tests for filter conditions
1 parent 2775da2 commit c4cd995

File tree

2 files changed

+152
-27
lines changed

2 files changed

+152
-27
lines changed

google/cloud/firestore_v1/pipeline_expressions.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -385,9 +385,11 @@ def __init__(
385385
self,
386386
*args,
387387
use_infix_repr:bool = True,
388+
infix_name_override:str | None= None,
388389
**kwargs,
389390
):
390391
self._use_infix_repr = use_infix_repr
392+
self._infix_name_override = infix_name_override
391393
super().__init__(*args, **kwargs)
392394

393395
def __repr__(self):
@@ -397,10 +399,11 @@ def __repr__(self):
397399
Display them this way in the repr string where possible
398400
"""
399401
if self._use_infix_repr:
402+
infix_name = self._infix_name_override or self.name
400403
if len(self.params) == 1:
401-
return f"{self.params[0]!r}.{self.name}()"
404+
return f"{self.params[0]!r}.{infix_name}()"
402405
elif len(self.params) == 2:
403-
return f"{self.params[0]!r}.{self.name}({self.params[1]!r})"
406+
return f"{self.params[0]!r}.{infix_name}({self.params[1]!r})"
404407
return super().__repr__()
405408

406409
@staticmethod
@@ -518,7 +521,7 @@ class In(FilterCondition):
518521
"""Represents checking if an expression's value is within a list of values."""
519522

520523
def __init__(self, left: Expr, others: List[Expr]):
521-
super().__init__("in", [left, ListOfExprs(others)])
524+
super().__init__("in", [left, ListOfExprs(others)], infix_name_override="in_any")
522525

523526

524527
class IsNaN(FilterCondition):

tests/unit/v1/test_pipeline_expressions.py

Lines changed: 146 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from google.cloud.firestore_v1.types.document import Value
2323
from google.cloud.firestore_v1.vector import Vector
2424
from google.cloud.firestore_v1._helpers import GeoPoint
25-
from google.cloud.firestore_v1.pipeline_expressions import FilterCondition
25+
from google.cloud.firestore_v1.pipeline_expressions import FilterCondition, ListOfExprs
2626
import google.cloud.firestore_v1.pipeline_expressions as expr
2727

2828

@@ -41,29 +41,6 @@ def test_ctor(self):
4141
with pytest.raises(TypeError):
4242
expr.Expr()
4343

44-
@pytest.mark.parametrize("method,args,result_cls", [
45-
("eq", (None,), expr.Eq),
46-
("neq", (None,), expr.Neq),
47-
("lt", (None,), expr.Lt),
48-
("lte", (None,), expr.Lte),
49-
("gt", (None,), expr.Gt),
50-
("gte", (None,), expr.Gte),
51-
("in_any", ([None],), expr.In),
52-
("not_in_any", ([None],),expr.Not),
53-
("array_contains", (None,), expr.ArrayContains),
54-
("array_contains_any", ([None],), expr.ArrayContainsAny),
55-
("is_nan", (), expr.IsNaN),
56-
("exists", (), expr.Exists),
57-
])
58-
def test_methods(self, method, args, result_cls):
59-
"""
60-
base expr should have methods for certain stages
61-
"""
62-
method_ptr = getattr(expr.Expr, method)
63-
result = method_ptr(mock.Mock(), *args)
64-
assert isinstance(result, result_cls)
65-
66-
6744

6845
class TestConstant:
6946
@pytest.mark.parametrize(
@@ -442,3 +419,148 @@ def test__from_query_filter_pb_unknown_filter_type(self, mock_client):
442419
# Test with an unexpected protobuf type
443420
with pytest.raises(TypeError, match="Unexpected filter type"):
444421
FilterCondition._from_query_filter_pb(document_pb.Value(), mock_client)
422+
423+
424+
@pytest.mark.parametrize("method,args,result_cls", [
425+
("eq", (2,), expr.Eq),
426+
("neq", (2,), expr.Neq),
427+
("lt", (2,), expr.Lt),
428+
("lte", (2,), expr.Lte),
429+
("gt", (2,), expr.Gt),
430+
("gte", (2,), expr.Gte),
431+
("in_any", ([None],), expr.In),
432+
("not_in_any", ([None],), expr.Not),
433+
("array_contains", (None,), expr.ArrayContains),
434+
("array_contains_any", ([None],), expr.ArrayContainsAny),
435+
("is_nan", (), expr.IsNaN),
436+
("exists", (), expr.Exists),
437+
])
438+
def test_infix_call(self, method, args, result_cls):
439+
"""
440+
most FilterExpressions should support infix execution
441+
"""
442+
base_instance = expr.Constant(1)
443+
method_ptr = getattr(base_instance, method)
444+
445+
result = method_ptr(*args)
446+
assert isinstance(result, result_cls)
447+
448+
def _make_arg(self, name="Mock"):
449+
arg = mock.Mock()
450+
arg.__repr__ = lambda x: name
451+
return arg
452+
453+
def test_and(self):
454+
arg1 = self._make_arg()
455+
arg2 = self._make_arg()
456+
instance = expr.And(arg1, arg2)
457+
assert instance.name == "and"
458+
assert instance.params == [arg1, arg2]
459+
assert repr(instance) == "And(Mock, Mock)"
460+
461+
def test_or(self):
462+
arg1 = self._make_arg("Arg1")
463+
arg2 = self._make_arg("Arg2")
464+
instance = expr.Or(arg1, arg2)
465+
assert instance.name == "or"
466+
assert instance.params == [arg1, arg2]
467+
assert repr(instance) == "Or(Arg1, Arg2)"
468+
469+
def test_array_contains(self):
470+
arg1 = self._make_arg("ArrayField")
471+
arg2 = self._make_arg("Element")
472+
instance = expr.ArrayContains(arg1, arg2)
473+
assert instance.name == "array_contains"
474+
assert instance.params == [arg1, arg2]
475+
assert repr(instance) == "ArrayField.array_contains(Element)"
476+
477+
def test_array_contains_any(self):
478+
arg1 = self._make_arg("ArrayField")
479+
arg2 = self._make_arg("Element1")
480+
arg3 = self._make_arg("Element2")
481+
instance = expr.ArrayContainsAny(arg1, [arg2, arg3])
482+
assert instance.name == "array_contains_any"
483+
assert isinstance(instance.params[1], ListOfExprs)
484+
assert instance.params[0] == arg1
485+
assert instance.params[1].exprs == [arg2, arg3]
486+
assert repr(instance) == "ArrayField.array_contains_any(ListOfExprs([Element1, Element2]))"
487+
488+
def test_exists(self):
489+
arg1 = self._make_arg("Field")
490+
instance = expr.Exists(arg1)
491+
assert instance.name == "exists"
492+
assert instance.params == [arg1]
493+
assert repr(instance) == "Field.exists()"
494+
495+
def test_eq(self):
496+
arg1 = self._make_arg("Left")
497+
arg2 = self._make_arg("Right")
498+
instance = expr.Eq(arg1, arg2)
499+
assert instance.name == "eq"
500+
assert instance.params == [arg1, arg2]
501+
assert repr(instance) == "Left.eq(Right)"
502+
503+
def test_gte(self):
504+
arg1 = self._make_arg("Left")
505+
arg2 = self._make_arg("Right")
506+
instance = expr.Gte(arg1, arg2)
507+
assert instance.name == "gte"
508+
assert instance.params == [arg1, arg2]
509+
assert repr(instance) == "Left.gte(Right)"
510+
511+
def test_gt(self):
512+
arg1 = self._make_arg("Left")
513+
arg2 = self._make_arg("Right")
514+
instance = expr.Gt(arg1, arg2)
515+
assert instance.name == "gt"
516+
assert instance.params == [arg1, arg2]
517+
assert repr(instance) == "Left.gt(Right)"
518+
519+
def test_lte(self):
520+
arg1 = self._make_arg("Left")
521+
arg2 = self._make_arg("Right")
522+
instance = expr.Lte(arg1, arg2)
523+
assert instance.name == "lte"
524+
assert instance.params == [arg1, arg2]
525+
assert repr(instance) == "Left.lte(Right)"
526+
527+
def test_lt(self):
528+
arg1 = self._make_arg("Left")
529+
arg2 = self._make_arg("Right")
530+
instance = expr.Lt(arg1, arg2)
531+
assert instance.name == "lt"
532+
assert instance.params == [arg1, arg2]
533+
assert repr(instance) == "Left.lt(Right)"
534+
535+
def test_neq(self):
536+
arg1 = self._make_arg("Left")
537+
arg2 = self._make_arg("Right")
538+
instance = expr.Neq(arg1, arg2)
539+
assert instance.name == "neq"
540+
assert instance.params == [arg1, arg2]
541+
assert repr(instance) == "Left.neq(Right)"
542+
543+
def test_in(self):
544+
arg1 = self._make_arg("Field")
545+
arg2 = self._make_arg("Value1")
546+
arg3 = self._make_arg("Value2")
547+
instance = expr.In(arg1, [arg2, arg3])
548+
assert instance.name == "in"
549+
assert isinstance(instance.params[1], ListOfExprs)
550+
assert instance.params[0] == arg1
551+
assert instance.params[1].exprs == [arg2, arg3]
552+
assert repr(instance) == "Field.in_any(ListOfExprs([Value1, Value2]))"
553+
554+
def test_is_nan(self):
555+
arg1 = self._make_arg("Value")
556+
instance = expr.IsNaN(arg1)
557+
assert instance.name == "is_nan"
558+
assert instance.params == [arg1]
559+
assert repr(instance) == "Value.is_nan()"
560+
561+
def test_not(self):
562+
arg1 = self._make_arg("Condition")
563+
instance = expr.Not(arg1)
564+
assert instance.name == "not"
565+
assert instance.params == [arg1]
566+
assert repr(instance) == "Not(Condition)"

0 commit comments

Comments
 (0)