Allow optional chains in MATCH
@@ -424,7 +424,7 @@ public class OMatchExecutionPlanner {
visitedEdges.add(edge);
resultingSchedule.add(new EdgeTraversal(edge, traversalDirection));
}
- } else if (!startNode.optional) {
+ } else if (!startNode.optional || isOptionalChain(startNode, edge, neighboringNode)) {
// If the neighboring node wasn't visited, we don't expand the optional node into it, hence the above check.
// Instead, we'll allow the neighboring node to add the edge we failed to visit, via the above block.
if (visitedEdges.contains(edge)) {
@@ -439,6 +439,28 @@ public class OMatchExecutionPlanner {
}
}
+ private boolean isOptionalChain(PatternNode startNode, PatternEdge edge, PatternNode neighboringNode) {
+ return isOptionalChain(startNode, edge, neighboringNode, new HashSet<>());
+ }
+
+ private boolean isOptionalChain(PatternNode startNode, PatternEdge edge, PatternNode neighboringNode, Set<PatternEdge> visitedEdges) {
+ if (!startNode.isOptionalNode() || !neighboringNode.isOptionalNode()) {
+ return false;
+ }
+
+ visitedEdges.add(edge);
+
+ if (neighboringNode.out != null) {
+ for (PatternEdge patternEdge : neighboringNode.out) {
+ if (!visitedEdges.contains(patternEdge) && !isOptionalChain(neighboringNode, patternEdge, patternEdge.in, visitedEdges)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
/**
* Calculate the set of dependency aliases for each alias in the pattern.
*
