import pool from '../src/config/database.js'; const migrateRatingSystem = async () => { try { console.log('🔄 Выполняю миграцию для системы рейтингов...'); // Создание таблицы ratings await pool.query(` CREATE TABLE IF NOT EXISTS ratings ( id SERIAL PRIMARY KEY, user_ip VARCHAR(45) NOT NULL, target_id INTEGER NOT NULL, target_type VARCHAR(20) NOT NULL CHECK (target_type IN ('route', 'guide', 'article')), rating INTEGER NOT NULL CHECK (rating IN (1, -1)), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UNIQUE(user_ip, target_id, target_type) ); `); // Создание таблицы guide_schedules await pool.query(` CREATE TABLE IF NOT EXISTS guide_schedules ( id SERIAL PRIMARY KEY, guide_id INTEGER NOT NULL REFERENCES guides(id) ON DELETE CASCADE, monday BOOLEAN DEFAULT true, tuesday BOOLEAN DEFAULT true, wednesday BOOLEAN DEFAULT true, thursday BOOLEAN DEFAULT true, friday BOOLEAN DEFAULT true, saturday BOOLEAN DEFAULT false, sunday BOOLEAN DEFAULT false, start_time TIME DEFAULT '09:00', end_time TIME DEFAULT '18:00', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UNIQUE(guide_id) ); `); // Создание таблицы holidays await pool.query(` CREATE TABLE IF NOT EXISTS holidays ( id SERIAL PRIMARY KEY, date DATE NOT NULL, title VARCHAR(255) NOT NULL, type VARCHAR(20) NOT NULL CHECK (type IN ('public', 'guide_personal')), guide_id INTEGER REFERENCES guides(id) ON DELETE CASCADE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UNIQUE(date, guide_id) ); `); // Добавление колонок в bookings (если не существуют) try { await pool.query('ALTER TABLE bookings ADD COLUMN guide_id INTEGER REFERENCES guides(id);'); } catch (e) { console.log('Колонка guide_id уже существует'); } try { await pool.query('ALTER TABLE bookings ADD COLUMN route_id INTEGER REFERENCES routes(id);'); } catch (e) { console.log('Колонка route_id уже существует'); } // Создание индексов await pool.query('CREATE INDEX IF NOT EXISTS idx_ratings_target ON ratings(target_type, target_id);'); await pool.query('CREATE INDEX IF NOT EXISTS idx_ratings_user_ip ON ratings(user_ip);'); await pool.query('CREATE INDEX IF NOT EXISTS idx_bookings_date ON bookings(preferred_date);'); await pool.query('CREATE INDEX IF NOT EXISTS idx_bookings_guide ON bookings(guide_id);'); await pool.query('CREATE INDEX IF NOT EXISTS idx_holidays_date ON holidays(date);'); // Функция для подсчета рейтинга await pool.query(` CREATE OR REPLACE FUNCTION calculate_rating(target_type_param VARCHAR, target_id_param INTEGER) RETURNS TABLE( likes_count BIGINT, dislikes_count BIGINT, total_votes BIGINT, rating_percentage NUMERIC(5,2) ) AS $$ BEGIN RETURN QUERY SELECT COUNT(CASE WHEN rating = 1 THEN 1 END) as likes_count, COUNT(CASE WHEN rating = -1 THEN 1 END) as dislikes_count, COUNT(*) as total_votes, CASE WHEN COUNT(*) = 0 THEN 0 ELSE ROUND((COUNT(CASE WHEN rating = 1 THEN 1 END)::NUMERIC / COUNT(*)::NUMERIC) * 100, 2) END as rating_percentage FROM ratings WHERE target_type = target_type_param AND target_id = target_id_param; END; $$ LANGUAGE plpgsql; `); console.log('✅ Миграция выполнена успешно!'); process.exit(0); } catch (error) { console.error('❌ Ошибка миграции:', error); process.exit(1); } }; migrateRatingSystem();