Skip to content

feat(gfql): native chain rows() bindings table (#880) - #1014

Merged
lmeyerov merged 8 commits into
masterfrom
feat/gfql-880-bindings-table
Apr 1, 2026
Merged

lmeyerov merged 8 commits into
masterfrom
feat/gfql-880-bindings-table

Conversation

@lmeyerov

@lmeyerov lmeyerov commented Apr 1, 2026

Copy link
Copy Markdown
Contributor

Summary

  • wire native chain rows() after named traversal ops to reuse connected binding_ops row materialization
  • reject duplicate aliases in the legacy chain path and in direct rows(binding_ops=...) execution
  • factor binding-op serialization into a shared helper and amplify guard-level regression coverage around injection

Testing

  • bash bin/pytest.sh graphistry/tests/test_compute_chain.py -k "ChainBindingsTable" -q
  • python3.12 -B -m pytest -q graphistry/tests/compute/gfql/cypher/test_lowering.py -k "multi_alias_return or multi_alias_with_stage_still_rejected or cypher_to_gfql_supports_multi_alias_scalar_projection"

Notes

  • select() on a missing alias-prefixed bindings column still raises the existing generic parser error and remains follow-up work
  • this PR also hardens the direct rows(binding_ops=...) path, which previously allowed duplicate aliases and produced corrupted duplicate-prefixed columns

lmeyerov and others added 8 commits April 1, 2026 10:45
When a native GFQL chain has named ops (n(name=...), e(name=...))
followed by a bare rows() call, automatically serialize the traversal
ops as binding_ops so rows() materializes a multi-alias bindings table
instead of a single-table view.

This enables patterns like:
  g.gfql([n(name='a'), e_forward(), n(name='b'), rows()])
to produce alias-prefixed columns (a.id, b.id, a.val, etc.)

The implementation reuses _gfql_connected_bindings_row_table from the
Cypher path — no new algorithms needed, just wiring in chain.py.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Add tests for: unnamed ops (no injection), explicit source param
(no override), empty match (empty result), three-hop chain.
Also guard against alias_endpoints override.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Verify that binding_ops injection works when the first node op
has no name but later ops do — bindings are still materialized
for the named aliases.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
combine_steps() previously silently discarded the second alias's
boolean tag when two ops shared the same name. Now raises
GFQLValidationError with a clear message identifying the conflicting
steps.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Add 8 tests covering:
- duplicate edge alias rejection
- four-hop chain with all aliases
- empty first-node match → empty bindings
- mid-chain empty edge match → empty bindings
- select() with edge alias property projection (r.weight)
- select() with missing column raises GFQLTypeError
- reverse edge direction bindings

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@lmeyerov
lmeyerov merged commit 7fa5f43 into master Apr 1, 2026
99 checks passed
@lmeyerov
lmeyerov deleted the feat/gfql-880-bindings-table branch April 1, 2026 20:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant