-- Система лайков/дизлайков для туров, гидов и статей CREATE TABLE ratings ( id SERIAL PRIMARY KEY, user_ip VARCHAR(45) NOT NULL, -- IP адрес для анонимных пользователей 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)), -- 1 = лайк, -1 = дизлайк created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UNIQUE(user_ip, target_id, target_type) -- Один пользователь - один голос за объект ); -- График работы гидов CREATE TABLE 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) ); -- Выходные дни (общие и индивидуальные) CREATE TABLE 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, -- NULL для публичных выходных created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UNIQUE(date, guide_id) -- Один выходной день для одного гида ); -- Обновляем таблицу бронирований для связи с гидом ALTER TABLE bookings ADD COLUMN guide_id INTEGER REFERENCES guides(id); ALTER TABLE bookings ADD COLUMN route_id INTEGER REFERENCES routes(id); -- Добавляем индексы для производительности CREATE INDEX idx_ratings_target ON ratings(target_type, target_id); CREATE INDEX idx_ratings_user_ip ON ratings(user_ip); CREATE INDEX idx_bookings_date ON bookings(preferred_date); CREATE INDEX idx_bookings_guide ON bookings(guide_id); CREATE INDEX idx_holidays_date ON holidays(date); -- Функция для подсчета рейтинга 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;