Convert PostgreSQL schemas to DBML

Inspect real DBML table, index and reference output generated from a PostgreSQL-shaped schema by Trellis’s DBML exporter.

target
DBML
access
Pro export
source specimen
2 of 13 tables · seed/schema.json

Trellis exports a schema drafted on its canvas using PostgreSQL types. This page does not claim to parse a PostgreSQL dump or a live database.

01 / portable model

Tables first, references after

The DBML exporter carries table descriptions, columns, defaults, key attributes, indexes, rules and questions before writing the reference lines.

actual exporter output2 of 13 tables · tag, article
// DBML generated from the schema canvas

Table tag {
  // One row is one label that can be attached to content. The path column carries the hierarchy, so a child tag can be found by prefix.
  id uuid [pk, not null, default: `gen_random_uuid()`]
  label citext [not null]
  path ltree [not null]
  created_at timestamptz [not null, default: 'now()']
  // not expressible in DBML: primary key (id)
  Indexes { (label) [unique] }
  // not expressible in DBML: index using gist (path)
  // open question: Should moving a tag rewrite the paths of its descendants, or should reads walk upwards instead?
}

Table article {
  // One row is one piece of writing. The current body lives here; every earlier body is a revision row.
  id uuid [pk, not null, default: `gen_random_uuid()`]
  author_id uuid [not null]
  title text [not null]
  slug text [not null]
  body text [not null, default: '\'\'']
  labels text[] [not null, default: '\'{}\'']
  search_vector tsvector
  published_at timestamptz
  created_at timestamptz [not null, default: 'now()']
  updated_at timestamptz [not null, default: 'now()']
  // not expressible in DBML: primary key (id)
  Indexes { (author_id, title) [unique] }
  Indexes { (slug) [unique, note: 'published_at is not null'] }
  // not expressible in DBML: index using gin (search_vector)
  // not expressible in DBML: index (labels) using gin
  // not expressible in DBML: index using gin (title gin_trgm_ops)
  // not expressible in DBML: index (author_id, published_at desc)
  // not expressible in DBML: check (published_at is null or the author's account must still be active)
  // open question: Should a slug stay reserved after unpublishing, so an old link never resolves to different writing?
  // rule: Publishing sets published_at once; unpublishing clears it and frees the slug.
  // rule: search_vector is derived from title and body — never written directly.
}
02 / DBML boundary

Index syntax is the pressure point

The real output identifies index methods, operator classes and other source lines that DBML cannot represent directly.

The full 13-table export writes its caveats into the generated file. These examples are copied from it:

  • // not expressible in DBML: index using gist (path)
  • // not expressible in DBML: check (entity_type in ('account', 'article', 'article_revision', 'comment', 'subscription', 'invoice', 'tag'))
  • // not expressible in DBML: index using gin (search_vector)
  • // not expressible in DBML: index using gin (title gin_trgm_ops)

source / generated DBML output