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.
synctv/migrations/20260426017_create_room_pla...

135 lines
6.2 KiB
SQL

CREATE TABLE IF NOT EXISTS room_playback_progress (
id BIGSERIAL PRIMARY KEY,
room_id BIGINT NOT NULL REFERENCES rooms(id) ON DELETE CASCADE,
media_id BIGINT NULL,
playlist_id BIGINT NULL,
target JSONB NULL,
target_hash TEXT NOT NULL,
"position" DOUBLE PRECISION NOT NULL DEFAULT 0.0,
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
version BIGINT NOT NULL DEFAULT 0,
CONSTRAINT room_playback_progress_position_non_negative
CHECK ("position" >= 0),
CONSTRAINT room_playback_progress_has_supported_source
CHECK (
(media_id IS NOT NULL AND target IS NULL)
OR (media_id IS NULL AND playlist_id IS NOT NULL AND target IS NOT NULL)
),
CONSTRAINT room_playback_progress_target_hash_sha256
CHECK (target_hash ~ '^[0-9a-f]{64}$'),
CONSTRAINT room_playback_progress_target_object
CHECK (target IS NULL OR jsonb_typeof(target) = 'object'),
CONSTRAINT room_playback_progress_media_same_room_fk
FOREIGN KEY (media_id, room_id)
REFERENCES media(id, room_id)
ON DELETE CASCADE,
CONSTRAINT room_playback_progress_playlist_same_room_fk
FOREIGN KEY (playlist_id, room_id)
REFERENCES playlists(id, room_id)
ON DELETE CASCADE
);
CREATE UNIQUE INDEX IF NOT EXISTS room_playback_progress_source_unique
ON room_playback_progress(
room_id,
COALESCE(media_id, 0),
COALESCE(playlist_id, 0),
target_hash
);
CREATE INDEX IF NOT EXISTS idx_room_playback_progress_media_id ON room_playback_progress(media_id);
CREATE INDEX IF NOT EXISTS idx_room_playback_progress_playlist_id ON room_playback_progress(playlist_id);
CREATE INDEX IF NOT EXISTS idx_room_playback_progress_updated_at ON room_playback_progress(updated_at);
CREATE TRIGGER update_room_playback_progress_updated_at
BEFORE UPDATE ON room_playback_progress
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
CREATE TABLE IF NOT EXISTS room_playback_history (
id BIGSERIAL,
room_id BIGINT NOT NULL REFERENCES rooms(id) ON DELETE CASCADE,
sequence BIGINT NOT NULL,
media_id BIGINT NULL,
playlist_id BIGINT NULL,
target JSONB NULL,
target_hash TEXT NOT NULL,
media_name TEXT NULL,
playlist_name TEXT NULL,
position_seconds DOUBLE PRECISION NOT NULL DEFAULT 0.0,
selected_by_user_id BIGINT NULL REFERENCES users(id) ON DELETE SET NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (room_id, id, created_at),
CONSTRAINT room_playback_history_position_seconds_non_negative CHECK (position_seconds >= 0),
CONSTRAINT room_playback_history_has_supported_source CHECK (
(media_id IS NOT NULL AND target IS NULL)
OR (media_id IS NULL AND playlist_id IS NOT NULL AND target IS NOT NULL)
),
CONSTRAINT room_playback_history_target_hash_sha256
CHECK (target_hash ~ '^[0-9a-f]{64}$'),
CONSTRAINT room_playback_history_target_object
CHECK (target IS NULL OR jsonb_typeof(target) = 'object'),
CONSTRAINT room_playback_history_media_same_room_fk
FOREIGN KEY (media_id, room_id) REFERENCES media(id, room_id) ON DELETE CASCADE,
CONSTRAINT room_playback_history_playlist_same_room_fk
FOREIGN KEY (playlist_id, room_id) REFERENCES playlists(id, room_id) ON DELETE CASCADE
) PARTITION BY RANGE (created_at);
CREATE INDEX IF NOT EXISTS idx_room_playback_history_room_sequence
ON room_playback_history(room_id, sequence DESC);
CREATE INDEX IF NOT EXISTS idx_room_playback_history_created_at
ON room_playback_history(created_at, room_id, id);
CREATE TRIGGER update_room_playback_history_updated_at
BEFORE UPDATE ON room_playback_history
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
CREATE TABLE IF NOT EXISTS room_playback_state (
room_id BIGINT PRIMARY KEY REFERENCES rooms(id) ON DELETE RESTRICT,
playing_media_id BIGINT NULL,
playing_playlist_id BIGINT NULL,
target JSONB NULL,
current_progress_id BIGINT NULL REFERENCES room_playback_progress(id) ON DELETE SET NULL,
history_cursor_id BIGINT NULL,
history_cursor_created_at TIMESTAMPTZ NULL,
speed DOUBLE PRECISION NOT NULL DEFAULT 1.0,
is_playing BOOLEAN NOT NULL DEFAULT FALSE,
playback_generation BIGINT NOT NULL,
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
version BIGINT NOT NULL DEFAULT 0,
CONSTRAINT room_playback_state_target_object
CHECK (target IS NULL OR jsonb_typeof(target) = 'object'),
CONSTRAINT room_playback_state_generation_non_negative
CHECK (playback_generation >= 0),
CONSTRAINT playback_media_same_room_fk
FOREIGN KEY (playing_media_id, room_id)
REFERENCES media(id, room_id)
ON DELETE RESTRICT,
CONSTRAINT playback_playlist_same_room_fk
FOREIGN KEY (playing_playlist_id, room_id)
REFERENCES playlists(id, room_id)
ON DELETE RESTRICT,
CONSTRAINT room_playback_state_history_same_room_fk
FOREIGN KEY (room_id, history_cursor_id, history_cursor_created_at)
REFERENCES room_playback_history(room_id, id, created_at)
ON DELETE SET NULL (history_cursor_id, history_cursor_created_at),
CONSTRAINT room_playback_state_history_cursor_complete
CHECK (
(history_cursor_id IS NULL AND history_cursor_created_at IS NULL)
OR (history_cursor_id IS NOT NULL AND history_cursor_created_at IS NOT NULL)
)
);
CREATE INDEX IF NOT EXISTS idx_room_playback_state_media_id ON room_playback_state(playing_media_id);
CREATE INDEX IF NOT EXISTS idx_room_playback_state_playlist_id ON room_playback_state(playing_playlist_id);
CREATE INDEX IF NOT EXISTS idx_room_playback_state_current_progress_id ON room_playback_state(current_progress_id);
CREATE INDEX IF NOT EXISTS idx_room_playback_state_history_cursor_id ON room_playback_state(history_cursor_id);
CREATE INDEX IF NOT EXISTS idx_room_playback_state_updated_at ON room_playback_state(updated_at);
CREATE TRIGGER update_room_playback_state_updated_at
BEFORE UPDATE ON room_playback_state
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();