Skip to content

Run Postgres migrations atomically with Drizzle - #1854

Merged
Asherlc merged 4 commits into
mainfrom
Asherlc/atomic-pg-migrations
Jul 22, 2026
Merged

Asherlc merged 4 commits into
mainfrom
Asherlc/atomic-pg-migrations

Conversation

@Asherlc

@Asherlc Asherlc commented Jul 22, 2026

Copy link
Copy Markdown
Owner

Summary

  • replace the custom Postgres SQL loop with Drizzle's node-postgres migrator
  • retain the session-level advisory lock around migration execution
  • complete the Drizzle journal and reconcile legacy filename-based tracking rows
  • preserve fail-fast integrity checks for modified or missing applied migrations
  • make historical migration SQL compatible with Drizzle's transaction
  • add real-Postgres coverage for rollback, retry, integrity, and legacy migration history

Validation

  • pnpm lint
  • root, server, and web pnpm tsc --noEmit
  • drizzle-kit check --config drizzle.config.ts
  • src/db/migrate.integration.test.ts: 12/12 passed
  • fresh disposable Postgres database: all 65 journaled migrations applied
  • pnpm test: 715 suites passed; 14 suites hit local Vitest worker fetch timeouts
  • the 14 timed-out suites rerun with thread workers: 14/14 suites and 2,050/2,050 tests passed

Fixes #1778

Summary by CodeRabbit

  • New Features

    • Improved database migration handling, including baseline setup and compatibility with existing migration histories.
    • Added support for hierarchical OAuth refresh tokens.
    • Added improved migration tracking and integrity validation.
  • Bug Fixes

    • Improved migration rollback behavior when an update fails.
    • Removed transaction handling that could interfere with migration execution.
    • Improved index creation reliability during database updates.
  • Documentation

    • Expanded migration requirements, baseline behavior, and transaction compatibility guidance.

Delegate migration execution to Drizzle while retaining the session-level advisory lock. Complete the journal and reconcile legacy filename rows so existing databases continue from the correct migration.

Refs #1778
Copilot AI review requested due to automatic review settings July 22, 2026 04:43
@Asherlc Asherlc linked an issue Jul 22, 2026 that may be closed by this pull request
@cursor

cursor Bot commented Jul 22, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @Asherlc, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4c912aaf-0d24-4f1e-9613-b2300c940248

📥 Commits

Reviewing files that changed from the base of the PR and between dfe7e2c and 2ae2ba5.

📒 Files selected for processing (19)
  • README.md
  • drizzle/0009_metric_stream_id_not_null_primary_key.sql
  • drizzle/0018_migrate_body_measurements_to_metric_stream.sql
  • drizzle/0021_convert_v_activity_to_view.sql
  • drizzle/0047_sync_log_user_provider_synced_at_index.sql
  • drizzle/0048_mcp_oauth.sql
  • drizzle/0050_provider_data_deletion_outbox.sql
  • drizzle/0052_mcp_oauth_refresh_token_family.sql
  • drizzle/0053_file_upload_state_machine.sql
  • drizzle/meta/_journal.json
  • src/db/README.md
  • src/db/metric-stream-location-point-migration.integration.test.ts
  • src/db/metric-stream-replica-identity.integration.test.ts
  • src/db/migrate.integration.test.ts
  • src/db/migrate.test.ts
  • src/db/migrate.ts
  • src/db/postgres-migrator.test.ts
  • src/db/postgres-migrator.ts
  • src/db/test-helpers.ts
💤 Files with no reviewable changes (3)
  • drizzle/0009_metric_stream_id_not_null_primary_key.sql
  • drizzle/0021_convert_v_activity_to_view.sql
  • drizzle/0018_migrate_body_measurements_to_metric_stream.sql

📝 Walkthrough

Walkthrough

The migration runner now delegates PostgreSQL migration execution to Drizzle, reconciles legacy tracking data, handles baselines explicitly, and validates journal integrity. Migration SQL and tests were updated for transaction-compatible execution and atomic rollback behavior.

Changes

Postgres migration pipeline

