diff --git a/mpt_api_client/rql/query_builder.py b/mpt_api_client/rql/query_builder.py index 9ffde656..39733311 100644 --- a/mpt_api_client/rql/query_builder.py +++ b/mpt_api_client/rql/query_builder.py @@ -142,16 +142,18 @@ class RQLQuery: # noqa: WPS214 rql = RQLQuery().nested.field.eq('value') """ - AND = "and" # noqa: WPS115 - OR = "or" # noqa: WPS115 - EXPRESSION = "expr" # noqa: WPS115 + OP_AND = "and" # noqa: WPS115 + OP_OR = "or" # noqa: WPS115 + OP_ANY = "any" # noqa: WPS115 + OP_ALL = "all" # noqa: WPS115 + OP_EXPRESSION = "expr" # noqa: WPS115 def __init__( # noqa: WPS211 self, namespace_: str | None = None, # noqa: WPS120 **kwargs: QueryValue, ) -> None: - self.op: str = self.EXPRESSION + self.op: str = self.OP_EXPRESSION self.children: list[RQLQuery] = [] self.negated: bool = False self.expr: str | None = None @@ -160,10 +162,10 @@ def __init__( # noqa: WPS211 if namespace_: self.n(namespace_) if len(kwargs) == 1: - self.op = self.EXPRESSION + self.op = self.OP_EXPRESSION self.expr = parse_kwargs(kwargs)[0] if len(kwargs) > 1: - self.op = self.AND + self.op = self.OP_AND for token in parse_kwargs(kwargs): self.children.append(self.new(expr=token)) @@ -180,14 +182,14 @@ def new( if isinstance(children, set): children = list(children) query = cls() - query.op = op or cls.EXPRESSION + query.op = op or cls.OP_EXPRESSION query.children = children or [] query.negated = negated query.expr = expr return query def __len__(self) -> int: - if self.op == self.EXPRESSION: + if self.op == self.OP_EXPRESSION: if self.expr: return 1 return 0 @@ -220,23 +222,23 @@ def __hash__(self) -> int: @override def __repr__(self) -> str: - if self.op == self.EXPRESSION: + if self.op == self.OP_EXPRESSION: return f"" return f"" def __and__(self, other: object) -> Self: if not isinstance(other, type(self)): return NotImplemented - return self._join(other, self.AND) + return self._join(other, self.OP_AND) def __or__(self, other: object) -> Self: if not isinstance(other, type(self)): return NotImplemented - return self._join(other, self.OR) + return self._join(other, self.OP_OR) def __invert__(self) -> Self: inverted_query = self.new( - op=self.AND, + op=self.OP_AND, expr=self.expr, negated=True, ) @@ -250,6 +252,29 @@ def __getattr__(self, name: str) -> Self: def __str__(self) -> str: return self._to_string(self) + def any(self) -> Self: + """Any nested objects have to match the filter condition. + + Returns: + RQLQuery: RQLQuery with new condition + + Examples: + RQLQuery(saleDetails__orderQty__gt=11).any() + will result: any(saleDetails,orderQty=11) + """ + return self.new(op=self.OP_ANY, children=[self]) + + def all(self) -> Self: + """All nested objects have to match the filter condition. + + Returns: + RQLQuery: RQLQuery with new condition + + Example: + RQLQuery(saleDetails__orderQty__gt=1).all() + """ + return self.new(op=self.OP_ALL, children=[self]) + def n(self, name: str) -> Self: # noqa: WPS111 """Set the current field for this `RQLQuery` object. @@ -485,7 +510,7 @@ def _join(self, other: "RQLQuery", op: str) -> Self: def _append(self, query: "RQLQuery") -> "RQLQuery" | Self: if query in self.children: return query - single_operation = len(query) == 1 and query.op != self.EXPRESSION + single_operation = len(query) == 1 and query.op != self.OP_EXPRESSION if (query.op == self.op or single_operation) and not query.negated: self.children.extend(query.children) return self diff --git a/tests/rql/query_builder/test_create_rql.py b/tests/rql/query_builder/test_create_rql.py index e9a72bb8..b290cb4c 100644 --- a/tests/rql/query_builder/test_create_rql.py +++ b/tests/rql/query_builder/test_create_rql.py @@ -4,7 +4,7 @@ def test_create(): query = RQLQuery() - assert query.op == RQLQuery.EXPRESSION + assert query.op == RQLQuery.OP_EXPRESSION assert query.children == [] assert query.negated is False @@ -14,14 +14,14 @@ def test_create_with_field(): query.eq("value") - assert query.op == RQLQuery.EXPRESSION + assert query.op == RQLQuery.OP_EXPRESSION assert str(query) == "eq(field,value)" def test_create_single_kwarg(): query = RQLQuery(id="ID") - assert query.op == RQLQuery.EXPRESSION + assert query.op == RQLQuery.OP_EXPRESSION assert str(query) == "eq(id,ID)" assert query.children == [] assert query.negated is False @@ -30,16 +30,16 @@ def test_create_single_kwarg(): def test_create_multiple_kwargs(): # noqa: WPS218 query = RQLQuery(id="ID", status__in=("a", "b"), ok=True) - assert query.op == RQLQuery.AND + assert query.op == RQLQuery.OP_AND assert str(query) == "and(eq(id,ID),in(status,(a,b)),eq(ok,true))" assert len(query.children) == 3 - assert query.children[0].op == RQLQuery.EXPRESSION + assert query.children[0].op == RQLQuery.OP_EXPRESSION assert query.children[0].children == [] assert str(query.children[0]) == "eq(id,ID)" - assert query.children[1].op == RQLQuery.EXPRESSION + assert query.children[1].op == RQLQuery.OP_EXPRESSION assert query.children[1].children == [] assert str(query.children[1]) == "in(status,(a,b))" - assert query.children[2].op == RQLQuery.EXPRESSION + assert query.children[2].op == RQLQuery.OP_EXPRESSION assert query.children[2].children == [] assert str(query.children[2]) == "eq(ok,true)" @@ -47,7 +47,7 @@ def test_create_multiple_kwargs(): # noqa: WPS218 def test_new_empty(): query = RQLQuery.new() - assert query.op == RQLQuery.EXPRESSION + assert query.op == RQLQuery.OP_EXPRESSION assert query.children == [] assert query.negated is False @@ -57,7 +57,7 @@ def test_new_with_parameters(): status_not_done = RQLQuery.new("status=done", negated=True) query = RQLQuery.new( - op=RQLQuery.AND, + op=RQLQuery.OP_AND, children=[project_rql, status_not_done], ) @@ -69,7 +69,7 @@ def test_new_with_set(): status_not_done = RQLQuery.new("status=done", negated=True) query = RQLQuery.new( - op=RQLQuery.AND, + op=RQLQuery.OP_AND, children={project_rql, status_not_done}, ) diff --git a/tests/rql/query_builder/test_multiple_ops.py b/tests/rql/query_builder/test_multiple_ops.py index 3de85909..e7e09def 100644 --- a/tests/rql/query_builder/test_multiple_ops.py +++ b/tests/rql/query_builder/test_multiple_ops.py @@ -10,7 +10,7 @@ def test_and_or(): # noqa: WPS218 WPS473 r5 = r1 & r2 & (r3 | r4) - assert r5.op == RQLQuery.AND + assert r5.op == RQLQuery.OP_AND assert str(r5) == "and(eq(id,ID),eq(field,value),or(eq(other,value2),in(inop,(a,b))))" # noqa: WPS204 r5 = r1 & r2 | r3 @@ -43,6 +43,6 @@ def test_and_merge(): # noqa: WPS210 and3 = and1 & and2 - assert and3.op == RQLQuery.AND + assert and3.op == RQLQuery.OP_AND assert len(and3.children) == 4 assert [r1, r2, r3, r4] == and3.children diff --git a/tests/rql/query_builder/test_rql_all_any.py b/tests/rql/query_builder/test_rql_all_any.py new file mode 100644 index 00000000..9c8c67a0 --- /dev/null +++ b/tests/rql/query_builder/test_rql_all_any.py @@ -0,0 +1,14 @@ +from mpt_api_client.rql import RQLQuery + + +def test_all(): + query = RQLQuery(saleDetails__orderQty__gt=1).all() + + rql = str(query) + assert rql == "all(gt(saleDetails.orderQty,1))" + + +def test_any(): + query = RQLQuery(saleDetails__orderQty__gt=1).any() + rql = str(query) + assert rql == "any(gt(saleDetails.orderQty,1))" diff --git a/tests/rql/query_builder/test_rql_and.py b/tests/rql/query_builder/test_rql_and.py index b6e7f30e..d9445a18 100644 --- a/tests/rql/query_builder/test_rql_and.py +++ b/tests/rql/query_builder/test_rql_and.py @@ -41,7 +41,7 @@ def test_and_different(): assert r3 != r1 assert r3 != r2 - assert r3.op == RQLQuery.AND + assert r3.op == RQLQuery.OP_AND assert r1 in r3.children assert r2 in r3.children @@ -60,5 +60,5 @@ def test_and_triple(): r3 = r1 & r2 & r2 assert len(r3) == 2 - assert r3.op == RQLQuery.AND + assert r3.op == RQLQuery.OP_AND assert [r1, r2] == r3.children diff --git a/tests/rql/query_builder/test_rql_or.py b/tests/rql/query_builder/test_rql_or.py index a1460454..1dcaee7b 100644 --- a/tests/rql/query_builder/test_rql_or.py +++ b/tests/rql/query_builder/test_rql_or.py @@ -42,7 +42,7 @@ def test_or_not_equals(): assert r3 != r1 assert r3 != r2 - assert r3.op == RQLQuery.OR + assert r3.op == RQLQuery.OP_OR assert r1 in r3.children assert r2 in r3.children @@ -65,7 +65,7 @@ def test_or_merge(): # noqa: WPS210 or2 = r3 | r4 or3 = or1 | or2 - assert or3.op == RQLQuery.OR + assert or3.op == RQLQuery.OP_OR assert len(or3.children) == 4 assert [r1, r2, r3, r4] == or3.children @@ -77,5 +77,5 @@ def test_or_merge_duplicates(): r3 = r1 | r2 | r2 assert len(r3) == 2 - assert r3.op == RQLQuery.OR + assert r3.op == RQLQuery.OP_OR assert [r1, r2] == r3.children