#!/usr/bin/env node const { spawnSync } = require('node:child_process') const { readdirSync } = require('node:fs') const path = require('node:path') 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() { 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) })