Files
tt-booking/scripts/check-database.ts
T
2025-09-28 18:47:31 +01:00

130 lines
3.9 KiB
TypeScript

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<InitResult> {
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 };