feat(migrate): Cloudflare D1 runner#30
Conversation
Builds on the MigrationRunner contract from the migrate package refactor (this PR stacks on feat/relayauth-migrate-package). Provides createD1Runner(db) for any async driver that matches the D1 prepared- statement surface — Workers D1 binding or an HTTP client wrapper in build-time/CI contexts. Atomicity: each migration is split into statements and submitted via db.batch(...), which the Cloudflare side runs inside a transaction — partially-applied DDL is impossible. The splitter strips -- line comments and splits on ; with no tokenizer; sufficient for pure DDL files that follow the existing relayauth convention. Documented caveats for strings and BEGIN/END blocks so future consumers don't trip over it. Structural typing (D1DatabaseLike, D1PreparedStatementLike, D1ResultLike) instead of @cloudflare/workers-types so Node consumers can wrap the Cloudflare REST API without pulling Workers types into their build. Tests exercise the runner against node:sqlite wrapped in an async D1- like facade — fresh DB, rerun, checksum drift, multi-statement rollback, idempotent recordApplied, splitter correctness. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0453568da1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const idx = line.indexOf("--"); | ||
| return idx >= 0 ? line.slice(0, idx) : line; |
There was a problem hiding this comment.
Preserve quoted
-- text when stripping SQL comments
splitSqlStatements removes everything after the first -- on each line, even when the dashes appear inside a quoted string literal (for example INSERT ... VALUES('foo--bar')). In that case the migration SQL is truncated before execution, which can either produce syntax errors or alter data and block D1 migrations in production. Because this runner is meant to execute shared .sql migrations, comment stripping needs to be quote-aware (or delegated to the database parser) rather than a raw indexOf("--") cut.
Useful? React with 👍 / 👎.
Codex flagged (relayauth#30): the prior indexOf("--") + split(";")
splitter corrupted any migration with -- or ; inside a quoted string
literal (e.g. INSERT INTO t VALUES ('foo--bar') or ('hello; world')).
Replaced with a char-by-char scanner that tracks single-quoted strings
(with '' escape), double-quoted identifiers (with "" escape), and --
line comments; semicolons are only statement terminators outside those
regions.
Not supported with a documented caveat so a bad migration fails at
review rather than silently at runtime:
- block comments /* ... */
- backslash escapes (SQLite doesn't honor them anyway)
Tests added: -- inside strings preserved, ; inside strings preserved,
'' escape inside strings, "" in identifiers — all covering the exact
patterns Codex pointed at.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Addressed the Codex P1 in 2016517.
New tests cover the exact patterns Codex pointed at:
10/10 |
Summary
Adds `createD1Runner(db)` to `@relayauth/migrate` — the D1 backend for the `MigrationRunner` contract introduced in #26.
Stacks on #26. Base branch is `feat/relayauth-migrate-package`; this will want a rebase-merge once #26 lands on main.
Why now
Cloud (AgentWorkforce/cloud) is currently maintaining its own snapshot of `packages/server/src/db/migrations/` because there was no shared async migrator. That's how we ended up with a `POST /v1/tokens` outage today — cloud's snapshot was missing `session_id`, `issued_at`, and `expires_at` from the `tokens` table even though the server's route handlers had already started referencing them. Details in AgentWorkforce/cloud#312.
With this runner + the source-of-truth migrations dir #26 introduces, cloud can delete its snapshot and run the server's bundled migrations directly — follow-up PR in cloud.
Design
Tests
6 tests covering the runner against `node:sqlite` wrapped in an async D1-like facade:
All pass: `node --test --import tsx src/tests/d1-runner.test.ts` → `# pass 6`.
Full `npx turbo typecheck` across the workspace — `11 successful, 11 total`.
Follow-up
🤖 Generated with Claude Code