22
33import pandas as pd
44import pytest
5- from typing import Any , Dict , List , Tuple , cast
5+ from typing import Any , Dict , List , Optional , Tuple , cast
66
77from graphistry .compute .ast import ASTCall , ASTNode , ASTEdgeForward , ASTEdgeReverse , ASTEdgeUndirected
88from graphistry .compute .exceptions import ErrorCode , GFQLSyntaxError , GFQLTypeError , GFQLValidationError
@@ -116,6 +116,23 @@ def _compiled_reentry_projection_outputs(compiled: CompiledCypherQuery) -> Tuple
116116 return whole_row_columns [0 ], carried_columns
117117
118118
119+ def _reentry_query (
120+ with_clause : str ,
121+ * ,
122+ return_clause : str ,
123+ match_alias : str = "a" ,
124+ order_by : Optional [str ] = None ,
125+ where_clause : Optional [str ] = None ,
126+ ) -> str :
127+ parts = ["MATCH (a:A) " , f"WITH { with_clause } " , f"MATCH ({ match_alias } )-->(b) " ]
128+ if where_clause is not None :
129+ parts .append (f"WHERE { where_clause } " )
130+ parts .append (f"RETURN { return_clause } " )
131+ if order_by is not None :
132+ parts .append (f" ORDER BY { order_by } " )
133+ return "" .join (parts )
134+
135+
119136def _assert_query_rows (
120137 query : str ,
121138 expected_rows : list [dict [str , object ]],
@@ -5049,29 +5066,26 @@ def test_string_cypher_executes_with_match_reentry_multihop_shape() -> None:
50495066 ("query" , "expected_whole_row_output" , "expected_columns" ),
50505067 [
50515068 (
5052- "MATCH (a:A) "
5053- "WITH a, a.num AS property "
5054- "MATCH (a)-->(b) "
5055- "RETURN property "
5056- "ORDER BY property DESC" ,
5069+ _reentry_query ("a, a.num AS property" , return_clause = "property" , order_by = "property DESC" ),
50575070 "a" ,
50585071 ("property" ,),
50595072 ),
50605073 (
5061- "MATCH (a:A) "
5062- "WITH a, a.num AS property, a.num + 10 AS property2 "
5063- "MATCH (a)-->(b) "
5064- "RETURN property, property2 "
5065- "ORDER BY property DESC" ,
5074+ _reentry_query (
5075+ " a, a.num AS property, a.num + 10 AS property2" ,
5076+ return_clause = "property, property2" ,
5077+ order_by = "property DESC" ,
5078+ ) ,
50665079 "a" ,
50675080 ("property" , "property2" ),
50685081 ),
50695082 (
5070- "MATCH (a:A) "
5071- "WITH a AS x, a.num AS property "
5072- "MATCH (x)-->(b) "
5073- "RETURN property "
5074- "ORDER BY property DESC" ,
5083+ _reentry_query (
5084+ "a AS x, a.num AS property" ,
5085+ match_alias = "x" ,
5086+ return_clause = "property" ,
5087+ order_by = "property DESC" ,
5088+ ),
50755089 "x" ,
50765090 ("property" ,),
50775091 ),
@@ -5093,43 +5107,32 @@ def test_compile_cypher_tracks_reentry_carried_scalar_columns(
50935107 ("query" , "expected" ),
50945108 [
50955109 (
5096- "MATCH (a:A) "
5097- "WITH a AS x "
5098- "MATCH (x)-->(b) "
5099- "RETURN b.id AS bid "
5100- "ORDER BY bid" ,
5110+ _reentry_query ("a AS x" , match_alias = "x" , return_clause = "b.id AS bid" , order_by = "bid" ),
51015111 [{"bid" : "b1" }, {"bid" : "b2" }],
51025112 ),
51035113 (
5104- "MATCH (a:A) "
5105- "WITH a, a.num AS property "
5106- "MATCH (a)-->(b) "
5107- "RETURN property "
5108- "ORDER BY property DESC" ,
5114+ _reentry_query ("a, a.num AS property" , return_clause = "property" , order_by = "property DESC" ),
51095115 [{"property" : 2 }, {"property" : 1 }],
51105116 ),
51115117 (
5112- "MATCH (a:A) "
5113- "WITH a, a.num AS property "
5114- "MATCH (a)-->(b) "
5115- "RETURN a "
5116- "ORDER BY property DESC" ,
5118+ _reentry_query ("a, a.num AS property" , return_clause = "a" , order_by = "property DESC" ),
51175119 [{"a" : "(:A {num: 2})" }, {"a" : "(:A {num: 1})" }],
51185120 ),
51195121 (
5120- "MATCH (a:A) "
5121- "WITH a, a.num AS property, a.num + 10 AS property2 "
5122- "MATCH (a)-->(b) "
5123- "RETURN property, property2 "
5124- "ORDER BY property DESC" ,
5122+ _reentry_query (
5123+ " a, a.num AS property, a.num + 10 AS property2" ,
5124+ return_clause = "property, property2" ,
5125+ order_by = "property DESC" ,
5126+ ) ,
51255127 [{"property" : 2 , "property2" : 12 }, {"property" : 1 , "property2" : 11 }],
51265128 ),
51275129 (
5128- "MATCH (a:A) "
5129- "WITH a AS x, a.num AS property "
5130- "MATCH (x)-->(b) "
5131- "RETURN x, property "
5132- "ORDER BY property DESC" ,
5130+ _reentry_query (
5131+ "a AS x, a.num AS property" ,
5132+ match_alias = "x" ,
5133+ return_clause = "x, property" ,
5134+ order_by = "property DESC" ,
5135+ ),
51335136 [{"x" : "(:A {num: 2})" , "property" : 2 }, {"x" : "(:A {num: 1})" , "property" : 1 }],
51345137 ),
51355138 ],
@@ -5143,13 +5146,7 @@ def test_string_cypher_reentry_carried_scalars_ignore_internal_hidden_column_col
51435146 g = _mk_reentry_carried_scalar_graph ()
51445147 g ._nodes = g ._nodes .assign (__cypher_reentry_property__ = ["orig1" , "orig2" , None , None ])
51455148
5146- result = g .gfql (
5147- "MATCH (a:A) "
5148- "WITH a, a.num AS property "
5149- "MATCH (a)-->(b) "
5150- "RETURN property "
5151- "ORDER BY property DESC"
5152- )
5149+ result = g .gfql (_reentry_query ("a, a.num AS property" , return_clause = "property" , order_by = "property DESC" ))
51535150
51545151 assert result ._nodes .to_dict (orient = "records" ) == [{"property" : 2 }, {"property" : 1 }]
51555152
@@ -5158,11 +5155,11 @@ def test_string_cypher_reentry_carried_scalars_ignore_internal_hidden_column_col
51585155 ("query" , "match" ),
51595156 [
51605157 (
5161- "MATCH (a:A) "
5162- "WITH a, a.num AS property "
5163- "MATCH (a)-->(b) "
5164- "WHERE property = b.num "
5165- "RETURN b.id AS id" ,
5158+ _reentry_query (
5159+ " a, a.num AS property" ,
5160+ return_clause = "b.id AS id" ,
5161+ where_clause = " property = b.num" ,
5162+ ) ,
51665163 "one MATCH source alias at a time" ,
51675164 ),
51685165 (
0 commit comments