Add parseable `@<namespace>[(<target>)]: <args>` directives embedded in DBML.
They are stored losslessly on each object's Metadata, round-trip unchanged
through the DBML writer, and are translated to SQL only by the writer for the
matching dialect.
- models: Directive type + catalog; Metadata map added to Column and Index
- dbml reader: parse and attach directives at database/table/column/index
level; line-numbered errors; repeatable by default with singleton duplicate
detection. Fixes a preexisting bug where an `indexes {}` closing brace ended
the table early, dropping trailing Note: and directive lines.
- dbml writer: re-emit directives at their location; idempotent output
- pgsql writer: PARTITION BY / INHERITS / WITH / TABLESPACE (table),
STORAGE / COMPRESSION / identity (column), WITH / TABLESPACE (index)
- sqlite writer: WITHOUT ROWID / STRICT (table), COLLATE (column)
- --strict-directives flag on ReaderOptions and WriterOptions
- docs/DBML_DIRECTIVES.md + reader/writer READMEs
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ss2MY5J11cRGwEz86ZXk7d
4.3 KiB
4.3 KiB
DBML Writer
Generates Database Markup Language (DBML) files from database schema information.
Overview
The DBML Writer converts RelSpec's internal database model representation into DBML syntax, suitable for use with dbdiagram.io and other DBML-compatible tools.
Features
- Generates DBML syntax
- Creates table definitions with columns
- Defines relationships
- Includes indexes
- Adds notes and documentation
- Supports enums
Usage
Basic Example
package main
import (
"git.warky.dev/wdevs/relspecgo/pkg/models"
"git.warky.dev/wdevs/relspecgo/pkg/writers"
"git.warky.dev/wdevs/relspecgo/pkg/writers/dbml"
)
func main() {
options := &writers.WriterOptions{
OutputPath: "schema.dbml",
}
writer := dbml.NewWriter(options)
err := writer.WriteDatabase(db)
if err != nil {
panic(err)
}
}
CLI Examples
# Generate DBML from PostgreSQL database
relspec --input pgsql \
--conn "postgres://localhost/mydb" \
--output dbml \
--out-file schema.dbml
# Convert GORM models to DBML
relspec --input gorm --in-file models.go --output dbml --out-file database.dbml
# Convert JSON to DBML for visualization
relspec --input json --in-file schema.json --output dbml --out-file diagram.dbml
Generated DBML Example
Project MyDatabase {
database_type: 'PostgreSQL'
}
Table users {
id bigserial [pk, increment]
username varchar(50) [not null, unique]
email varchar(100) [not null]
bio text [null]
created_at timestamp [not null, default: `now()`]
Note: 'Users table'
indexes {
email [name: 'idx_users_email']
}
}
Table posts {
id bigserial [pk, increment]
user_id bigint [not null]
title varchar(200) [not null]
content text [null]
created_at timestamp [default: `now()`]
indexes {
user_id [name: 'idx_posts_user_id']
(user_id, created_at) [name: 'idx_posts_user_created']
}
}
Ref: posts.user_id > users.id [delete: cascade, update: no action]
DBML Features
Table Definitions
Table table_name {
column_name type [attributes]
}
Column Attributes
pk- Primary keyincrement- Auto-incrementnot null- NOT NULL constraintnull- Nullable (explicit)unique- Unique constraintdefault: value- Default valuenote: 'text'- Column note
Relationships
Ref: table1.column > table2.column
Ref: table1.column < table2.column
Ref: table1.column - table2.column
Relationship types:
>- Many-to-one<- One-to-many-- One-to-one
Relationship actions:
Ref: posts.user_id > users.id [delete: cascade, update: restrict]
Indexes
indexes {
column_name
(column1, column2) [name: 'idx_name', unique]
}
Dialect directives
Dialect directives stored on a model object's Metadata (namespace postgres,
sqlite, …) are re-emitted verbatim, one line per directive, at the location
they belong to:
@postgres: search_path myapp
Table myapp.events {
id bigint [pk]
created_at timestamp [not null]
@postgres(id): identity always
@postgres: partition by RANGE (created_at)
@sqlite: without rowid
indexes {
(created_at) [name: 'idx_events_created']
@postgres: with (fillfactor=90)
}
}
| Emitted at | From |
|---|---|
| Before the first table | Database.Metadata |
After a column line, as @ns(col): … |
Column.Metadata |
After an index line, inside indexes { } |
Index.Metadata |
After the indexes block, before Note: |
Table.Metadata |
Output is deterministic (ordered by namespace, then source line, then args), so a
DBML → model → DBML round-trip is idempotent. See
docs/DBML_DIRECTIVES.md for the grammar and
the list of directives the PostgreSQL and SQLite writers translate to SQL.
Type Mapping
| SQL Type | DBML Type |
|---|---|
| bigint | bigint |
| integer | int |
| varchar(n) | varchar(n) |
| text | text |
| boolean | boolean |
| timestamp | timestamp |
| date | date |
| json | json |
| uuid | uuid |
Notes
- DBML is designed for database visualization
- Can be imported into dbdiagram.io
- Human-readable format
- Schema names can be included in table names
- Comments and notes are preserved
- Ideal for documentation and sharing designs