3737 * Tests for the OPTIONAL MATCH + count() → countEdges() optimization.
3838 * Verifies that the optimization produces correct results and falls back
3939 * to full materialization when the pattern is not optimizable.
40+ *
41+ * @author Luca Garulli (l.garulli@arcadedata.com)
4042 */
4143class CountEdgesOptimizationTest {
4244 private Database database ;
@@ -84,7 +86,8 @@ void tearDown() {
8486 void basicOptionalMatchCount () {
8587 // Basic optimization: count comments per question
8688 final ResultSet rs = database .query ("opencypher" ,
87- "MATCH (q:Question) OPTIONAL MATCH (c:Comment)-[:COMMENTED_ON]->(q) WITH q, count(c) AS cnt RETURN q.name AS name, cnt ORDER BY name" );
89+ "MATCH (q:Question) OPTIONAL MATCH (c:Comment)-[:COMMENTED_ON]->(q) WITH q, count(c) AS cnt RETURN q.name AS " +
90+ "name, cnt ORDER BY name" );
8891
8992 final Map <String , Long > results = collectNameCount (rs );
9093 assertThat (results ).hasSize (3 );
@@ -97,7 +100,8 @@ void basicOptionalMatchCount() {
97100 void noEdgesReturnsZero () {
98101 // q3 has no comments — should return 0
99102 final ResultSet rs = database .query ("opencypher" ,
100- "MATCH (q:Question {name: 'q3'}) OPTIONAL MATCH (c:Comment)-[:COMMENTED_ON]->(q) WITH q, count(c) AS cnt RETURN cnt" );
103+ "MATCH (q:Question {name: 'q3'}) OPTIONAL MATCH (c:Comment)-[:COMMENTED_ON]->(q) WITH q, count(c) AS cnt " +
104+ "RETURN cnt" );
101105
102106 assertThat (rs .hasNext ()).isTrue ();
103107 assertThat (rs .next ().<Long >getProperty ("cnt" )).isEqualTo (0L );
@@ -109,7 +113,8 @@ void noEdgesReturnsZero() {
109113 void typedEdgeFilter () {
110114 // Count only COMMENTED_ON edges (not ANSWERED)
111115 final ResultSet rs = database .query ("opencypher" ,
112- "MATCH (q:Question {name: 'q1'}) OPTIONAL MATCH (c:Comment)-[:COMMENTED_ON]->(q) WITH q, count(c) AS cnt RETURN cnt" );
116+ "MATCH (q:Question {name: 'q1'}) OPTIONAL MATCH (c:Comment)-[:COMMENTED_ON]->(q) WITH q, count(c) AS cnt " +
117+ "RETURN cnt" );
113118
114119 assertThat (rs .hasNext ()).isTrue ();
115120 assertThat (rs .next ().<Long >getProperty ("cnt" )).isEqualTo (3L );
@@ -121,7 +126,8 @@ void typedEdgeFilter() {
121126 void multiTypePattern () {
122127 // Count both COMMENTED_ON and ANSWERED edges using pipe syntax
123128 final ResultSet rs = database .query ("opencypher" ,
124- "MATCH (q:Question {name: 'q1'}) OPTIONAL MATCH (x)-[:COMMENTED_ON|ANSWERED]->(q) WITH q, count(x) AS cnt RETURN cnt" );
129+ "MATCH (q:Question {name: 'q1'}) OPTIONAL MATCH (x)-[:COMMENTED_ON|ANSWERED]->(q) WITH q, count(x) AS cnt " +
130+ "RETURN cnt" );
125131
126132 assertThat (rs .hasNext ()).isTrue ();
127133 assertThat (rs .next ().<Long >getProperty ("cnt" )).isEqualTo (5L );
@@ -133,7 +139,8 @@ void multiTypePattern() {
133139 void reverseDirection () {
134140 // OPTIONAL MATCH (q)<-[:COMMENTED_ON]-(c) — should produce same results as (c)-[:COMMENTED_ON]->(q)
135141 final ResultSet rs = database .query ("opencypher" ,
136- "MATCH (q:Question) OPTIONAL MATCH (q)<-[:COMMENTED_ON]-(c:Comment) WITH q, count(c) AS cnt RETURN q.name AS name, cnt ORDER BY name" );
142+ "MATCH (q:Question) OPTIONAL MATCH (q)<-[:COMMENTED_ON]-(c:Comment) WITH q, count(c) AS cnt RETURN q.name AS " +
143+ "name, cnt ORDER BY name" );
137144
138145 final Map <String , Long > results = collectNameCount (rs );
139146 assertThat (results ).hasSize (3 );
@@ -159,7 +166,8 @@ void bothDirection() {
159166 void whereClausePreventsOptimization () {
160167 // WHERE clause should prevent optimization, but still produce correct results via fallback
161168 final ResultSet rs = database .query ("opencypher" ,
162- "MATCH (q:Question) OPTIONAL MATCH (c:Comment)-[:COMMENTED_ON]->(q) WHERE c.text = 'c0' WITH q, count(c) AS cnt RETURN q.name AS name, cnt ORDER BY name" );
169+ "MATCH (q:Question) OPTIONAL MATCH (c:Comment)-[:COMMENTED_ON]->(q) WHERE c.text = 'c0' WITH q, count(c) AS " +
170+ "cnt RETURN q.name AS name, cnt ORDER BY name" );
163171
164172 final Map <String , Long > results = collectNameCount (rs );
165173 assertThat (results ).hasSize (3 );
@@ -172,7 +180,8 @@ void whereClausePreventsOptimization() {
172180 void distinctPreventsOptimization () {
173181 // count(DISTINCT c) should prevent optimization but still produce correct results
174182 final ResultSet rs = database .query ("opencypher" ,
175- "MATCH (q:Question) OPTIONAL MATCH (c:Comment)-[:COMMENTED_ON]->(q) WITH q, count(DISTINCT c) AS cnt RETURN q.name AS name, cnt ORDER BY name" );
183+ "MATCH (q:Question) OPTIONAL MATCH (c:Comment)-[:COMMENTED_ON]->(q) WITH q, count(DISTINCT c) AS cnt RETURN q" +
184+ ".name AS name, cnt ORDER BY name" );
176185
177186 final Map <String , Long > results = collectNameCount (rs );
178187 assertThat (results ).hasSize (3 );
@@ -185,7 +194,8 @@ void distinctPreventsOptimization() {
185194 void variableLengthPreventsOptimization () {
186195 // Variable-length path should prevent optimization but still produce correct results
187196 final ResultSet rs = database .query ("opencypher" ,
188- "MATCH (q:Question {name: 'q1'}) OPTIONAL MATCH (c)-[:COMMENTED_ON*1..1]->(q) WITH q, count(c) AS cnt RETURN cnt" );
197+ "MATCH (q:Question {name: 'q1'}) OPTIONAL MATCH (c)-[:COMMENTED_ON*1..1]->(q) WITH q, count(c) AS cnt RETURN " +
198+ "cnt" );
189199
190200 assertThat (rs .hasNext ()).isTrue ();
191201 assertThat (rs .next ().<Long >getProperty ("cnt" )).isEqualTo (3L );
0 commit comments