Repository navigation
Conversation
STRUCT values previously rendered as a single JSON blob per cell. They
now expand into grouped sub-columns with a multi-row header, up to a
configurable depth (`duckdb.nestedColumnMaxDepth`, default 2; 0 restores
the old flat JSON rendering).
Nested leaves are first-class: sorting, filtering, column stats, distinct
values, selection, copy and column resize all work on them, not just on
top-level columns.
Making that work required fixing how column names reach SQL. Every call
site built references as `"${column}"`, so a nested path would emit
`"s.x"` — a request for a column literally named `s.x` — instead of the
struct-field reference `"s"."x"`. A new shared `ColumnRef` type (name or
path) plus `quoteColumnRef()` quotes segment-by-segment and replaces the
hand-rolled quoting in fetchPage, exportCache, getCopyData,
getCacheColumnStats, getColumnDistinctValues, getColumnCardinality and
filterToSql.
DuckDB's SUMMARIZE only reports top-level columns, so nested leaves are
summarized separately via a projection that aliases each leaf to its
dotted label; that query is best-effort and never blocks the flat
summaries.
Cell editing stays top-level only: write-back targets a whole column, so
editing a struct field would require rebuilding the struct value. Nested
cells remain viewable but read-only.
Tests: 21 new (13 pure-function, 8 integration against a real DuckDB
connection covering ORDER BY / WHERE / aggregates / distinct+cardinality
/ SUMMARIZE on nested fields). One asserts the naive `"s.we.ird"` form
fails, pinning the dotted-field-name bug.
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.
What
STRUCT columns previously rendered as a single JSON blob per cell. They now expand into grouped sub-columns with a multi-row header.
s→{"x":10,"y":{"z":"a"}}sgroup header spanningx|y.zleaf columnsDepth is configurable via
duckdb.nestedColumnMaxDepth(default2). Setting it to0restores the previous flat JSON rendering, so this is opt-out.Nested leaves are first-class — sorting, filtering, column stats, distinct values, selection, copy, and column resize all work on them, not just on top-level columns.
The SQL quoting fix underneath
Making nested columns sortable/filterable surfaced a latent issue: every call site built column references as
`"${column}"`. For a nested path that emits"s.x"— a request for a column literally nameds.x— instead of the struct-field reference"s"."x".A new shared
ColumnReftype (string | string[]) plusquoteColumnRef()quotes segment-by-segment and replaces the hand-rolled quoting infetchPage,exportCache,getCopyData,getCacheColumnStats,getColumnDistinctValues,getColumnCardinality, andfilterToSql. Top-level columns still pass plain strings, so existing behavior is unchanged.This also handles field names containing dots or quotes correctly.
SUMMARIZE
DuckDB's
SUMMARIZEonly reports top-level columns, so nested leaves would be missing from the columns panel. They're summarized separately via a projection aliasing each leaf to its dotted label:That query is best-effort — if it fails, the flat summaries still render.
Scope / limitations
STRUCT(...)[](list-of-struct),MAP, andUNIONare not expanded and render as before.Testing
21 new tests, all passing (185 total in the suite):
src/test/nestedColumns.test.ts(13) — pure functions: STRUCT type-string parsing (quoted identifiers, embedded commas/parens/escaped quotes,DECIMAL(18,3), rejection of list-of-struct/MAP), header colSpan/rowSpan construction, depth limiting, path-based value extraction.src/test/nestedColumnSql.test.ts(8) — integration against a real DuckDB connection, verifyingORDER BY/WHERE/ aggregates / distinct+cardinality / the SUMMARIZE projection all execute correctly on nested fields. One test asserts the naive"s.we.ird"form fails, pinning the dotted-field-name bug so it can't regress.tsc --noEmitclean, esbuild passes,eslint srcreports 0 errors (warning count is below the pre-existing baseline onmain).