109 lines
3.3 KiB
JavaScript
109 lines
3.3 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
const { spawnSync } = require('node:child_process')
|
|
const { readdirSync } = require('node:fs')
|
|
const path = require('node:path')
|
|
const { ensureDatabaseUrl } = require('../src/runtime-config')
|
|
const { PrismaClient } = require('../generated')
|
|
|
|
const repoRoot = path.resolve(__dirname, '../../..')
|
|
const prismaBin = path.join(repoRoot, 'node_modules', '.bin', 'prisma')
|
|
const schemaPath = path.join(repoRoot, 'packages/database/prisma/schema.prisma')
|
|
const migrationsDir = path.join(repoRoot, 'packages/database/prisma/migrations')
|
|
|
|
function run(command, args) {
|
|
const result = spawnSync(command, args, {
|
|
stdio: 'inherit',
|
|
cwd: repoRoot,
|
|
env: process.env,
|
|
})
|
|
|
|
if (result.status !== 0) {
|
|
process.exit(result.status ?? 1)
|
|
}
|
|
}
|
|
|
|
async function main() {
|
|
ensureDatabaseUrl()
|
|
const prisma = new PrismaClient()
|
|
|
|
try {
|
|
const [state] = await prisma.$queryRawUnsafe(`
|
|
SELECT
|
|
to_regclass('public.companies') IS NOT NULL AS "hasCompanies",
|
|
to_regclass('public.employees') IS NOT NULL AS "hasEmployees",
|
|
to_regclass('public._prisma_migrations') IS NOT NULL AS "hasMigrationsTable"
|
|
`)
|
|
|
|
const failedMigrations = state.hasMigrationsTable
|
|
? await prisma.$queryRawUnsafe(`
|
|
SELECT migration_name
|
|
FROM "_prisma_migrations"
|
|
WHERE finished_at IS NULL
|
|
AND rolled_back_at IS NULL
|
|
ORDER BY started_at
|
|
`)
|
|
: []
|
|
|
|
const hasBaseSchema = state.hasCompanies || state.hasEmployees
|
|
|
|
if (!hasBaseSchema) {
|
|
if (failedMigrations.length > 0) {
|
|
console.log('[db:deploy] Fresh database with failed migration records detected; marking them rolled back before bootstrap')
|
|
for (const migration of failedMigrations) {
|
|
run(prismaBin, [
|
|
'migrate',
|
|
'resolve',
|
|
'--schema',
|
|
schemaPath,
|
|
'--rolled-back',
|
|
migration.migration_name,
|
|
])
|
|
}
|
|
}
|
|
|
|
console.log('[db:deploy] Fresh database detected; bootstrapping schema with prisma db push')
|
|
run(prismaBin, ['db', 'push', '--schema', schemaPath])
|
|
|
|
const migrationNames = readdirSync(migrationsDir, { withFileTypes: true })
|
|
.filter((entry) => entry.isDirectory())
|
|
.map((entry) => entry.name)
|
|
.sort()
|
|
|
|
if (migrationNames.length > 0) {
|
|
console.log('[db:deploy] Marking existing migrations as applied for the bootstrapped schema')
|
|
for (const migrationName of migrationNames) {
|
|
run(prismaBin, [
|
|
'migrate',
|
|
'resolve',
|
|
'--schema',
|
|
schemaPath,
|
|
'--applied',
|
|
migrationName,
|
|
])
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
if (failedMigrations.length > 0) {
|
|
console.error('[db:deploy] Found failed migrations in a non-empty database. Resolve them manually before deploying again.')
|
|
for (const migration of failedMigrations) {
|
|
console.error(`- ${migration.migration_name}`)
|
|
}
|
|
process.exit(1)
|
|
}
|
|
|
|
console.log('[db:deploy] Existing database detected; applying Prisma migrations')
|
|
run(prismaBin, ['migrate', 'deploy', '--schema', schemaPath])
|
|
} finally {
|
|
await prisma.$disconnect()
|
|
}
|
|
}
|
|
|
|
main().catch((error) => {
|
|
console.error('[db:deploy] Failed:', error)
|
|
process.exit(1)
|
|
})
|