Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not prevent mixed filters when using OR operator. #865

Merged
merged 1 commit into from
Mar 7, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions neomodel/async_/match.py
Original file line number Diff line number Diff line change
@@ -825,9 +825,11 @@ def add_to_target(statement: str, connector: Q, optional: bool) -> None:
match_filters = [filter[0] for filter in target if not filter[1]]
opt_match_filters = [filter[0] for filter in target if filter[1]]
if q.connector == Q.OR and match_filters and opt_match_filters:
raise ValueError(
"Cannot filter using OR operator on variables coming from both MATCH and OPTIONAL MATCH statements"
)
# In this case, we can't split filters in two WHERE statements so we move
# everything into the one applied after OPTIONAL MATCH statements...
opt_match_filters += match_filters
match_filters = []

ret = f" {q.connector} ".join(match_filters)
if ret and q.negated:
ret = f"NOT ({ret})"
8 changes: 5 additions & 3 deletions neomodel/sync_/match.py
Original file line number Diff line number Diff line change
@@ -823,9 +823,11 @@ def add_to_target(statement: str, connector: Q, optional: bool) -> None:
match_filters = [filter[0] for filter in target if not filter[1]]
opt_match_filters = [filter[0] for filter in target if filter[1]]
if q.connector == Q.OR and match_filters and opt_match_filters:
raise ValueError(
"Cannot filter using OR operator on variables coming from both MATCH and OPTIONAL MATCH statements"
)
# In this case, we can't split filters in two WHERE statements so we move
# everything into the one applied after OPTIONAL MATCH statements...
opt_match_filters += match_filters
match_filters = []

ret = f" {q.connector} ".join(match_filters)
if ret and q.negated:
ret = f"NOT ({ret})"
15 changes: 8 additions & 7 deletions test/async_/test_match_api.py
Original file line number Diff line number Diff line change
@@ -545,13 +545,14 @@ async def test_q_filters():
assert c6 in combined_coffees
assert c3 not in combined_coffees

with raises(
ValueError,
match=r"Cannot filter using OR operator on variables coming from both MATCH and OPTIONAL MATCH statements",
):
await Coffee.nodes.fetch_relations(Optional("species")).filter(
Q(name="Latte") | Q(species__name="Robusta")
).all()
robusta = await Species(name="Robusta").save()
await c4.species.connect(robusta)
latte_or_robusta_coffee = (
await Coffee.nodes.fetch_relations(Optional("species"))
.filter(Q(name="Latte") | Q(species__name="Robusta"))
.all()
)
assert len(latte_or_robusta_coffee) == 2

class QQ:
pass
15 changes: 8 additions & 7 deletions test/sync_/test_match_api.py
Original file line number Diff line number Diff line change
@@ -541,13 +541,14 @@ def test_q_filters():
assert c6 in combined_coffees
assert c3 not in combined_coffees

with raises(
ValueError,
match=r"Cannot filter using OR operator on variables coming from both MATCH and OPTIONAL MATCH statements",
):
Coffee.nodes.fetch_relations(Optional("species")).filter(
Q(name="Latte") | Q(species__name="Robusta")
).all()
robusta = Species(name="Robusta").save()
c4.species.connect(robusta)
latte_or_robusta_coffee = (
Coffee.nodes.fetch_relations(Optional("species"))
.filter(Q(name="Latte") | Q(species__name="Robusta"))
.all()
)
assert len(latte_or_robusta_coffee) == 2

class QQ:
pass