@@ -155,3 +155,87 @@ def test_to_json_python_param_with_homogeneous_list_uses_typed_binding(
155155
156156 assert normalized_query == query
157157 assert normalized_parameters == parameters
158+
159+
160+ def test_get_as_df_json_scalar (conn_db_empty : ConnDB ) -> None :
161+ """
162+ Scalar JSON values convert through get_as_df() as Python strings.
163+
164+ Covers non-null values, typed JSON nulls, and a mixed column in a single query.
165+ """
166+ conn , _ = conn_db_empty
167+ df = conn .execute (
168+ "UNWIND ["
169+ 'CAST(\' {"a": 1, "b": [2, 3]}\' AS JSON), '
170+ "CAST(NULL AS JSON), "
171+ "CAST('[1, 2, 3]' AS JSON)"
172+ "] AS j RETURN j"
173+ ).get_as_df ()
174+
175+ assert str (df ["j" ].dtype ) == "object"
176+ assert df ["j" ].isna ().tolist () == [False , True , False ]
177+
178+ first = df ["j" ].iloc [0 ]
179+ assert isinstance (first , str )
180+ assert json .loads (first ) == {"a" : 1 , "b" : [2 , 3 ]}
181+
182+ third = df ["j" ].iloc [2 ]
183+ assert isinstance (third , str )
184+ assert json .loads (third ) == [1 , 2 , 3 ]
185+
186+
187+ def test_get_as_df_json_empty_result (conn_db_empty : ConnDB ) -> None :
188+ """
189+ An empty result over a JSON column builds the column without crashing.
190+
191+ convertToArrayType() runs during NPArrayWrapper construction, before any
192+ rows are iterated, so a zero-row JSON result is the minimal reproduction
193+ for the original dtype-selection crash.
194+ """
195+ conn , _ = conn_db_empty
196+ conn .execute ("CREATE NODE TABLE t (id SERIAL PRIMARY KEY, data JSON)" )
197+
198+ df = conn .execute ("MATCH (n:t) RETURN n.data AS data" ).get_as_df ()
199+
200+ assert len (df ) == 0
201+ assert str (df ["data" ].dtype ) == "object"
202+
203+
204+ def test_get_as_df_json_extract (conn_db_empty : ConnDB ) -> None :
205+ """json_extract() produces a scalar JSON result that converts via get_as_df()."""
206+ conn , _ = conn_db_empty
207+ conn .execute ("INSTALL json; LOAD json;" )
208+ conn .execute ("CREATE NODE TABLE t (id SERIAL PRIMARY KEY, data JSON)" )
209+
210+ data = {"name" : {"first" : "Alice" , "last" : "Smith" }}
211+ conn .execute (
212+ "CREATE (n:t {data: to_json($data)})" ,
213+ parameters = {"data" : json .dumps (data )},
214+ )
215+
216+ df = conn .execute (
217+ "MATCH (n:t) RETURN json_extract(n.data, '$.name') AS name"
218+ ).get_as_df ()
219+
220+ assert str (df ["name" ].dtype ) == "object"
221+ val = df ["name" ].iloc [0 ]
222+ assert isinstance (val , str )
223+ assert json .loads (val ) == {"first" : "Alice" , "last" : "Smith" }
224+
225+
226+ def test_get_as_df_json_list (conn_db_empty : ConnDB ) -> None :
227+ """JSON[] (LIST of JSON) columns keep their existing pandas behavior."""
228+ conn , _ = conn_db_empty
229+ conn .execute ("INSTALL json; LOAD json;" )
230+ conn .execute ("CREATE NODE TABLE t (id SERIAL PRIMARY KEY, data JSON[])" )
231+
232+ data = [{"x" : 1 }, {"x" : 2 }, {"x" : 3 }]
233+ conn .execute ("CREATE (n:t {data: $d})" , parameters = {"d" : data })
234+
235+ df = conn .execute ("MATCH (n:t) RETURN n.data AS data" ).get_as_df ()
236+
237+ assert str (df ["data" ].dtype ) == "object"
238+ val = df ["data" ].iloc [0 ]
239+ assert isinstance (val , list )
240+ assert len (val ) == 3
241+ assert all (isinstance (e , str ) for e in val )
0 commit comments