#!/usr/bin/env node /** * Database Migration Script * Automatically runs database migrations for production deployment */ const { Pool } = require('pg'); const fs = require('fs'); const path = require('path'); // Database connection const pool = new Pool({ connectionString: process.env.DATABASE_URL, ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false }); async function runMigrations() { console.log('🔄 Starting database migrations...'); try { // Create migrations table if it doesn't exist await pool.query(` CREATE TABLE IF NOT EXISTS migrations ( id SERIAL PRIMARY KEY, filename VARCHAR(255) UNIQUE NOT NULL, executed_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); `); console.log('✅ Migrations table ready'); // Get list of executed migrations const { rows: executedMigrations } = await pool.query( 'SELECT filename FROM migrations ORDER BY executed_at' ); const executedSet = new Set(executedMigrations.map(row => row.filename)); // Read migration files const migrationsDir = path.join(__dirname); const files = fs.readdirSync(migrationsDir) .filter(file => file.endsWith('.sql')) .sort(); console.log(`📁 Found ${files.length} migration files`); let appliedCount = 0; for (const file of files) { if (executedSet.has(file)) { console.log(`⏭️ Skipping ${file} (already executed)`); continue; } console.log(`🔄 Executing migration: ${file}`); const filePath = path.join(migrationsDir, file); const sql = fs.readFileSync(filePath, 'utf8'); // Execute migration in a transaction const client = await pool.connect(); try { await client.query('BEGIN'); await client.query(sql); await client.query( 'INSERT INTO migrations (filename) VALUES ($1)', [file] ); await client.query('COMMIT'); console.log(`✅ Successfully executed: ${file}`); appliedCount++; } catch (error) { await client.query('ROLLBACK'); throw new Error(`Failed to execute ${file}: ${error.message}`); } finally { client.release(); } } if (appliedCount === 0) { console.log('✅ All migrations are up to date'); } else { console.log(`✅ Successfully applied ${appliedCount} migration(s)`); } } catch (error) { console.error('❌ Migration failed:', error.message); process.exit(1); } finally { await pool.end(); } } // Run migrations if this file is executed directly if (require.main === module) { runMigrations(); } module.exports = { runMigrations };