feat(columns): expose domain identity on domain-typed columns#1093
Open
coderdan wants to merge 1 commit into
Open
feat(columns): expose domain identity on domain-typed columns#1093coderdan wants to merge 1 commit into
coderdan wants to merge 1 commit into
Conversation
For a column whose type is a DOMAIN, the columns query resolved the
column to the domain's base type and never surfaced the domain itself.
Both fields that could carry the type name collapsed to the base type:
- `format` used COALESCE(bt.typname, t.typname), and `bt` is joined
only for domains, so the base type always won.
- `data_type` used format_type(t.typbasetype, NULL) for a domain whose
base type lives in pg_catalog.
Downstream consumers had no way to tell a `jsonb` column apart from a
column of a domain over `jsonb`, so the Studio table editor grid and
schema visualizer label such columns with the base type, while the
"New column" type picker shows the domain name because it reads from
the types query (format_type(t.oid)). The same type rendered
inconsistently across the UI.
Add `domain_schema` and `domain_name`, both null unless the column's
type is a domain. This follows information_schema.columns, which
columns.sql.ts is adapted from: `data_type` there reports the underlying
type and the domain is carried in separate domain_* columns.
The addition is deliberately non-breaking. `format` still reports the
base type because all four type generators feed it into resolvers that
only know base types, enums, composites, tables and views; a domain name
would fall through to `unknown` and silently regress generated types for
every domain column. The typegen snapshots confirm domain columns still
resolve to their base type (Json, number).
COLUMNS_SQL is the single source for tables, views, materialized views
and foreign tables, so all five endpoints pick this up.
As with information_schema, arrays of domains are not covered: the
domain identity there belongs to the element type.
Fixes supabase#1092
coderdan
marked this pull request as ready for review
July 24, 2026 11:05
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.
Fixes #1092.
Authored using Claude/Opus 4.8.
All code manually reviewed be me before PR was opened :)
Problem
For a column whose type is a
DOMAIN, thecolumnsquery resolves the column to the domain's base type and never surfaces the domain itself. Both output fields that could carry the type name collapse to the base type:formatusesCOALESCE(bt.typname, t.typname), andbtis joined only for domains so for a domain the base type always wins over the domain's ownt.typname.data_typeusesformat_type(t.typbasetype, NULL)for a domain whose base type lives inpg_catalog.So a
jsonbcolumn and a column of a domain overjsonbare indistinguishable in the API response. The Studio table editor grid and schema visualizer therefore label domain columns with the base type, while the "New column" type picker shows the domain name - it reads from thetypesquery, which usesformat_type(t.oid)and is domain-aware. The same type renders inconsistently across the UI.psql \dgets this right for the same reason.Change
Adds
domain_schemaanddomain_nameto the columns output. Both arenullunless the column's type is a domain:{ "name": "search", "data_type": "jsonb", "format": "jsonb", "domain_schema": "public", "domain_name": "eql_v3_text_search" }This follows
information_schema.columns— whichcolumns.sql.tssays in its first line it is adapted from — wheredata_typereports the underlying type and the domain identity is carried in separatedomain_*columns.COLUMNS_SQLis the single source of column introspection for tables, views, materialized views and foreign tables, so all five endpoints pick this up.Why additive, rather than changing
formatMaking
formatreport the domain name looks like the more direct fix, but I think it would break type generation.Keeping
formatas the base type means generators are entirely unaffected. The regenerated typegen snapshots confirm it — for the new fixtures, a domain overjsonbstill resolves toJson | null, and a domain overint4 NOT NULLto a non-nullablenumber.Scope
Arrays of domains are not covered.
information_schemadoes the same — for an array column it reportsdata_type = 'ARRAY'withdomain_namenull, and the domain identity belongs to the element type. Happy to extend this throught.typelemif you'd prefer it here.Tests
New fixtures in
test/db/00-init.sql(a domain overjsonb, and aNOT NULLdomain overint4) plus a test intest/lib/columns.tswhose snapshot is the before/after of the bug -searchandplainare bothjsonbinformatbut are now distinguishable:The remaining snapshot churn is the mechanical
domain_name: null, domain_schema: nulladdition across existing column assertions.