mirror of https://github.com/synctv-org/synctv
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
215 lines
8.9 KiB
SQL
215 lines
8.9 KiB
SQL
CREATE TABLE IF NOT EXISTS chat_messages (
|
|
id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL,
|
|
room_id BIGINT NOT NULL,
|
|
user_id BIGINT,
|
|
client_message_id TEXT,
|
|
content TEXT NOT NULL DEFAULT '',
|
|
message_type SMALLINT NOT NULL DEFAULT 1,
|
|
status SMALLINT NOT NULL DEFAULT 1,
|
|
version BIGINT NOT NULL DEFAULT 1,
|
|
reply_to_message_id BIGINT,
|
|
reply_to_message_created_at TIMESTAMPTZ,
|
|
metadata JSONB,
|
|
edited_at TIMESTAMPTZ,
|
|
deleted_at TIMESTAMPTZ,
|
|
deleted_by BIGINT,
|
|
delete_reason TEXT,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
content_search TSVECTOR GENERATED ALWAYS AS (to_tsvector('simple', content)) STORED,
|
|
CHECK (version >= 1),
|
|
CHECK (metadata IS NULL OR jsonb_typeof(metadata) = 'object'),
|
|
CHECK (
|
|
(reply_to_message_id IS NULL AND reply_to_message_created_at IS NULL)
|
|
OR (reply_to_message_id IS NOT NULL AND reply_to_message_created_at IS NOT NULL)
|
|
),
|
|
PRIMARY KEY (id, created_at),
|
|
UNIQUE (room_id, id, created_at),
|
|
FOREIGN KEY (room_id) REFERENCES rooms(id) ON DELETE RESTRICT,
|
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL,
|
|
FOREIGN KEY (deleted_by) REFERENCES users(id) ON DELETE SET NULL,
|
|
FOREIGN KEY (room_id, reply_to_message_id, reply_to_message_created_at)
|
|
REFERENCES chat_messages(room_id, id, created_at)
|
|
ON DELETE SET NULL (reply_to_message_id, reply_to_message_created_at)
|
|
) PARTITION BY RANGE (created_at);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_chat_messages_room_pagination
|
|
ON chat_messages(room_id, created_at DESC, id DESC);
|
|
CREATE INDEX IF NOT EXISTS idx_chat_messages_user_created
|
|
ON chat_messages(user_id, created_at DESC);
|
|
CREATE INDEX IF NOT EXISTS idx_chat_messages_created_at
|
|
ON chat_messages(created_at DESC);
|
|
CREATE INDEX IF NOT EXISTS idx_chat_messages_status
|
|
ON chat_messages(room_id, status, created_at DESC, id DESC);
|
|
CREATE INDEX IF NOT EXISTS idx_chat_messages_reply_target
|
|
ON chat_messages(reply_to_message_id, reply_to_message_created_at);
|
|
CREATE INDEX IF NOT EXISTS idx_chat_messages_content_search
|
|
ON chat_messages USING gin(content_search);
|
|
CREATE INDEX IF NOT EXISTS idx_chat_messages_content_trgm
|
|
ON chat_messages USING gin(content gin_trgm_ops);
|
|
CREATE INDEX IF NOT EXISTS idx_chat_messages_playback_media
|
|
ON chat_messages(
|
|
room_id,
|
|
((metadata #>> '{playback,mediaId}')),
|
|
(
|
|
CASE
|
|
WHEN jsonb_typeof(metadata #> '{playback,positionSeconds}') = 'number'
|
|
THEN (metadata #>> '{playback,positionSeconds}')::double precision
|
|
ELSE NULL
|
|
END
|
|
),
|
|
created_at,
|
|
id
|
|
)
|
|
WHERE metadata ? 'playback';
|
|
CREATE INDEX IF NOT EXISTS idx_chat_messages_playback_playlist_target
|
|
ON chat_messages(
|
|
room_id,
|
|
((metadata #>> '{playback,playlistId}')),
|
|
((metadata #>> '{playback,targetHash}')),
|
|
(
|
|
CASE
|
|
WHEN jsonb_typeof(metadata #> '{playback,positionSeconds}') = 'number'
|
|
THEN (metadata #>> '{playback,positionSeconds}')::double precision
|
|
ELSE NULL
|
|
END
|
|
),
|
|
created_at,
|
|
id
|
|
)
|
|
WHERE metadata ? 'playback';
|
|
|
|
CREATE TABLE IF NOT EXISTS chat_message_events (
|
|
sequence BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
|
|
event_id TEXT NOT NULL UNIQUE,
|
|
room_id BIGINT NOT NULL,
|
|
actor_user_id BIGINT NOT NULL,
|
|
message_id BIGINT NOT NULL,
|
|
message_created_at TIMESTAMPTZ NOT NULL,
|
|
event_type TEXT NOT NULL,
|
|
event_version BIGINT NOT NULL DEFAULT 1,
|
|
message_version BIGINT NOT NULL,
|
|
payload JSONB NOT NULL,
|
|
summary JSONB NOT NULL,
|
|
occurred_at TIMESTAMPTZ NOT NULL,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
CHECK (event_version >= 1),
|
|
CHECK (message_version >= 1),
|
|
CHECK (jsonb_typeof(payload) = 'object'),
|
|
CHECK (jsonb_typeof(summary) = 'object'),
|
|
FOREIGN KEY (room_id) REFERENCES rooms(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (room_id, message_id, message_created_at)
|
|
REFERENCES chat_messages(room_id, id, created_at) ON DELETE CASCADE
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_chat_message_events_room_sequence
|
|
ON chat_message_events(room_id, sequence);
|
|
CREATE INDEX IF NOT EXISTS idx_chat_message_events_message_sequence
|
|
ON chat_message_events(room_id, message_id, message_created_at, sequence);
|
|
CREATE INDEX IF NOT EXISTS idx_chat_message_events_created_at
|
|
ON chat_message_events(created_at, sequence);
|
|
CREATE INDEX IF NOT EXISTS idx_chat_message_events_type_sequence
|
|
ON chat_message_events(room_id, event_type, sequence);
|
|
|
|
CREATE TABLE IF NOT EXISTS chat_message_idempotency (
|
|
room_id BIGINT NOT NULL,
|
|
user_id BIGINT NOT NULL,
|
|
client_message_id TEXT NOT NULL,
|
|
request_hash TEXT NOT NULL,
|
|
message_id BIGINT,
|
|
message_created_at TIMESTAMPTZ,
|
|
event_id TEXT,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
PRIMARY KEY (room_id, user_id, client_message_id),
|
|
FOREIGN KEY (room_id) REFERENCES rooms(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (room_id, message_id, message_created_at)
|
|
REFERENCES chat_messages(room_id, id, created_at) ON DELETE CASCADE
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_chat_message_idempotency_created
|
|
ON chat_message_idempotency(created_at DESC);
|
|
CREATE INDEX IF NOT EXISTS idx_chat_message_idempotency_message
|
|
ON chat_message_idempotency(message_id, message_created_at);
|
|
CREATE INDEX IF NOT EXISTS idx_chat_message_idempotency_event
|
|
ON chat_message_idempotency(event_id)
|
|
WHERE event_id IS NOT NULL;
|
|
|
|
CREATE TABLE IF NOT EXISTS chat_message_attachments (
|
|
id TEXT NOT NULL,
|
|
kind SMALLINT NOT NULL,
|
|
room_id BIGINT NOT NULL,
|
|
message_id BIGINT NOT NULL,
|
|
message_created_at TIMESTAMPTZ NOT NULL,
|
|
filename TEXT,
|
|
storage_backend TEXT NOT NULL,
|
|
object_key TEXT NOT NULL,
|
|
url TEXT,
|
|
mime_type TEXT,
|
|
size_bytes BIGINT,
|
|
width INTEGER,
|
|
height INTEGER,
|
|
metadata JSONB NOT NULL,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
CHECK (size_bytes IS NULL OR size_bytes > 0),
|
|
CHECK (width IS NULL OR width > 0),
|
|
CHECK (height IS NULL OR height > 0),
|
|
CHECK (jsonb_typeof(metadata) = 'object'),
|
|
PRIMARY KEY (room_id, message_id, message_created_at, id),
|
|
FOREIGN KEY (room_id, message_id, message_created_at)
|
|
REFERENCES chat_messages(room_id, id, created_at) ON DELETE CASCADE
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_chat_message_attachments_message
|
|
ON chat_message_attachments(message_id, message_created_at, created_at, id);
|
|
CREATE INDEX IF NOT EXISTS idx_chat_message_attachments_room
|
|
ON chat_message_attachments(room_id, created_at DESC);
|
|
|
|
CREATE TABLE IF NOT EXISTS chat_message_operation_idempotency (
|
|
room_id BIGINT NOT NULL,
|
|
user_id BIGINT NOT NULL,
|
|
client_operation_id TEXT NOT NULL,
|
|
operation_kind SMALLINT NOT NULL,
|
|
request_hash TEXT NOT NULL,
|
|
message_id BIGINT NOT NULL,
|
|
message_created_at TIMESTAMPTZ NOT NULL,
|
|
event_id TEXT,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
PRIMARY KEY (room_id, user_id, client_operation_id),
|
|
FOREIGN KEY (room_id) REFERENCES rooms(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (room_id, message_id, message_created_at)
|
|
REFERENCES chat_messages(room_id, id, created_at) ON DELETE CASCADE
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_chat_message_operation_idempotency_message
|
|
ON chat_message_operation_idempotency(room_id, message_id, message_created_at);
|
|
CREATE INDEX IF NOT EXISTS idx_chat_message_operation_idempotency_event
|
|
ON chat_message_operation_idempotency(event_id)
|
|
WHERE event_id IS NOT NULL;
|
|
|
|
CREATE TABLE IF NOT EXISTS chat_read_states (
|
|
room_id BIGINT NOT NULL,
|
|
user_id BIGINT NOT NULL,
|
|
last_read_message_id BIGINT,
|
|
last_read_message_created_at TIMESTAMPTZ,
|
|
last_read_event_id TEXT,
|
|
last_read_event_sequence BIGINT,
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
PRIMARY KEY (room_id, user_id),
|
|
CHECK (
|
|
(last_read_message_id IS NULL AND last_read_message_created_at IS NULL)
|
|
OR (last_read_message_id IS NOT NULL AND last_read_message_created_at IS NOT NULL)
|
|
),
|
|
CHECK (last_read_event_sequence IS NULL OR last_read_event_sequence >= 1),
|
|
FOREIGN KEY (room_id) REFERENCES rooms(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (room_id, last_read_message_id, last_read_message_created_at)
|
|
REFERENCES chat_messages(room_id, id, created_at)
|
|
ON DELETE SET NULL (last_read_message_id, last_read_message_created_at)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_chat_read_states_room_updated
|
|
ON chat_read_states(room_id, updated_at DESC);
|
|
CREATE INDEX IF NOT EXISTS idx_chat_read_states_message
|
|
ON chat_read_states(last_read_message_id, last_read_message_created_at);
|