Skip to content

Cypher engine hardcodes id as the node-identity column #1490

Closed

Description

@lmeyerov

Summary

The GFQL Cypher lowering assumes the node-identity column is literally named
id
. It does not respect the node-id column bound via g.nodes(df, node_col),
and it cannot distinguish a node's identity from a Cypher property that
happens to be named id.

Surfaced while working graphistry/tck-gfql#126 (the TCK harness wanted to model
a node with an id property distinct from its synthetic identity, per the
openCypher with2-1 setup CREATE (a:End {num: 42, id: 0}), ...).

Where id is hardcoded

graphistry/compute/gfql/cypher/lowering.py:

  • L3456 — repeated node-variable dedup:
    compare(col(alias, "id"), "==", col(rewritten_alias, "id"))
  • L1427 — connected-join alias identity: prop = "id" if isinstance(target, ASTNode) else ...
  • L6549, L6623 — aggregate / alias identity helpers: return "id" for ASTNode.

When the bound node-id column is not named id, repeated-variable patterns
(e.g. MATCH (n)-[]->(n)) fail validation:

GFQLValidationError: [unsupported-cypher-query] WHERE references missing
column 'id' on alias 'n' (node, step=2). Available columns: __node_id__, ...

Impact / two facets

  1. Bound node-id column ignored. g.nodes(df, "__node_id__").gfql("<cypher>")
    with a repeated node variable raises E108 even though the graph is valid.
  2. Identity vs. id property conflated. Because identity is the id
    column, a node that genuinely has a Cypher property named id (distinct
    from identity) cannot be represented — the renderer only surfaces id as a
    property via a numeric-dtype heuristic
    (row/entity_props.py::_include_numeric_id_as_property), which breaks on
    mixed-dtype id columns.

Suggested fix

Thread the graph's bound node-id column name through Cypher lowering instead of
the "id" string literal (and likewise for edges, which already use
__gfql_edge_index_0__). Longer term, model node identity as an internal
column separate from user-visible properties so a Cypher id property is
representable.

Links

Activity

  1. lmeyerov commented on May 17, 2026

    @lmeyerov
    ContributorAuthor

    tck-gfql #126 now has an implementation PR that adopts reserved harness-side node identity and records the resulting direct-Cypher fallout:

    Relevant count changes from the corrected fixture:

    • Direct-Cypher promoted-only snapshot: 933 (rows 794, errors 139) -> 926 (rows 787, errors 139)
    • Direct-Cypher total snapshot: 2893 / 3627 (79.8%) -> 2886 / 3627 (79.6%)
    • Status counts: supported 2910, xfail 717 -> supported 2903, xfail 724

    Seven scenarios returned from direct-Cypher promotion to xfail because graph_fixture_from_create no longer exposes synthetic node identity as data column id: match7-24, return-orderby2-6, expr-graph3-5, expr-graph7-1, usecase-countingsubgraphmatches1-6, usecase-countingsubgraphmatches1-7, usecase-countingsubgraphmatches1-9.

    This is the expected evidence for this pygraphistry issue: tck-gfql can now model Cypher id separately from fixture identity, and the remaining failures are direct-Cypher lowering/runtime assumptions about identity column name. No pygraphistry runtime changes were made in the tck-gfql PR.

  2. lmeyerov commented on May 17, 2026

    @lmeyerov
    ContributorAuthor

    tck-gfql #126 is now merged via PR #131:

    The merged tck-gfql baseline keeps the corrected harness fixture model and records the pygraphistry fallout here:

    • Direct-Cypher promoted-only snapshot: 926 (rows 787, errors 139)
    • Direct-Cypher total snapshot: 2886 / 3627 (79.6%)
    • Status counts: supported 2903, xfail 724
    • Seven identity-assumption scenarios remain xfailed: match7-24, return-orderby2-6, expr-graph3-5, expr-graph7-1, usecase-countingsubgraphmatches1-6, usecase-countingsubgraphmatches1-7, usecase-countingsubgraphmatches1-9

    No pygraphistry runtime changes landed in that PR; this issue remains the upstream follow-up for direct-Cypher lowering honoring the bound node-id column separately from a Cypher id property.

  3. lmeyerov commented on May 17, 2026

    @lmeyerov
    ContributorAuthor

    Closeout after conflict resolution/merge:

    Issue is closed by #1504. Remaining direct-Cypher/TCK work should be recalculated from pygraphistry master plus tck-gfql main, not the pre-#1490 drift snapshot.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions