import Database from 'better-sqlite3'; import { drizzle } from 'drizzle-orm/better-sqlite3'; import * as schema from '../lib/db/schema'; import { eq } from 'drizzle-orm'; import { existsSync } from 'fs'; interface InitResult { needsMigration: boolean; needsSeeding: boolean; hasData: boolean; adminExists: boolean; summary: string; } async function checkDatabaseState(): Promise { const dbPath = process.env.DATABASE_URL || './data/sqlite.db'; const result: InitResult = { needsMigration: false, needsSeeding: false, hasData: false, adminExists: false, summary: '' }; // Check if database file exists if (!existsSync(dbPath)) { result.needsMigration = true; result.needsSeeding = true; result.summary = 'Database file does not exist - full initialization needed'; return result; } let sqlite: Database.Database | null = null; try { sqlite = new Database(dbPath); const db = drizzle(sqlite, { schema }); // Check if core tables exist by trying to query them try { const userCount = db.select().from(schema.users).limit(1).all(); const courtCount = db.select().from(schema.courts).limit(1).all(); const settingsCount = db.select().from(schema.settings).limit(1).all(); // Database has tables and some basic structure result.hasData = userCount.length > 0 || courtCount.length > 0 || settingsCount.length > 0; // Check for admin users specifically const adminUsers = db .select() .from(schema.users) .where(eq(schema.users.role, 'admin')) .limit(1) .all(); result.adminExists = adminUsers.length > 0; // Determine what's needed if (!result.hasData) { result.needsSeeding = true; result.summary = 'Database exists with empty tables - seeding needed'; } else if (!result.adminExists) { result.needsSeeding = true; result.summary = 'Database has data but no admin users found - admin creation needed'; } else { result.summary = `Database ready - found ${userCount.length ? 'users' : 'no users'}, ${courtCount.length ? 'courts' : 'no courts'}, admin users present`; } } catch (tableError) { // Tables don't exist or schema is outdated result.needsMigration = true; result.needsSeeding = true; result.summary = 'Database exists but tables missing/outdated - migration and seeding needed'; } } catch (dbError) { // Database file exists but is corrupted or inaccessible result.needsMigration = true; result.needsSeeding = true; result.summary = `Database file exists but inaccessible: ${(dbError as Error).message}`; } finally { if (sqlite) { try { sqlite.close(); } catch (e) { // Ignore close errors } } } return result; } async function main() { try { console.log('🔍 Checking database state...'); const state = await checkDatabaseState(); console.log(`📊 ${state.summary}`); console.log(` Migration needed: ${state.needsMigration ? '✅' : '❌'}`); console.log(` Seeding needed: ${state.needsSeeding ? '✅' : '❌'}`); console.log(` Has existing data: ${state.hasData ? '✅' : '❌'}`); console.log(` Admin user exists: ${state.adminExists ? '✅' : '❌'}`); // Output structured result for shell consumption process.env.DB_NEEDS_MIGRATION = state.needsMigration.toString(); process.env.DB_NEEDS_SEEDING = state.needsSeeding.toString(); process.env.DB_HAS_DATA = state.hasData.toString(); process.env.DB_ADMIN_EXISTS = state.adminExists.toString(); // Exit codes for shell scripting // 0 = ready, 1 = needs migration, 2 = needs seeding, 3 = needs both if (state.needsMigration && state.needsSeeding) { process.exit(3); } else if (state.needsMigration) { process.exit(1); } else if (state.needsSeeding) { process.exit(2); } else { process.exit(0); } } catch (error) { console.error('❌ Database state check failed:', error); process.exit(4); // Error state } } if (require.main === module) { main(); } export { checkDatabaseState, type InitResult };