import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; import { dirname } from 'path'; import db from '../src/config/database.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); export async function initDatabase() { try { console.log('🚀 Starting complete database initialization...'); // Check if database is connected await db.query('SELECT 1'); console.log('✅ Database connection successful'); // 1. Create schema with trigger safety console.log('📋 Creating database schema...'); // Сначала создаем или заменяем функцию await db.query(` CREATE OR REPLACE FUNCTION update_updated_at_column() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = CURRENT_TIMESTAMP; RETURN NEW; END; $$ language 'plpgsql'; `); const schemaPath = path.join(__dirname, 'schema.sql'); const schema = fs.readFileSync(schemaPath, 'utf8'); await db.query(schema); // Проверяем и создаем триггеры только если не существуют const existingTriggers = await db.query(` SELECT trigger_name FROM information_schema.triggers WHERE event_object_schema = 'public' AND trigger_name LIKE '%update%updated_at%' `); const triggerNames = new Set(existingTriggers.rows.map(row => row.trigger_name)); const triggersToCreate = [ { table: 'admins', name: 'update_admins_updated_at' }, { table: 'routes', name: 'update_routes_updated_at' }, { table: 'articles', name: 'update_articles_updated_at' }, { table: 'guides', name: 'update_guides_updated_at' } ]; for (const { table, name } of triggersToCreate) { if (!triggerNames.has(name)) { await db.query(` CREATE TRIGGER ${name} BEFORE UPDATE ON ${table} FOR EACH ROW EXECUTE FUNCTION update_updated_at_column(); `); console.log(`✅ Created trigger ${name}`); } else { console.log(`ℹ️ Trigger ${name} already exists`); } } console.log('✅ Database schema created successfully'); // 2. Check if tables are empty (first run) const checkResult = await db.query('SELECT COUNT(*) FROM admins'); const isEmpty = parseInt(checkResult.rows[0].count) === 0; if (isEmpty) { console.log('📝 Database is empty, inserting mock data...'); // Insert mock data const mockDataPath = path.join(__dirname, 'mock-data.sql'); const mockData = fs.readFileSync(mockDataPath, 'utf8'); await db.query(mockData); console.log('✅ Mock data inserted successfully'); } else { console.log('ℹ️ Database already contains data, skipping mock data insertion'); } // 3. Run any pending migrations console.log('🔄 Checking for pending migrations...'); // Check if rating system exists try { await db.query('SELECT 1 FROM route_ratings LIMIT 1'); console.log('ℹ️ Rating system already exists'); } catch (error) { console.log('📈 Installing rating system...'); const ratingMigrationPath = path.join(__dirname, 'rating-system-migration.sql'); if (fs.existsSync(ratingMigrationPath)) { const ratingMigration = fs.readFileSync(ratingMigrationPath, 'utf8'); await db.query(ratingMigration); console.log('✅ Rating system installed successfully'); } } // Check if style editor migration is applied try { const result = await db.query("SELECT 1 FROM site_settings WHERE setting_key = 'primary_color' LIMIT 1"); if (result.rows.length === 0) { console.log('🎨 Installing style editor features...'); const styleMigrationPath = path.join(__dirname, 'style-editor-migration.sql'); if (fs.existsSync(styleMigrationPath)) { const styleMigration = fs.readFileSync(styleMigrationPath, 'utf8'); await db.query(styleMigration); console.log('✅ Style editor installed successfully'); } } else { console.log('ℹ️ Style editor already installed'); } } catch (error) { console.log('🎨 Installing style editor features...'); const styleMigrationPath = path.join(__dirname, 'style-editor-migration.sql'); if (fs.existsSync(styleMigrationPath)) { const styleMigration = fs.readFileSync(styleMigrationPath, 'utf8'); await db.query(styleMigration); console.log('✅ Style editor installed successfully'); } } // 4. Apply image triggers fix migration try { console.log('🖼️ Installing image triggers fix...'); const imageTriggersMigrationPath = path.join(__dirname, 'image-triggers-fix.sql'); if (fs.existsSync(imageTriggersMigrationPath)) { const imageTriggersMigration = fs.readFileSync(imageTriggersMigrationPath, 'utf8'); await db.query(imageTriggersMigration); console.log('✅ Image triggers fix applied successfully'); } } catch (error) { console.log('ℹ️ Image triggers fix - some changes may already be applied:', error.message); } console.log('✨ Database initialization completed successfully!'); } catch (error) { console.error('❌ Database initialization failed:', error); throw error; } } // Run if called directly if (process.argv[1] === fileURLToPath(import.meta.url)) { initDatabase() .then(() => { console.log('🎉 All done!'); process.exit(0); }) .catch((error) => { console.error('💥 Initialization failed:', error); process.exit(1); }); }