From dd635c4e30487cf4a99e50823c9913c143338b22 Mon Sep 17 00:00:00 2001 From: Deluan Date: Tue, 28 Oct 2025 08:09:46 -0400 Subject: [PATCH] convert schema to postgres Signed-off-by: Deluan --- db/migrations/20200130083147_create_schema.go | 184 ------ .../20200131183653_standardize_item_type.go | 64 -- ...00208222418_add_defaults_to_annotations.go | 56 -- ...20200220143731_change_duration_to_float.go | 130 ---- ...0310171621_enable_search_by_albumartist.go | 21 - ...81627_add_transcoding_and_player_tables.go | 54 -- ...319211049_merge_search_into_main_tables.go | 42 -- .../20200325185135_add_album_artist_id.go | 35 -- ...00326090707_fix_album_artists_importing.go | 21 - .../20200327193744_add_year_range_to_album.go | 81 --- db/migrations/20200404214704_add_indexes.go | 30 - ...9002249_enable_search_by_tracks_artists.go | 21 - ...created_and_updated_fields_to_playlists.go | 28 - ...200418110522_reindex_to_fix_album_years.go | 21 - ...2708_reindex_to_change_full_text_search.go | 21 - .../20200423204116_add_sort_fields.go | 66 -- .../20200508093059_add_artist_song_count.go | 28 - .../20200512104202_add_disc_subtitle.go | 28 - ...0200516140647_add_playlist_tracks_table.go | 101 ---- .../20200608153717_referential_integrity.go | 138 ----- ...20200706231659_add_default_transcodings.go | 43 -- .../20200710211442_add_playlist_path.go | 28 - ...20200731095603_create_play_queues_table.go | 37 -- .../20200801101355_create_bookmark_table.go | 54 -- ...0819111809_drop_email_unique_constraint.go | 43 -- .../20201003111749_add_starred_at_index.go | 24 - .../20201010162350_add_album_size.go | 34 -- ...20201012210022_add_artist_playlist_size.go | 45 -- db/migrations/20201021085410_add_mbids.go | 59 -- .../20201021093209_add_media_file_indexes.go | 28 - ...01021135455_add_media_file_artist_index.go | 24 - .../20201030162009_add_artist_info_table.go | 36 -- .../20201110205344_add_comments_and_lyrics.go | 33 - .../20201128100726_add_real-path_option.go | 24 - ...01213124814_add_all_artist_ids_to_album.go | 64 -- .../20210322132848_add_timestamp_indexes.go | 34 -- .../20210418232815_fix_album_comments.go | 68 --- .../20210430212322_add_bpm_metadata.go | 31 - .../20210530121921_create_shares_table.go | 35 -- .../20210601231734_update_share_fieldnames.go | 26 - .../20210616150710_encrypt_all_passwords.go | 56 -- ...1716_drop_player_name_unique_constraint.go | 48 -- ...add_user_prefs_player_scrobbler_enabled.go | 45 -- ...add_referential_integrity_to_user_props.go | 39 -- .../20210626213026_add_scrobble_buffer.go | 39 -- .../20210715151153_add_genre_tables.go | 69 --- .../20210821212604_add_mediafile_channels.go | 31 - .../20211008205505_add_smart_playlist.go | 38 -- ...023184825_add_order_title_to_media_file.go | 62 -- ...1026191915_unescape_lyrics_and_comments.go | 48 -- .../20211029213200_add_userid_to_playlist.go | 61 -- ...215414_add_alphabetical_by_artist_index.go | 24 - ...0211105162746_remove_invalid_artist_ids.go | 23 - ...231849_add_musicbrainz_release_track_id.go | 29 - .../20221219112733_add_album_image_paths.go | 27 - .../20221219140528_remove_cover_art_id.go | 28 - .../20230112111457_add_album_paths.go | 68 --- .../20230114121537_touch_playlists.go | 21 - .../20230115103212_create_internet_radio.go | 31 - .../20230117155559_add_replaygain_metadata.go | 35 -- .../20230117180400_add_album_info.go | 34 -- .../20230119152657_recreate_share_table.go | 42 -- ...230202143713_change_path_list_separator.go | 63 -- ...81414_change_image_files_list_separator.go | 60 -- .../20230310222612_add_download_to_share.go | 24 - .../20230404104309_empty_sql_migration.sql | 13 - .../20230515184510_add_release_date.go | 50 -- ...6214944_rename_musicbrainz_recording_id.go | 28 - .../20231208182311_add_discs_to_album.go | 36 -- .../20231209211223_alter_lyric_column.go | 82 --- ...0_add_default_values_to_null_columns.go.go | 563 ------------------ ...0240426202913_add_id_to_scrobble_buffer.go | 30 - .../20240511210036_add_sample_rate.go | 29 - .../20240511220020_add_library_table.go | 71 --- .../20240629152843_remove_annotation_id.go | 66 -- ...044339_player_use_user_id_over_username.go | 62 -- .../20241020003138_add_sort_tags_index.sql | 9 - ...5533_fix_sort_tags_collation_and_index.sql | 512 ---------------- .../20241026183640_support_new_scanner.go | 319 ---------- ...20250522013904_share_user_id_on_delete.sql | 36 -- ...250611010101_playqueue_current_to_index.go | 80 --- .../20250701010101_add_folder_hash.go | 21 - ...010102_add_annotation_user_foreign_key.sql | 46 -- .../20250701010103_add_library_stats.go | 48 -- ...1010104_make_replaygain_fields_nullable.go | 49 -- .../20250701010105_remove_dangling_items.sql | 7 - ...6_add_participant_stats_to_all_artists.sql | 65 -- .../20250701010107_add_mbid_indexes.sql | 27 - ...0250701010108_add_multi_library_support.go | 119 ---- .../20251027000000_create_schema.sql | 489 +++++++++++++++ 90 files changed, 489 insertions(+), 5353 deletions(-) delete mode 100644 db/migrations/20200130083147_create_schema.go delete mode 100644 db/migrations/20200131183653_standardize_item_type.go delete mode 100644 db/migrations/20200208222418_add_defaults_to_annotations.go delete mode 100644 db/migrations/20200220143731_change_duration_to_float.go delete mode 100644 db/migrations/20200310171621_enable_search_by_albumartist.go delete mode 100644 db/migrations/20200310181627_add_transcoding_and_player_tables.go delete mode 100644 db/migrations/20200319211049_merge_search_into_main_tables.go delete mode 100644 db/migrations/20200325185135_add_album_artist_id.go delete mode 100644 db/migrations/20200326090707_fix_album_artists_importing.go delete mode 100644 db/migrations/20200327193744_add_year_range_to_album.go delete mode 100644 db/migrations/20200404214704_add_indexes.go delete mode 100644 db/migrations/20200409002249_enable_search_by_tracks_artists.go delete mode 100644 db/migrations/20200411164603_add_created_and_updated_fields_to_playlists.go delete mode 100644 db/migrations/20200418110522_reindex_to_fix_album_years.go delete mode 100644 db/migrations/20200419222708_reindex_to_change_full_text_search.go delete mode 100644 db/migrations/20200423204116_add_sort_fields.go delete mode 100644 db/migrations/20200508093059_add_artist_song_count.go delete mode 100644 db/migrations/20200512104202_add_disc_subtitle.go delete mode 100644 db/migrations/20200516140647_add_playlist_tracks_table.go delete mode 100644 db/migrations/20200608153717_referential_integrity.go delete mode 100644 db/migrations/20200706231659_add_default_transcodings.go delete mode 100644 db/migrations/20200710211442_add_playlist_path.go delete mode 100644 db/migrations/20200731095603_create_play_queues_table.go delete mode 100644 db/migrations/20200801101355_create_bookmark_table.go delete mode 100644 db/migrations/20200819111809_drop_email_unique_constraint.go delete mode 100644 db/migrations/20201003111749_add_starred_at_index.go delete mode 100644 db/migrations/20201010162350_add_album_size.go delete mode 100644 db/migrations/20201012210022_add_artist_playlist_size.go delete mode 100644 db/migrations/20201021085410_add_mbids.go delete mode 100644 db/migrations/20201021093209_add_media_file_indexes.go delete mode 100644 db/migrations/20201021135455_add_media_file_artist_index.go delete mode 100644 db/migrations/20201030162009_add_artist_info_table.go delete mode 100644 db/migrations/20201110205344_add_comments_and_lyrics.go delete mode 100644 db/migrations/20201128100726_add_real-path_option.go delete mode 100644 db/migrations/20201213124814_add_all_artist_ids_to_album.go delete mode 100644 db/migrations/20210322132848_add_timestamp_indexes.go delete mode 100644 db/migrations/20210418232815_fix_album_comments.go delete mode 100644 db/migrations/20210430212322_add_bpm_metadata.go delete mode 100644 db/migrations/20210530121921_create_shares_table.go delete mode 100644 db/migrations/20210601231734_update_share_fieldnames.go delete mode 100644 db/migrations/20210616150710_encrypt_all_passwords.go delete mode 100644 db/migrations/20210619231716_drop_player_name_unique_constraint.go delete mode 100644 db/migrations/20210623155401_add_user_prefs_player_scrobbler_enabled.go delete mode 100644 db/migrations/20210625223901_add_referential_integrity_to_user_props.go delete mode 100644 db/migrations/20210626213026_add_scrobble_buffer.go delete mode 100644 db/migrations/20210715151153_add_genre_tables.go delete mode 100644 db/migrations/20210821212604_add_mediafile_channels.go delete mode 100644 db/migrations/20211008205505_add_smart_playlist.go delete mode 100644 db/migrations/20211023184825_add_order_title_to_media_file.go delete mode 100644 db/migrations/20211026191915_unescape_lyrics_and_comments.go delete mode 100644 db/migrations/20211029213200_add_userid_to_playlist.go delete mode 100644 db/migrations/20211102215414_add_alphabetical_by_artist_index.go delete mode 100644 db/migrations/20211105162746_remove_invalid_artist_ids.go delete mode 100644 db/migrations/20220724231849_add_musicbrainz_release_track_id.go delete mode 100644 db/migrations/20221219112733_add_album_image_paths.go delete mode 100644 db/migrations/20221219140528_remove_cover_art_id.go delete mode 100644 db/migrations/20230112111457_add_album_paths.go delete mode 100644 db/migrations/20230114121537_touch_playlists.go delete mode 100644 db/migrations/20230115103212_create_internet_radio.go delete mode 100644 db/migrations/20230117155559_add_replaygain_metadata.go delete mode 100644 db/migrations/20230117180400_add_album_info.go delete mode 100644 db/migrations/20230119152657_recreate_share_table.go delete mode 100644 db/migrations/20230202143713_change_path_list_separator.go delete mode 100644 db/migrations/20230209181414_change_image_files_list_separator.go delete mode 100644 db/migrations/20230310222612_add_download_to_share.go delete mode 100644 db/migrations/20230404104309_empty_sql_migration.sql delete mode 100644 db/migrations/20230515184510_add_release_date.go delete mode 100644 db/migrations/20230616214944_rename_musicbrainz_recording_id.go delete mode 100644 db/migrations/20231208182311_add_discs_to_album.go delete mode 100644 db/migrations/20231209211223_alter_lyric_column.go delete mode 100644 db/migrations/20240122223340_add_default_values_to_null_columns.go.go delete mode 100644 db/migrations/20240426202913_add_id_to_scrobble_buffer.go delete mode 100644 db/migrations/20240511210036_add_sample_rate.go delete mode 100644 db/migrations/20240511220020_add_library_table.go delete mode 100644 db/migrations/20240629152843_remove_annotation_id.go delete mode 100644 db/migrations/20240802044339_player_use_user_id_over_username.go delete mode 100644 db/migrations/20241020003138_add_sort_tags_index.sql delete mode 100644 db/migrations/20241024125533_fix_sort_tags_collation_and_index.sql delete mode 100644 db/migrations/20241026183640_support_new_scanner.go delete mode 100644 db/migrations/20250522013904_share_user_id_on_delete.sql delete mode 100644 db/migrations/20250611010101_playqueue_current_to_index.go delete mode 100644 db/migrations/20250701010101_add_folder_hash.go delete mode 100644 db/migrations/20250701010102_add_annotation_user_foreign_key.sql delete mode 100644 db/migrations/20250701010103_add_library_stats.go delete mode 100644 db/migrations/20250701010104_make_replaygain_fields_nullable.go delete mode 100644 db/migrations/20250701010105_remove_dangling_items.sql delete mode 100644 db/migrations/20250701010106_add_participant_stats_to_all_artists.sql delete mode 100644 db/migrations/20250701010107_add_mbid_indexes.sql delete mode 100644 db/migrations/20250701010108_add_multi_library_support.go create mode 100644 db/migrations/20251027000000_create_schema.sql diff --git a/db/migrations/20200130083147_create_schema.go b/db/migrations/20200130083147_create_schema.go deleted file mode 100644 index 2fae4f57d..000000000 --- a/db/migrations/20200130083147_create_schema.go +++ /dev/null @@ -1,184 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/navidrome/navidrome/log" - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20200130083147, Down20200130083147) -} - -func Up20200130083147(_ context.Context, tx *sql.Tx) error { - log.Info("Creating DB Schema") - _, err := tx.Exec(` -create table if not exists album -( - id varchar(255) not null - primary key, - name varchar(255) default '' not null, - artist_id varchar(255) default '' not null, - cover_art_path varchar(255) default '' not null, - cover_art_id varchar(255) default '' not null, - artist varchar(255) default '' not null, - album_artist varchar(255) default '' not null, - year integer default 0 not null, - compilation bool default FALSE not null, - song_count integer default 0 not null, - duration integer default 0 not null, - genre varchar(255) default '' not null, - created_at datetime, - updated_at datetime -); - -create index if not exists album_artist - on album (artist); - -create index if not exists album_artist_id - on album (artist_id); - -create index if not exists album_genre - on album (genre); - -create index if not exists album_name - on album (name); - -create index if not exists album_year - on album (year); - -create table if not exists annotation -( - ann_id varchar(255) not null - primary key, - user_id varchar(255) default '' not null, - item_id varchar(255) default '' not null, - item_type varchar(255) default '' not null, - play_count integer, - play_date datetime, - rating integer, - starred bool default FALSE not null, - starred_at datetime, - unique (user_id, item_id, item_type) -); - -create index if not exists annotation_play_count - on annotation (play_count); - -create index if not exists annotation_play_date - on annotation (play_date); - -create index if not exists annotation_rating - on annotation (rating); - -create index if not exists annotation_starred - on annotation (starred); - -create table if not exists artist -( - id varchar(255) not null - primary key, - name varchar(255) default '' not null, - album_count integer default 0 not null -); - -create index if not exists artist_name - on artist (name); - -create table if not exists media_file -( - id varchar(255) not null - primary key, - path varchar(255) default '' not null, - title varchar(255) default '' not null, - album varchar(255) default '' not null, - artist varchar(255) default '' not null, - artist_id varchar(255) default '' not null, - album_artist varchar(255) default '' not null, - album_id varchar(255) default '' not null, - has_cover_art bool default FALSE not null, - track_number integer default 0 not null, - disc_number integer default 0 not null, - year integer default 0 not null, - size integer default 0 not null, - suffix varchar(255) default '' not null, - duration integer default 0 not null, - bit_rate integer default 0 not null, - genre varchar(255) default '' not null, - compilation bool default FALSE not null, - created_at datetime, - updated_at datetime -); - -create index if not exists media_file_album_id - on media_file (album_id); - -create index if not exists media_file_genre - on media_file (genre); - -create index if not exists media_file_path - on media_file (path); - -create index if not exists media_file_title - on media_file (title); - -create table if not exists playlist -( - id varchar(255) not null - primary key, - name varchar(255) default '' not null, - comment varchar(255) default '' not null, - duration integer default 0 not null, - owner varchar(255) default '' not null, - public bool default FALSE not null, - tracks text not null -); - -create index if not exists playlist_name - on playlist (name); - -create table if not exists property -( - id varchar(255) not null - primary key, - value varchar(255) default '' not null -); - -create table if not exists search -( - id varchar(255) not null - primary key, - "table" varchar(255) default '' not null, - full_text varchar(255) default '' not null -); - -create index if not exists search_full_text - on search (full_text); - -create index if not exists search_table - on search ("table"); - -create table if not exists user -( - id varchar(255) not null - primary key, - user_name varchar(255) default '' not null - unique, - name varchar(255) default '' not null, - email varchar(255) default '' not null - unique, - password varchar(255) default '' not null, - is_admin bool default FALSE not null, - last_login_at datetime, - last_access_at datetime, - created_at datetime not null, - updated_at datetime not null -);`) - return err -} - -func Down20200130083147(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20200131183653_standardize_item_type.go b/db/migrations/20200131183653_standardize_item_type.go deleted file mode 100644 index 471dc8002..000000000 --- a/db/migrations/20200131183653_standardize_item_type.go +++ /dev/null @@ -1,64 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20200131183653, Down20200131183653) -} - -func Up20200131183653(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -create table search_dg_tmp -( - id varchar(255) not null - primary key, - item_type varchar(255) default '' not null, - full_text varchar(255) default '' not null -); - -insert into search_dg_tmp(id, item_type, full_text) select id, "table", full_text from search; - -drop table search; - -alter table search_dg_tmp rename to search; - -create index search_full_text - on search (full_text); -create index search_table - on search (item_type); - -update annotation set item_type = 'media_file' where item_type = 'mediaFile'; -`) - return err -} - -func Down20200131183653(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -create table search_dg_tmp -( - id varchar(255) not null - primary key, - "table" varchar(255) default '' not null, - full_text varchar(255) default '' not null -); - -insert into search_dg_tmp(id, "table", full_text) select id, item_type, full_text from search; - -drop table search; - -alter table search_dg_tmp rename to search; - -create index search_full_text - on search (full_text); -create index search_table - on search ("table"); - -update annotation set item_type = 'mediaFile' where item_type = 'media_file'; -`) - return err -} diff --git a/db/migrations/20200208222418_add_defaults_to_annotations.go b/db/migrations/20200208222418_add_defaults_to_annotations.go deleted file mode 100644 index d058b02c3..000000000 --- a/db/migrations/20200208222418_add_defaults_to_annotations.go +++ /dev/null @@ -1,56 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20200208222418, Down20200208222418) -} - -func Up20200208222418(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -update annotation set play_count = 0 where play_count is null; -update annotation set rating = 0 where rating is null; -create table annotation_dg_tmp -( - ann_id varchar(255) not null - primary key, - user_id varchar(255) default '' not null, - item_id varchar(255) default '' not null, - item_type varchar(255) default '' not null, - play_count integer default 0, - play_date datetime, - rating integer default 0, - starred bool default FALSE not null, - starred_at datetime, - unique (user_id, item_id, item_type) -); - -insert into annotation_dg_tmp(ann_id, user_id, item_id, item_type, play_count, play_date, rating, starred, starred_at) select ann_id, user_id, item_id, item_type, play_count, play_date, rating, starred, starred_at from annotation; - -drop table annotation; - -alter table annotation_dg_tmp rename to annotation; - -create index annotation_play_count - on annotation (play_count); - -create index annotation_play_date - on annotation (play_date); - -create index annotation_rating - on annotation (rating); - -create index annotation_starred - on annotation (starred); -`) - return err -} - -func Down20200208222418(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20200220143731_change_duration_to_float.go b/db/migrations/20200220143731_change_duration_to_float.go deleted file mode 100644 index 72b785ef8..000000000 --- a/db/migrations/20200220143731_change_duration_to_float.go +++ /dev/null @@ -1,130 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20200220143731, Down20200220143731) -} - -func Up20200220143731(_ context.Context, tx *sql.Tx) error { - notice(tx, "This migration will force the next scan to be a full rescan!") - _, err := tx.Exec(` -create table media_file_dg_tmp -( - id varchar(255) not null - primary key, - path varchar(255) default '' not null, - title varchar(255) default '' not null, - album varchar(255) default '' not null, - artist varchar(255) default '' not null, - artist_id varchar(255) default '' not null, - album_artist varchar(255) default '' not null, - album_id varchar(255) default '' not null, - has_cover_art bool default FALSE not null, - track_number integer default 0 not null, - disc_number integer default 0 not null, - year integer default 0 not null, - size integer default 0 not null, - suffix varchar(255) default '' not null, - duration real default 0 not null, - bit_rate integer default 0 not null, - genre varchar(255) default '' not null, - compilation bool default FALSE not null, - created_at datetime, - updated_at datetime -); - -insert into media_file_dg_tmp(id, path, title, album, artist, artist_id, album_artist, album_id, has_cover_art, track_number, disc_number, year, size, suffix, duration, bit_rate, genre, compilation, created_at, updated_at) select id, path, title, album, artist, artist_id, album_artist, album_id, has_cover_art, track_number, disc_number, year, size, suffix, duration, bit_rate, genre, compilation, created_at, updated_at from media_file; - -drop table media_file; - -alter table media_file_dg_tmp rename to media_file; - -create index media_file_album_id - on media_file (album_id); - -create index media_file_genre - on media_file (genre); - -create index media_file_path - on media_file (path); - -create index media_file_title - on media_file (title); - -create table album_dg_tmp -( - id varchar(255) not null - primary key, - name varchar(255) default '' not null, - artist_id varchar(255) default '' not null, - cover_art_path varchar(255) default '' not null, - cover_art_id varchar(255) default '' not null, - artist varchar(255) default '' not null, - album_artist varchar(255) default '' not null, - year integer default 0 not null, - compilation bool default FALSE not null, - song_count integer default 0 not null, - duration real default 0 not null, - genre varchar(255) default '' not null, - created_at datetime, - updated_at datetime -); - -insert into album_dg_tmp(id, name, artist_id, cover_art_path, cover_art_id, artist, album_artist, year, compilation, song_count, duration, genre, created_at, updated_at) select id, name, artist_id, cover_art_path, cover_art_id, artist, album_artist, year, compilation, song_count, duration, genre, created_at, updated_at from album; - -drop table album; - -alter table album_dg_tmp rename to album; - -create index album_artist - on album (artist); - -create index album_artist_id - on album (artist_id); - -create index album_genre - on album (genre); - -create index album_name - on album (name); - -create index album_year - on album (year); - -create table playlist_dg_tmp -( - id varchar(255) not null - primary key, - name varchar(255) default '' not null, - comment varchar(255) default '' not null, - duration real default 0 not null, - owner varchar(255) default '' not null, - public bool default FALSE not null, - tracks text not null -); - -insert into playlist_dg_tmp(id, name, comment, duration, owner, public, tracks) select id, name, comment, duration, owner, public, tracks from playlist; - -drop table playlist; - -alter table playlist_dg_tmp rename to playlist; - -create index playlist_name - on playlist (name); - --- Force a full rescan -delete from property where id like 'LastScan%'; -update media_file set updated_at = '0001-01-01'; -`) - return err -} - -func Down20200220143731(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20200310171621_enable_search_by_albumartist.go b/db/migrations/20200310171621_enable_search_by_albumartist.go deleted file mode 100644 index 373e0a475..000000000 --- a/db/migrations/20200310171621_enable_search_by_albumartist.go +++ /dev/null @@ -1,21 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20200310171621, Down20200310171621) -} - -func Up20200310171621(_ context.Context, tx *sql.Tx) error { - notice(tx, "A full rescan will be performed to enable search by Album Artist!") - return forceFullRescan(tx) -} - -func Down20200310171621(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20200310181627_add_transcoding_and_player_tables.go b/db/migrations/20200310181627_add_transcoding_and_player_tables.go deleted file mode 100644 index 3be91ac35..000000000 --- a/db/migrations/20200310181627_add_transcoding_and_player_tables.go +++ /dev/null @@ -1,54 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20200310181627, Down20200310181627) -} - -func Up20200310181627(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -create table transcoding -( - id varchar(255) not null primary key, - name varchar(255) not null, - target_format varchar(255) not null, - command varchar(255) default '' not null, - default_bit_rate int default 192, - unique (name), - unique (target_format) -); - -create table player -( - id varchar(255) not null primary key, - name varchar not null, - type varchar, - user_name varchar not null, - client varchar not null, - ip_address varchar, - last_seen timestamp, - max_bit_rate int default 0, - transcoding_id varchar, - unique (name), - foreign key (transcoding_id) - references transcoding(id) - on update restrict - on delete restrict -); -`) - return err -} - -func Down20200310181627(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -drop table transcoding; -drop table player; -`) - return err -} diff --git a/db/migrations/20200319211049_merge_search_into_main_tables.go b/db/migrations/20200319211049_merge_search_into_main_tables.go deleted file mode 100644 index f888cdd4c..000000000 --- a/db/migrations/20200319211049_merge_search_into_main_tables.go +++ /dev/null @@ -1,42 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20200319211049, Down20200319211049) -} - -func Up20200319211049(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -alter table media_file - add full_text varchar(255) default ''; -create index if not exists media_file_full_text - on media_file (full_text); - -alter table album - add full_text varchar(255) default ''; -create index if not exists album_full_text - on album (full_text); - -alter table artist - add full_text varchar(255) default ''; -create index if not exists artist_full_text - on artist (full_text); - -drop table if exists search; -`) - if err != nil { - return err - } - notice(tx, "A full rescan will be performed!") - return forceFullRescan(tx) -} - -func Down20200319211049(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20200325185135_add_album_artist_id.go b/db/migrations/20200325185135_add_album_artist_id.go deleted file mode 100644 index f01f2c558..000000000 --- a/db/migrations/20200325185135_add_album_artist_id.go +++ /dev/null @@ -1,35 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20200325185135, Down20200325185135) -} - -func Up20200325185135(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -alter table album - add album_artist_id varchar(255) default ''; -create index album_artist_album_id - on album (album_artist_id); - -alter table media_file - add album_artist_id varchar(255) default ''; -create index media_file_artist_album_id - on media_file (album_artist_id); -`) - if err != nil { - return err - } - notice(tx, "A full rescan will be performed!") - return forceFullRescan(tx) -} - -func Down20200325185135(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20200326090707_fix_album_artists_importing.go b/db/migrations/20200326090707_fix_album_artists_importing.go deleted file mode 100644 index c42e8c327..000000000 --- a/db/migrations/20200326090707_fix_album_artists_importing.go +++ /dev/null @@ -1,21 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20200326090707, Down20200326090707) -} - -func Up20200326090707(_ context.Context, tx *sql.Tx) error { - notice(tx, "A full rescan will be performed!") - return forceFullRescan(tx) -} - -func Down20200326090707(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20200327193744_add_year_range_to_album.go b/db/migrations/20200327193744_add_year_range_to_album.go deleted file mode 100644 index 66f2b23e8..000000000 --- a/db/migrations/20200327193744_add_year_range_to_album.go +++ /dev/null @@ -1,81 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20200327193744, Down20200327193744) -} - -func Up20200327193744(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -create table album_dg_tmp -( - id varchar(255) not null - primary key, - name varchar(255) default '' not null, - artist_id varchar(255) default '' not null, - cover_art_path varchar(255) default '' not null, - cover_art_id varchar(255) default '' not null, - artist varchar(255) default '' not null, - album_artist varchar(255) default '' not null, - min_year int default 0 not null, - max_year integer default 0 not null, - compilation bool default FALSE not null, - song_count integer default 0 not null, - duration real default 0 not null, - genre varchar(255) default '' not null, - created_at datetime, - updated_at datetime, - full_text varchar(255) default '', - album_artist_id varchar(255) default '' -); - -insert into album_dg_tmp(id, name, artist_id, cover_art_path, cover_art_id, artist, album_artist, max_year, compilation, song_count, duration, genre, created_at, updated_at, full_text, album_artist_id) select id, name, artist_id, cover_art_path, cover_art_id, artist, album_artist, year, compilation, song_count, duration, genre, created_at, updated_at, full_text, album_artist_id from album; - -drop table album; - -alter table album_dg_tmp rename to album; - -create index album_artist - on album (artist); - -create index album_artist_album - on album (artist); - -create index album_artist_album_id - on album (album_artist_id); - -create index album_artist_id - on album (artist_id); - -create index album_full_text - on album (full_text); - -create index album_genre - on album (genre); - -create index album_name - on album (name); - -create index album_min_year - on album (min_year); - -create index album_max_year - on album (max_year); - -`) - if err != nil { - return err - } - notice(tx, "A full rescan will be performed!") - return forceFullRescan(tx) -} - -func Down20200327193744(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20200404214704_add_indexes.go b/db/migrations/20200404214704_add_indexes.go deleted file mode 100644 index 6207b0a3d..000000000 --- a/db/migrations/20200404214704_add_indexes.go +++ /dev/null @@ -1,30 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20200404214704, Down20200404214704) -} - -func Up20200404214704(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -create index if not exists media_file_year - on media_file (year); - -create index if not exists media_file_duration - on media_file (duration); - -create index if not exists media_file_track_number - on media_file (disc_number, track_number); -`) - return err -} - -func Down20200404214704(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20200409002249_enable_search_by_tracks_artists.go b/db/migrations/20200409002249_enable_search_by_tracks_artists.go deleted file mode 100644 index 22006c8af..000000000 --- a/db/migrations/20200409002249_enable_search_by_tracks_artists.go +++ /dev/null @@ -1,21 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20200409002249, Down20200409002249) -} - -func Up20200409002249(_ context.Context, tx *sql.Tx) error { - notice(tx, "A full rescan will be performed to enable search by individual Artist in an Album!") - return forceFullRescan(tx) -} - -func Down20200409002249(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20200411164603_add_created_and_updated_fields_to_playlists.go b/db/migrations/20200411164603_add_created_and_updated_fields_to_playlists.go deleted file mode 100644 index 266dc087d..000000000 --- a/db/migrations/20200411164603_add_created_and_updated_fields_to_playlists.go +++ /dev/null @@ -1,28 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20200411164603, Down20200411164603) -} - -func Up20200411164603(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -alter table playlist - add created_at datetime; -alter table playlist - add updated_at datetime; -update playlist - set created_at = datetime('now'), updated_at = datetime('now'); -`) - return err -} - -func Down20200411164603(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20200418110522_reindex_to_fix_album_years.go b/db/migrations/20200418110522_reindex_to_fix_album_years.go deleted file mode 100644 index 22b024cea..000000000 --- a/db/migrations/20200418110522_reindex_to_fix_album_years.go +++ /dev/null @@ -1,21 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20200418110522, Down20200418110522) -} - -func Up20200418110522(_ context.Context, tx *sql.Tx) error { - notice(tx, "A full rescan will be performed to fix search Albums by year") - return forceFullRescan(tx) -} - -func Down20200418110522(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20200419222708_reindex_to_change_full_text_search.go b/db/migrations/20200419222708_reindex_to_change_full_text_search.go deleted file mode 100644 index efeb1bb84..000000000 --- a/db/migrations/20200419222708_reindex_to_change_full_text_search.go +++ /dev/null @@ -1,21 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20200419222708, Down20200419222708) -} - -func Up20200419222708(_ context.Context, tx *sql.Tx) error { - notice(tx, "A full rescan will be performed to change the search behaviour") - return forceFullRescan(tx) -} - -func Down20200419222708(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20200423204116_add_sort_fields.go b/db/migrations/20200423204116_add_sort_fields.go deleted file mode 100644 index 4097a9d60..000000000 --- a/db/migrations/20200423204116_add_sort_fields.go +++ /dev/null @@ -1,66 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20200423204116, Down20200423204116) -} - -func Up20200423204116(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -alter table artist - add order_artist_name varchar(255) collate nocase; -alter table artist - add sort_artist_name varchar(255) collate nocase; -create index if not exists artist_order_artist_name - on artist (order_artist_name); - -alter table album - add order_album_name varchar(255) collate nocase; -alter table album - add order_album_artist_name varchar(255) collate nocase; -alter table album - add sort_album_name varchar(255) collate nocase; -alter table album - add sort_artist_name varchar(255) collate nocase; -alter table album - add sort_album_artist_name varchar(255) collate nocase; -create index if not exists album_order_album_name - on album (order_album_name); -create index if not exists album_order_album_artist_name - on album (order_album_artist_name); - -alter table media_file - add order_album_name varchar(255) collate nocase; -alter table media_file - add order_album_artist_name varchar(255) collate nocase; -alter table media_file - add order_artist_name varchar(255) collate nocase; -alter table media_file - add sort_album_name varchar(255) collate nocase; -alter table media_file - add sort_artist_name varchar(255) collate nocase; -alter table media_file - add sort_album_artist_name varchar(255) collate nocase; -alter table media_file - add sort_title varchar(255) collate nocase; -create index if not exists media_file_order_album_name - on media_file (order_album_name); -create index if not exists media_file_order_artist_name - on media_file (order_artist_name); -`) - if err != nil { - return err - } - notice(tx, "A full rescan will be performed to change the search behaviour") - return forceFullRescan(tx) -} - -func Down20200423204116(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20200508093059_add_artist_song_count.go b/db/migrations/20200508093059_add_artist_song_count.go deleted file mode 100644 index aac78e698..000000000 --- a/db/migrations/20200508093059_add_artist_song_count.go +++ /dev/null @@ -1,28 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20200508093059, Down20200508093059) -} - -func Up20200508093059(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -alter table artist - add song_count integer default 0 not null; -`) - if err != nil { - return err - } - notice(tx, "A full rescan will be performed to calculate artists' song counts") - return forceFullRescan(tx) -} - -func Down20200508093059(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20200512104202_add_disc_subtitle.go b/db/migrations/20200512104202_add_disc_subtitle.go deleted file mode 100644 index b3e907d8d..000000000 --- a/db/migrations/20200512104202_add_disc_subtitle.go +++ /dev/null @@ -1,28 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20200512104202, Down20200512104202) -} - -func Up20200512104202(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -alter table media_file - add disc_subtitle varchar(255); - `) - if err != nil { - return err - } - notice(tx, "A full rescan will be performed to import disc subtitles") - return forceFullRescan(tx) -} - -func Down20200512104202(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20200516140647_add_playlist_tracks_table.go b/db/migrations/20200516140647_add_playlist_tracks_table.go deleted file mode 100644 index fcaae9d8e..000000000 --- a/db/migrations/20200516140647_add_playlist_tracks_table.go +++ /dev/null @@ -1,101 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - "strings" - - "github.com/navidrome/navidrome/log" - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20200516140647, Down20200516140647) -} - -func Up20200516140647(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -create table if not exists playlist_tracks -( - id integer default 0 not null, - playlist_id varchar(255) not null, - media_file_id varchar(255) not null -); - -create unique index if not exists playlist_tracks_pos - on playlist_tracks (playlist_id, id); -`) - if err != nil { - return err - } - rows, err := tx.Query("select id, tracks from playlist") - if err != nil { - return err - } - defer rows.Close() - var id, tracks string - for rows.Next() { - err := rows.Scan(&id, &tracks) - if err != nil { - return err - } - err = Up20200516140647UpdatePlaylistTracks(tx, id, tracks) - if err != nil { - return err - } - } - err = rows.Err() - if err != nil { - return err - } - - _, err = tx.Exec(` -create table playlist_dg_tmp -( - id varchar(255) not null - primary key, - name varchar(255) default '' not null, - comment varchar(255) default '' not null, - duration real default 0 not null, - song_count integer default 0 not null, - owner varchar(255) default '' not null, - public bool default FALSE not null, - created_at datetime, - updated_at datetime -); - -insert into playlist_dg_tmp(id, name, comment, duration, owner, public, created_at, updated_at) - select id, name, comment, duration, owner, public, created_at, updated_at from playlist; - -drop table playlist; - -alter table playlist_dg_tmp rename to playlist; - -create index playlist_name - on playlist (name); - -update playlist set song_count = (select count(*) from playlist_tracks where playlist_id = playlist.id) -where id <> '' - -`) - return err -} - -func Up20200516140647UpdatePlaylistTracks(tx *sql.Tx, id string, tracks string) error { - trackList := strings.Split(tracks, ",") - stmt, err := tx.Prepare("insert into playlist_tracks (playlist_id, media_file_id, id) values (?, ?, ?)") - if err != nil { - return err - } - for i, trackId := range trackList { - _, err := stmt.Exec(id, trackId, i+1) - if err != nil { - log.Error("Error adding track to playlist", "playlistId", id, "trackId", trackId, err) - } - } - return nil -} - -func Down20200516140647(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20200608153717_referential_integrity.go b/db/migrations/20200608153717_referential_integrity.go deleted file mode 100644 index 2959237fa..000000000 --- a/db/migrations/20200608153717_referential_integrity.go +++ /dev/null @@ -1,138 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20200608153717, Down20200608153717) -} - -func Up20200608153717(_ context.Context, tx *sql.Tx) error { - // First delete dangling players - _, err := tx.Exec(` -delete from player where user_name not in (select user_name from user)`) - if err != nil { - return err - } - - // Also delete dangling players - _, err = tx.Exec(` -delete from playlist where owner not in (select user_name from user)`) - if err != nil { - return err - } - - // Also delete dangling playlist tracks - _, err = tx.Exec(` -delete from playlist_tracks where playlist_id not in (select id from playlist)`) - if err != nil { - return err - } - - // Add foreign key to player table - err = updatePlayer_20200608153717(tx) - if err != nil { - return err - } - - // Add foreign key to playlist table - err = updatePlaylist_20200608153717(tx) - if err != nil { - return err - } - - // Add foreign keys to playlist_tracks table - return updatePlaylistTracks_20200608153717(tx) -} - -func updatePlayer_20200608153717(tx *sql.Tx) error { - _, err := tx.Exec(` -create table player_dg_tmp -( - id varchar(255) not null - primary key, - name varchar not null - unique, - type varchar, - user_name varchar not null - references user (user_name) - on update cascade on delete cascade, - client varchar not null, - ip_address varchar, - last_seen timestamp, - max_bit_rate int default 0, - transcoding_id varchar null -); - -insert into player_dg_tmp(id, name, type, user_name, client, ip_address, last_seen, max_bit_rate, transcoding_id) select id, name, type, user_name, client, ip_address, last_seen, max_bit_rate, transcoding_id from player; - -drop table player; - -alter table player_dg_tmp rename to player; -`) - return err -} - -func updatePlaylist_20200608153717(tx *sql.Tx) error { - _, err := tx.Exec(` -create table playlist_dg_tmp -( - id varchar(255) not null - primary key, - name varchar(255) default '' not null, - comment varchar(255) default '' not null, - duration real default 0 not null, - song_count integer default 0 not null, - owner varchar(255) default '' not null - constraint playlist_user_user_name_fk - references user (user_name) - on update cascade on delete cascade, - public bool default FALSE not null, - created_at datetime, - updated_at datetime -); - -insert into playlist_dg_tmp(id, name, comment, duration, song_count, owner, public, created_at, updated_at) select id, name, comment, duration, song_count, owner, public, created_at, updated_at from playlist; - -drop table playlist; - -alter table playlist_dg_tmp rename to playlist; - -create index playlist_name - on playlist (name); -`) - return err -} - -func updatePlaylistTracks_20200608153717(tx *sql.Tx) error { - _, err := tx.Exec(` -create table playlist_tracks_dg_tmp -( - id integer default 0 not null, - playlist_id varchar(255) not null - constraint playlist_tracks_playlist_id_fk - references playlist - on update cascade on delete cascade, - media_file_id varchar(255) not null -); - -insert into playlist_tracks_dg_tmp(id, playlist_id, media_file_id) select id, playlist_id, media_file_id from playlist_tracks; - -drop table playlist_tracks; - -alter table playlist_tracks_dg_tmp rename to playlist_tracks; - -create unique index playlist_tracks_pos - on playlist_tracks (playlist_id, id); - -`) - return err -} - -func Down20200608153717(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20200706231659_add_default_transcodings.go b/db/migrations/20200706231659_add_default_transcodings.go deleted file mode 100644 index a498d32b0..000000000 --- a/db/migrations/20200706231659_add_default_transcodings.go +++ /dev/null @@ -1,43 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/navidrome/navidrome/consts" - "github.com/navidrome/navidrome/model/id" - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddDefaultTranscodings, downAddDefaultTranscodings) -} - -func upAddDefaultTranscodings(_ context.Context, tx *sql.Tx) error { - row := tx.QueryRow("SELECT COUNT(*) FROM transcoding") - var count int - err := row.Scan(&count) - if err != nil { - return err - } - if count > 0 { - return nil - } - - stmt, err := tx.Prepare("insert into transcoding (id, name, target_format, default_bit_rate, command) values (?, ?, ?, ?, ?)") - if err != nil { - return err - } - - for _, t := range consts.DefaultTranscodings { - _, err := stmt.Exec(id.NewRandom(), t.Name, t.TargetFormat, t.DefaultBitRate, t.Command) - if err != nil { - return err - } - } - return nil -} - -func downAddDefaultTranscodings(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20200710211442_add_playlist_path.go b/db/migrations/20200710211442_add_playlist_path.go deleted file mode 100644 index 8abfed6cf..000000000 --- a/db/migrations/20200710211442_add_playlist_path.go +++ /dev/null @@ -1,28 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddPlaylistPath, downAddPlaylistPath) -} - -func upAddPlaylistPath(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -alter table playlist - add path string default '' not null; - -alter table playlist - add sync bool default false not null; -`) - - return err -} - -func downAddPlaylistPath(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20200731095603_create_play_queues_table.go b/db/migrations/20200731095603_create_play_queues_table.go deleted file mode 100644 index d63a1ecb9..000000000 --- a/db/migrations/20200731095603_create_play_queues_table.go +++ /dev/null @@ -1,37 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upCreatePlayQueuesTable, downCreatePlayQueuesTable) -} - -func upCreatePlayQueuesTable(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -create table playqueue -( - id varchar(255) not null primary key, - user_id varchar(255) not null - references user (id) - on update cascade on delete cascade, - comment varchar(255), - current varchar(255) not null, - position integer, - changed_by varchar(255), - items varchar(255), - created_at datetime, - updated_at datetime -); -`) - - return err -} - -func downCreatePlayQueuesTable(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20200801101355_create_bookmark_table.go b/db/migrations/20200801101355_create_bookmark_table.go deleted file mode 100644 index fe68fafd7..000000000 --- a/db/migrations/20200801101355_create_bookmark_table.go +++ /dev/null @@ -1,54 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upCreateBookmarkTable, downCreateBookmarkTable) -} - -func upCreateBookmarkTable(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -create table bookmark -( - user_id varchar(255) not null - references user - on update cascade on delete cascade, - item_id varchar(255) not null, - item_type varchar(255) not null, - comment varchar(255), - position integer, - changed_by varchar(255), - created_at datetime, - updated_at datetime, - constraint bookmark_pk - unique (user_id, item_id, item_type) -); - -create table playqueue_dg_tmp -( - id varchar(255) not null, - user_id varchar(255) not null - references user - on update cascade on delete cascade, - current varchar(255), - position real, - changed_by varchar(255), - items varchar(255), - created_at datetime, - updated_at datetime -); -drop table playqueue; -alter table playqueue_dg_tmp rename to playqueue; -`) - - return err -} - -func downCreateBookmarkTable(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20200819111809_drop_email_unique_constraint.go b/db/migrations/20200819111809_drop_email_unique_constraint.go deleted file mode 100644 index b2dd4285c..000000000 --- a/db/migrations/20200819111809_drop_email_unique_constraint.go +++ /dev/null @@ -1,43 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upDropEmailUniqueConstraint, downDropEmailUniqueConstraint) -} - -func upDropEmailUniqueConstraint(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -create table user_dg_tmp -( - id varchar(255) not null - primary key, - user_name varchar(255) default '' not null - unique, - name varchar(255) default '' not null, - email varchar(255) default '' not null, - password varchar(255) default '' not null, - is_admin bool default FALSE not null, - last_login_at datetime, - last_access_at datetime, - created_at datetime not null, - updated_at datetime not null -); - -insert into user_dg_tmp(id, user_name, name, email, password, is_admin, last_login_at, last_access_at, created_at, updated_at) select id, user_name, name, email, password, is_admin, last_login_at, last_access_at, created_at, updated_at from user; - -drop table user; - -alter table user_dg_tmp rename to user; -`) - return err -} - -func downDropEmailUniqueConstraint(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20201003111749_add_starred_at_index.go b/db/migrations/20201003111749_add_starred_at_index.go deleted file mode 100644 index 7ee7a283f..000000000 --- a/db/migrations/20201003111749_add_starred_at_index.go +++ /dev/null @@ -1,24 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20201003111749, Down20201003111749) -} - -func Up20201003111749(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -create index if not exists annotation_starred_at - on annotation (starred_at); - `) - return err -} - -func Down20201003111749(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20201010162350_add_album_size.go b/db/migrations/20201010162350_add_album_size.go deleted file mode 100644 index f1182ab6c..000000000 --- a/db/migrations/20201010162350_add_album_size.go +++ /dev/null @@ -1,34 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20201010162350, Down20201010162350) -} - -func Up20201010162350(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -alter table album - add size integer default 0 not null; -create index if not exists album_size - on album(size); - -update album set size = ifnull(( -select sum(f.size) -from media_file f -where f.album_id = album.id -), 0) -where id not null;`) - - return err -} - -func Down20201010162350(_ context.Context, tx *sql.Tx) error { - // This code is executed when the migration is rolled back. - return nil -} diff --git a/db/migrations/20201012210022_add_artist_playlist_size.go b/db/migrations/20201012210022_add_artist_playlist_size.go deleted file mode 100644 index 4eb67f14e..000000000 --- a/db/migrations/20201012210022_add_artist_playlist_size.go +++ /dev/null @@ -1,45 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20201012210022, Down20201012210022) -} - -func Up20201012210022(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -alter table artist - add size integer default 0 not null; -create index if not exists artist_size - on artist(size); - -update artist set size = ifnull(( - select sum(f.size) - from album f - where f.album_artist_id = artist.id -), 0) -where id not null; - -alter table playlist - add size integer default 0 not null; -create index if not exists playlist_size - on playlist(size); - -update playlist set size = ifnull(( - select sum(size) - from media_file f - left join playlist_tracks pt on f.id = pt.media_file_id - where pt.playlist_id = playlist.id -), 0);`) - - return err -} - -func Down20201012210022(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20201021085410_add_mbids.go b/db/migrations/20201021085410_add_mbids.go deleted file mode 100644 index 624bb1a67..000000000 --- a/db/migrations/20201021085410_add_mbids.go +++ /dev/null @@ -1,59 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20201021085410, Down20201021085410) -} - -func Up20201021085410(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -alter table media_file - add mbz_track_id varchar(255); -alter table media_file - add mbz_album_id varchar(255); -alter table media_file - add mbz_artist_id varchar(255); -alter table media_file - add mbz_album_artist_id varchar(255); -alter table media_file - add mbz_album_type varchar(255); -alter table media_file - add mbz_album_comment varchar(255); -alter table media_file - add catalog_num varchar(255); - -alter table album - add mbz_album_id varchar(255); -alter table album - add mbz_album_artist_id varchar(255); -alter table album - add mbz_album_type varchar(255); -alter table album - add mbz_album_comment varchar(255); -alter table album - add catalog_num varchar(255); - -create index if not exists album_mbz_album_type - on album (mbz_album_type); - -alter table artist - add mbz_artist_id varchar(255); - -`) - if err != nil { - return err - } - notice(tx, "A full rescan needs to be performed to import more tags") - return forceFullRescan(tx) -} - -func Down20201021085410(_ context.Context, tx *sql.Tx) error { - // This code is executed when the migration is rolled back. - return nil -} diff --git a/db/migrations/20201021093209_add_media_file_indexes.go b/db/migrations/20201021093209_add_media_file_indexes.go deleted file mode 100644 index f3a800949..000000000 --- a/db/migrations/20201021093209_add_media_file_indexes.go +++ /dev/null @@ -1,28 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20201021093209, Down20201021093209) -} - -func Up20201021093209(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -create index if not exists media_file_artist - on media_file (artist); -create index if not exists media_file_album_artist - on media_file (album_artist); -create index if not exists media_file_mbz_track_id - on media_file (mbz_track_id); -`) - return err -} - -func Down20201021093209(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20201021135455_add_media_file_artist_index.go b/db/migrations/20201021135455_add_media_file_artist_index.go deleted file mode 100644 index ca04d8a20..000000000 --- a/db/migrations/20201021135455_add_media_file_artist_index.go +++ /dev/null @@ -1,24 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20201021135455, Down20201021135455) -} - -func Up20201021135455(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -create index if not exists media_file_artist_id - on media_file (artist_id); -`) - return err -} - -func Down20201021135455(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20201030162009_add_artist_info_table.go b/db/migrations/20201030162009_add_artist_info_table.go deleted file mode 100644 index f2917ae49..000000000 --- a/db/migrations/20201030162009_add_artist_info_table.go +++ /dev/null @@ -1,36 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddArtistImageUrl, downAddArtistImageUrl) -} - -func upAddArtistImageUrl(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -alter table artist - add biography varchar(255) default '' not null; -alter table artist - add small_image_url varchar(255) default '' not null; -alter table artist - add medium_image_url varchar(255) default '' not null; -alter table artist - add large_image_url varchar(255) default '' not null; -alter table artist - add similar_artists varchar(255) default '' not null; -alter table artist - add external_url varchar(255) default '' not null; -alter table artist - add external_info_updated_at datetime; -`) - return err -} - -func downAddArtistImageUrl(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20201110205344_add_comments_and_lyrics.go b/db/migrations/20201110205344_add_comments_and_lyrics.go deleted file mode 100644 index 5bb17b8d0..000000000 --- a/db/migrations/20201110205344_add_comments_and_lyrics.go +++ /dev/null @@ -1,33 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20201110205344, Down20201110205344) -} - -func Up20201110205344(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -alter table media_file - add comment varchar; -alter table media_file - add lyrics varchar; - -alter table album - add comment varchar; -`) - if err != nil { - return err - } - notice(tx, "A full rescan will be performed to import comments and lyrics") - return forceFullRescan(tx) -} - -func Down20201110205344(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20201128100726_add_real-path_option.go b/db/migrations/20201128100726_add_real-path_option.go deleted file mode 100644 index db102dfa9..000000000 --- a/db/migrations/20201128100726_add_real-path_option.go +++ /dev/null @@ -1,24 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20201128100726, Down20201128100726) -} - -func Up20201128100726(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -alter table player - add report_real_path bool default FALSE not null; -`) - return err -} - -func Down20201128100726(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20201213124814_add_all_artist_ids_to_album.go b/db/migrations/20201213124814_add_all_artist_ids_to_album.go deleted file mode 100644 index 170497f5c..000000000 --- a/db/migrations/20201213124814_add_all_artist_ids_to_album.go +++ /dev/null @@ -1,64 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/navidrome/navidrome/log" - "github.com/navidrome/navidrome/utils/str" - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20201213124814, Down20201213124814) -} - -func Up20201213124814(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -alter table album - add all_artist_ids varchar; - -create index if not exists album_all_artist_ids - on album (all_artist_ids); -`) - if err != nil { - return err - } - - return updateAlbums20201213124814(tx) -} - -func updateAlbums20201213124814(tx *sql.Tx) error { - rows, err := tx.Query(` -select a.id, a.name, a.artist_id, a.album_artist_id, group_concat(mf.artist_id, ' ') - from album a left join media_file mf on a.id = mf.album_id group by a.id - `) - if err != nil { - return err - } - defer rows.Close() - - stmt, err := tx.Prepare("update album set all_artist_ids = ? where id = ?") - if err != nil { - return err - } - - var id, name, artistId, albumArtistId string - var songArtistIds sql.NullString - for rows.Next() { - err = rows.Scan(&id, &name, &artistId, &albumArtistId, &songArtistIds) - if err != nil { - return err - } - all := str.SanitizeStrings(artistId, albumArtistId, songArtistIds.String) - _, err = stmt.Exec(all, id) - if err != nil { - log.Error("Error setting album's artist_ids", "album", name, "albumId", id, err) - } - } - return rows.Err() -} - -func Down20201213124814(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20210322132848_add_timestamp_indexes.go b/db/migrations/20210322132848_add_timestamp_indexes.go deleted file mode 100644 index 3341dd3d2..000000000 --- a/db/migrations/20210322132848_add_timestamp_indexes.go +++ /dev/null @@ -1,34 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddTimestampIndexesGo, downAddTimestampIndexesGo) -} - -func upAddTimestampIndexesGo(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -create index if not exists album_updated_at - on album (updated_at); -create index if not exists album_created_at - on album (created_at); -create index if not exists playlist_updated_at - on playlist (updated_at); -create index if not exists playlist_created_at - on playlist (created_at); -create index if not exists media_file_created_at - on media_file (created_at); -create index if not exists media_file_updated_at - on media_file (updated_at); -`) - return err -} - -func downAddTimestampIndexesGo(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20210418232815_fix_album_comments.go b/db/migrations/20210418232815_fix_album_comments.go deleted file mode 100644 index 59067640a..000000000 --- a/db/migrations/20210418232815_fix_album_comments.go +++ /dev/null @@ -1,68 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - "strings" - - "github.com/navidrome/navidrome/consts" - "github.com/navidrome/navidrome/log" - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upFixAlbumComments, downFixAlbumComments) -} - -func upFixAlbumComments(_ context.Context, tx *sql.Tx) error { - //nolint:gosec - rows, err := tx.Query(` - SELECT album.id, group_concat(media_file.comment, '` + consts.Zwsp + `') FROM album, media_file WHERE media_file.album_id = album.id GROUP BY album.id; - `) - if err != nil { - return err - } - defer rows.Close() - - stmt, err := tx.Prepare("UPDATE album SET comment = ? WHERE id = ?") - if err != nil { - return err - } - var id string - var comments sql.NullString - - for rows.Next() { - err = rows.Scan(&id, &comments) - if err != nil { - return err - } - if !comments.Valid { - continue - } - comment := getComment(comments.String, consts.Zwsp) - _, err = stmt.Exec(comment, id) - - if err != nil { - log.Error("Error setting album's comments", "albumId", id, err) - } - } - return rows.Err() -} - -func downFixAlbumComments(_ context.Context, tx *sql.Tx) error { - return nil -} - -func getComment(comments string, separator string) string { - cs := strings.Split(comments, separator) - if len(cs) == 0 { - return "" - } - first := cs[0] - for _, c := range cs[1:] { - if first != c { - return "" - } - } - return first -} diff --git a/db/migrations/20210430212322_add_bpm_metadata.go b/db/migrations/20210430212322_add_bpm_metadata.go deleted file mode 100644 index 721c9e179..000000000 --- a/db/migrations/20210430212322_add_bpm_metadata.go +++ /dev/null @@ -1,31 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddBpmMetadata, downAddBpmMetadata) -} - -func upAddBpmMetadata(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -alter table media_file - add bpm integer; - -create index if not exists media_file_bpm - on media_file (bpm); -`) - if err != nil { - return err - } - notice(tx, "A full rescan needs to be performed to import more tags") - return forceFullRescan(tx) -} - -func downAddBpmMetadata(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20210530121921_create_shares_table.go b/db/migrations/20210530121921_create_shares_table.go deleted file mode 100644 index e9208bd69..000000000 --- a/db/migrations/20210530121921_create_shares_table.go +++ /dev/null @@ -1,35 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upCreateSharesTable, downCreateSharesTable) -} - -func upCreateSharesTable(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -create table share -( - id varchar(255) not null primary key, - name varchar(255) not null unique, - description varchar(255), - expires datetime, - created datetime, - last_visited datetime, - resource_ids varchar not null, - resource_type varchar(255) not null, - visit_count integer default 0 -); -`) - - return err -} - -func downCreateSharesTable(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20210601231734_update_share_fieldnames.go b/db/migrations/20210601231734_update_share_fieldnames.go deleted file mode 100644 index 965c0186e..000000000 --- a/db/migrations/20210601231734_update_share_fieldnames.go +++ /dev/null @@ -1,26 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upUpdateShareFieldNames, downUpdateShareFieldNames) -} - -func upUpdateShareFieldNames(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -alter table share rename column expires to expires_at; -alter table share rename column created to created_at; -alter table share rename column last_visited to last_visited_at; -`) - - return err -} - -func downUpdateShareFieldNames(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20210616150710_encrypt_all_passwords.go b/db/migrations/20210616150710_encrypt_all_passwords.go deleted file mode 100644 index f67e3fb0a..000000000 --- a/db/migrations/20210616150710_encrypt_all_passwords.go +++ /dev/null @@ -1,56 +0,0 @@ -package migrations - -import ( - "context" - "crypto/sha256" - "database/sql" - - "github.com/navidrome/navidrome/consts" - "github.com/navidrome/navidrome/log" - "github.com/navidrome/navidrome/utils" - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upEncodeAllPasswords, downEncodeAllPasswords) -} - -func upEncodeAllPasswords(ctx context.Context, tx *sql.Tx) error { - rows, err := tx.Query(`SELECT id, user_name, password from user;`) - if err != nil { - return err - } - defer rows.Close() - - stmt, err := tx.Prepare("UPDATE user SET password = ? WHERE id = ?") - if err != nil { - return err - } - var id string - var username, password string - - data := sha256.Sum256([]byte(consts.DefaultEncryptionKey)) - encKey := data[0:] - - for rows.Next() { - err = rows.Scan(&id, &username, &password) - if err != nil { - return err - } - - password, err = utils.Encrypt(ctx, encKey, password) - if err != nil { - log.Error("Error encrypting user's password", "id", id, "username", username, err) - } - - _, err = stmt.Exec(password, id) - if err != nil { - log.Error("Error saving user's encrypted password", "id", id, "username", username, err) - } - } - return rows.Err() -} - -func downEncodeAllPasswords(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20210619231716_drop_player_name_unique_constraint.go b/db/migrations/20210619231716_drop_player_name_unique_constraint.go deleted file mode 100644 index 200332156..000000000 --- a/db/migrations/20210619231716_drop_player_name_unique_constraint.go +++ /dev/null @@ -1,48 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upDropPlayerNameUniqueConstraint, downDropPlayerNameUniqueConstraint) -} - -func upDropPlayerNameUniqueConstraint(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -create table player_dg_tmp -( - id varchar(255) not null - primary key, - name varchar not null, - user_agent varchar, - user_name varchar not null - references user (user_name) - on update cascade on delete cascade, - client varchar not null, - ip_address varchar, - last_seen timestamp, - max_bit_rate int default 0, - transcoding_id varchar, - report_real_path bool default FALSE not null -); - -insert into player_dg_tmp(id, name, user_agent, user_name, client, ip_address, last_seen, max_bit_rate, transcoding_id, report_real_path) select id, name, type, user_name, client, ip_address, last_seen, max_bit_rate, transcoding_id, report_real_path from player; - -drop table player; - -alter table player_dg_tmp rename to player; -create index if not exists player_match - on player (client, user_agent, user_name); -create index if not exists player_name - on player (name); -`) - return err -} - -func downDropPlayerNameUniqueConstraint(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20210623155401_add_user_prefs_player_scrobbler_enabled.go b/db/migrations/20210623155401_add_user_prefs_player_scrobbler_enabled.go deleted file mode 100644 index 5257dfab3..000000000 --- a/db/migrations/20210623155401_add_user_prefs_player_scrobbler_enabled.go +++ /dev/null @@ -1,45 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddUserPrefsPlayerScrobblerEnabled, downAddUserPrefsPlayerScrobblerEnabled) -} - -func upAddUserPrefsPlayerScrobblerEnabled(_ context.Context, tx *sql.Tx) error { - err := upAddUserPrefs(tx) - if err != nil { - return err - } - return upPlayerScrobblerEnabled(tx) -} - -func upAddUserPrefs(tx *sql.Tx) error { - _, err := tx.Exec(` -create table user_props -( - user_id varchar not null, - key varchar not null, - value varchar, - constraint user_props_pk - primary key (user_id, key) -); -`) - return err -} - -func upPlayerScrobblerEnabled(tx *sql.Tx) error { - _, err := tx.Exec(` -alter table player add scrobble_enabled bool default true; -`) - return err -} - -func downAddUserPrefsPlayerScrobblerEnabled(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20210625223901_add_referential_integrity_to_user_props.go b/db/migrations/20210625223901_add_referential_integrity_to_user_props.go deleted file mode 100644 index 033392d93..000000000 --- a/db/migrations/20210625223901_add_referential_integrity_to_user_props.go +++ /dev/null @@ -1,39 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddReferentialIntegrityToUserProps, downAddReferentialIntegrityToUserProps) -} - -func upAddReferentialIntegrityToUserProps(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -create table user_props_dg_tmp -( - user_id varchar not null - constraint user_props_user_id_fk - references user - on update cascade on delete cascade, - key varchar not null, - value varchar, - constraint user_props_pk - primary key (user_id, key) -); - -insert into user_props_dg_tmp(user_id, key, value) select user_id, key, value from user_props; - -drop table user_props; - -alter table user_props_dg_tmp rename to user_props; -`) - return err -} - -func downAddReferentialIntegrityToUserProps(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20210626213026_add_scrobble_buffer.go b/db/migrations/20210626213026_add_scrobble_buffer.go deleted file mode 100644 index 1c4d0de2a..000000000 --- a/db/migrations/20210626213026_add_scrobble_buffer.go +++ /dev/null @@ -1,39 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddScrobbleBuffer, downAddScrobbleBuffer) -} - -func upAddScrobbleBuffer(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -create table if not exists scrobble_buffer -( - 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, - constraint scrobble_buffer_pk - unique (user_id, service, media_file_id, play_time, user_id) -); -`) - - return err -} - -func downAddScrobbleBuffer(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20210715151153_add_genre_tables.go b/db/migrations/20210715151153_add_genre_tables.go deleted file mode 100644 index ab2c54239..000000000 --- a/db/migrations/20210715151153_add_genre_tables.go +++ /dev/null @@ -1,69 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddGenreTables, downAddGenreTables) -} - -func upAddGenreTables(_ context.Context, tx *sql.Tx) error { - notice(tx, "A full rescan will be performed to import multiple genres!") - _, err := tx.Exec(` -create table if not exists genre -( - id varchar not null primary key, - name varchar not null, - constraint genre_name_ux - unique (name) -); - -create table if not exists album_genres -( - album_id varchar default null not null - references album - on delete cascade, - genre_id varchar default null not null - references genre - on delete cascade, - constraint album_genre_ux - unique (album_id, genre_id) -); - -create table if not exists media_file_genres -( - media_file_id varchar default null not null - references media_file - on delete cascade, - genre_id varchar default null not null - references genre - on delete cascade, - constraint media_file_genre_ux - unique (media_file_id, genre_id) -); - -create table if not exists artist_genres -( - artist_id varchar default null not null - references artist - on delete cascade, - genre_id varchar default null not null - references genre - on delete cascade, - constraint artist_genre_ux - unique (artist_id, genre_id) -); -`) - if err != nil { - return err - } - return forceFullRescan(tx) -} - -func downAddGenreTables(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20210821212604_add_mediafile_channels.go b/db/migrations/20210821212604_add_mediafile_channels.go deleted file mode 100644 index 9a0988b17..000000000 --- a/db/migrations/20210821212604_add_mediafile_channels.go +++ /dev/null @@ -1,31 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddMediafileChannels, downAddMediafileChannels) -} - -func upAddMediafileChannels(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -alter table media_file - add channels integer; - -create index if not exists media_file_channels - on media_file (channels); -`) - if err != nil { - return err - } - notice(tx, "A full rescan needs to be performed to import more tags") - return forceFullRescan(tx) -} - -func downAddMediafileChannels(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20211008205505_add_smart_playlist.go b/db/migrations/20211008205505_add_smart_playlist.go deleted file mode 100644 index c8ed67c47..000000000 --- a/db/migrations/20211008205505_add_smart_playlist.go +++ /dev/null @@ -1,38 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddSmartPlaylist, downAddSmartPlaylist) -} - -func upAddSmartPlaylist(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -alter table playlist - add column rules varchar null; -alter table playlist - add column evaluated_at datetime null; -create index if not exists playlist_evaluated_at - on playlist(evaluated_at); - -create table playlist_fields ( - field varchar(255) not null, - playlist_id varchar(255) not null - constraint playlist_fields_playlist_id_fk - references playlist - on update cascade on delete cascade -); -create unique index playlist_fields_idx - on playlist_fields (field, playlist_id); -`) - return err -} - -func downAddSmartPlaylist(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20211023184825_add_order_title_to_media_file.go b/db/migrations/20211023184825_add_order_title_to_media_file.go deleted file mode 100644 index ee6fc67d1..000000000 --- a/db/migrations/20211023184825_add_order_title_to_media_file.go +++ /dev/null @@ -1,62 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - "strings" - - "github.com/deluan/sanitize" - "github.com/navidrome/navidrome/log" - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddOrderTitleToMediaFile, downAddOrderTitleToMediaFile) -} - -func upAddOrderTitleToMediaFile(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -alter table main.media_file - add order_title varchar null collate NOCASE; -create index if not exists media_file_order_title - on media_file (order_title); -`) - if err != nil { - return err - } - - return upAddOrderTitleToMediaFile_populateOrderTitle(tx) -} - -//goland:noinspection GoSnakeCaseUsage -func upAddOrderTitleToMediaFile_populateOrderTitle(tx *sql.Tx) error { - rows, err := tx.Query(`select id, title from media_file`) - if err != nil { - return err - } - defer rows.Close() - - stmt, err := tx.Prepare("update media_file set order_title = ? where id = ?") - if err != nil { - return err - } - - var id, title string - for rows.Next() { - err = rows.Scan(&id, &title) - if err != nil { - return err - } - - orderTitle := strings.TrimSpace(sanitize.Accents(title)) - _, err = stmt.Exec(orderTitle, id) - if err != nil { - log.Error("Error setting media_file's order_title", "title", title, "id", id, err) - } - } - return rows.Err() -} - -func downAddOrderTitleToMediaFile(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20211026191915_unescape_lyrics_and_comments.go b/db/migrations/20211026191915_unescape_lyrics_and_comments.go deleted file mode 100644 index d4ba5e194..000000000 --- a/db/migrations/20211026191915_unescape_lyrics_and_comments.go +++ /dev/null @@ -1,48 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/navidrome/navidrome/log" - "github.com/navidrome/navidrome/utils/str" - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upUnescapeLyricsAndComments, downUnescapeLyricsAndComments) -} - -func upUnescapeLyricsAndComments(_ context.Context, tx *sql.Tx) error { - rows, err := tx.Query(`select id, comment, lyrics, title from media_file`) - if err != nil { - return err - } - defer rows.Close() - - stmt, err := tx.Prepare("update media_file set comment = ?, lyrics = ? where id = ?") - if err != nil { - return err - } - - var id, title string - var comment, lyrics sql.NullString - for rows.Next() { - err = rows.Scan(&id, &comment, &lyrics, &title) - if err != nil { - return err - } - - newComment := str.SanitizeText(comment.String) - newLyrics := str.SanitizeText(lyrics.String) - _, err = stmt.Exec(newComment, newLyrics, id) - if err != nil { - log.Error("Error unescaping media_file's lyrics and comments", "title", title, "id", id, err) - } - } - return rows.Err() -} - -func downUnescapeLyricsAndComments(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20211029213200_add_userid_to_playlist.go b/db/migrations/20211029213200_add_userid_to_playlist.go deleted file mode 100644 index e262fc205..000000000 --- a/db/migrations/20211029213200_add_userid_to_playlist.go +++ /dev/null @@ -1,61 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddUseridToPlaylist, downAddUseridToPlaylist) -} - -func upAddUseridToPlaylist(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -create table playlist_dg_tmp -( - id varchar(255) not null - primary key, - name varchar(255) default '' not null, - comment varchar(255) default '' not null, - duration real default 0 not null, - song_count integer default 0 not null, - public bool default FALSE not null, - created_at datetime, - updated_at datetime, - path string default '' not null, - sync bool default false not null, - size integer default 0 not null, - rules varchar, - evaluated_at datetime, - owner_id varchar(255) not null - constraint playlist_user_user_id_fk - references user - on update cascade on delete cascade -); - -insert into playlist_dg_tmp(id, name, comment, duration, song_count, public, created_at, updated_at, path, sync, size, rules, evaluated_at, owner_id) -select id, name, comment, duration, song_count, public, created_at, updated_at, path, sync, size, rules, evaluated_at, - (select id from user where user_name = owner) as user_id from playlist; - -drop table playlist; -alter table playlist_dg_tmp rename to playlist; -create index playlist_created_at - on playlist (created_at); -create index playlist_evaluated_at - on playlist (evaluated_at); -create index playlist_name - on playlist (name); -create index playlist_size - on playlist (size); -create index playlist_updated_at - on playlist (updated_at); - -`) - return err -} - -func downAddUseridToPlaylist(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20211102215414_add_alphabetical_by_artist_index.go b/db/migrations/20211102215414_add_alphabetical_by_artist_index.go deleted file mode 100644 index 4ab4305d0..000000000 --- a/db/migrations/20211102215414_add_alphabetical_by_artist_index.go +++ /dev/null @@ -1,24 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddAlphabeticalByArtistIndex, downAddAlphabeticalByArtistIndex) -} - -func upAddAlphabeticalByArtistIndex(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -create index album_alphabetical_by_artist - ON album(compilation, order_album_artist_name, order_album_name) -`) - return err -} - -func downAddAlphabeticalByArtistIndex(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20211105162746_remove_invalid_artist_ids.go b/db/migrations/20211105162746_remove_invalid_artist_ids.go deleted file mode 100644 index 5e078c820..000000000 --- a/db/migrations/20211105162746_remove_invalid_artist_ids.go +++ /dev/null @@ -1,23 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upRemoveInvalidArtistIds, downRemoveInvalidArtistIds) -} - -func upRemoveInvalidArtistIds(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -update media_file set artist_id = '' where not exists(select 1 from artist where id = artist_id) -`) - return err -} - -func downRemoveInvalidArtistIds(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20220724231849_add_musicbrainz_release_track_id.go b/db/migrations/20220724231849_add_musicbrainz_release_track_id.go deleted file mode 100644 index 481762117..000000000 --- a/db/migrations/20220724231849_add_musicbrainz_release_track_id.go +++ /dev/null @@ -1,29 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddMusicbrainzReleaseTrackId, downAddMusicbrainzReleaseTrackId) -} - -func upAddMusicbrainzReleaseTrackId(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -alter table media_file - add mbz_release_track_id varchar(255); -`) - if err != nil { - return err - } - notice(tx, "A full rescan needs to be performed to import more tags") - return forceFullRescan(tx) -} - -func downAddMusicbrainzReleaseTrackId(_ context.Context, tx *sql.Tx) error { - // This code is executed when the migration is rolled back. - return nil -} diff --git a/db/migrations/20221219112733_add_album_image_paths.go b/db/migrations/20221219112733_add_album_image_paths.go deleted file mode 100644 index ee9c77c8a..000000000 --- a/db/migrations/20221219112733_add_album_image_paths.go +++ /dev/null @@ -1,27 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddAlbumImagePaths, downAddAlbumImagePaths) -} - -func upAddAlbumImagePaths(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -alter table main.album add image_files varchar; -`) - if err != nil { - return err - } - notice(tx, "A full rescan needs to be performed to import all album images") - return forceFullRescan(tx) -} - -func downAddAlbumImagePaths(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20221219140528_remove_cover_art_id.go b/db/migrations/20221219140528_remove_cover_art_id.go deleted file mode 100644 index a1eaa89f9..000000000 --- a/db/migrations/20221219140528_remove_cover_art_id.go +++ /dev/null @@ -1,28 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upRemoveCoverArtId, downRemoveCoverArtId) -} - -func upRemoveCoverArtId(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -alter table album drop column cover_art_id; -alter table album rename column cover_art_path to embed_art_path -`) - if err != nil { - return err - } - notice(tx, "A full rescan needs to be performed to import all album images") - return forceFullRescan(tx) -} - -func downRemoveCoverArtId(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20230112111457_add_album_paths.go b/db/migrations/20230112111457_add_album_paths.go deleted file mode 100644 index 2dfb9a747..000000000 --- a/db/migrations/20230112111457_add_album_paths.go +++ /dev/null @@ -1,68 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - "path/filepath" - "slices" - "strings" - - "github.com/navidrome/navidrome/consts" - "github.com/navidrome/navidrome/log" - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddAlbumPaths, downAddAlbumPaths) -} - -func upAddAlbumPaths(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(`alter table album add paths varchar;`) - if err != nil { - return err - } - - //nolint:gosec - rows, err := tx.Query(` - select album_id, group_concat(path, '` + consts.Zwsp + `') from media_file group by album_id - `) - if err != nil { - return err - } - - stmt, err := tx.Prepare("update album set paths = ? where id = ?") - if err != nil { - return err - } - - var id, filePaths string - for rows.Next() { - err = rows.Scan(&id, &filePaths) - if err != nil { - return err - } - - paths := upAddAlbumPathsDirs(filePaths) - _, err = stmt.Exec(paths, id) - if err != nil { - log.Error("Error updating album's paths", "paths", paths, "id", id, err) - } - } - return rows.Err() -} - -func upAddAlbumPathsDirs(filePaths string) string { - allPaths := strings.Split(filePaths, consts.Zwsp) - var dirs []string - for _, p := range allPaths { - dir, _ := filepath.Split(p) - dirs = append(dirs, filepath.Clean(dir)) - } - slices.Sort(dirs) - dirs = slices.Compact(dirs) - return strings.Join(dirs, string(filepath.ListSeparator)) -} - -func downAddAlbumPaths(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20230114121537_touch_playlists.go b/db/migrations/20230114121537_touch_playlists.go deleted file mode 100644 index 0f10e275c..000000000 --- a/db/migrations/20230114121537_touch_playlists.go +++ /dev/null @@ -1,21 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upTouchPlaylists, downTouchPlaylists) -} - -func upTouchPlaylists(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(`update playlist set updated_at = datetime('now');`) - return err -} - -func downTouchPlaylists(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20230115103212_create_internet_radio.go b/db/migrations/20230115103212_create_internet_radio.go deleted file mode 100644 index 5c014dac2..000000000 --- a/db/migrations/20230115103212_create_internet_radio.go +++ /dev/null @@ -1,31 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upCreateInternetRadio, downCreateInternetRadio) -} - -func upCreateInternetRadio(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -create table if not exists radio -( - id varchar(255) not null primary key, - name varchar not null unique, - stream_url varchar not null, - home_page_url varchar default '' not null, - created_at datetime, - updated_at datetime -); -`) - return err -} - -func downCreateInternetRadio(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20230117155559_add_replaygain_metadata.go b/db/migrations/20230117155559_add_replaygain_metadata.go deleted file mode 100644 index d6be3b313..000000000 --- a/db/migrations/20230117155559_add_replaygain_metadata.go +++ /dev/null @@ -1,35 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddReplaygainMetadata, downAddReplaygainMetadata) -} - -func upAddReplaygainMetadata(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -alter table media_file add - rg_album_gain real; -alter table media_file add - rg_album_peak real; -alter table media_file add - rg_track_gain real; -alter table media_file add - rg_track_peak real; -`) - if err != nil { - return err - } - - notice(tx, "A full rescan needs to be performed to import more tags") - return forceFullRescan(tx) -} - -func downAddReplaygainMetadata(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20230117180400_add_album_info.go b/db/migrations/20230117180400_add_album_info.go deleted file mode 100644 index 5d6dd8230..000000000 --- a/db/migrations/20230117180400_add_album_info.go +++ /dev/null @@ -1,34 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddAlbumInfo, downAddAlbumInfo) -} - -func upAddAlbumInfo(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -alter table album - add description varchar(255) default '' not null; -alter table album - add small_image_url varchar(255) default '' not null; -alter table album - add medium_image_url varchar(255) default '' not null; -alter table album - add large_image_url varchar(255) default '' not null; -alter table album - add external_url varchar(255) default '' not null; -alter table album - add external_info_updated_at datetime; -`) - return err -} - -func downAddAlbumInfo(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20230119152657_recreate_share_table.go b/db/migrations/20230119152657_recreate_share_table.go deleted file mode 100644 index e1ae816c0..000000000 --- a/db/migrations/20230119152657_recreate_share_table.go +++ /dev/null @@ -1,42 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddMissingShareInfo, downAddMissingShareInfo) -} - -func upAddMissingShareInfo(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -drop table if exists share; -create table share -( - id varchar(255) not null - primary key, - description varchar(255), - expires_at datetime, - last_visited_at datetime, - resource_ids varchar not null, - resource_type varchar(255) not null, - contents varchar, - format varchar, - max_bit_rate integer, - visit_count integer default 0, - created_at datetime, - updated_at datetime, - user_id varchar(255) not null - constraint share_user_id_fk - references user -); -`) - return err -} - -func downAddMissingShareInfo(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20230202143713_change_path_list_separator.go b/db/migrations/20230202143713_change_path_list_separator.go deleted file mode 100644 index 78b030ae4..000000000 --- a/db/migrations/20230202143713_change_path_list_separator.go +++ /dev/null @@ -1,63 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - "path/filepath" - "slices" - "strings" - - "github.com/navidrome/navidrome/consts" - "github.com/navidrome/navidrome/log" - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upChangePathListSeparator, downChangePathListSeparator) -} - -func upChangePathListSeparator(_ context.Context, tx *sql.Tx) error { - //nolint:gosec - rows, err := tx.Query(` - select album_id, group_concat(path, '` + consts.Zwsp + `') from media_file group by album_id - `) - if err != nil { - return err - } - - stmt, err := tx.Prepare("update album set paths = ? where id = ?") - if err != nil { - return err - } - - var id, filePaths string - for rows.Next() { - err = rows.Scan(&id, &filePaths) - if err != nil { - return err - } - - paths := upChangePathListSeparatorDirs(filePaths) - _, err = stmt.Exec(paths, id) - if err != nil { - log.Error("Error updating album's paths", "paths", paths, "id", id, err) - } - } - return rows.Err() -} - -func upChangePathListSeparatorDirs(filePaths string) string { - allPaths := strings.Split(filePaths, consts.Zwsp) - var dirs []string - for _, p := range allPaths { - dir, _ := filepath.Split(p) - dirs = append(dirs, filepath.Clean(dir)) - } - slices.Sort(dirs) - dirs = slices.Compact(dirs) - return strings.Join(dirs, consts.Zwsp) -} - -func downChangePathListSeparator(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20230209181414_change_image_files_list_separator.go b/db/migrations/20230209181414_change_image_files_list_separator.go deleted file mode 100644 index 7f4d4cb0e..000000000 --- a/db/migrations/20230209181414_change_image_files_list_separator.go +++ /dev/null @@ -1,60 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - "path/filepath" - "slices" - "strings" - - "github.com/navidrome/navidrome/consts" - "github.com/navidrome/navidrome/log" - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upChangeImageFilesListSeparator, downChangeImageFilesListSeparator) -} - -func upChangeImageFilesListSeparator(_ context.Context, tx *sql.Tx) error { - rows, err := tx.Query(`select id, image_files from album`) - if err != nil { - return err - } - - stmt, err := tx.Prepare("update album set image_files = ? where id = ?") - if err != nil { - return err - } - - var id string - var imageFiles sql.NullString - for rows.Next() { - err = rows.Scan(&id, &imageFiles) - if err != nil { - return err - } - - files := upChangeImageFilesListSeparatorDirs(imageFiles.String) - if files == imageFiles.String { - continue - } - _, err = stmt.Exec(files, id) - if err != nil { - log.Error("Error updating album's image file list", "files", files, "id", id, err) - } - } - return rows.Err() -} - -func upChangeImageFilesListSeparatorDirs(filePaths string) string { - allPaths := filepath.SplitList(filePaths) - slices.Sort(allPaths) - allPaths = slices.Compact(allPaths) - return strings.Join(allPaths, consts.Zwsp) -} - -func downChangeImageFilesListSeparator(_ context.Context, tx *sql.Tx) error { - // This code is executed when the migration is rolled back. - return nil -} diff --git a/db/migrations/20230310222612_add_download_to_share.go b/db/migrations/20230310222612_add_download_to_share.go deleted file mode 100644 index ed2879ec3..000000000 --- a/db/migrations/20230310222612_add_download_to_share.go +++ /dev/null @@ -1,24 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddDownloadToShare, downAddDownloadToShare) -} - -func upAddDownloadToShare(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -alter table share - add downloadable bool not null default false; -`) - return err -} - -func downAddDownloadToShare(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20230404104309_empty_sql_migration.sql b/db/migrations/20230404104309_empty_sql_migration.sql deleted file mode 100644 index 7a2c92116..000000000 --- a/db/migrations/20230404104309_empty_sql_migration.sql +++ /dev/null @@ -1,13 +0,0 @@ --- This file has intentionally no SQL logic. It is here to avoid an error in the linter: --- db/db.go:23:4: invalid go:embed: build system did not supply embed configuration (typecheck) --- - --- +goose Up --- +goose StatementBegin -SELECT 'up SQL query'; --- +goose StatementEnd - --- +goose Down --- +goose StatementBegin -SELECT 'down SQL query'; --- +goose StatementEnd diff --git a/db/migrations/20230515184510_add_release_date.go b/db/migrations/20230515184510_add_release_date.go deleted file mode 100644 index 1141a1e74..000000000 --- a/db/migrations/20230515184510_add_release_date.go +++ /dev/null @@ -1,50 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddRelRecYear, downAddRelRecYear) -} - -func upAddRelRecYear(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -alter table media_file - add date varchar(255) default '' not null; -alter table media_file - add original_year int default 0 not null; -alter table media_file - add original_date varchar(255) default '' not null; -alter table media_file - add release_year int default 0 not null; -alter table media_file - add release_date varchar(255) default '' not null; - -alter table album - add date varchar(255) default '' not null; -alter table album - add min_original_year int default 0 not null; -alter table album - add max_original_year int default 0 not null; -alter table album - add original_date varchar(255) default '' not null; -alter table album - add release_date varchar(255) default '' not null; -alter table album - add releases integer default 0 not null; -`) - if err != nil { - return err - } - - notice(tx, "A full rescan needs to be performed to import more tags") - return forceFullRescan(tx) -} - -func downAddRelRecYear(_ context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20230616214944_rename_musicbrainz_recording_id.go b/db/migrations/20230616214944_rename_musicbrainz_recording_id.go deleted file mode 100644 index 170fc264c..000000000 --- a/db/migrations/20230616214944_rename_musicbrainz_recording_id.go +++ /dev/null @@ -1,28 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upRenameMusicbrainzRecordingId, downRenameMusicbrainzRecordingId) -} - -func upRenameMusicbrainzRecordingId(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -alter table media_file - rename column mbz_track_id to mbz_recording_id; -`) - return err -} - -func downRenameMusicbrainzRecordingId(_ context.Context, tx *sql.Tx) error { - _, err := tx.Exec(` -alter table media_file - rename column mbz_recording_id to mbz_track_id; -`) - return err -} diff --git a/db/migrations/20231208182311_add_discs_to_album.go b/db/migrations/20231208182311_add_discs_to_album.go deleted file mode 100644 index e4bf9a778..000000000 --- a/db/migrations/20231208182311_add_discs_to_album.go +++ /dev/null @@ -1,36 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddDiscToAlbum, downAddDiscToAlbum) -} - -func upAddDiscToAlbum(ctx context.Context, tx *sql.Tx) error { - _, err := tx.ExecContext(ctx, `alter table album add discs JSONB default '{}';`) - if err != nil { - return err - } - _, err = tx.ExecContext(ctx, ` -update album set discs = t.discs -from (select album_id, json_group_object(disc_number, disc_subtitle) as discs - from (select distinct album_id, disc_number, disc_subtitle - from media_file - where disc_number > 0 - order by album_id, disc_number) - group by album_id - having discs <> '{"1":""}') as t -where album.id = t.album_id; -`) - return err -} - -func downAddDiscToAlbum(ctx context.Context, tx *sql.Tx) error { - _, err := tx.ExecContext(ctx, `alter table album drop discs;`) - return err -} diff --git a/db/migrations/20231209211223_alter_lyric_column.go b/db/migrations/20231209211223_alter_lyric_column.go deleted file mode 100644 index ac73fc98f..000000000 --- a/db/migrations/20231209211223_alter_lyric_column.go +++ /dev/null @@ -1,82 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - "encoding/json" - - "github.com/navidrome/navidrome/model" - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAlterLyricColumn, downAlterLyricColumn) -} - -func upAlterLyricColumn(ctx context.Context, tx *sql.Tx) error { - _, err := tx.ExecContext(ctx, `alter table media_file rename COLUMN lyrics TO lyrics_old`) - if err != nil { - return err - } - - _, err = tx.ExecContext(ctx, `alter table media_file add lyrics JSONB default '[]';`) - if err != nil { - return err - } - - stmt, err := tx.Prepare(`update media_file SET lyrics = ? where id = ?`) - if err != nil { - return err - } - - rows, err := tx.Query(`select id, lyrics_old FROM media_file WHERE lyrics_old <> '';`) - if err != nil { - return err - } - - var id string - var lyrics sql.NullString - for rows.Next() { - err = rows.Scan(&id, &lyrics) - if err != nil { - return err - } - - if !lyrics.Valid { - continue - } - - lyrics, err := model.ToLyrics("xxx", lyrics.String) - if err != nil { - return err - } - - text, err := json.Marshal(model.LyricList{*lyrics}) - if err != nil { - return err - } - - _, err = stmt.Exec(string(text), id) - if err != nil { - return err - } - } - - err = rows.Err() - if err != nil { - return err - } - - _, err = tx.ExecContext(ctx, `ALTER TABLE media_file DROP COLUMN lyrics_old;`) - if err != nil { - return err - } - - notice(tx, "A full rescan should be performed to pick up additional lyrics (existing lyrics have been preserved)") - return nil -} - -func downAlterLyricColumn(ctx context.Context, tx *sql.Tx) error { - // This code is executed when the migration is rolled back. - return nil -} diff --git a/db/migrations/20240122223340_add_default_values_to_null_columns.go.go b/db/migrations/20240122223340_add_default_values_to_null_columns.go.go deleted file mode 100644 index a65b0aefd..000000000 --- a/db/migrations/20240122223340_add_default_values_to_null_columns.go.go +++ /dev/null @@ -1,563 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(Up20240122223340, Down20240122223340) -} - -func Up20240122223340(ctx context.Context, tx *sql.Tx) error { - _, err := tx.ExecContext(ctx, ` -drop index if exists album_alphabetical_by_artist; -drop index if exists album_order_album_name; -drop index if exists album_order_album_artist_name; -drop index if exists album_mbz_album_type; - -drop index if exists artist_order_artist_name; - -drop index if exists media_file_order_album_name; -drop index if exists media_file_order_artist_name; -drop index if exists media_file_order_title; -drop index if exists media_file_bpm; -drop index if exists media_file_channels; -drop index if exists media_file_mbz_track_id; - -alter table album - add image_files_new varchar not null default ''; -update album -set image_files_new = image_files -where image_files is not null; -alter table album - drop image_files; -alter table album - rename image_files_new to image_files; - -alter table album - add order_album_name_new varchar not null default ''; -update album -set order_album_name_new = order_album_name -where order_album_name is not null; -alter table album - drop order_album_name; -alter table album - rename order_album_name_new to order_album_name; - -alter table album - add order_album_artist_name_new varchar not null default ''; -update album -set order_album_artist_name_new = order_album_artist_name -where order_album_artist_name is not null; -alter table album - drop order_album_artist_name; -alter table album - rename order_album_artist_name_new to order_album_artist_name; - -alter table album - add sort_album_name_new varchar not null default ''; -update album -set sort_album_name_new = sort_album_name -where sort_album_name is not null; -alter table album - drop sort_album_name; -alter table album - rename sort_album_name_new to sort_album_name; - -alter table album - add sort_artist_name_new varchar not null default ''; -update album -set sort_artist_name_new = sort_artist_name -where sort_artist_name is not null; -alter table album - drop sort_artist_name; -alter table album - rename sort_artist_name_new to sort_artist_name; - -alter table album - add sort_album_artist_name_new varchar not null default ''; -update album -set sort_album_artist_name_new = sort_album_artist_name -where sort_album_artist_name is not null; -alter table album - drop sort_album_artist_name; -alter table album - rename sort_album_artist_name_new to sort_album_artist_name; - -alter table album - add catalog_num_new varchar not null default ''; -update album -set catalog_num_new = catalog_num -where catalog_num is not null; -alter table album - drop catalog_num; -alter table album - rename catalog_num_new to catalog_num; - -alter table album - add comment_new varchar not null default ''; -update album -set comment_new = comment -where comment is not null; -alter table album - drop comment; -alter table album - rename comment_new to comment; - -alter table album - add paths_new varchar not null default ''; -update album -set paths_new = paths -where paths is not null; -alter table album - drop paths; -alter table album - rename paths_new to paths; - -alter table album - add mbz_album_id_new varchar not null default ''; -update album -set mbz_album_id_new = mbz_album_id -where mbz_album_id is not null; -alter table album - drop mbz_album_id; -alter table album - rename mbz_album_id_new to mbz_album_id; - -alter table album - add mbz_album_artist_id_new varchar not null default ''; -update album -set mbz_album_artist_id_new = mbz_album_artist_id -where mbz_album_artist_id is not null; -alter table album - drop mbz_album_artist_id; -alter table album - rename mbz_album_artist_id_new to mbz_album_artist_id; - -alter table album - add mbz_album_type_new varchar not null default ''; -update album -set mbz_album_type_new = mbz_album_type -where mbz_album_type is not null; -alter table album - drop mbz_album_type; -alter table album - rename mbz_album_type_new to mbz_album_type; - -alter table album - add mbz_album_comment_new varchar not null default ''; -update album -set mbz_album_comment_new = mbz_album_comment -where mbz_album_comment is not null; -alter table album - drop mbz_album_comment; -alter table album - rename mbz_album_comment_new to mbz_album_comment; - -alter table album - add discs_new jsonb not null default '{}'; -update album -set discs_new = discs -where discs is not null; -alter table album - drop discs; -alter table album - rename discs_new to discs; - --- ARTIST -alter table artist - add order_artist_name_new varchar not null default ''; -update artist -set order_artist_name_new = order_artist_name -where order_artist_name is not null; -alter table artist - drop order_artist_name; -alter table artist - rename order_artist_name_new to order_artist_name; - -alter table artist - add sort_artist_name_new varchar not null default ''; -update artist -set sort_artist_name_new = sort_artist_name -where sort_artist_name is not null; -alter table artist - drop sort_artist_name; -alter table artist - rename sort_artist_name_new to sort_artist_name; - -alter table artist - add mbz_artist_id_new varchar not null default ''; -update artist -set mbz_artist_id_new = mbz_artist_id -where mbz_artist_id is not null; -alter table artist - drop mbz_artist_id; -alter table artist - rename mbz_artist_id_new to mbz_artist_id; - --- MEDIA_FILE -alter table media_file - add order_album_name_new varchar not null default ''; -update media_file -set order_album_name_new = order_album_name -where order_album_name is not null; -alter table media_file - drop order_album_name; -alter table media_file - rename order_album_name_new to order_album_name; - -alter table media_file - add order_album_artist_name_new varchar not null default ''; -update media_file -set order_album_artist_name_new = order_album_artist_name -where order_album_artist_name is not null; -alter table media_file - drop order_album_artist_name; -alter table media_file - rename order_album_artist_name_new to order_album_artist_name; - -alter table media_file - add order_artist_name_new varchar not null default ''; -update media_file -set order_artist_name_new = order_artist_name -where order_artist_name is not null; -alter table media_file - drop order_artist_name; -alter table media_file - rename order_artist_name_new to order_artist_name; - -alter table media_file - add sort_album_name_new varchar not null default ''; -update media_file -set sort_album_name_new = sort_album_name -where sort_album_name is not null; -alter table media_file - drop sort_album_name; -alter table media_file - rename sort_album_name_new to sort_album_name; - -alter table media_file - add sort_artist_name_new varchar not null default ''; -update media_file -set sort_artist_name_new = sort_artist_name -where sort_artist_name is not null; -alter table media_file - drop sort_artist_name; -alter table media_file - rename sort_artist_name_new to sort_artist_name; - -alter table media_file - add sort_album_artist_name_new varchar not null default ''; -update media_file -set sort_album_artist_name_new = sort_album_artist_name -where sort_album_artist_name is not null; -alter table media_file - drop sort_album_artist_name; -alter table media_file - rename sort_album_artist_name_new to sort_album_artist_name; - -alter table media_file - add sort_title_new varchar not null default ''; -update media_file -set sort_title_new = sort_title -where sort_title is not null; -alter table media_file - drop sort_title; -alter table media_file - rename sort_title_new to sort_title; - -alter table media_file - add disc_subtitle_new varchar not null default ''; -update media_file -set disc_subtitle_new = disc_subtitle -where disc_subtitle is not null; -alter table media_file - drop disc_subtitle; -alter table media_file - rename disc_subtitle_new to disc_subtitle; - -alter table media_file - add catalog_num_new varchar not null default ''; -update media_file -set catalog_num_new = catalog_num -where catalog_num is not null; -alter table media_file - drop catalog_num; -alter table media_file - rename catalog_num_new to catalog_num; - -alter table media_file - add comment_new varchar not null default ''; -update media_file -set comment_new = comment -where comment is not null; -alter table media_file - drop comment; -alter table media_file - rename comment_new to comment; - -alter table media_file - add order_title_new varchar not null default ''; -update media_file -set order_title_new = order_title -where order_title is not null; -alter table media_file - drop order_title; -alter table media_file - rename order_title_new to order_title; - -alter table media_file - add mbz_recording_id_new varchar not null default ''; -update media_file -set mbz_recording_id_new = mbz_recording_id -where mbz_recording_id is not null; -alter table media_file - drop mbz_recording_id; -alter table media_file - rename mbz_recording_id_new to mbz_recording_id; - -alter table media_file - add mbz_album_id_new varchar not null default ''; -update media_file -set mbz_album_id_new = mbz_album_id -where mbz_album_id is not null; -alter table media_file - drop mbz_album_id; -alter table media_file - rename mbz_album_id_new to mbz_album_id; - -alter table media_file - add mbz_artist_id_new varchar not null default ''; -update media_file -set mbz_artist_id_new = mbz_artist_id -where mbz_artist_id is not null; -alter table media_file - drop mbz_artist_id; -alter table media_file - rename mbz_artist_id_new to mbz_artist_id; - -alter table media_file - add mbz_artist_id_new varchar not null default ''; -update media_file -set mbz_artist_id_new = mbz_artist_id -where mbz_artist_id is not null; -alter table media_file - drop mbz_artist_id; -alter table media_file - rename mbz_artist_id_new to mbz_artist_id; - -alter table media_file - add mbz_album_artist_id_new varchar not null default ''; -update media_file -set mbz_album_artist_id_new = mbz_album_artist_id -where mbz_album_artist_id is not null; -alter table media_file - drop mbz_album_artist_id; -alter table media_file - rename mbz_album_artist_id_new to mbz_album_artist_id; - -alter table media_file - add mbz_album_type_new varchar not null default ''; -update media_file -set mbz_album_type_new = mbz_album_type -where mbz_album_type is not null; -alter table media_file - drop mbz_album_type; -alter table media_file - rename mbz_album_type_new to mbz_album_type; - -alter table media_file - add mbz_album_comment_new varchar not null default ''; -update media_file -set mbz_album_comment_new = mbz_album_comment -where mbz_album_comment is not null; -alter table media_file - drop mbz_album_comment; -alter table media_file - rename mbz_album_comment_new to mbz_album_comment; - -alter table media_file - add mbz_release_track_id_new varchar not null default ''; -update media_file -set mbz_release_track_id_new = mbz_release_track_id -where mbz_release_track_id is not null; -alter table media_file - drop mbz_release_track_id; -alter table media_file - rename mbz_release_track_id_new to mbz_release_track_id; - -alter table media_file - add bpm_new integer not null default 0; -update media_file -set bpm_new = bpm -where bpm is not null; -alter table media_file - drop bpm; -alter table media_file - rename bpm_new to bpm; - -alter table media_file - add channels_new integer not null default 0; -update media_file -set channels_new = channels -where channels is not null; -alter table media_file - drop channels; -alter table media_file - rename channels_new to channels; - -alter table media_file - add rg_album_gain_new real not null default 0; -update media_file -set rg_album_gain_new = rg_album_gain -where rg_album_gain is not null; -alter table media_file - drop rg_album_gain; -alter table media_file - rename rg_album_gain_new to rg_album_gain; - -alter table media_file - add rg_album_peak_new real not null default 0; -update media_file -set rg_album_peak_new = rg_album_peak -where rg_album_peak is not null; -alter table media_file - drop rg_album_peak; -alter table media_file - rename rg_album_peak_new to rg_album_peak; - -alter table media_file - add rg_track_gain_new real not null default 0; -update media_file -set rg_track_gain_new = rg_track_gain -where rg_track_gain is not null; -alter table media_file - drop rg_track_gain; -alter table media_file - rename rg_track_gain_new to rg_track_gain; - -alter table media_file - add rg_track_peak_new real not null default 0; -update media_file -set rg_track_peak_new = rg_track_peak -where rg_track_peak is not null; -alter table media_file - drop rg_track_peak; -alter table media_file - rename rg_track_peak_new to rg_track_peak; - -alter table media_file - add lyrics_new jsonb not null default '[]'; -update media_file -set lyrics_new = lyrics -where lyrics is not null; -alter table media_file - drop lyrics; -alter table media_file - rename lyrics_new to lyrics; - --- SHARE -alter table share - add description_new varchar not null default ''; -update share -set description_new = description -where description is not null; -alter table share - drop description; -alter table share - rename description_new to description; - -alter table share - add resource_type_new varchar not null default ''; -update share -set resource_type_new = resource_type -where resource_type is not null; -alter table share - drop resource_type; -alter table share - rename resource_type_new to resource_type; - -alter table share - add contents_new varchar not null default ''; -update share -set contents_new = contents -where contents is not null; -alter table share - drop contents; -alter table share - rename contents_new to contents; - -alter table share - add format_new varchar not null default ''; -update share -set format_new = format -where format is not null; -alter table share - drop format; -alter table share - rename format_new to format; - -alter table share - add max_bit_rate_new integer not null default 0; -update share -set max_bit_rate_new = max_bit_rate -where max_bit_rate is not null; -alter table share - drop max_bit_rate; -alter table share - rename max_bit_rate_new to max_bit_rate; - -alter table share - add visit_count_new integer not null default 0; -update share -set visit_count_new = visit_count -where visit_count is not null; -alter table share - drop visit_count; -alter table share - rename visit_count_new to visit_count; - --- INDEX -create index album_alphabetical_by_artist - on album (compilation, order_album_artist_name, order_album_name); - -create index album_order_album_name - on album (order_album_name); - -create index album_order_album_artist_name - on album (order_album_artist_name); - -create index album_mbz_album_type - on album (mbz_album_type); - -create index artist_order_artist_name - on artist (order_artist_name); - -create index media_file_order_album_name - on media_file (order_album_name); - -create index media_file_order_artist_name - on media_file (order_artist_name); - -create index media_file_order_title - on media_file (order_title); - -create index media_file_bpm - on media_file (bpm); - -create index media_file_channels - on media_file (channels); - -create index media_file_mbz_track_id - on media_file (mbz_recording_id); - -`) - return err -} - -func Down20240122223340(context.Context, *sql.Tx) error { - return nil -} diff --git a/db/migrations/20240426202913_add_id_to_scrobble_buffer.go b/db/migrations/20240426202913_add_id_to_scrobble_buffer.go deleted file mode 100644 index e3df63595..000000000 --- a/db/migrations/20240426202913_add_id_to_scrobble_buffer.go +++ /dev/null @@ -1,30 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddIdToScrobbleBuffer, downAddIdToScrobbleBuffer) -} - -func upAddIdToScrobbleBuffer(ctx context.Context, tx *sql.Tx) error { - _, err := tx.ExecContext(ctx, ` -delete from scrobble_buffer where user_id <> ''; -alter table scrobble_buffer add id varchar not null default ''; -create unique index scrobble_buffer_id_ix - on scrobble_buffer (id); -`) - return err -} - -func downAddIdToScrobbleBuffer(ctx context.Context, tx *sql.Tx) error { - _, err := tx.ExecContext(ctx, ` -drop index scrobble_buffer_id_ix; -alter table scrobble_buffer drop id; -`) - return err -} diff --git a/db/migrations/20240511210036_add_sample_rate.go b/db/migrations/20240511210036_add_sample_rate.go deleted file mode 100644 index 619cdcffd..000000000 --- a/db/migrations/20240511210036_add_sample_rate.go +++ /dev/null @@ -1,29 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddSampleRate, downAddSampleRate) -} - -func upAddSampleRate(ctx context.Context, tx *sql.Tx) error { - _, err := tx.ExecContext(ctx, ` -alter table media_file - add sample_rate integer not null default 0; - -create index if not exists media_file_sample_rate - on media_file (sample_rate); -`) - notice(tx, "A full rescan should be performed to pick up additional tags") - return err -} - -func downAddSampleRate(ctx context.Context, tx *sql.Tx) error { - _, err := tx.ExecContext(ctx, `alter table media_file drop sample_rate;`) - return err -} diff --git a/db/migrations/20240511220020_add_library_table.go b/db/migrations/20240511220020_add_library_table.go deleted file mode 100644 index 55b521ca9..000000000 --- a/db/migrations/20240511220020_add_library_table.go +++ /dev/null @@ -1,71 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - "fmt" - - "github.com/navidrome/navidrome/conf" - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddLibraryTable, downAddLibraryTable) -} - -func upAddLibraryTable(ctx context.Context, tx *sql.Tx) error { - _, err := tx.ExecContext(ctx, ` - create table library ( - id integer primary key autoincrement, - name text not null unique, - path text not null unique, - remote_path text null default '', - last_scan_at datetime not null default '0000-00-00 00:00:00', - updated_at datetime not null default current_timestamp, - created_at datetime not null default current_timestamp - );`) - if err != nil { - return err - } - - _, err = tx.ExecContext(ctx, fmt.Sprintf(` - insert into library(id, name, path) values(1, 'Music Library', '%s'); - delete from property where id like 'LastScan-%%'; -`, conf.Server.MusicFolder)) - if err != nil { - return err - } - - _, err = tx.ExecContext(ctx, ` - alter table media_file add column library_id integer not null default 1 - references library(id) on delete cascade; - alter table album add column library_id integer not null default 1 - references library(id) on delete cascade; - - create table if not exists library_artist - ( - 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, - constraint library_artist_ux - unique (library_id, artist_id) - ); - - insert into library_artist(library_id, artist_id) select 1, id from artist; -`) - - return err -} - -func downAddLibraryTable(ctx context.Context, tx *sql.Tx) error { - _, err := tx.ExecContext(ctx, ` - alter table media_file drop column library_id; - alter table album drop column library_id; - drop table library_artist; - drop table library; -`) - return err -} diff --git a/db/migrations/20240629152843_remove_annotation_id.go b/db/migrations/20240629152843_remove_annotation_id.go deleted file mode 100644 index b450b26d4..000000000 --- a/db/migrations/20240629152843_remove_annotation_id.go +++ /dev/null @@ -1,66 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upRemoveAnnotationId, downRemoveAnnotationId) -} - -func upRemoveAnnotationId(ctx context.Context, tx *sql.Tx) error { - _, err := tx.ExecContext(ctx, ` -create table annotation_dg_tmp -( - user_id varchar(255) default '' not null, - item_id varchar(255) default '' not null, - item_type varchar(255) default '' not null, - play_count integer default 0, - play_date datetime, - rating integer default 0, - starred bool default FALSE not null, - starred_at datetime, - unique (user_id, item_id, item_type) -); - -insert into annotation_dg_tmp(user_id, item_id, item_type, play_count, play_date, rating, starred, starred_at) -select user_id, - item_id, - item_type, - play_count, - play_date, - rating, - starred, - starred_at -from annotation; - -drop table annotation; - -alter table annotation_dg_tmp - rename to annotation; - -create index annotation_play_count - on annotation (play_count); - -create index annotation_play_date - on annotation (play_date); - -create index annotation_rating - on annotation (rating); - -create index annotation_starred - on annotation (starred); - -create index annotation_starred_at - on annotation (starred_at); - -`) - return err -} - -func downRemoveAnnotationId(ctx context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20240802044339_player_use_user_id_over_username.go b/db/migrations/20240802044339_player_use_user_id_over_username.go deleted file mode 100644 index 6532f0f45..000000000 --- a/db/migrations/20240802044339_player_use_user_id_over_username.go +++ /dev/null @@ -1,62 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upPlayerUseUserIdOverUsername, downPlayerUseUserIdOverUsername) -} - -func upPlayerUseUserIdOverUsername(ctx context.Context, tx *sql.Tx) error { - _, err := tx.ExecContext(ctx, ` -CREATE TABLE player_dg_tmp -( - id varchar(255) not null - primary key, - name varchar not null, - user_agent varchar, - user_id varchar not null - references user (id) - on update cascade on delete cascade, - client varchar not null, - ip varchar, - last_seen timestamp, - max_bit_rate int default 0, - transcoding_id varchar, - report_real_path bool default FALSE not null, - scrobble_enabled bool default true -); - -INSERT INTO player_dg_tmp( - id, name, user_agent, user_id, client, ip, last_seen, max_bit_rate, - transcoding_id, report_real_path, scrobble_enabled -) -SELECT - id, name, user_agent, - IFNULL( - (select id from user where user_name = player.user_name), 'UNKNOWN_USERNAME' - ), - client, ip_address, last_seen, max_bit_rate, transcoding_id, report_real_path, scrobble_enabled -FROM player; - -DELETE FROM player_dg_tmp WHERE user_id = 'UNKNOWN_USERNAME'; -DROP TABLE player; -ALTER TABLE player_dg_tmp RENAME TO player; - -CREATE INDEX IF NOT EXISTS player_match - on player (client, user_agent, user_id); -CREATE INDEX IF NOT EXISTS player_name - on player (name); -`) - - return err -} - -func downPlayerUseUserIdOverUsername(ctx context.Context, tx *sql.Tx) error { - // This code is executed when the migration is rolled back. - return nil -} diff --git a/db/migrations/20241020003138_add_sort_tags_index.sql b/db/migrations/20241020003138_add_sort_tags_index.sql deleted file mode 100644 index 6d86971e7..000000000 --- a/db/migrations/20241020003138_add_sort_tags_index.sql +++ /dev/null @@ -1,9 +0,0 @@ --- +goose Up -create index if not exists media_file_sort_title on media_file(coalesce(nullif(sort_title,''),order_title)); -create index if not exists album_sort_name on album(coalesce(nullif(sort_album_name,''),order_album_name)); -create index if not exists artist_sort_name on artist(coalesce(nullif(sort_artist_name,''),order_artist_name)); - --- +goose Down -drop index if exists media_file_sort_title; -drop index if exists album_sort_name; -drop index if exists artist_sort_name; \ No newline at end of file diff --git a/db/migrations/20241024125533_fix_sort_tags_collation_and_index.sql b/db/migrations/20241024125533_fix_sort_tags_collation_and_index.sql deleted file mode 100644 index d2edde0ec..000000000 --- a/db/migrations/20241024125533_fix_sort_tags_collation_and_index.sql +++ /dev/null @@ -1,512 +0,0 @@ --- +goose Up ---region Artist Table -create table artist_dg_tmp -( - id varchar(255) not null - primary key, - name varchar(255) default '' not null, - album_count integer default 0 not null, - full_text varchar(255) default '', - song_count integer default 0 not null, - size integer default 0 not null, - biography varchar(255) default '' not null, - small_image_url varchar(255) default '' not null, - medium_image_url varchar(255) default '' not null, - large_image_url varchar(255) default '' not null, - similar_artists varchar(255) default '' not null, - external_url varchar(255) default '' not null, - external_info_updated_at datetime, - order_artist_name varchar collate NOCASE default '' not null, - sort_artist_name varchar collate NOCASE default '' not null, - mbz_artist_id varchar default '' not null -); - -insert into artist_dg_tmp(id, name, album_count, full_text, song_count, size, biography, small_image_url, - medium_image_url, large_image_url, similar_artists, external_url, external_info_updated_at, - order_artist_name, sort_artist_name, mbz_artist_id) -select id, - name, - album_count, - full_text, - song_count, - size, - biography, - small_image_url, - medium_image_url, - large_image_url, - similar_artists, - external_url, - external_info_updated_at, - order_artist_name, - sort_artist_name, - mbz_artist_id -from artist; - -drop table artist; - -alter table artist_dg_tmp - rename to artist; - -create index artist_full_text - on artist (full_text); - -create index artist_name - on artist (name); - -create index artist_order_artist_name - on artist (order_artist_name); - -create index artist_size - on artist (size); - -create index artist_sort_name - on artist (coalesce(nullif(sort_artist_name,''),order_artist_name) collate NOCASE); - ---endregion - ---region Album Table -create table album_dg_tmp -( - id varchar(255) not null - primary key, - name varchar(255) default '' not null, - artist_id varchar(255) default '' not null, - embed_art_path varchar(255) default '' not null, - artist varchar(255) default '' not null, - album_artist varchar(255) default '' not null, - min_year int default 0 not null, - max_year integer default 0 not null, - compilation bool default FALSE not null, - song_count integer default 0 not null, - duration real default 0 not null, - genre varchar(255) default '' not null, - created_at datetime, - updated_at datetime, - full_text varchar(255) default '', - album_artist_id varchar(255) default '', - size integer default 0 not null, - all_artist_ids varchar, - description varchar(255) default '' not null, - small_image_url varchar(255) default '' not null, - medium_image_url varchar(255) default '' not null, - large_image_url varchar(255) default '' not null, - external_url varchar(255) default '' not null, - external_info_updated_at datetime, - date varchar(255) default '' not null, - min_original_year int default 0 not null, - max_original_year int default 0 not null, - original_date varchar(255) default '' not null, - release_date varchar(255) default '' not null, - releases integer default 0 not null, - image_files varchar default '' not null, - order_album_name varchar collate NOCASE default '' not null, - order_album_artist_name varchar collate NOCASE default '' not null, - sort_album_name varchar collate NOCASE default '' not null, - sort_album_artist_name varchar collate NOCASE default '' not null, - catalog_num varchar default '' not null, - comment varchar default '' not null, - paths varchar default '' not null, - mbz_album_id varchar default '' not null, - mbz_album_artist_id varchar default '' not null, - mbz_album_type varchar default '' not null, - mbz_album_comment varchar default '' not null, - discs jsonb default '{}' not null, - library_id integer default 1 not null - references library - on delete cascade -); - -insert into album_dg_tmp(id, name, artist_id, embed_art_path, artist, album_artist, min_year, max_year, compilation, - song_count, duration, genre, created_at, updated_at, full_text, album_artist_id, size, - all_artist_ids, description, small_image_url, medium_image_url, large_image_url, external_url, - external_info_updated_at, date, min_original_year, max_original_year, original_date, - release_date, releases, image_files, order_album_name, order_album_artist_name, - sort_album_name, sort_album_artist_name, catalog_num, comment, paths, - mbz_album_id, mbz_album_artist_id, mbz_album_type, mbz_album_comment, discs, library_id) -select id, - name, - artist_id, - embed_art_path, - artist, - album_artist, - min_year, - max_year, - compilation, - song_count, - duration, - genre, - created_at, - updated_at, - full_text, - album_artist_id, - size, - all_artist_ids, - description, - small_image_url, - medium_image_url, - large_image_url, - external_url, - external_info_updated_at, - date, - min_original_year, - max_original_year, - original_date, - release_date, - releases, - image_files, - order_album_name, - order_album_artist_name, - sort_album_name, - sort_album_artist_name, - catalog_num, - comment, - paths, - mbz_album_id, - mbz_album_artist_id, - mbz_album_type, - mbz_album_comment, - discs, - library_id -from album; - -drop table album; - -alter table album_dg_tmp - rename to album; - -create index album_all_artist_ids - on album (all_artist_ids); - -create index album_alphabetical_by_artist - on album (compilation, order_album_artist_name, order_album_name); - -create index album_artist - on album (artist); - -create index album_artist_album - on album (artist); - -create index album_artist_album_id - on album (album_artist_id); - -create index album_artist_id - on album (artist_id); - -create index album_created_at - on album (created_at); - -create index album_full_text - on album (full_text); - -create index album_genre - on album (genre); - -create index album_max_year - on album (max_year); - -create index album_mbz_album_type - on album (mbz_album_type); - -create index album_min_year - on album (min_year); - -create index album_name - on album (name); - -create index album_order_album_artist_name - on album (order_album_artist_name); - -create index album_order_album_name - on album (order_album_name); - -create index album_size - on album (size); - -create index album_sort_name - on album (coalesce(nullif(sort_album_name,''),order_album_name) collate NOCASE); - -create index album_sort_album_artist_name - on album (coalesce(nullif(sort_album_artist_name,''),order_album_artist_name) collate NOCASE); - -create index album_updated_at - on album (updated_at); ---endregion - ---region Media File Table -create table media_file_dg_tmp -( - id varchar(255) not null - primary key, - path varchar(255) default '' not null, - title varchar(255) default '' not null, - album varchar(255) default '' not null, - artist varchar(255) default '' not null, - artist_id varchar(255) default '' not null, - album_artist varchar(255) default '' not null, - album_id varchar(255) default '' not null, - has_cover_art bool default FALSE not null, - track_number integer default 0 not null, - disc_number integer default 0 not null, - year integer default 0 not null, - size integer default 0 not null, - suffix varchar(255) default '' not null, - duration real default 0 not null, - bit_rate integer default 0 not null, - genre varchar(255) default '' not null, - compilation bool default FALSE not null, - created_at datetime, - updated_at datetime, - full_text varchar(255) default '', - album_artist_id varchar(255) default '', - date varchar(255) default '' not null, - original_year int default 0 not null, - original_date varchar(255) default '' not null, - release_year int default 0 not null, - release_date varchar(255) default '' not null, - order_album_name varchar collate NOCASE default '' not null, - order_album_artist_name varchar collate NOCASE default '' not null, - order_artist_name varchar collate NOCASE default '' not null, - sort_album_name varchar collate NOCASE default '' not null, - sort_artist_name varchar collate NOCASE default '' not null, - sort_album_artist_name varchar collate NOCASE default '' not null, - sort_title varchar collate NOCASE default '' not null, - disc_subtitle varchar default '' not null, - catalog_num varchar default '' not null, - comment varchar default '' not null, - order_title varchar collate NOCASE default '' not null, - mbz_recording_id varchar default '' not null, - mbz_album_id varchar default '' not null, - mbz_artist_id varchar default '' not null, - mbz_album_artist_id varchar default '' not null, - mbz_album_type varchar default '' not null, - mbz_album_comment varchar default '' not null, - mbz_release_track_id varchar default '' not null, - bpm integer default 0 not null, - channels integer default 0 not null, - rg_album_gain real default 0 not null, - rg_album_peak real default 0 not null, - rg_track_gain real default 0 not null, - rg_track_peak real default 0 not null, - lyrics jsonb default '[]' not null, - sample_rate integer default 0 not null, - library_id integer default 1 not null - references library - on delete cascade -); - -insert into media_file_dg_tmp(id, path, title, album, artist, artist_id, album_artist, album_id, has_cover_art, - track_number, disc_number, year, size, suffix, duration, bit_rate, genre, compilation, - created_at, updated_at, full_text, album_artist_id, date, original_year, original_date, - release_year, release_date, order_album_name, order_album_artist_name, order_artist_name, - sort_album_name, sort_artist_name, sort_album_artist_name, sort_title, disc_subtitle, - catalog_num, comment, order_title, mbz_recording_id, mbz_album_id, mbz_artist_id, - mbz_album_artist_id, mbz_album_type, mbz_album_comment, mbz_release_track_id, bpm, - channels, rg_album_gain, rg_album_peak, rg_track_gain, rg_track_peak, lyrics, sample_rate, - library_id) -select id, - path, - title, - album, - artist, - artist_id, - album_artist, - album_id, - has_cover_art, - track_number, - disc_number, - year, - size, - suffix, - duration, - bit_rate, - genre, - compilation, - created_at, - updated_at, - full_text, - album_artist_id, - date, - original_year, - original_date, - release_year, - release_date, - order_album_name, - order_album_artist_name, - order_artist_name, - sort_album_name, - sort_artist_name, - sort_album_artist_name, - sort_title, - disc_subtitle, - catalog_num, - comment, - order_title, - mbz_recording_id, - mbz_album_id, - mbz_artist_id, - mbz_album_artist_id, - mbz_album_type, - mbz_album_comment, - mbz_release_track_id, - bpm, - channels, - rg_album_gain, - rg_album_peak, - rg_track_gain, - rg_track_peak, - lyrics, - sample_rate, - library_id -from media_file; - -drop table media_file; - -alter table media_file_dg_tmp - rename to media_file; - -create index media_file_album_artist - on media_file (album_artist); - -create index media_file_album_id - on media_file (album_id); - -create index media_file_artist - on media_file (artist); - -create index media_file_artist_album_id - on media_file (album_artist_id); - -create index media_file_artist_id - on media_file (artist_id); - -create index media_file_bpm - on media_file (bpm); - -create index media_file_channels - on media_file (channels); - -create index media_file_created_at - on media_file (created_at); - -create index media_file_duration - on media_file (duration); - -create index media_file_full_text - on media_file (full_text); - -create index media_file_genre - on media_file (genre); - -create index media_file_mbz_track_id - on media_file (mbz_recording_id); - -create index media_file_order_album_name - on media_file (order_album_name); - -create index media_file_order_artist_name - on media_file (order_artist_name); - -create index media_file_order_title - on media_file (order_title); - -create index media_file_path - on media_file (path); - -create index media_file_path_nocase - on media_file (path collate NOCASE); - -create index media_file_sample_rate - on media_file (sample_rate); - -create index media_file_sort_title - on media_file (coalesce(nullif(sort_title,''),order_title) collate NOCASE); - -create index media_file_sort_artist_name - on media_file (coalesce(nullif(sort_artist_name,''),order_artist_name) collate NOCASE); - -create index media_file_sort_album_name - on media_file (coalesce(nullif(sort_album_name,''),order_album_name) collate NOCASE); - -create index media_file_title - on media_file (title); - -create index media_file_track_number - on media_file (disc_number, track_number); - -create index media_file_updated_at - on media_file (updated_at); - -create index media_file_year - on media_file (year); - ---endregion - ---region Radio Table -create table radio_dg_tmp -( - id varchar(255) not null - primary key, - name varchar collate NOCASE not null - unique, - stream_url varchar not null, - home_page_url varchar default '' not null, - created_at datetime, - updated_at datetime -); - -insert into radio_dg_tmp(id, name, stream_url, home_page_url, created_at, updated_at) -select id, name, stream_url, home_page_url, created_at, updated_at -from radio; - -drop table radio; - -alter table radio_dg_tmp - rename to radio; - -create index radio_name - on radio(name); ---endregion - ---region users Table -create table user_dg_tmp -( - id varchar(255) not null - primary key, - user_name varchar(255) default '' not null - unique, - name varchar(255) collate NOCASE default '' not null, - email varchar(255) default '' not null, - password varchar(255) default '' not null, - is_admin bool default FALSE not null, - last_login_at datetime, - last_access_at datetime, - created_at datetime not null, - updated_at datetime not null -); - -insert into user_dg_tmp(id, user_name, name, email, password, is_admin, last_login_at, last_access_at, created_at, - updated_at) -select id, - user_name, - name, - email, - password, - is_admin, - last_login_at, - last_access_at, - created_at, - updated_at -from user; - -drop table user; - -alter table user_dg_tmp - rename to user; - -create index user_username_password - on user(user_name collate NOCASE, password); ---endregion - --- +goose Down -alter table album - add column sort_artist_name varchar default '' not null; diff --git a/db/migrations/20241026183640_support_new_scanner.go b/db/migrations/20241026183640_support_new_scanner.go deleted file mode 100644 index fcbef7e4e..000000000 --- a/db/migrations/20241026183640_support_new_scanner.go +++ /dev/null @@ -1,319 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - "fmt" - "io/fs" - "os" - "path/filepath" - "strings" - "testing/fstest" - "unicode/utf8" - - "github.com/navidrome/navidrome/log" - "github.com/navidrome/navidrome/model" - "github.com/navidrome/navidrome/utils/run" - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upSupportNewScanner, downSupportNewScanner) -} - -func upSupportNewScanner(ctx context.Context, tx *sql.Tx) error { - execute := createExecuteFunc(ctx, tx) - addColumn := createAddColumnFunc(ctx, tx) - - return run.Sequentially( - upSupportNewScanner_CreateTableFolder(ctx, execute), - upSupportNewScanner_PopulateTableFolder(ctx, tx), - upSupportNewScanner_UpdateTableMediaFile(ctx, execute, addColumn), - upSupportNewScanner_UpdateTableAlbum(ctx, execute), - upSupportNewScanner_UpdateTableArtist(ctx, execute, addColumn), - execute(` -alter table library - add column last_scan_started_at datetime default '0000-00-00 00:00:00' not null; -alter table library - add column full_scan_in_progress boolean default false not null; - -create table if not exists media_file_artists( - media_file_id varchar not null - references media_file (id) - on delete cascade, - artist_id varchar not null - references artist (id) - on delete cascade, - role varchar default '' not null, - sub_role varchar default '' not null, - constraint artist_tracks - unique (artist_id, media_file_id, role, sub_role) -); -create index if not exists media_file_artists_media_file_id - on media_file_artists (media_file_id); -create index if not exists media_file_artists_role - on media_file_artists (role); - -create table if not exists album_artists( - album_id varchar not null - references album (id) - on delete cascade, - artist_id varchar not null - references artist (id) - on delete cascade, - role varchar default '' not null, - sub_role varchar default '' not null, - constraint album_artists - unique (album_id, artist_id, role, sub_role) -); -create index if not exists album_artists_album_id - on album_artists (album_id); -create index if not exists album_artists_role - on album_artists (role); - -create table if not exists tag( - id varchar not null primary key, - tag_name varchar default '' not null, - tag_value varchar default '' not null, - album_count integer default 0 not null, - media_file_count integer default 0 not null, - constraint tags_name_value - unique (tag_name, tag_value) -); - --- Genres are now stored in the tag table -drop table if exists media_file_genres; -drop table if exists album_genres; -drop table if exists artist_genres; -drop table if exists genre; - --- Drop full_text indexes, as they are not being used by SQLite -drop index if exists media_file_full_text; -drop index if exists album_full_text; -drop index if exists artist_full_text; - --- Add PID config to properties -insert into property (id, value) values ('PIDTrack', 'track_legacy') on conflict do nothing; -insert into property (id, value) values ('PIDAlbum', 'album_legacy') on conflict do nothing; -`), - func() error { - notice(tx, "A full scan will be triggered to populate the new tables. This may take a while.") - return forceFullRescan(tx) - }, - ) -} - -func upSupportNewScanner_CreateTableFolder(_ context.Context, execute execStmtFunc) execFunc { - return execute(` -create table if not exists folder( - id varchar not null - primary key, - library_id integer not null - references library (id) - on delete cascade, - path varchar default '' not null, - name varchar default '' not null, - missing boolean default false not null, - parent_id varchar default '' not null, - num_audio_files integer default 0 not null, - num_playlists integer default 0 not null, - image_files jsonb default '[]' not null, - images_updated_at datetime default '0000-00-00 00:00:00' not null, - updated_at datetime default (datetime(current_timestamp, 'localtime')) not null, - created_at datetime default (datetime(current_timestamp, 'localtime')) not null -); -create index folder_parent_id on folder(parent_id); -`) -} - -// Use paths from `media_file` table to populate `folder` table. The `folder` table must contain all paths, including -// the ones that do not contain any media_file. We can get all paths from the media_file table to populate a -// fstest.MapFS{}, and then walk the filesystem to insert all folders into the DB, including empty parent ones. -func upSupportNewScanner_PopulateTableFolder(ctx context.Context, tx *sql.Tx) execFunc { - return func() error { - // First, get all folder paths from media_file table - rows, err := tx.QueryContext(ctx, fmt.Sprintf(` -select distinct rtrim(media_file.path, replace(media_file.path, '%s', '')), library_id, library.path -from media_file -join library on media_file.library_id = library.id`, string(os.PathSeparator))) - if err != nil { - return err - } - defer rows.Close() - - // Then create an in-memory filesystem with all paths - var path string - var lib model.Library - fsys := fstest.MapFS{} - - for rows.Next() { - err = rows.Scan(&path, &lib.ID, &lib.Path) - if err != nil { - return err - } - - path = strings.TrimPrefix(path, filepath.Clean(lib.Path)) - path = strings.TrimPrefix(path, string(os.PathSeparator)) - path = filepath.Clean(path) - fsys[path] = &fstest.MapFile{Mode: fs.ModeDir} - } - if err = rows.Err(); err != nil { - return fmt.Errorf("error loading folders from media_file table: %w", err) - } - if len(fsys) == 0 { - return nil - } - - stmt, err := tx.PrepareContext(ctx, - "insert into folder (id, library_id, path, name, parent_id, updated_at) values (?, ?, ?, ?, ?, '0000-00-00 00:00:00')", - ) - if err != nil { - return err - } - - // Finally, walk the in-mem filesystem and insert all folders into the DB. - err = fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error { - if err != nil { - // Don't abort the walk, just log the error - log.Error("error walking folder to DB", "path", path, err) - return nil - } - // Skip entries that are not directories - if !d.IsDir() { - return nil - } - - // Create a folder in the DB - f := model.NewFolder(lib, path) - _, err = stmt.ExecContext(ctx, f.ID, lib.ID, f.Path, f.Name, f.ParentID) - if err != nil { - log.Error("error writing folder to DB", "path", path, err) - } - return err - }) - if err != nil { - return fmt.Errorf("error populating folder table: %w", err) - } - - // Count the number of characters in the library path - libPath := filepath.Clean(lib.Path) - libPathLen := utf8.RuneCountInString(libPath) - - // In one go, update all paths in the media_file table, removing the library path prefix - // and replacing any backslashes with slashes (the path separator used by the io/fs package) - _, err = tx.ExecContext(ctx, fmt.Sprintf(` -update media_file set path = replace(substr(path, %d), '\', '/');`, libPathLen+2)) - if err != nil { - return fmt.Errorf("error updating media_file path: %w", err) - } - - return nil - } -} - -func upSupportNewScanner_UpdateTableMediaFile(_ context.Context, execute execStmtFunc, addColumn addColumnFunc) execFunc { - return func() error { - return run.Sequentially( - execute(` -alter table media_file - add column folder_id varchar default '' not null; -alter table media_file - add column pid varchar default '' not null; -alter table media_file - add column missing boolean default false not null; -alter table media_file - add column mbz_release_group_id varchar default '' not null; -alter table media_file - add column tags jsonb default '{}' not null; -alter table media_file - add column participants jsonb default '{}' not null; -alter table media_file - add column bit_depth integer default 0 not null; -alter table media_file - add column explicit_status varchar default '' not null; -`), - addColumn("media_file", "birth_time", "datetime", "current_timestamp", "created_at"), - execute(` -update media_file - set pid = id where pid = ''; -create index if not exists media_file_birth_time - on media_file (birth_time); -create index if not exists media_file_folder_id - on media_file (folder_id); -create index if not exists media_file_pid - on media_file (pid); -create index if not exists media_file_missing - on media_file (missing); -`), - ) - } -} - -func upSupportNewScanner_UpdateTableAlbum(_ context.Context, execute execStmtFunc) execFunc { - return execute(` -drop index if exists album_all_artist_ids; -alter table album - drop column all_artist_ids; -drop index if exists album_artist; -drop index if exists album_artist_album; -alter table album - drop column artist; -drop index if exists album_artist_id; -alter table album - drop column artist_id; -alter table album - add column imported_at datetime default '0000-00-00 00:00:00' not null; -alter table album - add column missing boolean default false not null; -alter table album - add column mbz_release_group_id varchar default '' not null; -alter table album - add column tags jsonb default '{}' not null; -alter table album - add column participants jsonb default '{}' not null; -alter table album - drop column paths; -alter table album - drop column image_files; -alter table album - add column folder_ids jsonb default '[]' not null; -alter table album - add column explicit_status varchar default '' not null; -create index if not exists album_imported_at - on album (imported_at); -create index if not exists album_mbz_release_group_id - on album (mbz_release_group_id); -`) -} - -func upSupportNewScanner_UpdateTableArtist(_ context.Context, execute execStmtFunc, addColumn addColumnFunc) execFunc { - return func() error { - return run.Sequentially( - execute(` -alter table artist - drop column album_count; -alter table artist - drop column song_count; -drop index if exists artist_size; -alter table artist - drop column size; -alter table artist - add column missing boolean default false not null; -alter table artist - add column stats jsonb default '{"albumartist":{}}' not null; -alter table artist - drop column similar_artists; -alter table artist - add column similar_artists jsonb default '[]' not null; -`), - addColumn("artist", "updated_at", "datetime", "current_time", "(select min(album.updated_at) from album where album_artist_id = artist.id)"), - addColumn("artist", "created_at", "datetime", "current_time", "(select min(album.created_at) from album where album_artist_id = artist.id)"), - execute(`create index if not exists artist_updated_at on artist (updated_at);`), - execute(`update artist set external_info_updated_at = '0000-00-00 00:00:00';`), - ) - } -} - -func downSupportNewScanner(context.Context, *sql.Tx) error { - return nil -} diff --git a/db/migrations/20250522013904_share_user_id_on_delete.sql b/db/migrations/20250522013904_share_user_id_on_delete.sql deleted file mode 100644 index 91ff653ac..000000000 --- a/db/migrations/20250522013904_share_user_id_on_delete.sql +++ /dev/null @@ -1,36 +0,0 @@ --- +goose Up --- +goose StatementBegin -CREATE TABLE share_tmp -( - id varchar(255) not null - primary key, - expires_at datetime, - last_visited_at datetime, - resource_ids varchar not null, - created_at datetime, - updated_at datetime, - user_id varchar(255) not null - constraint share_user_id_fk - references user - on update cascade on delete cascade, - downloadable bool not null default false, - description varchar not null default '', - resource_type varchar not null default '', - contents varchar not null default '', - format varchar not null default '', - max_bit_rate integer not null default 0, - visit_count integer not null default 0 -); - - -INSERT INTO share_tmp( - id, expires_at, last_visited_at, resource_ids, created_at, updated_at, user_id, downloadable, description, resource_type, contents, format, max_bit_rate, visit_count -) SELECT id, expires_at, last_visited_at, resource_ids, created_at, updated_at, user_id, downloadable, description, resource_type, contents, format, max_bit_rate, visit_count -FROM share; - -DROP TABLE share; - -ALTER TABLE share_tmp RENAME To share; --- +goose StatementEnd - --- +goose Down diff --git a/db/migrations/20250611010101_playqueue_current_to_index.go b/db/migrations/20250611010101_playqueue_current_to_index.go deleted file mode 100644 index d9250eba2..000000000 --- a/db/migrations/20250611010101_playqueue_current_to_index.go +++ /dev/null @@ -1,80 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - "strings" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upPlayQueueCurrentToIndex, downPlayQueueCurrentToIndex) -} - -func upPlayQueueCurrentToIndex(ctx context.Context, tx *sql.Tx) error { - _, err := tx.ExecContext(ctx, ` -create table playqueue_dg_tmp( - id varchar(255) not null, - user_id varchar(255) not null - references user(id) - on update cascade on delete cascade, - current integer not null default 0, - position real, - changed_by varchar(255), - items varchar(255), - created_at datetime, - updated_at datetime -);`) - if err != nil { - return err - } - - rows, err := tx.QueryContext(ctx, `select id, user_id, current, position, changed_by, items, created_at, updated_at from playqueue`) - if err != nil { - return err - } - defer rows.Close() - - stmt, err := tx.PrepareContext(ctx, `insert into playqueue_dg_tmp(id, user_id, current, position, changed_by, items, created_at, updated_at) values(?,?,?,?,?,?,?,?)`) - if err != nil { - return err - } - defer stmt.Close() - - for rows.Next() { - var id, userID, currentID, changedBy, items string - var position sql.NullFloat64 - var createdAt, updatedAt sql.NullString - if err = rows.Scan(&id, &userID, ¤tID, &position, &changedBy, &items, &createdAt, &updatedAt); err != nil { - return err - } - index := 0 - if currentID != "" && items != "" { - parts := strings.Split(items, ",") - for i, p := range parts { - if p == currentID { - index = i - break - } - } - } - _, err = stmt.Exec(id, userID, index, position, changedBy, items, createdAt, updatedAt) - if err != nil { - return err - } - } - if err = rows.Err(); err != nil { - return err - } - - if _, err = tx.ExecContext(ctx, `drop table playqueue;`); err != nil { - return err - } - _, err = tx.ExecContext(ctx, `alter table playqueue_dg_tmp rename to playqueue;`) - return err -} - -func downPlayQueueCurrentToIndex(ctx context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20250701010101_add_folder_hash.go b/db/migrations/20250701010101_add_folder_hash.go deleted file mode 100644 index e82a0749f..000000000 --- a/db/migrations/20250701010101_add_folder_hash.go +++ /dev/null @@ -1,21 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddFolderHash, downAddFolderHash) -} - -func upAddFolderHash(ctx context.Context, tx *sql.Tx) error { - _, err := tx.ExecContext(ctx, `alter table folder add column hash varchar default '' not null;`) - return err -} - -func downAddFolderHash(ctx context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20250701010102_add_annotation_user_foreign_key.sql b/db/migrations/20250701010102_add_annotation_user_foreign_key.sql deleted file mode 100644 index 114de2a88..000000000 --- a/db/migrations/20250701010102_add_annotation_user_foreign_key.sql +++ /dev/null @@ -1,46 +0,0 @@ --- +goose Up --- +goose StatementBegin -CREATE TABLE IF NOT EXISTS annotation_tmp -( - user_id varchar(255) not null - REFERENCES user(id) - ON DELETE CASCADE - ON UPDATE CASCADE, - item_id varchar(255) default '' not null, - item_type varchar(255) default '' not null, - play_count integer default 0, - play_date datetime, - rating integer default 0, - starred bool default FALSE not null, - starred_at datetime, - unique (user_id, item_id, item_type) -); - - -INSERT INTO annotation_tmp( - user_id, item_id, item_type, play_count, play_date, rating, starred, starred_at -) -SELECT user_id, item_id, item_type, play_count, play_date, rating, starred, starred_at -FROM annotation -WHERE user_id IN ( - SELECT id FROM user -); - -DROP TABLE annotation; -ALTER TABLE annotation_tmp RENAME TO annotation; - -CREATE INDEX annotation_play_count - on annotation (play_count); -CREATE INDEX annotation_play_date - on annotation (play_date); -CREATE INDEX annotation_rating - on annotation (rating); -CREATE INDEX annotation_starred - on annotation (starred); -CREATE INDEX annotation_starred_at - on annotation (starred_at); - --- +goose StatementEnd - --- +goose Down - diff --git a/db/migrations/20250701010103_add_library_stats.go b/db/migrations/20250701010103_add_library_stats.go deleted file mode 100644 index 8025229cc..000000000 --- a/db/migrations/20250701010103_add_library_stats.go +++ /dev/null @@ -1,48 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddLibraryStats, downAddLibraryStats) -} - -func upAddLibraryStats(ctx context.Context, tx *sql.Tx) error { - _, err := tx.ExecContext(ctx, ` -alter table library add column total_songs integer default 0 not null; -alter table library add column total_albums integer default 0 not null; -alter table library add column total_artists integer default 0 not null; -alter table library add column total_folders integer default 0 not null; - alter table library add column total_files integer default 0 not null; - alter table library add column total_missing_files integer default 0 not null; - alter table library add column total_size integer default 0 not null; -update library set - total_songs = ( - select count(*) from media_file where library_id = library.id and missing = 0 - ), - total_albums = (select count(*) from album where library_id = library.id and missing = 0), - total_artists = ( - select count(*) from library_artist la - join artist a on la.artist_id = a.id - where la.library_id = library.id and a.missing = 0 - ), - total_folders = (select count(*) from folder where library_id = library.id and missing = 0 and num_audio_files > 0), - total_files = ( - select ifnull(sum(num_audio_files + num_playlists + json_array_length(image_files)),0) - from folder where library_id = library.id and missing = 0 - ), - total_missing_files = ( - select count(*) from media_file where library_id = library.id and missing = 1 - ), - total_size = (select ifnull(sum(size),0) from album where library_id = library.id and missing = 0); -`) - return err -} - -func downAddLibraryStats(ctx context.Context, tx *sql.Tx) error { - return nil -} diff --git a/db/migrations/20250701010104_make_replaygain_fields_nullable.go b/db/migrations/20250701010104_make_replaygain_fields_nullable.go deleted file mode 100644 index 163608d32..000000000 --- a/db/migrations/20250701010104_make_replaygain_fields_nullable.go +++ /dev/null @@ -1,49 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upMakeReplaygainFieldsNullable, downMakeReplaygainFieldsNullable) -} - -func upMakeReplaygainFieldsNullable(ctx context.Context, tx *sql.Tx) error { - _, err := tx.ExecContext(ctx, ` -ALTER TABLE media_file ADD COLUMN rg_album_gain_new real; -ALTER TABLE media_file ADD COLUMN rg_album_peak_new real; -ALTER TABLE media_file ADD COLUMN rg_track_gain_new real; -ALTER TABLE media_file ADD COLUMN rg_track_peak_new real; - -UPDATE media_file SET - rg_album_gain_new = rg_album_gain, - rg_album_peak_new = rg_album_peak, - rg_track_gain_new = rg_track_gain, - rg_track_peak_new = rg_track_peak; - -ALTER TABLE media_file DROP COLUMN rg_album_gain; -ALTER TABLE media_file DROP COLUMN rg_album_peak; -ALTER TABLE media_file DROP COLUMN rg_track_gain; -ALTER TABLE media_file DROP COLUMN rg_track_peak; - -ALTER TABLE media_file RENAME COLUMN rg_album_gain_new TO rg_album_gain; -ALTER TABLE media_file RENAME COLUMN rg_album_peak_new TO rg_album_peak; -ALTER TABLE media_file RENAME COLUMN rg_track_gain_new TO rg_track_gain; -ALTER TABLE media_file RENAME COLUMN rg_track_peak_new TO rg_track_peak; - `) - - if err != nil { - return err - } - - notice(tx, "Fetching replaygain fields properly will require a full scan") - return nil -} - -func downMakeReplaygainFieldsNullable(ctx context.Context, tx *sql.Tx) error { - // This code is executed when the migration is rolled back. - return nil -} diff --git a/db/migrations/20250701010105_remove_dangling_items.sql b/db/migrations/20250701010105_remove_dangling_items.sql deleted file mode 100644 index aede49b6e..000000000 --- a/db/migrations/20250701010105_remove_dangling_items.sql +++ /dev/null @@ -1,7 +0,0 @@ --- +goose Up --- +goose StatementBegin -update media_file set missing = 1 where folder_id = ''; -update album set missing = 1 where folder_ids = '[]'; --- +goose StatementEnd - --- +goose Down diff --git a/db/migrations/20250701010106_add_participant_stats_to_all_artists.sql b/db/migrations/20250701010106_add_participant_stats_to_all_artists.sql deleted file mode 100644 index 1cd67dc32..000000000 --- a/db/migrations/20250701010106_add_participant_stats_to_all_artists.sql +++ /dev/null @@ -1,65 +0,0 @@ --- +goose Up --- +goose StatementBegin -WITH artist_role_counters AS ( - SELECT jt.atom AS artist_id, - substr( - replace(jt.path, '$.', ''), - 1, - CASE WHEN instr(replace(jt.path, '$.', ''), '[') > 0 - THEN instr(replace(jt.path, '$.', ''), '[') - 1 - ELSE length(replace(jt.path, '$.', '')) - END - ) AS role, - count(DISTINCT mf.album_id) AS album_count, - count(mf.id) AS count, - sum(mf.size) AS size - FROM media_file mf - JOIN json_tree(mf.participants) jt ON jt.key = 'id' AND jt.atom IS NOT NULL - GROUP BY jt.atom, role -), -artist_total_counters AS ( - SELECT mfa.artist_id, - 'total' AS role, - count(DISTINCT mf.album_id) AS album_count, - count(DISTINCT mf.id) AS count, - sum(mf.size) AS size - FROM media_file_artists mfa - JOIN media_file mf ON mfa.media_file_id = mf.id - GROUP BY mfa.artist_id -), -artist_participant_counter AS ( - SELECT mfa.artist_id, - 'maincredit' AS role, - count(DISTINCT mf.album_id) AS album_count, - count(DISTINCT mf.id) AS count, - sum(mf.size) AS size - FROM media_file_artists mfa - JOIN media_file mf ON mfa.media_file_id = mf.id - AND mfa.role IN ('albumartist', 'artist') - GROUP BY mfa.artist_id -), -combined_counters AS ( - SELECT artist_id, role, album_count, count, size FROM artist_role_counters - UNION - SELECT artist_id, role, album_count, count, size FROM artist_total_counters - UNION - SELECT artist_id, role, album_count, count, size FROM artist_participant_counter -), -artist_counters AS ( - SELECT artist_id AS id, - json_group_object( - replace(role, '"', ''), - json_object('a', album_count, 'm', count, 's', size) - ) AS counters - FROM combined_counters - GROUP BY artist_id -) -UPDATE artist -SET stats = coalesce((SELECT counters FROM artist_counters ac WHERE ac.id = artist.id), '{}'), - updated_at = datetime(current_timestamp, 'localtime') -WHERE artist.id <> ''; --- +goose StatementEnd - --- +goose Down --- +goose StatementBegin --- +goose StatementEnd diff --git a/db/migrations/20250701010107_add_mbid_indexes.sql b/db/migrations/20250701010107_add_mbid_indexes.sql deleted file mode 100644 index f8a5a444b..000000000 --- a/db/migrations/20250701010107_add_mbid_indexes.sql +++ /dev/null @@ -1,27 +0,0 @@ --- +goose Up --- +goose StatementBegin - --- Add indexes for MBID fields to improve lookup performance --- Artists table -create index if not exists artist_mbz_artist_id - on artist (mbz_artist_id); - --- Albums table -create index if not exists album_mbz_album_id - on album (mbz_album_id); - --- Media files table -create index if not exists media_file_mbz_release_track_id - on media_file (mbz_release_track_id); - --- +goose StatementEnd - --- +goose Down --- +goose StatementBegin - --- Remove MBID indexes -drop index if exists artist_mbz_artist_id; -drop index if exists album_mbz_album_id; -drop index if exists media_file_mbz_release_track_id; - --- +goose StatementEnd diff --git a/db/migrations/20250701010108_add_multi_library_support.go b/db/migrations/20250701010108_add_multi_library_support.go deleted file mode 100644 index 654784d09..000000000 --- a/db/migrations/20250701010108_add_multi_library_support.go +++ /dev/null @@ -1,119 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddMultiLibrarySupport, downAddMultiLibrarySupport) -} - -func upAddMultiLibrarySupport(ctx context.Context, tx *sql.Tx) error { - _, err := tx.ExecContext(ctx, ` - -- Create user_library association table - CREATE TABLE user_library ( - user_id VARCHAR(255) NOT NULL, - library_id INTEGER NOT NULL, - PRIMARY KEY (user_id, library_id), - FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE, - FOREIGN KEY (library_id) REFERENCES library(id) ON DELETE CASCADE - ); - -- Create indexes for performance - CREATE INDEX idx_user_library_user_id ON user_library(user_id); - CREATE INDEX idx_user_library_library_id ON user_library(library_id); - - -- Populate with existing users having access to library ID 1 (existing setup) - -- Admin users get access to all libraries, regular users get access to library 1 - INSERT INTO user_library (user_id, library_id) - SELECT u.id, 1 - FROM user u; - - -- Add total_duration column to library table - ALTER TABLE library ADD COLUMN total_duration real DEFAULT 0; - UPDATE library SET total_duration = ( - SELECT IFNULL(SUM(duration),0) from album where album.library_id = library.id and missing = 0 - ); - - -- Add default_new_users column to library table - ALTER TABLE library ADD COLUMN default_new_users boolean DEFAULT false; - -- Set library ID 1 (default library) as default for new users - UPDATE library SET default_new_users = true WHERE id = 1; - - -- Add stats column to library_artist junction table for per-library artist statistics - ALTER TABLE library_artist ADD COLUMN stats text DEFAULT '{}'; - - -- Migrate existing global artist stats to per-library format in library_artist table - -- For each library_artist association, copy the artist's global stats - UPDATE library_artist - SET stats = ( - SELECT COALESCE(artist.stats, '{}') - FROM artist - WHERE artist.id = library_artist.artist_id - ); - - -- Remove stats column from artist table to eliminate duplication - -- Stats are now stored per-library in library_artist table - ALTER TABLE artist DROP COLUMN stats; - - -- Create library_tag table for per-library tag statistics - CREATE TABLE library_tag ( - tag_id VARCHAR NOT NULL, - library_id INTEGER NOT NULL, - album_count INTEGER DEFAULT 0 NOT NULL, - media_file_count INTEGER DEFAULT 0 NOT NULL, - PRIMARY KEY (tag_id, library_id), - FOREIGN KEY (tag_id) REFERENCES tag(id) ON DELETE CASCADE, - FOREIGN KEY (library_id) REFERENCES library(id) ON DELETE CASCADE - ); - - -- Create indexes for optimal query performance - CREATE INDEX idx_library_tag_tag_id ON library_tag(tag_id); - CREATE INDEX idx_library_tag_library_id ON library_tag(library_id); - - -- Migrate existing tag stats to per-library format in library_tag table - -- For existing installations, copy current global stats to library ID 1 (default library) - INSERT INTO library_tag (tag_id, library_id, album_count, media_file_count) - SELECT t.id, 1, t.album_count, t.media_file_count - FROM tag t - WHERE EXISTS (SELECT 1 FROM library WHERE id = 1); - - -- Remove global stats from tag table as they are now per-library - ALTER TABLE tag DROP COLUMN album_count; - ALTER TABLE tag DROP COLUMN media_file_count; - `) - - return err -} - -func downAddMultiLibrarySupport(ctx context.Context, tx *sql.Tx) error { - _, err := tx.ExecContext(ctx, ` - -- Restore stats column to artist table before removing from library_artist - ALTER TABLE artist ADD COLUMN stats text DEFAULT '{}'; - - -- Restore global stats by aggregating from library_artist (simplified approach) - -- In a real rollback scenario, this might need more sophisticated logic - UPDATE artist - SET stats = ( - SELECT COALESCE(la.stats, '{}') - FROM library_artist la - WHERE la.artist_id = artist.id - LIMIT 1 - ); - - ALTER TABLE library_artist DROP COLUMN IF EXISTS stats; - DROP INDEX IF EXISTS idx_user_library_library_id; - DROP INDEX IF EXISTS idx_user_library_user_id; - DROP TABLE IF EXISTS user_library; - ALTER TABLE library DROP COLUMN IF EXISTS total_duration; - ALTER TABLE library DROP COLUMN IF EXISTS default_new_users; - - -- Drop library_tag table and its indexes - DROP INDEX IF EXISTS idx_library_tag_library_id; - DROP INDEX IF EXISTS idx_library_tag_tag_id; - DROP TABLE IF EXISTS library_tag; - `) - return err -} diff --git a/db/migrations/20251027000000_create_schema.sql b/db/migrations/20251027000000_create_schema.sql new file mode 100644 index 000000000..a24f85725 --- /dev/null +++ b/db/migrations/20251027000000_create_schema.sql @@ -0,0 +1,489 @@ +-- +goose Up +-- PostgreSQL Schema for Navidrome +-- Converted from SQLite schema + +-- Enable extensions +CREATE EXTENSION IF NOT EXISTS citext; + +-- Property table +CREATE TABLE property ( + id VARCHAR NOT NULL PRIMARY KEY, + value VARCHAR DEFAULT '' NOT NULL +); + +-- Transcoding table +CREATE TABLE transcoding ( + id VARCHAR NOT NULL PRIMARY KEY, + name VARCHAR NOT NULL UNIQUE, + target_format VARCHAR NOT NULL UNIQUE, + command VARCHAR DEFAULT '' NOT NULL, + default_bit_rate SMALLINT DEFAULT 192 +); + +-- User table +CREATE TABLE "user" ( + id VARCHAR NOT NULL PRIMARY KEY, + user_name CITEXT NOT NULL UNIQUE, -- CITEXT for case-insensitive username + name VARCHAR DEFAULT '' NOT NULL, + email VARCHAR DEFAULT '' NOT NULL, + password VARCHAR DEFAULT '' NOT NULL, + is_admin BOOLEAN DEFAULT FALSE NOT NULL, + last_login_at TIMESTAMP, + last_access_at TIMESTAMP, + created_at TIMESTAMP NOT NULL, + updated_at TIMESTAMP NOT NULL +); + +CREATE INDEX user_username_password ON "user"(user_name, password); + +-- Library table +CREATE TABLE library ( + id SERIAL PRIMARY KEY, + name VARCHAR NOT NULL UNIQUE, + path VARCHAR NOT NULL UNIQUE, + remote_path VARCHAR DEFAULT '', + last_scan_at TIMESTAMP NOT NULL DEFAULT '1970-01-01 00:00:00', + last_scan_started_at TIMESTAMP DEFAULT '1970-01-01 00:00:00' NOT NULL, + full_scan_in_progress BOOLEAN DEFAULT FALSE NOT NULL, + total_songs BIGINT DEFAULT 0 NOT NULL, + total_albums BIGINT DEFAULT 0 NOT NULL, + total_artists BIGINT DEFAULT 0 NOT NULL, + total_folders BIGINT DEFAULT 0 NOT NULL, + total_files BIGINT DEFAULT 0 NOT NULL, + total_missing_files BIGINT DEFAULT 0 NOT NULL, + total_size BIGINT DEFAULT 0 NOT NULL, + total_duration REAL DEFAULT 0, + default_new_users BOOLEAN DEFAULT FALSE, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +-- Artist table +CREATE TABLE artist ( + id VARCHAR NOT NULL PRIMARY KEY, + name VARCHAR DEFAULT '' NOT NULL, + full_text VARCHAR DEFAULT '', + biography VARCHAR DEFAULT '' NOT NULL, -- VARCHAR: biographies can be long + small_image_url VARCHAR DEFAULT '' NOT NULL, + medium_image_url VARCHAR DEFAULT '' NOT NULL, + large_image_url VARCHAR DEFAULT '' NOT NULL, + external_url VARCHAR DEFAULT '' NOT NULL, + external_info_updated_at TIMESTAMP, + order_artist_name VARCHAR DEFAULT '' NOT NULL, + sort_artist_name VARCHAR DEFAULT '' NOT NULL, + mbz_artist_id VARCHAR DEFAULT '' NOT NULL, + missing BOOLEAN DEFAULT FALSE NOT NULL, + similar_artists JSONB DEFAULT '[]' NOT NULL, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL +); + +CREATE INDEX artist_name ON artist(name); +CREATE INDEX artist_order_artist_name ON artist(order_artist_name); +CREATE INDEX artist_sort_name ON artist(COALESCE(NULLIF(sort_artist_name, ''), order_artist_name)); +CREATE INDEX artist_updated_at ON artist(updated_at); +CREATE INDEX artist_mbz_artist_id ON artist(mbz_artist_id); + +-- Library-Artist association table +CREATE TABLE library_artist ( + library_id INT NOT NULL DEFAULT 1 REFERENCES library(id) ON DELETE CASCADE, + artist_id VARCHAR NOT NULL REFERENCES artist(id) ON DELETE CASCADE, + stats VARCHAR DEFAULT '{}', + CONSTRAINT library_artist_ux UNIQUE (library_id, artist_id) +); + +-- Album table +CREATE TABLE album ( + id VARCHAR NOT NULL PRIMARY KEY, + name VARCHAR DEFAULT '' NOT NULL, + embed_art_path VARCHAR DEFAULT '' NOT NULL, + album_artist VARCHAR DEFAULT '' NOT NULL, + min_year SMALLINT DEFAULT 0 NOT NULL, + max_year SMALLINT DEFAULT 0 NOT NULL, + compilation BOOLEAN DEFAULT FALSE NOT NULL, + song_count INT DEFAULT 0 NOT NULL, + duration REAL DEFAULT 0 NOT NULL, + genre VARCHAR DEFAULT '' NOT NULL, + created_at TIMESTAMP, + updated_at TIMESTAMP, + full_text VARCHAR DEFAULT '', + album_artist_id VARCHAR DEFAULT '', + size BIGINT DEFAULT 0 NOT NULL, + description VARCHAR DEFAULT '' NOT NULL, + small_image_url VARCHAR DEFAULT '' NOT NULL, + medium_image_url VARCHAR DEFAULT '' NOT NULL, + large_image_url VARCHAR DEFAULT '' NOT NULL, + external_url VARCHAR DEFAULT '' NOT NULL, + external_info_updated_at TIMESTAMP, + date VARCHAR DEFAULT '' NOT NULL, + min_original_year SMALLINT DEFAULT 0 NOT NULL, + max_original_year SMALLINT DEFAULT 0 NOT NULL, + original_date VARCHAR DEFAULT '' NOT NULL, + release_date VARCHAR DEFAULT '' NOT NULL, + order_album_name VARCHAR DEFAULT '' NOT NULL, + order_album_artist_name VARCHAR DEFAULT '' NOT NULL, + sort_album_name VARCHAR DEFAULT '' NOT NULL, + sort_album_artist_name VARCHAR DEFAULT '' NOT NULL, + catalog_num VARCHAR DEFAULT '' NOT NULL, + comment VARCHAR DEFAULT '' NOT NULL, + mbz_album_id VARCHAR DEFAULT '' NOT NULL, + mbz_album_artist_id VARCHAR DEFAULT '' NOT NULL, + mbz_album_type VARCHAR DEFAULT '' NOT NULL, + mbz_album_comment VARCHAR DEFAULT '' NOT NULL, + discs JSONB DEFAULT '{}' NOT NULL, + library_id INT DEFAULT 1 NOT NULL REFERENCES library ON DELETE CASCADE, + imported_at TIMESTAMP DEFAULT '1970-01-01 00:00:00' NOT NULL, + missing BOOLEAN DEFAULT FALSE NOT NULL, + mbz_release_group_id VARCHAR DEFAULT '' NOT NULL, + tags JSONB DEFAULT '{}' NOT NULL, + participants JSONB DEFAULT '{}' NOT NULL, + folder_ids JSONB DEFAULT '[]' NOT NULL, + explicit_status VARCHAR DEFAULT '' NOT NULL +); + +CREATE INDEX album_alphabetical_by_artist ON album(compilation, order_album_artist_name, order_album_name); +CREATE INDEX album_artist_album_id ON album(album_artist_id); +CREATE INDEX album_created_at ON album(created_at); +CREATE INDEX album_genre ON album(genre); +CREATE INDEX album_max_year ON album(max_year); +CREATE INDEX album_mbz_album_type ON album(mbz_album_type); +CREATE INDEX album_min_year ON album(min_year); +CREATE INDEX album_name ON album(name); +CREATE INDEX album_order_album_artist_name ON album(order_album_artist_name); +CREATE INDEX album_order_album_name ON album(order_album_name); +CREATE INDEX album_size ON album(size); +CREATE INDEX album_sort_name ON album(COALESCE(NULLIF(sort_album_name, ''), order_album_name)); +CREATE INDEX album_sort_album_artist_name ON album(COALESCE(NULLIF(sort_album_artist_name, ''), order_album_artist_name)); +CREATE INDEX album_updated_at ON album(updated_at); +CREATE INDEX album_imported_at ON album(imported_at); +CREATE INDEX album_mbz_album_id ON album(mbz_album_id); +CREATE INDEX album_mbz_release_group_id ON album(mbz_release_group_id); + +-- Folder table +CREATE TABLE folder ( + id VARCHAR NOT NULL PRIMARY KEY, + library_id INT NOT NULL REFERENCES library(id) ON DELETE CASCADE, + path VARCHAR DEFAULT '' NOT NULL, + name VARCHAR DEFAULT '' NOT NULL, + missing BOOLEAN DEFAULT FALSE NOT NULL, + parent_id VARCHAR DEFAULT '' NOT NULL, + num_audio_files INT DEFAULT 0 NOT NULL, + num_playlists INT DEFAULT 0 NOT NULL, + image_files JSONB DEFAULT '[]' NOT NULL, + images_updated_at TIMESTAMP DEFAULT '1970-01-01 00:00:00' NOT NULL, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, + hash VARCHAR DEFAULT '' NOT NULL +); + +CREATE INDEX folder_parent_id ON folder(parent_id); + +-- Media File table +CREATE TABLE media_file ( + id VARCHAR NOT NULL PRIMARY KEY, + path VARCHAR DEFAULT '' NOT NULL, + title VARCHAR DEFAULT '' NOT NULL, + album VARCHAR DEFAULT '' NOT NULL, + artist VARCHAR DEFAULT '' NOT NULL, + artist_id VARCHAR DEFAULT '' NOT NULL, + album_artist VARCHAR DEFAULT '' NOT NULL, + album_id VARCHAR DEFAULT '' NOT NULL, + has_cover_art BOOLEAN DEFAULT FALSE NOT NULL, + track_number SMALLINT DEFAULT 0 NOT NULL, + disc_number SMALLINT DEFAULT 0 NOT NULL, + year SMALLINT DEFAULT 0 NOT NULL, + size BIGINT DEFAULT 0 NOT NULL, + suffix VARCHAR DEFAULT '' NOT NULL, + duration REAL DEFAULT 0 NOT NULL, + bit_rate SMALLINT DEFAULT 0 NOT NULL, + genre VARCHAR DEFAULT '' NOT NULL, + compilation BOOLEAN DEFAULT FALSE NOT NULL, + created_at TIMESTAMP, + updated_at TIMESTAMP, + full_text VARCHAR DEFAULT '', + album_artist_id VARCHAR DEFAULT '', + date VARCHAR DEFAULT '' NOT NULL, + original_year SMALLINT DEFAULT 0 NOT NULL, + original_date VARCHAR DEFAULT '' NOT NULL, + release_year SMALLINT DEFAULT 0 NOT NULL, + release_date VARCHAR DEFAULT '' NOT NULL, + order_album_name VARCHAR DEFAULT '' NOT NULL, + order_album_artist_name VARCHAR DEFAULT '' NOT NULL, + order_artist_name VARCHAR DEFAULT '' NOT NULL, + sort_album_name VARCHAR DEFAULT '' NOT NULL, + sort_artist_name VARCHAR DEFAULT '' NOT NULL, + sort_album_artist_name VARCHAR DEFAULT '' NOT NULL, + sort_title VARCHAR DEFAULT '' NOT NULL, + disc_subtitle VARCHAR DEFAULT '' NOT NULL, + catalog_num VARCHAR DEFAULT '' NOT NULL, + comment VARCHAR DEFAULT '' NOT NULL, + order_title VARCHAR DEFAULT '' NOT NULL, + mbz_recording_id VARCHAR DEFAULT '' NOT NULL, + mbz_album_id VARCHAR DEFAULT '' NOT NULL, + mbz_artist_id VARCHAR DEFAULT '' NOT NULL, + mbz_album_artist_id VARCHAR DEFAULT '' NOT NULL, + mbz_album_type VARCHAR DEFAULT '' NOT NULL, + mbz_album_comment VARCHAR DEFAULT '' NOT NULL, + mbz_release_track_id VARCHAR DEFAULT '' NOT NULL, + bpm SMALLINT DEFAULT 0 NOT NULL, + channels SMALLINT DEFAULT 0 NOT NULL, + lyrics JSONB DEFAULT '[]' NOT NULL, + sample_rate INT DEFAULT 0 NOT NULL, + library_id INT DEFAULT 1 NOT NULL REFERENCES library ON DELETE CASCADE, + folder_id VARCHAR DEFAULT '' NOT NULL, + pid VARCHAR DEFAULT '' NOT NULL, + missing BOOLEAN DEFAULT FALSE NOT NULL, + mbz_release_group_id VARCHAR DEFAULT '' NOT NULL, + tags JSONB DEFAULT '{}' NOT NULL, + participants JSONB DEFAULT '{}' NOT NULL, + bit_depth SMALLINT DEFAULT 0 NOT NULL, + explicit_status VARCHAR DEFAULT '' NOT NULL, + birth_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, + rg_album_gain REAL, + rg_album_peak REAL, + rg_track_gain REAL, + rg_track_peak REAL +); + +CREATE INDEX media_file_album_artist ON media_file(album_artist); +CREATE INDEX media_file_album_id ON media_file(album_id); +CREATE INDEX media_file_artist ON media_file(artist); +CREATE INDEX media_file_artist_album_id ON media_file(album_artist_id); +CREATE INDEX media_file_artist_id ON media_file(artist_id); +CREATE INDEX media_file_bpm ON media_file(bpm); +CREATE INDEX media_file_channels ON media_file(channels); +CREATE INDEX media_file_created_at ON media_file(created_at); +CREATE INDEX media_file_duration ON media_file(duration); +CREATE INDEX media_file_genre ON media_file(genre); +CREATE INDEX media_file_mbz_track_id ON media_file(mbz_recording_id); +CREATE INDEX media_file_order_album_name ON media_file(order_album_name); +CREATE INDEX media_file_order_artist_name ON media_file(order_artist_name); +CREATE INDEX media_file_order_title ON media_file(order_title); +CREATE INDEX media_file_path ON media_file(path); +CREATE INDEX media_file_sample_rate ON media_file(sample_rate); +CREATE INDEX media_file_sort_title ON media_file(COALESCE(NULLIF(sort_title, ''), order_title)); +CREATE INDEX media_file_sort_artist_name ON media_file(COALESCE(NULLIF(sort_artist_name, ''), order_artist_name)); +CREATE INDEX media_file_sort_album_name ON media_file(COALESCE(NULLIF(sort_album_name, ''), order_album_name)); +CREATE INDEX media_file_title ON media_file(title); +CREATE INDEX media_file_track_number ON media_file(disc_number, track_number); +CREATE INDEX media_file_updated_at ON media_file(updated_at); +CREATE INDEX media_file_year ON media_file(year); +CREATE INDEX media_file_birth_time ON media_file(birth_time); +CREATE INDEX media_file_folder_id ON media_file(folder_id); +CREATE INDEX media_file_pid ON media_file(pid); +CREATE INDEX media_file_missing ON media_file(missing); +CREATE INDEX media_file_mbz_release_track_id ON media_file(mbz_release_track_id); + +-- Media File Artists (many-to-many with roles) +CREATE TABLE media_file_artists ( + media_file_id VARCHAR NOT NULL REFERENCES media_file(id) ON DELETE CASCADE, + artist_id VARCHAR NOT NULL REFERENCES artist(id) ON DELETE CASCADE, + role VARCHAR DEFAULT '' NOT NULL, + sub_role VARCHAR DEFAULT '' NOT NULL, + CONSTRAINT artist_tracks UNIQUE (artist_id, media_file_id, role, sub_role) +); + +CREATE INDEX media_file_artists_media_file_id ON media_file_artists(media_file_id); +CREATE INDEX media_file_artists_role ON media_file_artists(role); + +-- Album Artists (many-to-many with roles) +CREATE TABLE album_artists ( + album_id VARCHAR NOT NULL REFERENCES album(id) ON DELETE CASCADE, + artist_id VARCHAR NOT NULL REFERENCES artist(id) ON DELETE CASCADE, + role VARCHAR DEFAULT '' NOT NULL, + sub_role VARCHAR DEFAULT '' NOT NULL, + CONSTRAINT album_artists_ux UNIQUE (album_id, artist_id, role, sub_role) +); + +CREATE INDEX album_artists_album_id ON album_artists(album_id); +CREATE INDEX album_artists_role ON album_artists(role); + +-- Playlist table +CREATE TABLE playlist ( + id VARCHAR NOT NULL PRIMARY KEY, + name VARCHAR DEFAULT '' NOT NULL, + comment VARCHAR DEFAULT '' NOT NULL, + duration REAL DEFAULT 0 NOT NULL, + song_count INT DEFAULT 0 NOT NULL, + public BOOLEAN DEFAULT FALSE NOT NULL, + created_at TIMESTAMP, + updated_at TIMESTAMP, + path VARCHAR DEFAULT '' NOT NULL, + sync BOOLEAN DEFAULT FALSE NOT NULL, + size BIGINT DEFAULT 0 NOT NULL, + rules VARCHAR, + evaluated_at TIMESTAMP, + owner_id VARCHAR NOT NULL REFERENCES "user"(id) ON UPDATE CASCADE ON DELETE CASCADE +); + +CREATE INDEX playlist_created_at ON playlist(created_at); +CREATE INDEX playlist_evaluated_at ON playlist(evaluated_at); +CREATE INDEX playlist_name ON playlist(name); +CREATE INDEX playlist_size ON playlist(size); +CREATE INDEX playlist_updated_at ON playlist(updated_at); + +-- Playlist Tracks table +CREATE TABLE playlist_tracks ( + id INT DEFAULT 0 NOT NULL, + playlist_id VARCHAR NOT NULL REFERENCES playlist(id) ON UPDATE CASCADE ON DELETE CASCADE, + media_file_id VARCHAR NOT NULL +); + +CREATE UNIQUE INDEX playlist_tracks_pos ON playlist_tracks(playlist_id, id); + +-- Playlist Fields table (for smart playlists) +CREATE TABLE playlist_fields ( + field VARCHAR NOT NULL, + playlist_id VARCHAR NOT NULL REFERENCES playlist(id) ON UPDATE CASCADE ON DELETE CASCADE +); + +CREATE UNIQUE INDEX playlist_fields_idx ON playlist_fields(field, playlist_id); + +-- Radio table +CREATE TABLE radio ( + id VARCHAR NOT NULL PRIMARY KEY, + name VARCHAR NOT NULL UNIQUE, + stream_url VARCHAR NOT NULL, + home_page_url VARCHAR DEFAULT '' NOT NULL, + created_at TIMESTAMP, + updated_at TIMESTAMP +); + +CREATE INDEX radio_name ON radio(name); + +-- Player table +CREATE TABLE player ( + id VARCHAR NOT NULL PRIMARY KEY, + name VARCHAR NOT NULL, + user_agent VARCHAR, + user_id VARCHAR NOT NULL REFERENCES "user"(id) ON UPDATE CASCADE ON DELETE CASCADE, + client VARCHAR NOT NULL, + ip VARCHAR, + last_seen TIMESTAMP, + max_bit_rate SMALLINT DEFAULT 0, + transcoding_id VARCHAR, + report_real_path BOOLEAN DEFAULT FALSE NOT NULL, + scrobble_enabled BOOLEAN DEFAULT TRUE +); + +CREATE INDEX player_match ON player(client, user_agent, user_id); +CREATE INDEX player_name ON player(name); + +-- Annotation table (play counts, ratings, stars) +CREATE TABLE annotation ( + user_id VARCHAR NOT NULL REFERENCES "user"(id) ON DELETE CASCADE ON UPDATE CASCADE, + item_id VARCHAR DEFAULT '' NOT NULL, + item_type VARCHAR DEFAULT '' NOT NULL, + play_count BIGINT DEFAULT 0, + play_date TIMESTAMP, + rating SMALLINT DEFAULT 0, + starred BOOLEAN DEFAULT FALSE NOT NULL, + starred_at TIMESTAMP, + UNIQUE (user_id, item_id, item_type) +); + +CREATE INDEX annotation_play_count ON annotation(play_count); +CREATE INDEX annotation_play_date ON annotation(play_date); +CREATE INDEX annotation_rating ON annotation(rating); +CREATE INDEX annotation_starred ON annotation(starred); +CREATE INDEX annotation_starred_at ON annotation(starred_at); + +-- Bookmark table +CREATE TABLE bookmark ( + user_id VARCHAR NOT NULL REFERENCES "user"(id) ON UPDATE CASCADE ON DELETE CASCADE, + item_id VARCHAR NOT NULL, + item_type VARCHAR NOT NULL, + comment VARCHAR, + position BIGINT, + changed_by VARCHAR, + created_at TIMESTAMP, + updated_at TIMESTAMP, + CONSTRAINT bookmark_pk UNIQUE (user_id, item_id, item_type) +); + +-- User Properties table +CREATE TABLE user_props ( + user_id VARCHAR NOT NULL REFERENCES "user"(id) ON UPDATE CASCADE ON DELETE CASCADE, + key VARCHAR NOT NULL, + value VARCHAR, + CONSTRAINT user_props_pk PRIMARY KEY (user_id, key) +); + +-- Scrobble Buffer table +CREATE TABLE scrobble_buffer ( + id VARCHAR NOT NULL DEFAULT '' PRIMARY KEY, + user_id VARCHAR NOT NULL REFERENCES "user"(id) ON UPDATE CASCADE ON DELETE CASCADE, + service VARCHAR NOT NULL, + media_file_id VARCHAR NOT NULL REFERENCES media_file(id) ON UPDATE CASCADE ON DELETE CASCADE, + play_time TIMESTAMP NOT NULL, + enqueue_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE UNIQUE INDEX scrobble_buffer_unique ON scrobble_buffer(user_id, service, media_file_id, play_time); + +-- Share table +CREATE TABLE share ( + id VARCHAR NOT NULL PRIMARY KEY, + expires_at TIMESTAMP, + last_visited_at TIMESTAMP, + resource_ids VARCHAR NOT NULL, + created_at TIMESTAMP, + updated_at TIMESTAMP, + user_id VARCHAR NOT NULL REFERENCES "user"(id) ON UPDATE CASCADE ON DELETE CASCADE, + downloadable BOOLEAN NOT NULL DEFAULT FALSE, + description VARCHAR NOT NULL DEFAULT '', + resource_type VARCHAR NOT NULL DEFAULT '', + contents VARCHAR NOT NULL DEFAULT '', + format VARCHAR NOT NULL DEFAULT '', + max_bit_rate SMALLINT NOT NULL DEFAULT 0, + visit_count BIGINT NOT NULL DEFAULT 0 +); + +-- Playqueue table +CREATE TABLE playqueue ( + id VARCHAR NOT NULL PRIMARY KEY, + user_id VARCHAR NOT NULL REFERENCES "user"(id) ON UPDATE CASCADE ON DELETE CASCADE, + current BIGINT NOT NULL DEFAULT 0, + position REAL, + changed_by VARCHAR, + items VARCHAR, + created_at TIMESTAMP, + updated_at TIMESTAMP +); + +-- Tag table +CREATE TABLE tag ( + id VARCHAR NOT NULL PRIMARY KEY, + tag_name VARCHAR DEFAULT '' NOT NULL, + tag_value VARCHAR DEFAULT '' NOT NULL, + CONSTRAINT tags_name_value UNIQUE (tag_name, tag_value) +); + +-- Library Tag table (tag statistics per library) +CREATE TABLE library_tag ( + tag_id VARCHAR NOT NULL REFERENCES tag(id) ON DELETE CASCADE, + library_id INT NOT NULL REFERENCES library(id) ON DELETE CASCADE, + album_count INT DEFAULT 0 NOT NULL, + media_file_count BIGINT DEFAULT 0 NOT NULL, + PRIMARY KEY (tag_id, library_id) +); + +CREATE INDEX idx_library_tag_tag_id ON library_tag(tag_id); +CREATE INDEX idx_library_tag_library_id ON library_tag(library_id); + +-- User Library association table (many-to-many) +CREATE TABLE user_library ( + user_id VARCHAR NOT NULL REFERENCES "user"(id) ON DELETE CASCADE, + library_id INT NOT NULL REFERENCES library(id) ON DELETE CASCADE, + PRIMARY KEY (user_id, library_id) +); + +CREATE INDEX idx_user_library_user_id ON user_library(user_id); +CREATE INDEX idx_user_library_library_id ON user_library(library_id); + +-- Insert default library +INSERT INTO library (id, name, path, default_new_users) +VALUES (1, 'Music Library', './music', true); + +-- +goose Down +SELECT 1;