Open
Conversation
Implements bidirectional migrations across all dialects and drivers. drizzle-kit: - `writeResult()` auto-generates and writes `<tag>.down.sql` alongside each `<tag>.sql` by calling the diff function with prev/cur arguments swapped (no-rename auto-resolvers used so it is non-interactive) - `embeddedMigrations()` bundles `.down.sql` imports for expo-sqlite, op-sqlite, and durable-sqlite - `Journal` entry type gains optional `hasDown: boolean` flag drizzle-orm/src/migrator.ts: - `MigrationMeta` gains `downSql?: string[]` - `readMigrationFiles()` reads `<tag>.down.sql` alongside each migration if it exists Dialect rollback() methods (pg-core, mysql-core, singlestore-core, sqlite-core sync+async): - Query the last `steps` rows from `__drizzle_migrations` DESC - Match each by hash against the in-memory migration list - Throw a descriptive error if the migration file or down SQL is missing - Execute down SQL statements in reverse order inside a transaction - DELETE the rolled-back rows from `__drizzle_migrations` Per-driver rollback() exports added to all 22 driver migrator files: - Standard drivers (node-postgres, postgres-js, pglite, neon-serverless, vercel-postgres, aws-data-api/pg, mysql2, planetscale-serverless, tidb-serverless, singlestore, better-sqlite3, bun-sqlite, bun-sql, sql-js): delegate to dialect.rollback() - Proxy drivers (pg-proxy, mysql-proxy, sqlite-proxy, singlestore-proxy): build queries array and pass to existing ProxyMigrator callback - Batch drivers (libsql, d1): collect statements and use session.migrate()/session.batch() - Embedded drivers (expo-sqlite, op-sqlite, durable-sqlite): MigrationConfig gains optional `downMigrations` bundle field; rollback works with the same embedded bundle pattern as migrate() - neon-http, xata-http: custom implementations without transactions (noted in JSDoc)
drizzle-kit/tests/migrate/down-sql.test.ts (10 tests): - writeResult() writes .down.sql when downSqlStatements are provided - writeResult() does not write .down.sql when downSqlStatements is undefined - writeResult() sets hasDown: true in journal entry when down SQL is provided - writeResult() does not set hasDown when downSqlStatements is undefined - writeResult() does not set hasDown when downSqlStatements is empty array - writeResult() respects breakpoints delimiter in .down.sql - embeddedMigrations() includes downMigrations block when entries have hasDown - embeddedMigrations() omits downMigrations block when no entries have hasDown - embeddedMigrations() only imports .down.sql for entries that have hasDown - embeddedMigrations() adds expo header for expo driver integration-tests/tests/sqlite/rollback.test.ts (13 tests): - readMigrationFiles() populates downSql when .down.sql exists - readMigrationFiles() leaves downSql undefined when .down.sql is absent - readMigrationFiles() leaves downSql undefined when .down.sql is empty - readMigrationFiles() leaves downSql undefined when .down.sql is whitespace only - readMigrationFiles() splits downSql on statement-breakpoint delimiter - readMigrationFiles() reads downSql independently per migration - rollback(1) removes last migration table and tracking row - rollback(2) undoes both migrations - rollback with default steps=1 rolls back one migration - rollback when no migrations applied is a no-op - rollback then migrate re-applies the migration - rollback throws when migration file not found by hash - rollback throws when migration has no down SQL Adds migration fixtures in integration-tests/drizzle2/sqlite-rollback/ with two migrations each having .down.sql files.
Wrap the forward resolvers with capture helpers so rename decisions (table, column, view) made during `generate` are inverted for the down SQL diff, matching the rename-aware approach already applied to PostgreSQL, MySQL, and SingleStore.
Use rowid instead of hash for SQLite migration deletion to fix hash collision bugs with bundled migrations (empty hash). Add PGlite rollback integration tests and bundled migration rollback tests. Fix down-sql test assertions for updated key format.
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.
Summary
.sqlmigration file can now have a corresponding.down.sqlthat reverses the changesreadMigrationFilesextended to parse.down.sqlalongside each.sql;MigrationMetagains optionaldownSql?: string[]rollback(db, config, steps?)exported from every driver migratorwriteResultwrites.down.sqlfiles;embeddedMigrationsbundles down SQL imports for embedded drivers (expo-sqlite, op-sqlite, durable-sqlite)Journalentry type gains optionalhasDown?: booleanflagrowidfor precise single-row deletion and falls back tofolderMillismatching for bundled drivers that sethash: ''Drivers covered
All 25 drivers: node-postgres, postgres-js, pglite, neon-serverless, neon-http, vercel-postgres, aws-data-api/pg, pg-proxy, mysql2, planetscale-serverless, tidb-serverless, singlestore, singlestore-proxy, mysql-proxy, better-sqlite3, bun-sqlite, bun-sql, sql-js, sqlite-proxy, libsql, d1, expo-sqlite, op-sqlite, durable-sqlite, xata-http
Test plan
pnpm vitest run tests/migrate/down-sql.test.ts(drizzle-kit) — 10 testspnpm vitest run tests/sqlite/rollback.test.ts(integration-tests) — 17 tests including bundled empty-hash scenariopnpm vitest run tests/pg/pglite.test.ts(integration-tests) — PGlite rollback tests