DatabaseTableSchema
DatabaseTableSchema shows one table’s shape - columns, keys, constraints, defaults, the indexes behind its access paths, and engine-specific DDL outside the schema grammar - as a dense psql-style grid with titled verbatim-SQL bands, so a plan that proposes or changes a table can be reviewed on the schema itself instead of prose approximations of it.
Anatomy
Section titled “Anatomy”The figure opens with a header band carrying the schema-qualified name and table note, above a Column | Type | Constraints | Default | Comment grid in which every column is exactly one equal-rhythm row.
The Constraints cell carries key badges, explicit nullability, foreign keys with their actions, check expressions, and numbered index references beside the column they govern.
The tinted Indexes band below the grid numbers each index (INDX 1, INDX 2, …) and leads with its name; the columns, method, and partial predicate follow in demoted muted text with the invariant note beneath.
A column that an index uses as a key carries the matching INDX n pill, while a column that only appears in a partial-index predicate is marked WHERE INDX n, so a reviewer can answer “is this column indexed?” without leaving the row.
Each Ddl child adds a titled band of verbatim SQL after the indexes - row security, triggers, partitioning, grants, whatever the schema grammar deliberately leaves out.
Every band renders stacked and labeled, so nothing is hidden from the reader.
The rendering is optimized for Postgres but generic: column types are opaque text, any engine’s types render unchanged, and the component never parses Ddl SQL - it displays exactly what was authored.
When to use it
Section titled “When to use it”Use DatabaseTableSchema whenever a plan proposes or modifies a table and the reviewer must judge its shape: keys, nullability, defaults, relationships, and the indexes that back the access paths.
When not to use it
Section titled “When not to use it”- Exact DDL the reader will execute standalone - use a fenced
sqlblock, which preserves every clause verbatim outside the figure - Multi-table relationship overviews - render one component per table; a diagram of the whole schema is a different concern
- Restating the columns grid as a
CREATE TABLEinside aDdlchild - that creates a second source of truth the component cannot check against the grid; reserveDdlfor what the grammar deliberately leaves out
Use cases
Section titled “Use cases”- Propose a new table and let the reviewer approve its keys, constraints, and indexes before a migration exists
- Show the current shape of a table a plan is about to alter, beside a second component showing the planned shape
<DatabaseTableSchema name="catalog.refresh_jobs">
```dbmlid bigint [pk, increment]cache_key text [not null, note: 'The catalog cache key this job refreshes.']requested_by bigint [ref: > catalog.api_instances.id, delete: set null]attempts integer [not null, default: 0, check: 'attempts <= 5']status text [not null, default: 'queued', note: 'Allowed: queued | running | done | failed.']enqueued_at timestamptz [not null, default: `now()`]
indexes { cache_key [unique, name: 'refresh_jobs_live_key_idx', where: 'status <> \'done\'', note: 'Ensures one unfinished job per cache key.'] (status, enqueued_at) [name: 'refresh_jobs_scan_idx']}
Note: 'One row per queued catalog refresh.'```
<Ddl title="Row security">
```sqlALTER TABLE catalog.refresh_jobs ENABLE ROW LEVEL SECURITY;```
</Ddl>
</DatabaseTableSchema>Authoring
Section titled “Authoring”Attributes
Section titled “Attributes”| Attribute | Type | Required | Behavior |
|---|---|---|---|
name |
string (non-empty) | Yes | The table identity, optionally schema-qualified (catalog.refresh_jobs); the last dot splits the muted schema prefix from the emphasized table name. |
Any other attribute is a positional authoring error.
Children
Section titled “Children”The component takes exactly one fenced code block with the dbml language, followed by any number of Ddl children.
Each Ddl child carries one titled band of verbatim SQL: a required non-empty title attribute, unique within the component after surrounding and repeated whitespace are normalized, and exactly one fenced code block with the sql language as its whole body.
The component displays the statements exactly as authored and highlighted, never parsed or validated as SQL, so engine-specific DDL renders truthfully for any engine.
Schema grammar
Section titled “Schema grammar”The fence carries a deliberate subset of DBML - column lines, one optional indexes { ... } block, and one optional table Note: - with Postgres-motivated referential-action and partial-index extensions.
Every violation reports a positional diagnostic pointing at the offending fence line, and out-of-subset DBML (Table blocks, standalone Ref: lines, Enum blocks) is rejected with the supported alternative named in the message.
Each column is one line, name type [settings]:
- The name must be a unique bare identifier, and the fence must declare at least one column; the type is opaque text and may contain spaces (
timestamp with time zone) or array brackets (text[]). - Marker settings are bare:
pk(orprimary key),not null,null,unique,increment(rendered as an Identity badge). Either primary-key spelling impliesnot null; combiningnullwithpkornot nullis rejected. default:takes a number,true,false,null, a quoted string, or a backtick expression such as`now()`.note:andcheck:take a single-line quoted value, and a check cannot be empty; notes render in the column’s Comment cell, and checks render asCHECK (...)in its Constraints cell.ref: > table.columnorref: > schema.table.columndeclares a many-to-one foreign key; other relationship operators are outside the subset.delete:andupdate:add referential actions (cascade,restrict,set null,set default,no action) and require theref:on the same line.
Each indexes block entry is a declared column, a composite (a, b) tuple whose members are declared columns or backtick expressions, or a backtick expression on its own.
Every backtick expression must span its whole entry or tuple member.
Its optional settings are the bare unique marker; a quoted, non-empty name: that must be unique in the table; type: (btree, hash, gin, gist); a quoted note:; and the extension where: with a non-empty quoted partial-index predicate.
When an expression names a declared column directly, including as a double-quoted identifier, the column receives the matching INDX n pill.
Only direct unqualified references drive those pills; SQL string literals are ignored.
The table Note: is the table’s comment, headed for COMMENT ON TABLE: one sentence saying what a single row represents.
Operational behavior - pruning schedules, rollout plans, lifecycle narration - belongs in the prose around the component, not inside the schema.
What stays outside the grammar
Section titled “What stays outside the grammar”Triggers, row-level security, partitioning, storage parameters, collation, and grants are deliberately not part of the schema grammar; they enter as verbatim SQL through Ddl children instead.
Decision-worthy rationale still belongs in a Callout beside the component, and one-line facts in the table Note:.
Reader layout
Section titled “Reader layout”The grid and every section are server-rendered in authored order, and a wide grid scrolls inside the figure instead of widening the page.
With the viewer script active, drag a column header to reorder it or focus the header and use Left / Right; keyboard moves are announced.
The columns menu can hide non-identity columns, persists order and visibility for this table in this exact plan revision, and resets both choices with Reset column layout.
With scripts disabled, the complete authored grid remains visible in authored order and no dormant controls appear.
The INDX n and WHERE INDX n references remain compact visual links between columns and the numbered index list.
With the viewer script active, each reference is a focusable button that moves focus to its named index and briefly tints it; keyboard activation is native, and reduced-motion preferences remove the scroll and tint transitions.