update: add validation for migration process
This commit is contained in:
1 parent
6b3065ba3b
commit
0b9fb00218
1 file changed
+205
-1
+205
-1
@@ -43,7 +43,211 @@ check();
|
||||
NODE
|
||||
|
||||
if [ -d /app/prisma/migrations ] && [ "$(find /app/prisma/migrations -mindepth 1 -maxdepth 1 | wc -l)" -gt 0 ]; then
|
||||
npx prisma migrate deploy
|
||||
db_action="$(node <<'NODE'
|
||||
const { PrismaClient } = require("@prisma/client");
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
async function main() {
|
||||
const tableRows = await prisma.$queryRaw`
|
||||
SELECT table_name
|
||||
FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
AND table_type = 'BASE TABLE'
|
||||
`;
|
||||
|
||||
const enumRows = await prisma.$queryRaw`
|
||||
SELECT typname
|
||||
FROM pg_type t
|
||||
JOIN pg_namespace n ON n.oid = t.typnamespace
|
||||
WHERE n.nspname = 'public'
|
||||
AND t.typtype = 'e'
|
||||
`;
|
||||
|
||||
const tables = new Set(tableRows.map((row) => row.table_name));
|
||||
|
||||
const hasMigrationTable = tables.has("_prisma_migrations");
|
||||
|
||||
const appTables = [...tables].filter(
|
||||
(table) => table !== "_prisma_migrations"
|
||||
);
|
||||
|
||||
const hasEnums = enumRows.length > 0;
|
||||
|
||||
let failedMigrations = [];
|
||||
let migrationCount = 0;
|
||||
|
||||
if (hasMigrationTable) {
|
||||
failedMigrations = await prisma.$queryRaw`
|
||||
SELECT migration_name
|
||||
FROM "_prisma_migrations"
|
||||
WHERE finished_at IS NULL
|
||||
AND rolled_back_at IS NULL
|
||||
`;
|
||||
|
||||
const migrationCountResult = await prisma.$queryRaw`
|
||||
SELECT COUNT(*)::int AS count
|
||||
FROM "_prisma_migrations"
|
||||
`;
|
||||
|
||||
migrationCount = migrationCountResult[0].count;
|
||||
}
|
||||
|
||||
/**
|
||||
* STATE #1
|
||||
* Fresh database
|
||||
*/
|
||||
if (
|
||||
appTables.length === 0 &&
|
||||
!hasMigrationTable &&
|
||||
!hasEnums
|
||||
) {
|
||||
console.error(
|
||||
"Fresh database detected. Applying migrations."
|
||||
);
|
||||
|
||||
console.log("migrate");
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* STATE #2
|
||||
* Existing schema without Prisma migration history
|
||||
*/
|
||||
if (
|
||||
appTables.length > 0 &&
|
||||
!hasMigrationTable
|
||||
) {
|
||||
console.error(
|
||||
"Application tables exist but Prisma migration history table is missing."
|
||||
);
|
||||
|
||||
console.error(
|
||||
"Database state is inconsistent."
|
||||
);
|
||||
|
||||
console.log("blocked");
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* STATE #3
|
||||
* Prisma migration history exists
|
||||
*/
|
||||
if (hasMigrationTable) {
|
||||
if (
|
||||
migrationCount === 0 &&
|
||||
(
|
||||
appTables.length > 0 ||
|
||||
hasEnums
|
||||
)
|
||||
) {
|
||||
console.error(
|
||||
"Database contains schema objects but Prisma migration history is empty."
|
||||
);
|
||||
|
||||
console.error(
|
||||
"Database state is inconsistent."
|
||||
);
|
||||
|
||||
console.error(
|
||||
"Do not delete records from _prisma_migrations manually."
|
||||
);
|
||||
|
||||
console.log("blocked");
|
||||
return;
|
||||
}
|
||||
|
||||
if (failedMigrations.length > 0) {
|
||||
console.error(
|
||||
`Failed Prisma migrations detected: ${failedMigrations
|
||||
.map((row) => row.migration_name)
|
||||
.join(", ")}`
|
||||
);
|
||||
|
||||
console.error(
|
||||
"Resolve the failed migration before starting Doktainer."
|
||||
);
|
||||
|
||||
console.log("blocked");
|
||||
return;
|
||||
}
|
||||
|
||||
console.error(
|
||||
"Prisma migration history detected. Applying pending migrations."
|
||||
);
|
||||
|
||||
console.log("migrate");
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* STATE #4
|
||||
* Partial schema / inconsistent state
|
||||
*/
|
||||
console.error("");
|
||||
console.error(
|
||||
"Database appears to be partially initialized."
|
||||
);
|
||||
|
||||
console.error(
|
||||
"Found Prisma objects without a valid schema state."
|
||||
);
|
||||
|
||||
console.error("");
|
||||
console.error(
|
||||
"This may happen when:"
|
||||
);
|
||||
|
||||
console.error(
|
||||
"- a migration failed previously"
|
||||
);
|
||||
|
||||
console.error(
|
||||
"- the database was partially restored"
|
||||
);
|
||||
|
||||
console.error(
|
||||
"- schema objects were created manually"
|
||||
);
|
||||
|
||||
console.error("");
|
||||
console.error(
|
||||
"Doktainer will not automatically modify the database."
|
||||
);
|
||||
|
||||
console.error(
|
||||
"Manual intervention is required."
|
||||
);
|
||||
|
||||
console.log("blocked");
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
console.log("blocked");
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
NODE
|
||||
)"
|
||||
|
||||
case "$db_action" in
|
||||
migrate)
|
||||
npx prisma migrate deploy
|
||||
;;
|
||||
push)
|
||||
npx prisma db push
|
||||
;;
|
||||
blocked)
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
echo "Unknown database setup action: $db_action" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
else
|
||||
npx prisma db push
|
||||
fi
|
||||
|
||||
Reference in new issue
Block a user