diff --git a/dist/index.cjs b/dist/index.cjs index 4db0dd0..ffb7c58 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -23833,6 +23833,21 @@ var import_node_path = require("node:path"); var core5 = __toESM(require_core(), 1); var import_exec3 = __toESM(require_exec(), 1); var sleep = (ms) => new Promise((r) => setTimeout(r, ms)); +function reorderDdlBeforeDml(sql) { + const ddl = []; + const dml = []; + for (const line of sql.split(` +`)) { + if (/^INSERT INTO/i.test(line)) { + dml.push(line); + } else { + ddl.push(line); + } + } + return ["PRAGMA foreign_keys=OFF;", ...ddl, ...dml].join(` +`) + ` +`; +} async function syncD1(fromDb, previewDb, previewConfig) { core5.startGroup(`sync D1 ${fromDb} -> ${previewDb}`); try { @@ -23849,6 +23864,8 @@ async function syncD1(fromDb, previewDb, previewConfig) { } if (!exported) throw new Error(`failed to export source D1 ${fromDb} after retries`); + const reordered = import_node_path.join(import_node_os.tmpdir(), "cf-pr-preview-dev-d1-reordered.sql"); + import_node_fs2.writeFileSync(reordered, reorderDdlBeforeDml(import_node_fs2.readFileSync(dump, "utf8"))); const rows = await wranglerJson([ "d1", "execute", @@ -23889,7 +23906,7 @@ async function syncD1(fromDb, previewDb, previewConfig) { previewConfig, "--remote", "--file", - dump + reordered ]); core5.info(`cloned ${fromDb} into ${previewDb}`); } finally { diff --git a/src/sync.ts b/src/sync.ts index 5faa771..6b66851 100644 --- a/src/sync.ts +++ b/src/sync.ts @@ -1,4 +1,4 @@ -import { writeFileSync } from 'node:fs' +import { readFileSync, writeFileSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' import * as core from '@actions/core' @@ -7,6 +7,22 @@ import { runWrangler, wrangler, wranglerJson } from './wrangler' const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms)) +// D1 export interleaves CREATE+INSERT per table, so a FK-target table can be +// inserted into before it's created (e.g. `workers` -> `cycles`), failing +// with "no such table". Reorder so every CREATE runs before any INSERT. +function reorderDdlBeforeDml(sql: string): string { + const ddl: string[] = [] + const dml: string[] = [] + for (const line of sql.split('\n')) { + if (/^INSERT INTO/i.test(line)) { + dml.push(line) + } else { + ddl.push(line) + } + } + return ['PRAGMA foreign_keys=OFF;', ...ddl, ...dml].join('\n') + '\n' +} + export async function syncD1( fromDb: string, previewDb: string, @@ -28,6 +44,9 @@ export async function syncD1( } if (!exported) throw new Error(`failed to export source D1 ${fromDb} after retries`) + const reordered = join(tmpdir(), 'cf-pr-preview-dev-d1-reordered.sql') + writeFileSync(reordered, reorderDdlBeforeDml(readFileSync(dump, 'utf8'))) + const rows = await wranglerJson( [ 'd1', @@ -73,7 +92,7 @@ export async function syncD1( previewConfig, '--remote', '--file', - dump, + reordered, ]) core.info(`cloned ${fromDb} into ${previewDb}`) } finally {