- Объединены ресурсы в 5 логических групп: Контент сайта, Бронирования, Отзывы и рейтинги, Персонал и гиды, Администрирование - Удалены дублирующие настройки navigation для чистой группировки - Добавлены CSS стили для визуального отображения иерархии с отступами - Добавлены эмодзи-иконки для каждого типа ресурсов через CSS - Улучшена навигация с правильной вложенностью элементов
158 lines
5.6 KiB
JavaScript
158 lines
5.6 KiB
JavaScript
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);
|
||
});
|
||
} |