feat: chat reactions
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
-- Emoji reactions on chat messages.
|
||||
--
|
||||
-- One reaction per person per message: reacting again REPLACES rather than
|
||||
-- accumulates, which is what the primary key enforces. That matches how the
|
||||
-- UI reads — a row of distinct emoji with counts — and stops someone stacking
|
||||
-- twenty reactions on one bubble.
|
||||
--
|
||||
-- The emoji is stored as text rather than a code point or shortname: what the
|
||||
-- sender picked is what everyone should see, and a mapping table would need
|
||||
-- updating every time the emoji set grows.
|
||||
CREATE TABLE IF NOT EXISTS message_reactions (
|
||||
message_id UUID NOT NULL REFERENCES messages(id) ON DELETE CASCADE,
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
-- Denormalized so deleting a conversation takes its reactions with it
|
||||
-- without relying on the messages cascade alone.
|
||||
conversation_id UUID NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
|
||||
emoji VARCHAR(32) NOT NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
PRIMARY KEY (message_id, user_id),
|
||||
-- A stray empty string would render as an invisible reaction chip.
|
||||
CONSTRAINT message_reactions_emoji_not_blank CHECK (btrim(emoji) <> '')
|
||||
);
|
||||
|
||||
-- Hydrating a page of messages: one index range scan per batch.
|
||||
CREATE INDEX IF NOT EXISTS message_reactions_message_idx
|
||||
ON message_reactions (message_id);
|
||||
Reference in New Issue
Block a user