feat(sidebar): browse PostgreSQL user-defined types, edit enum labels and offer them in the type picker - #2612
Merged
Merged
Conversation
… and offer them in the type picker Claude-Session: https://claude.ai/code/session_014THhVdsUjbCboxNLnQB1dR
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Automations to automatically generate PRs for you. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
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 #2484
What this adds
A Types section under each PostgreSQL schema beside Functions and Triggers, listing enums, composites, domains and ranges. Opening one shows its
CREATEstatement rebuilt frompg_type, with the catalog's properties beside it. An enum's labels sit above the definition and can be added, at the end or before or after a neighbour, and renamed in place. The structure editor's type picker gains a User-Defined group of the table's own types, Open Quickly indexes types, and the MCP server getslist_types.PostgreSQL and PGlite in this PR. CockroachDB and Redshift are sibling driver classes in the same plugin and keep the empty default. DuckDB, Cassandra, MSSQL and Oracle each have a comparable catalog, and the PluginKit surface makes each one a single
+Types.swift, but each needs a probe against a live server, so they are follow-ups.How it is built
PluginKit, additive:
PluginUserDefinedTypeInfo,PluginUserDefinedTypeKind,PluginUserDefinedTypeField,PluginEnumLabelPlacement, and five defaulted requirements onPluginDatabaseDriver(fetchUserDefinedTypes,fetchUserDefinedType,createTypeTemplate,generateAddEnumLabelSQL,generateRenameEnumLabelSQL) plusDriverPlugin.supportsUserDefinedTypeBrowse. PluginKit 21 is still unreleased onmain(#2607's bump has no tag), so these ride that bump and every registry plugin is rebuilt with it anyway.PostgreSQL: one catalog query over
pg_typegated ontyptype IN ('e','c','d','r'). Composites are kept only where the backing relation is a stand-alone type (relkind = 'c'), so every table's row type stays out; extension members are excluded throughpg_dependthe way routines are; arrays and the multirange 14 creates beside every range are othertyptypes. PostgreSQL 17 records a domain's NOT NULL as apg_constraintrow, so the constraint list keepscontype = 'c'alone. There is nopg_get_typedef, soPostgreSQLTypeDefinitionrebuilds the statement from the row and is pure so every shape is pinned by a test; it carries a domain's own collation, a composite field's collation, a range's collation, its non-default operator class qualified, and a multirange name the creator chose (PostgreSQL's default replaces a trailingrangerather than appending). The listing also carries the server's ownquote_identspelling of each type, which is what the picker offers. Version gates:pg_rangeat 9.2,json_build_objectat 9.4,ADD VALUE BEFORE/AFTERat 9.1,RENAME VALUEat 10. A literal carrying a backslash is written as anE''string so it reads the same understandard_conforming_strings=off; the oid predicate accepts only an integer.App: a fourth
SidebarObjectCategory,.type, threaded through the same seams routines and triggers use:SchemaServicefor the flat list,DatabaseTreeMetadataServiceper database and schema,DatabaseTreeNode.Kind.userType, the row view, menu spec, type-select, double-click, selection, filter buckets and the quick switcher.SidebarObjectListPresentation.resolvetakes onehasSideObjectsinstead of two parallel bools.DatabaseObjectRefgains.userTypeand an optionaltypeKind, so a persisted tab from before this change still decodes.One fix outside the new paths: the tree's empty-container check counted every side fetch as pending, and a fetch an engine never runs stays idle for good. Types made that universal, so
sideLoadStatesnow counts only the kinds the engine declares. The same gap already held triggers on a tree-layout engine without trigger browsing.Enum editing runs each edit as one statement the moment the field commits, authorised through
ExecutionGateProvideras a schema mutation, recorded in history, then the listings reload and the open grids get the same refresh a trigger edit sends. It runs on the metadata route, a dedicated autocommit connection wherever the engine can pool one, not the session driver: that one holds whatever transaction the user opened in a query tab, and a label added inside it is unusable until the commit, gone on a rollback, and invisible to the reload.ADD VALUEis writtenIF NOT EXISTSfrom 9.3 on, so the driver's one reconnect-and-resend cannot fail on a label that already landed; rename has no such form and stays the same class as every other DDL the driver sends.ALTER TYPE … ADD VALUEcannot run inside a transaction block before 12 anyway, so there is nothing to stage. PostgreSQL cannot drop or reorder a label; the UI does not offer it and the docs say why.Type picker: fetched for the table's own database on popover open through
DatabaseManager.withMetadataDriver, across every non-system schema, because the tree service's cache is expansion-driven and empty in the default flat layout. Every entry is schema-qualified, the table's own schema included, because PostgreSQL searchespg_catalogahead of the search path and a baretextnames the built-in even where the schema holds a domain calledtext. The spelling is the server'squote_ident, so reserved and mixed-case names arrive quoted; the client-side fallback quotes anything that is not a plain lower-case identifier.Verified
psqlagainst PostgreSQL 17.11 on a throwaway cluster holding an enum, a composite, two domains, a range, a table,hstoreandtablefunc: only the user types came back, with labels, fields, constraints and the range's subtype diff parsed as expected.+control ranALTER TYPE … ADD VALUE(confirmed inpsql) and refreshed the labels and the statement.verify.sh generate,build,test(the suites owning every touched type),build PostgreSQLDriver,lint,docs: see the verdicts in the thread.verify.sh pluginsis inconclusive on this machine for the known oracle-nio@TaskLocalmacro issue; CI runs the aggregate.review(working tree) returned nine findings; all four P1s and three P2s are fixed here. The remaining P2, keying the flat-list type fetch by scope rather than connection, is the same shape routines and triggers already use and is listed below as a follow-up.adversarial-reviewreturned six findings. Fixed here: enum edits joining the user's open transaction (now the metadata route), the non-idempotentADD VALUEunder the driver's reconnect resend (nowIF NOT EXISTS), a same-schema type resolving to a built-in and reserved names left bare (server-side spelling, always qualified), the catalog state the rebuilt definition dropped (collations, opclass namespace, multirange name), and the identity lookup that widened a malformed oid into a schema listing and took the first row (fails closed, verifies the oid, no schema predicate). Dismissed: the PluginKit version bump. Adding defaulted requirements does break a plugin rebuilt against them under an older host, but PluginKit 21 has not shipped: v0.71.0 carries 20 and the registry holds 19 and 20 only, so every registry plugin is rebuilt for 21 with the release that feat(plugins)!: order SQL exports by foreign key dependency and report what the order cannot fix (#2517) #2607 already requires.TableProUITestscase: the flow needs a live PostgreSQL, which CI does not have.Before / After
Before: a column of type
order_statusshows the type name and nothing else; nothing lists the schema's types.After: the docs screenshot pair committed at
docs/images/user-defined-types-sidebar(-dark).pngshows the Types section, the definition tab and the label list. They were captured on a 1x display, so they are 1512x861 rather than the 3024x1722 the other docs images carry.Follow-ups noticed, not changed here
PostgresColumnTypeResolver.swift:53: anyUSER-DEFINEDcolumn type without enum labels is labelledENUM(name), so a composite or range column reads as an enum in the structure grid.SchemaService.swift:36: the routine, trigger and type fetches are deduplicated per connection rather than per scope, so two windows loading different databases at once can share one result.https://claude.ai/code/session_014THhVdsUjbCboxNLnQB1dR