Add pscale import d1 for Cloudflare D1 offline migration#1278
Add pscale import d1 for Cloudflare D1 offline migration#1278no-itsbackpack wants to merge 6 commits into
Conversation
Introduce `pscale import d1` (doctor, lint, convert-schema, start, verify, status, complete) backed by internal/import/d1, with pgloader-based loading, local migration state, Slack lifecycle notifications, and Postgres helpers. Co-authored-by: Cursor <cursoragent@cursor.com>
18731b9 to
8aa1a34
Compare
Persist migration state before imported/verified Slack notifications, track schema_applied so failed pgloader runs can resume without re-applying DDL, and match column UNIQUE constraints with word boundaries only. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Unit tests do not shell out to pgloader. SQLite integration tests use requireSQLite3 and skip when the CLI is absent. Co-authored-by: Cursor <cursoragent@cursor.com>
Named returns were cleared by return nil, err after lint/plan, so start JSON errors and failure Slack payloads lost migration_id, issues, and method metadata. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 541a200. Configure here.
| } | ||
| if conflicts := conflictingImportTables(importNames, existing); len(conflicts) > 0 { | ||
| return errExistingImportTables(conflicts) | ||
| } |
There was a problem hiding this comment.
Partial schema blocks import retry
Medium Severity
Schema is applied via psql -f without a wrapping transaction, so a mid-file error can leave some import tables on the branch while schema_applied stays false. A later start retry resets progress and hits errExistingImportTables against those partial tables, blocking resume unless tables are dropped manually.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 541a200. Configure here.


Summary
Adds
pscale import d1— an offline migration path from Cloudflare D1 (SQLite export) into PlanetScale Postgres.Workflow: export with wrangler → lint/plan → import → verify → complete
CLI commands (
pscale import d1 …)doctorlintconvert-schemastart--dry-runfor preview only)verifystatuscompleteteardownalias)Export is done with wrangler, not the CLI:
Example import flow:
Also includes
internal/import/d1/— schema conversion, lint/plan, pgloader import, verify, local migration stateinternal/postgres/— connection URI parsing, pgx open, psql discovery/version check (no logical replication / pg_dump pipeline)internal/import/d1/andinternal/cmd/importcmd/How to test
Prerequisites:
pscaleauth, a Postgres database branch,pgloader,sqlite3, and a D1 SQL export (from wrangler or the repo fixture).1. Smoke test (no PlanetScale load)
Dry-run returns a
migration_id— save it for verify/complete.2. Full import (against a dev branch)
3. Automated tests
go test ./internal/import/d1/... ./internal/cmd/importcmd/...4. Slack notifications (optional)
Run against local api-bb with Sidekiq running. Import lifecycle events should appear in
#d1-migrations. Pass--no-notifyon start/verify/complete to skip.Test plan
doctorpasses with pgloader + sqlite3 installedlintandstart --dry-runsucceed on the sample fixturego test ./internal/import/d1/... ./internal/cmd/importcmd/...passes in CI