Repository navigation
feat(gfql/index): index DDL travels with the query that uses it, in one gfql() call (#2119) - #2132
Merged
Merged
Conversation
…ne gfql() call
There was no way to build an index and use it in one call: DDL was a whole-string
fast path, CreateIndex/DropIndex were wire ops the chain and let() type gates
rejected, and `CREATE ...; MATCH ...` was "malformed DDL". Now:
* `call('create_index', {kind, column?, name?})` and `call('drop_index', {kind?,
column?})` are safelisted GFQL ops over the existing Plottable methods, so DDL sits
at the front of a chain, in a let() binding, or in chain JSON.
* CreateIndex/DropIndex objects (and their JSON) in a chain list or let binding
normalize to those calls; ShowIndexes (a table) and a drop-by-name (no method
form) are rejected with the standalone form they do have.
* A Cypher string may lead with `CREATE GFQL INDEX ...;` statements: they build
first and the remainder runs on the indexed graph. One statement, with or without
';', keeps the one-op path.
* Two registry drops found on the way: gfql()'s index_policy branch copied `self`
instead of the DDL-applied graph, and the chain's all-call branch rebuilt its result
from `self` when it had attached its edge-index column. Both fixed; every fused
form is pinned to be served by the same index seams as the two-step form, on
pandas and cuDF; the polars chain engine's existing "no call() before a
traversal" decline is pinned for the list form, and the string form works there.
Closes #2119.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_017ropeBMLJUuy6ViYwy15ud
…docs snippet runs on the page fixture A caller's later mutation of their list must still be seen and re-validated on execute (test_mutated_operation_list_is_not_trusted); only a list with CreateIndex/DropIndex gets a normalized copy. The indexing page's one-call example now uses the fixture's string ids so the doc-example audit executes it. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_017ropeBMLJUuy6ViYwy15ud
This was referenced Oct 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2119.
What
There was no way to build an index and use it in one
g.gfql(...): DDL was a whole-string fast path,CreateIndex/DropIndexwere wire ops the chain andlet()type gates rejected, andCREATE ...; MATCH ...was "malformed DDL". Now:call('create_index', {kind, column?, name?})/call('drop_index', {kind?, column?})are safelisted GFQL ops over the existing Plottable methods — so DDL sits at the front of a chain (the chain already runscall()prefixes before traversals), in alet()binding, or in chain JSON.CreateIndex/DropIndexobjects, and their JSON, in a chain list orletbinding normalize to those calls.ShowIndexes(a table, not a graph) and a drop-by-name (no method form) are rejected with the standalone form they do have.CREATE GFQL INDEX ...;statements: they build first, the remainder runs on the indexed graph. One statement — with or without;— keeps the one-op path; a;inside the query body is never a boundary.Two registry drops found on the way and fixed:
gfql()'sindex_policybranch copiedselfinstead of the DDL-applied graph; the chain's all-call()branch rebuilt its result fromselfwhen it had attached its synthetic edge-index column (migrated with the existingrebind_edgesidiom).Pinned
test_index_ddl_in_one_call.py: every fused form is served by the same index seams as the two-step form (gfql_explain), on pandas and cuDF (with and without an edge-id binding); the string form works on polars too, while the polars chain engine's pre-existing "nocall()before a traversal" decline is pinned for the list form. Negatives:ShowIndexesin a chain, drop-by-name in a chain, unknown/missing kind,SHOWinside a multi-statement, malformed leading DDL. Wire round-trip of a chain holding a rawCreateIndexdocument.create_index/drop_indexjoin the polars chain-vs-DAG consistency matrix so the conformance ledger counts them exercised (no waiver). Docs: one-call forms inindexing.rst.Local: ruff/guards/surface guard/mypy clean; 602 related tests pass; route-off replay clean.
Not here (said on the issue)
CREATE GFQL INDEXas a statement insideGRAPH { }/ aCALL graphistry.index.*procedure — grammar and procedure-resolver work; the one-call need the docs example had is met by the forms above.🤖 Generated with Claude Code
https://claude.ai/code/session_017ropeBMLJUuy6ViYwy15ud