Layer / File(s) Summary
Journal history reconciliation
drizzle/meta/_journal.json, src/db/postgres-migrator.ts
Drizzle journal history, baseline metadata, legacy hashes, applied migration integrity, and reconciliation are now handled before migration execution.
Baseline and runner delegation
src/db/migrate.ts, src/db/migrate.test.ts
runMigrations() records required baselines, delegates to Drizzle under the advisory lock, and returns the applied migration count delta.
Pipeline validation and fixtures
src/db/postgres-migrator.test.ts, src/db/migrate.integration.test.ts, src/db/test-helpers.ts, src/db/*migration.integration.test.ts
Tests cover baseline handling, journal integrity, legacy reconciliation, advisory-lock cleanup, atomic rollback, and timestamped migration journals.
Transaction-compatible migration SQL
drizzle/*.sql, README.md, src/db/README.md
Migration procedures and scripts remove internal transaction control, and index creation no longer uses CREATE INDEX CONCURRENTLY.

Estimated code review effort: 4 (Complex) | ~45 minutes

Assessment against linked issues

Objective Addressed Explanation
Run each migration file atomically with its tracking record [#1778]
Rollback all migration changes when a statement fails [#1778]
Verify rollback and retry behavior with real-Postgres integration coverage [#1778]
Preserve advisory-lock and baseline behavior [#1778]

Sequence Diagram(s)

sequenceDiagram
  participant Application
  participant runMigrations
  participant PostgreSQL
  participant DrizzleMigrator

  Application->>runMigrations: start migrations
  runMigrations->>PostgreSQL: acquire advisory lock and inspect state
  runMigrations->>PostgreSQL: record baseline if required
  runMigrations->>DrizzleMigrator: execute journal migrations
  DrizzleMigrator->>PostgreSQL: apply each migration atomically
  PostgreSQL-->>DrizzleMigrator: commit or rollback migration
  DrizzleMigrator-->>runMigrations: migration result
  runMigrations->>PostgreSQL: release advisory lock
Loading

Possibly related PRs

Suggested labels: area/db, type/refactor, breaking-change

🚥 Pre-merge checks | ✅ 1 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Title check ⚠️ Warning Violates the AGENTS.md title rule: clear and imperative, but missing the required area prefix for this db change. Prefix it with the relevant area, e.g. [db] Run Postgres migrations atomically with Drizzle.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codereviewbot-ai

Copy link
Copy Markdown

🤖 Review skipped: Repository rate limit exceeded. Free accounts are limited to 2 reviews per 4 hours per repository. Upgrade to a paid plan for unlimited reviews.

Preserve the new applied-migration integrity checks while reconciling legacy tracker rows with Drizzle hashes.
@codereviewbot-ai

Copy link
Copy Markdown

🤖 Review skipped: Repository rate limit exceeded. Free accounts are limited to 2 reviews per 4 hours per repository. Upgrade to a paid plan for unlimited reviews.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

Exercise empty query results and both false baseline conditions so mutation testing verifies the migration guard logic.
@codereviewbot-ai

Copy link
Copy Markdown

🤖 Review skipped: Repository rate limit exceeded. Free accounts are limited to 2 reviews per 4 hours per repository. Upgrade to a paid plan for unlimited reviews.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@gitguardian

gitguardian Bot commented Jul 22, 2026

Copy link
Copy Markdown

️✅ There are no secrets present in this pull request anymore.

If these secrets were true positive and are still valid, we highly recommend you to revoke them.
While these secrets were previously flagged, we no longer have a reference to the
specific commits where they were detected. Once a secret has been leaked into a git
repository, you should consider it compromised, even if it was deleted immediately.
Find here more information about risks.


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@codereviewbot-ai

Copy link
Copy Markdown

🤖 Review skipped: Repository rate limit exceeded. Free accounts are limited to 2 reviews per 4 hours per repository. Upgrade to a paid plan for unlimited reviews.

@Asherlc
Asherlc force-pushed the Asherlc/atomic-pg-migrations branch from 8bcc778 to 2ae2ba5 Compare July 22, 2026 05:22
@codereviewbot-ai

Copy link
Copy Markdown

🤖 Review skipped: Repository rate limit exceeded. Free accounts are limited to 2 reviews per 4 hours per repository. Upgrade to a paid plan for unlimited reviews.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

@Asherlc
Asherlc merged commit de79644 into main Jul 22, 2026
100 checks passed
@Asherlc
Asherlc deleted the Asherlc/atomic-pg-migrations branch July 22, 2026 13:42
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.

Run each Postgres migration file atomically

2 participants