fix(dev): avoid native deps in predev migrate
This commit is contained in:
@@ -34,6 +34,33 @@ process.env.DATABASE_URL = databaseUrl;
|
|||||||
|
|
||||||
const nodeEnv = process.env.NODE_ENV || "development";
|
const nodeEnv = process.env.NODE_ENV || "development";
|
||||||
|
|
||||||
|
const runCapture = (cmd) => {
|
||||||
|
try {
|
||||||
|
const stdout = execSync(cmd, {
|
||||||
|
cwd: backendRoot,
|
||||||
|
encoding: "utf8",
|
||||||
|
stdio: ["ignore", "pipe", "pipe"],
|
||||||
|
env: { ...process.env, DATABASE_URL: databaseUrl },
|
||||||
|
});
|
||||||
|
return { ok: true, stdout: stdout || "", stderr: "" };
|
||||||
|
} catch (error) {
|
||||||
|
const err = error;
|
||||||
|
const stderr =
|
||||||
|
err && err.stderr
|
||||||
|
? Buffer.isBuffer(err.stderr)
|
||||||
|
? err.stderr.toString("utf8")
|
||||||
|
: String(err.stderr)
|
||||||
|
: "";
|
||||||
|
const stdout =
|
||||||
|
err && err.stdout
|
||||||
|
? Buffer.isBuffer(err.stdout)
|
||||||
|
? err.stdout.toString("utf8")
|
||||||
|
: String(err.stdout)
|
||||||
|
: "";
|
||||||
|
return { ok: false, stdout, stderr, error: err };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const run = (cmd) => {
|
const run = (cmd) => {
|
||||||
execSync(cmd, {
|
execSync(cmd, {
|
||||||
cwd: backendRoot,
|
cwd: backendRoot,
|
||||||
@@ -47,33 +74,6 @@ const getDbFilePath = () => {
|
|||||||
return databaseUrl.replace(/^file:/, "");
|
return databaseUrl.replace(/^file:/, "");
|
||||||
};
|
};
|
||||||
|
|
||||||
const isNonEmptyLegacyDbWithoutMigrations = () => {
|
|
||||||
const dbPath = getDbFilePath();
|
|
||||||
if (!dbPath) return false;
|
|
||||||
if (!fs.existsSync(dbPath)) return false;
|
|
||||||
|
|
||||||
// Only attempt this heuristic for SQLite file DBs.
|
|
||||||
const Database = require("better-sqlite3");
|
|
||||||
const db = new Database(dbPath, { readonly: true });
|
|
||||||
try {
|
|
||||||
const hasMigrations =
|
|
||||||
db
|
|
||||||
.prepare(
|
|
||||||
"SELECT 1 FROM sqlite_master WHERE type='table' AND name='_prisma_migrations' LIMIT 1",
|
|
||||||
)
|
|
||||||
.get() !== undefined;
|
|
||||||
|
|
||||||
const nonEmptyRow = db
|
|
||||||
.prepare("SELECT COUNT(*) AS cnt FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'")
|
|
||||||
.get();
|
|
||||||
const nonEmpty = Number(nonEmptyRow?.cnt || 0) > 0;
|
|
||||||
|
|
||||||
return nonEmpty && !hasMigrations;
|
|
||||||
} finally {
|
|
||||||
db.close();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const backupDbIfPresent = () => {
|
const backupDbIfPresent = () => {
|
||||||
const dbPath = getDbFilePath();
|
const dbPath = getDbFilePath();
|
||||||
if (!dbPath) return null;
|
if (!dbPath) return null;
|
||||||
@@ -91,17 +91,28 @@ const backupDbIfPresent = () => {
|
|||||||
const isNonProd = nodeEnv !== "production";
|
const isNonProd = nodeEnv !== "production";
|
||||||
const isFileDb = databaseUrl.startsWith("file:");
|
const isFileDb = databaseUrl.startsWith("file:");
|
||||||
|
|
||||||
if (isNonProd && isFileDb && isNonEmptyLegacyDbWithoutMigrations()) {
|
const deploy = runCapture("npx prisma migrate deploy");
|
||||||
const backupPath = backupDbIfPresent();
|
if (deploy.ok) {
|
||||||
console.warn(
|
if (deploy.stdout) process.stdout.write(deploy.stdout);
|
||||||
`[predev] Prisma migrations cannot be deployed because the database was created without migrations.\n` +
|
} else {
|
||||||
` DATABASE_URL=${databaseUrl}\n` +
|
if (deploy.stdout) process.stdout.write(deploy.stdout);
|
||||||
(backupPath ? ` Backup: ${backupPath}\n` : "") +
|
if (deploy.stderr) process.stderr.write(deploy.stderr);
|
||||||
` Resetting local SQLite database to apply migrations.`,
|
|
||||||
);
|
|
||||||
|
|
||||||
run("npx prisma migrate reset --force --skip-seed");
|
const stderr = deploy.stderr || "";
|
||||||
process.exit(0);
|
const isP3005 = stderr.includes("P3005");
|
||||||
|
|
||||||
|
// Common when an older dev.db exists but migrations weren't used previously.
|
||||||
|
if (isNonProd && isFileDb && isP3005) {
|
||||||
|
const backupPath = backupDbIfPresent();
|
||||||
|
console.warn(
|
||||||
|
`[predev] Prisma migrate baseline required (P3005). Resetting local SQLite database.\n` +
|
||||||
|
` DATABASE_URL=${databaseUrl}\n` +
|
||||||
|
(backupPath ? ` Backup: ${backupPath}\n` : "") +
|
||||||
|
` If you need to preserve local data, restore the backup and baseline manually.`,
|
||||||
|
);
|
||||||
|
|
||||||
|
run("npx prisma migrate reset --force --skip-seed");
|
||||||
|
} else {
|
||||||
|
throw deploy.error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
run("npx prisma migrate deploy");
|
|
||||||
|
|||||||
Reference in New Issue
Block a user