Files
alrahma_sunday_school_api/packages/database/scripts/db-deploy.cjs
T
2026-06-11 03:22:12 -04:00

118 lines
3.7 KiB
JavaScript

#!/usr/bin/env node
const { spawnSync } = require('node:child_process')
const { readdirSync } = require('node:fs')
const path = require('node:path')
const {
ensureDatabaseUrl,
loadDefaultEnvFiles,
normalizeDatabaseUrlForExecution,
} = 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() {
loadDefaultEnvFiles(repoRoot)
ensureDatabaseUrl()
normalizeDatabaseUrlForExecution()
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) => {
if (error?.message?.includes("Can't reach database server at `localhost:5432`")) {
console.error('[db:deploy] Hint: start the local Postgres service first. In this repo that is usually `docker compose -f docker-compose.dev.yml up -d postgres`.')
}
console.error('[db:deploy] Failed:', error)
process.exit(1)
})