From 8e291ff7d593ef6918fd0ccbfe0b40047b65c847 Mon Sep 17 00:00:00 2001 From: Barend van der Walt <38956787+bvdwalt@users.noreply.github.com> Date: Fri, 13 Feb 2026 21:17:37 +0100 Subject: [PATCH 1/2] fix(db): resolve schema inconsistencies in library_artist and scrobble_buffer tables --- ...60213132541_fix_schema_inconsistencies.sql | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 db/migrations/20260213132541_fix_schema_inconsistencies.sql diff --git a/db/migrations/20260213132541_fix_schema_inconsistencies.sql b/db/migrations/20260213132541_fix_schema_inconsistencies.sql new file mode 100644 index 000000000..b33138db8 --- /dev/null +++ b/db/migrations/20260213132541_fix_schema_inconsistencies.sql @@ -0,0 +1,95 @@ +-- +goose Up +-- +goose StatementBegin + +-- Fix library_artist table: Remove contradictory 'default null' from 'not null' column +CREATE TABLE library_artist_new +( + library_id integer NOT NULL DEFAULT 1 + REFERENCES library(id) ON DELETE CASCADE, + artist_id varchar NOT NULL + REFERENCES artist(id) ON DELETE CASCADE, + stats text DEFAULT '{}', + CONSTRAINT library_artist_ux UNIQUE (library_id, artist_id) +); + +INSERT INTO library_artist_new (library_id, artist_id, stats) +SELECT library_id, artist_id, stats FROM library_artist; + +DROP TABLE library_artist; + +ALTER TABLE library_artist_new RENAME TO library_artist; + +-- Fix scrobble_buffer table: Remove duplicate user_id from unique constraint +CREATE TABLE scrobble_buffer_new +( + user_id varchar NOT NULL + CONSTRAINT scrobble_buffer_user_id_fk + REFERENCES user ON UPDATE CASCADE ON DELETE CASCADE, + service varchar NOT NULL, + media_file_id varchar NOT NULL + CONSTRAINT scrobble_buffer_media_file_id_fk + REFERENCES media_file ON UPDATE CASCADE ON DELETE CASCADE, + play_time datetime NOT NULL, + enqueue_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + id varchar NOT NULL DEFAULT '', + CONSTRAINT scrobble_buffer_pk UNIQUE (user_id, service, media_file_id, play_time) +); + +INSERT INTO scrobble_buffer_new (user_id, service, media_file_id, play_time, enqueue_time, id) +SELECT user_id, service, media_file_id, play_time, enqueue_time, id FROM scrobble_buffer; + +DROP TABLE scrobble_buffer; + +ALTER TABLE scrobble_buffer_new RENAME TO scrobble_buffer; + +CREATE UNIQUE INDEX scrobble_buffer_id_ix ON scrobble_buffer (id); + +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin + +-- Restore library_artist table with original schema (including the contradictory default null) +CREATE TABLE library_artist_new +( + library_id integer NOT NULL DEFAULT 1 + REFERENCES library(id) ON DELETE CASCADE, + artist_id varchar NOT NULL DEFAULT NULL + REFERENCES artist(id) ON DELETE CASCADE, + stats text DEFAULT '{}', + CONSTRAINT library_artist_ux UNIQUE (library_id, artist_id) +); + +INSERT INTO library_artist_new (library_id, artist_id, stats) +SELECT library_id, artist_id, stats FROM library_artist; + +DROP TABLE library_artist; + +ALTER TABLE library_artist_new RENAME TO library_artist; + +-- Restore scrobble_buffer table with original schema (including duplicate user_id in constraint) +CREATE TABLE scrobble_buffer_new +( + user_id varchar NOT NULL + CONSTRAINT scrobble_buffer_user_id_fk + REFERENCES user ON UPDATE CASCADE ON DELETE CASCADE, + service varchar NOT NULL, + media_file_id varchar NOT NULL + CONSTRAINT scrobble_buffer_media_file_id_fk + REFERENCES media_file ON UPDATE CASCADE ON DELETE CASCADE, + play_time datetime NOT NULL, + enqueue_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + id varchar NOT NULL DEFAULT '', + CONSTRAINT scrobble_buffer_pk UNIQUE (user_id, service, media_file_id, play_time, user_id) +); + +INSERT INTO scrobble_buffer_new (user_id, service, media_file_id, play_time, enqueue_time, id) +SELECT user_id, service, media_file_id, play_time, enqueue_time, id FROM scrobble_buffer; + +DROP TABLE scrobble_buffer; + +ALTER TABLE scrobble_buffer_new RENAME TO scrobble_buffer; + +CREATE UNIQUE INDEX scrobble_buffer_id_ix ON scrobble_buffer (id); + +-- +goose StatementEnd From f364db5ffc17dec90db4a8dc4ff70dc17f0ca14d Mon Sep 17 00:00:00 2001 From: Barend van der Walt <38956787+bvdwalt@users.noreply.github.com> Date: Fri, 13 Feb 2026 22:18:24 +0100 Subject: [PATCH 2/2] fix(db): address PR comments around speed of the migration --- ...60213132541_fix_schema_inconsistencies.sql | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/db/migrations/20260213132541_fix_schema_inconsistencies.sql b/db/migrations/20260213132541_fix_schema_inconsistencies.sql index b33138db8..7302ac5bf 100644 --- a/db/migrations/20260213132541_fix_schema_inconsistencies.sql +++ b/db/migrations/20260213132541_fix_schema_inconsistencies.sql @@ -1,7 +1,20 @@ -- +goose Up -- +goose StatementBegin +-- NOTE: This migration recreates two tables to fix schema inconsistencies. +-- On large production databases, the data copy may take some time as tables are locked during the transaction. +-- This is necessary because SQLite does not support altering table constraints directly. +-- Consider applying this migration during a maintenance window if the tables are large. + +-- Performance optimization: Temporarily disable foreign key constraints during schema rebuild +-- They are re-enabled automatically at the end of the transaction +PRAGMA foreign_keys = OFF; + +-- Increase cache size temporarily for faster data operations +PRAGMA cache_size = 10000; + -- Fix library_artist table: Remove contradictory 'default null' from 'not null' column +-- This is a cosmetic fix (NOT NULL takes precedence), but improves schema consistency CREATE TABLE library_artist_new ( library_id integer NOT NULL DEFAULT 1 @@ -20,6 +33,8 @@ DROP TABLE library_artist; ALTER TABLE library_artist_new RENAME TO library_artist; -- Fix scrobble_buffer table: Remove duplicate user_id from unique constraint +-- Original constraint had: UNIQUE (user_id, service, media_file_id, play_time, user_id) +-- Fixed constraint is: UNIQUE (user_id, service, media_file_id, play_time) CREATE TABLE scrobble_buffer_new ( user_id varchar NOT NULL @@ -44,11 +59,18 @@ ALTER TABLE scrobble_buffer_new RENAME TO scrobble_buffer; CREATE UNIQUE INDEX scrobble_buffer_id_ix ON scrobble_buffer (id); +-- Re-enable foreign key constraints (automatic but explicit for clarity) +PRAGMA foreign_keys = ON; + -- +goose StatementEnd -- +goose Down -- +goose StatementBegin +-- Apply same performance optimizations for rollback +PRAGMA foreign_keys = OFF; +PRAGMA cache_size = 10000; + -- Restore library_artist table with original schema (including the contradictory default null) CREATE TABLE library_artist_new ( @@ -92,4 +114,6 @@ ALTER TABLE scrobble_buffer_new RENAME TO scrobble_buffer; CREATE UNIQUE INDEX scrobble_buffer_id_ix ON scrobble_buffer (id); +PRAGMA foreign_keys = ON; + -- +goose StatementEnd