Skip to content

feat: Add Declarative Schema DSL and Reversible Migrations - #4

Merged
ThomasHartDev merged 5 commits into
mainfrom
thomas/feat/schema-dsl
Sep 4, 2026
Merged

ThomasHartDev merged 5 commits into
mainfrom
thomas/feat/schema-dsl

Conversation

@ThomasHartDev

Copy link
Copy Markdown
Owner

Schema is a value now: tables, columns, indexes, and foreign keys. diffSchema walks two schemas and emits create/drop/add ops in foreign-key order. Indexes that reference a removed column are dropped before the column, and only once. The down path is the same function with the arguments swapped, so a drop still knows how to recreate the table.

The runner records zero-padded ids in _schema_migrations, refuses holes in the applied prefix, and wraps each step in a transaction. Changing a column in place throws. SQLite refuses UNIQUE or PRIMARY KEY on ADD COLUMN, DROP COLUMN on UNIQUE, PRIMARY KEY, or foreign-key columns, ADD COLUMN NOT NULL without a non-NULL DEFAULT, ADD COLUMN REFERENCES with a non-NULL default, and ADD COLUMN with CURRENT_TIME/DATE/TIMESTAMP or a parenthesized default. Those need a table rebuild, a unique index, or a nullable FK with no default. CREATE TABLE still accepts a non-NULL FK default and a NOT NULL DEFAULT NULL column. defineSchema also refuses a foreign key unless the parent column is a primary key, UNIQUE, or the single column of a unique index, so sqlite cannot CREATE TABLE then fail INSERT with a foreign key mismatch. Live apply is sqlite; postgres is compileOps string checks plus journal placeholders.

Closes #3

Schema is a value you can diff. Up is desired minus current, down is the
reverse diff so drops still recreate tables. The runner journals
zero-padded ids and refuses holes in the applied prefix.
SQLite rejects DROP COLUMN while an index still references the column.
Postgres would drop the index with the column and then fail the extra
DROP INDEX. Emit those index drops first, and only once.

SQLite also cannot DROP COLUMN for PRIMARY KEY, UNIQUE, or foreign keys,
or ADD COLUMN NOT NULL without DEFAULT. Fail at compile time instead of
emitting data-dependent DDL.
SQLite and Postgres both require the referenced column to be a primary
key, UNIQUE, or covered by a single-column unique index. defineSchema
now throws at schema time instead of letting CREATE TABLE succeed and
INSERT fail with a foreign key mismatch.
SQLite refuses ADD COLUMN with a REFERENCES clause and a non-NULL
default, and it refuses CURRENT_TIME/DATE/TIMESTAMP or parenthesized
defaults. Fail those in compileOps before apply. CREATE TABLE with the
same column, and constant defaults on ADD COLUMN, still compile.
SQLite treats DEFAULT NULL the same as a missing default on ADD COLUMN
NOT NULL. Fail those in compileOps. CREATE TABLE with the same column
still compiles and applies.
@ThomasHartDev
ThomasHartDev merged commit 5aa2af3 into main Sep 4, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Declarative schema DSL with reversible migrations and a schema diff

1 participant