-- ============================================================ -- Migration: 004_message_social_part2.sql -- Tables: message_reaction, message_bookmark, message_mention, -- message_thread, message_thread_participant -- ============================================================ BEGIN; -- models/message_reaction.rs → message_reaction CREATE TABLE IF NOT EXISTS message_reaction ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), message_id UUID NOT NULL REFERENCES message(id) ON DELETE CASCADE, channel_id UUID NOT NULL, user_id UUID NOT NULL, content TEXT NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), CONSTRAINT uq_message_reaction_user_content UNIQUE (message_id, user_id, content) ); CREATE INDEX IF NOT EXISTS idx_message_reaction_message_id ON message_reaction (message_id); CREATE INDEX IF NOT EXISTS idx_message_reaction_user_id ON message_reaction (user_id); -- models/message_bookmark.rs → message_bookmark CREATE TABLE IF NOT EXISTS message_bookmark ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), message_id UUID NOT NULL REFERENCES message(id) ON DELETE CASCADE, channel_id UUID NOT NULL, user_id UUID NOT NULL, note TEXT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), CONSTRAINT uq_message_bookmark_user_message UNIQUE (user_id, message_id) ); CREATE INDEX IF NOT EXISTS idx_message_bookmark_user_id ON message_bookmark (user_id); CREATE INDEX IF NOT EXISTS idx_message_bookmark_message_id ON message_bookmark (message_id); -- models/message_mention.rs → message_mention CREATE TABLE IF NOT EXISTS message_mention ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), message_id UUID NOT NULL REFERENCES message(id) ON DELETE CASCADE, channel_id UUID NOT NULL, mentioned_user_id UUID NOT NULL, mentioned_by UUID NOT NULL, read_at TIMESTAMPTZ NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX IF NOT EXISTS idx_message_mention_message_id ON message_mention (message_id); CREATE INDEX IF NOT EXISTS idx_message_mention_mentioned_user ON message_mention (mentioned_user_id); -- models/message_thread.rs → message_thread CREATE TABLE IF NOT EXISTS message_thread ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), channel_id UUID NOT NULL, root_message_id UUID NOT NULL REFERENCES message(id) ON DELETE CASCADE, created_by UUID NOT NULL, replies_count BIGINT NOT NULL DEFAULT 0, participants_count BIGINT NOT NULL DEFAULT 0, last_reply_message_id UUID NULL REFERENCES message(id) ON DELETE SET NULL, last_reply_at TIMESTAMPTZ NULL, resolved BOOLEAN NOT NULL DEFAULT FALSE, resolved_by UUID NULL, resolved_at TIMESTAMPTZ NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), CONSTRAINT uq_message_thread_root UNIQUE (root_message_id) ); CREATE INDEX IF NOT EXISTS idx_message_thread_channel_id ON message_thread (channel_id); CREATE INDEX IF NOT EXISTS idx_message_thread_last_reply_at ON message_thread (last_reply_at DESC NULLS LAST); -- models/message_thread_participant.rs → message_thread_participant CREATE TABLE IF NOT EXISTS message_thread_participant ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), thread_id UUID NOT NULL REFERENCES message_thread(id) ON DELETE CASCADE, user_id UUID NOT NULL, joined_reason TEXT NULL, last_read_message_id UUID NULL REFERENCES message(id) ON DELETE SET NULL, last_read_at TIMESTAMPTZ NULL, joined_at TIMESTAMPTZ NOT NULL DEFAULT now(), CONSTRAINT uq_thread_participant UNIQUE (thread_id, user_id) ); CREATE INDEX IF NOT EXISTS idx_thread_participant_thread_id ON message_thread_participant (thread_id); CREATE INDEX IF NOT EXISTS idx_thread_participant_user_id ON message_thread_participant (user_id); COMMIT;