From 4ff3dd5579ebe5f9c5e4328b8e457365f1f0aed6 Mon Sep 17 00:00:00 2001 From: Gerrit Meier Date: Wed, 18 Dec 2024 10:37:55 +0100 Subject: [PATCH] fix: Fix scoping issue with existential subquery (#1151) Remove elements from scope cache when leaving existential subquery. Closes #1147 --- .../neo4j/cypherdsl/parser/ComparisonIT.java | 42 +++++++++++++++++++ .../core/internal/ScopingStrategy.java | 6 ++- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/neo4j-cypher-dsl-parser/src/test/java/org/neo4j/cypherdsl/parser/ComparisonIT.java b/neo4j-cypher-dsl-parser/src/test/java/org/neo4j/cypherdsl/parser/ComparisonIT.java index 633c6cb4f4..ed4d636315 100644 --- a/neo4j-cypher-dsl-parser/src/test/java/org/neo4j/cypherdsl/parser/ComparisonIT.java +++ b/neo4j-cypher-dsl-parser/src/test/java/org/neo4j/cypherdsl/parser/ComparisonIT.java @@ -728,4 +728,46 @@ static boolean areSemanticallyEquivalent(Statement statement1, Map(this0:Manufacturer) + WHERE (this0.name = $param0 AND edge.current = $param1) + } + OR EXISTS { + MATCH (this)-[edge:MANUFACTURER]->(this1:Manufacturer) + WHERE (this1.name = $param2 AND edge.current = $param3) + }) + AND EXISTS { + MATCH (this)-[edge:BRAND]->(this2:Brand) + WHERE (this2.name = $param4 AND edge.current = $param5) + }) + RETURN this"""; + var renderer = Renderer.getRenderer(Configuration.newConfig() + .withPrettyPrint(true) + .withGeneratedNames(true) + .build()); + var normalized = renderer.render(CypherParser.parse(cypher)); + assertThat(normalized).isEqualTo(""" + MATCH (v0:Series) + WHERE ((EXISTS { + MATCH (v0)-[v1:MANUFACTURER]->(v2:Manufacturer) + WHERE (v2.name = $p0 + AND v1.current = $p1) + } + OR EXISTS { + MATCH (v0)-[v1:MANUFACTURER]->(v2:Manufacturer) + WHERE (v2.name = $p2 + AND v1.current = $p3) + }) + AND EXISTS { + MATCH (v0)-[v1:BRAND]->(v2:Brand) + WHERE (v2.name = $p4 + AND v1.current = $p5) + }) + RETURN v0"""); + } } diff --git a/neo4j-cypher-dsl/src/main/java/org/neo4j/cypherdsl/core/internal/ScopingStrategy.java b/neo4j-cypher-dsl/src/main/java/org/neo4j/cypherdsl/core/internal/ScopingStrategy.java index 2e50301cef..7be901e458 100644 --- a/neo4j-cypher-dsl/src/main/java/org/neo4j/cypherdsl/core/internal/ScopingStrategy.java +++ b/neo4j-cypher-dsl/src/main/java/org/neo4j/cypherdsl/core/internal/ScopingStrategy.java @@ -42,6 +42,7 @@ import org.neo4j.cypherdsl.core.AliasedExpression; import org.neo4j.cypherdsl.core.Asterisk; import org.neo4j.cypherdsl.core.Cypher; +import org.neo4j.cypherdsl.core.ExistentialSubquery; import org.neo4j.cypherdsl.core.Expression; import org.neo4j.cypherdsl.core.Foreach; import org.neo4j.cypherdsl.core.FunctionInvocation; @@ -259,7 +260,10 @@ public void doLeave(Visitable visitable) { leaveStatement(visitable); } else if (hasLocalScope(visitable)) { notify = true; - this.dequeOfVisitedNamed.pop(); + Set lastVisitedNames = this.dequeOfVisitedNamed.pop(); + if (visitable instanceof ExistentialSubquery) { + this.afterStatement.retainAll(lastVisitedNames); + } } else { clearPreviouslyVisitedNamed(visitable); }