feat(query): add a GQL response format for query results
What does this MR do and why?
This adds an optional gql response format that prints query results as a cypher-shell style table. Columns are the query's node aliases, and each cell holds the full node. Defaults stay unchanged, so the format can be compared with GOON before replacing it.
Related Issues
Relates to #1263
Testing
Formatter, server, CLI, and migration-ledger tests pass, and workspace clippy passes. Real output from a local GDK through Rails and Workhorse:
+------------------------------------------------------------------------------------+
| u | g |
+------------------------------------------------------------------------------------+
| (:User {id: 1, username: "root"}) | (:Group {id: 22, name: "Toolbox"}) |
| (:User {id: 6, username: "georgine_keebler"}) | (:Group {id: 22, name: "Toolbox"}) |
+------------------------------------------------------------------------------------+
2 rows, more availablePerformance Analysis
- This merge request does not introduce any performance regression. If a performance regression is expected, explain why.
Rows repeat full node bodies, so output is larger than GOON's. Token cost and agent accuracy still need an evals-harness comparison.
Agent context: format, validation, and follow-ups
The format specification is in ADR 019.
Format
- Traversal columns are node aliases in pattern order; each row is one authorized, hydrated result row.
- Aggregations use their group and metric output names. Node groups print as node literals.
- Neighbors and path finding print a single
pathcolumn, such as(:Group {id: 22})<-[:MEMBER_OF]-(:User {id: 1}). - Values use cypher-shell literals: quoted strings,
TRUE,FALSE, andNULL. Long text keeps the GOON truncation limits. - The footer reports the row count, plus
more availableand the next cursor when paginated. Every traversal and aggregation row prints; duplicate paths and neighbors collapse, as in the raw format. - Truncated text adds a
<key>_lenproperty. Padding stops at 120 characters, so one long value does not widen every row. - The compiler does not keep
RETURNexpressions, so a returned property prints inside its node. The compiler is unchanged.
Other changes
- Only the query command advertises
gql. Graph-status accepts only raw and llm. - Unknown response-format integers fail before query execution. Schema queries under gql return TOON text.
- Schema-version lookup reads only the schema pin, so historical
versions.yamlfiles still parse after a new pin is added. - GOON 4.0.4 keeps edges that differ only in depth; it was dropping them.
[skip pinned-version-check]: shared formatter files match the raw pin's paths, but raw output is unchanged.
Validation
Companion Rails/Workhorse MR: gitlab-org/gitlab!258504. Real GDK requests through Rails and Workhorse returned tables for traversal, aggregation, neighbors, shortest path, named queries, and MCP. Earlier runs also confirmed invalid formats, anonymous access, and Rails redaction callbacks. The ClickHouse integration suite and agent evals were not run.
Required follow-ups
- Deploy the GKG release before enabling gql in GitLab; older servers return raw JSON for the new enum value.
- Land the companion Rails/Workhorse MR with a released protobuf client.
- Update glab-side format validation once GitLab accepts gql.
- Add the selected response format to query analytics through an Iglu schema change.
- Compare gql with llm in the evals harness before changing the default.