Skip to content

Commit 05b3dbe

Browse files
authored
Merge pull request #1698 from graphistry/fix/existentialsubquery-entity-text-whitespace
conformance: EXISTS existentialsubquery TCK scenarios green (tck-gfql#193)
2 parents 1fa0de2 + 410f925 commit 05b3dbe

3 files changed

Lines changed: 40 additions & 0 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
5959

6060
- **dgx GB10 benchmark safety harness**: `benchmarks/dgx/{safe_run.sh, preflight.py, sitecustomize.py, local_run.sh}` — an RMM device-allocation cap + host-memory watchdog + preflight refusal + hard timeout for running GPU / large-graph benchmarks on the unified-memory GB10 box without OOM-wedging it. Developer/benchmark tooling only; no runtime or library behavior change.
6161
- **Docs CI: polars in the doc-test image (pinned)**: the Sphinx doc-example runner now installs `polars` (pinned to cooldown-safe versions) so `engine='polars'` documentation examples execute — and are SKIPPED, not failed, where polars is unavailable (e.g. the minimal-deps job, Python 3.14). Doc-build / CI only; no runtime or library change.
62+
- **openCypher TCK conformance: `EXISTS { }` existential-subquery scenarios (`expr-existentialsubquery1-1`, `1-3`) now pass**, unblocking the `tck-gfql` CI job. No pygraphistry code change — pygraphistry already renders these correctly (a whole-entity `RETURN n` over a simple-pattern `EXISTS { }` yields the expected entity-text rows). The `success_wrong_rows` was purely a property-map display-whitespace convention (`(:A {prop: 1})` vs the TCK oracle's `(:A {prop:1})`; both valid Cypher). Reconciled harness-side in [tck-gfql#193](https://github.com/graphistry/tck-gfql/pull/193): entity-text whitespace normalization + promoting the two scenarios to supported (and deflaking the pre-existing scipy-`svds` `firstparty-networkx-hits-1` fixture). Conformance/CI only; no runtime or library behavior change.
6263

6364
## [0.57.0 - 2026-06-28]
6465

‎graphistry/compute/gfql/cypher/result_postprocess.py‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,12 @@ def render_entity_text(
186186
the Cypher display string (``(:Label {..})`` / ``[:TYPE {..}]``). Used by the
187187
conformance/TCK driver and by callers who want the human-readable form. The
188188
structured data path itself never pays this cost.
189+
190+
Property maps render with a space after the key colon (``(:A {prop: 1})``) —
191+
our long-standing display convention. The openCypher TCK oracle omits it
192+
(``(:A {prop:1})``); the whitespace is insignificant Cypher, so the TCK
193+
harness normalizes it rather than us changing this convention across ~350
194+
tests (see tck-gfql#193 / CHANGELOG).
189195
"""
190196
rows_df = cast(DataFrameT, result._nodes)
191197
if rows_df is None:

‎graphistry/tests/compute/gfql/test_engine_polars_conformance_matrix.py‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,39 @@ def test_exists_prune_isolated_flavors_all_engines():
752752
_assert_invariant(g, q, f"prune-isolated {q}")
753753

754754

755+
def test_exists_whole_entity_return_renders_entity_text():
756+
"""Regression for openCypher TCK expr-existentialsubquery1-1 (tck-gfql#193):
757+
a WHOLE-ENTITY ``RETURN n`` over a simple-pattern ``EXISTS { }`` renders the
758+
correct entity text (label + property), not leaked internal marker columns.
759+
Graph mirrors the TCK fixture — node ``a`` is the only one with an out-edge —
760+
so the EXISTS filter keeps exactly ``a`` and it renders ``(:A {prop: 1})``.
761+
762+
``id`` is a STRING on purpose: a numeric id would render as an extra
763+
property (``{id: 0, prop: 1}``). ``n.id`` is the #1650 flattened
764+
whole-entity projection column, not user-aliased output."""
765+
import pandas as pd
766+
from graphistry.compute.gfql.cypher.result_postprocess import render_entity_text
767+
nodes = pd.DataFrame({
768+
"id": ["a", "b", "c", "d"],
769+
"label__A": [True, False, False, False],
770+
"label__B": [False, True, False, False],
771+
"label__C": [False, False, True, False],
772+
"label__D": [False, False, False, True],
773+
"prop": [1, 1, 2, 3],
774+
})
775+
edges = pd.DataFrame({"s": ["a", "a", "a"], "d": ["b", "c", "d"], "eid": [0, 1, 2]})
776+
g = graphistry.nodes(nodes, "id").edges(edges, "s", "d").bind(edge="eid")
777+
q = "MATCH (n) WHERE EXISTS { (n)-->() } RETURN n"
778+
res = g.gfql(q, engine="pandas")
779+
pdf = _to_pd(res._nodes)
780+
assert len(pdf) == 1, "EXISTS keeps exactly the one node with an out-edge"
781+
assert pdf["n.id"].tolist() == ["a"]
782+
assert render_entity_text(res, "n", table="nodes").tolist() == ["(:A {prop: 1})"]
783+
# Cross-engine (this file's invariant): non-pandas engines match pandas
784+
# parity or decline honestly (NIE) — whole-entity RETURN declines on polars.
785+
_assert_invariant(g, q, "exists-whole-entity-return")
786+
787+
755788
def test_tolower_non_string_declines_never_fabricates():
756789
"""toLower/toUpper on a non-string column must never return values (neo4j: type error).
757790
Regression (#1675 wave-1, dgx-repro'd): the scalar fallback broadcast the lowercased

0 commit comments

Comments
 (0)