Added starred entries migration
This commit is contained in:
@@ -73,60 +73,45 @@ namespace Database::Migration
|
||||
Db& _db;
|
||||
};
|
||||
|
||||
static
|
||||
void
|
||||
doDbMigration(Session& session)
|
||||
migrateFromV5(Session& session)
|
||||
{
|
||||
static const std::string outdatedMsg {"Outdated database, please rebuild it (delete the .db file and restart)"};
|
||||
session.getDboSession().execute("DELETE FROM auth_token"); // format has changed
|
||||
}
|
||||
|
||||
ScopedNoForeignKeys noPragmaKeys {session.getDb()};
|
||||
static
|
||||
void
|
||||
migrateFromV6(Session& session)
|
||||
{
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
auto uniqueTransaction {session.createUniqueTransaction()};
|
||||
|
||||
Version version;
|
||||
try
|
||||
{
|
||||
version = VersionInfo::getOrCreate(session)->getVersion();
|
||||
LMS_LOG(DB, INFO) << "Database version = " << version << ", LMS binary version = " << LMS_DATABASE_VERSION;
|
||||
if (version == LMS_DATABASE_VERSION)
|
||||
{
|
||||
LMS_LOG(DB, DEBUG) << "Lms database version " << LMS_DATABASE_VERSION << ": up to date!";
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
LMS_LOG(DB, ERROR) << "Cannot get database version info: " << e.what();
|
||||
throw LmsException {outdatedMsg};
|
||||
}
|
||||
static
|
||||
void
|
||||
migrateFromV7(Session& session)
|
||||
{
|
||||
session.getDboSession().execute("DROP TABLE similarity_settings");
|
||||
session.getDboSession().execute("DROP TABLE similarity_settings_feature");
|
||||
session.getDboSession().execute("ALTER TABLE scan_settings ADD similarity_engine_type INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast<int>(ScanSettings::RecommendationEngineType::Clusters)) + ")");
|
||||
}
|
||||
|
||||
LMS_LOG(DB, INFO) << "Migrating database from version " << version << "...";
|
||||
static
|
||||
void
|
||||
migrateFromV8(Session& session)
|
||||
{
|
||||
// Better cover handling, need to rescan the whole files
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
|
||||
if (version == 5)
|
||||
{
|
||||
session.getDboSession().execute("DELETE FROM auth_token"); // format has changed
|
||||
}
|
||||
else if (version == 6)
|
||||
{
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
else if (version == 7)
|
||||
{
|
||||
session.getDboSession().execute("DROP TABLE similarity_settings");
|
||||
session.getDboSession().execute("DROP TABLE similarity_settings_feature");
|
||||
session.getDboSession().execute("ALTER TABLE scan_settings ADD similarity_engine_type INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast<int>(ScanSettings::RecommendationEngineType::Clusters)) + ")");
|
||||
}
|
||||
else if (version == 8)
|
||||
{
|
||||
// Better cover handling, need to rescan the whole files
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
else if (version == 9)
|
||||
{
|
||||
session.getDboSession().execute(R"(
|
||||
static
|
||||
void
|
||||
migrateFromV9(Session& session)
|
||||
{
|
||||
session.getDboSession().execute(R"(
|
||||
CREATE TABLE IF NOT EXISTS "track_bookmark" (
|
||||
"id" integer primary key autoincrement,
|
||||
"version" integer not null,
|
||||
@@ -137,78 +122,109 @@ CREATE TABLE IF NOT EXISTS "track_bookmark" (
|
||||
constraint "fk_track_bookmark_track" foreign key ("track_id") references "track" ("id") on delete cascade deferrable initially deferred,
|
||||
constraint "fk_track_bookmark_user" foreign key ("user_id") references "user" ("id") on delete cascade deferrable initially deferred
|
||||
);)");
|
||||
}
|
||||
else if (version == 10)
|
||||
{
|
||||
ScanSettings::get(session).modify()->addAudioFileExtension(".m4b");
|
||||
ScanSettings::get(session).modify()->addAudioFileExtension(".alac");
|
||||
}
|
||||
else if (version == 11)
|
||||
{
|
||||
// Sanitize bad MBID, need to rescan the whole files
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
else if (version == 12)
|
||||
{
|
||||
// Artist and release that have a badly parsed name but a MBID had no chance to updat the name
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
else if (version == 13)
|
||||
{
|
||||
// Always store UUID in lower case + better WMA parsing
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
else if (version == 14)
|
||||
{
|
||||
// SortName now set from metadata
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
else if (version == 15)
|
||||
{
|
||||
session.getDboSession().execute("ALTER TABLE user ADD ui_theme INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast<int>(User::defaultUITheme)) + ")");
|
||||
}
|
||||
else if (version == 16)
|
||||
{
|
||||
session.getDboSession().execute("ALTER TABLE track ADD total_disc INTEGER NOT NULL DEFAULT(0)");
|
||||
session.getDboSession().execute("ALTER TABLE track ADD total_track INTEGER NOT NULL DEFAULT(0)");
|
||||
}
|
||||
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
else if (version == 17)
|
||||
{
|
||||
// Drop colums total_disc/total_track from release
|
||||
session.getDboSession().execute(R"(
|
||||
static
|
||||
void
|
||||
migrateFromV10(Session& session)
|
||||
{
|
||||
ScanSettings::get(session).modify()->addAudioFileExtension(".m4b");
|
||||
ScanSettings::get(session).modify()->addAudioFileExtension(".alac");
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
migrateFromV11(Session& session)
|
||||
{
|
||||
// Sanitize bad MBID, need to rescan the whole files
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
migrateFromV12(Session& session)
|
||||
{
|
||||
// Artist and release that have a badly parsed name but a MBID had no chance to updat the name
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
migrateFromV13(Session& session)
|
||||
{
|
||||
// Always store UUID in lower case + better WMA parsing
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
migrateFromV14(Session& session)
|
||||
{
|
||||
// SortName now set from metadata
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
migrateFromV15(Session& session)
|
||||
{
|
||||
session.getDboSession().execute("ALTER TABLE user ADD ui_theme INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast<int>(User::defaultUITheme)) + ")");
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
migrateFromV16(Session& session)
|
||||
{
|
||||
session.getDboSession().execute("ALTER TABLE track ADD total_disc INTEGER NOT NULL DEFAULT(0)");
|
||||
session.getDboSession().execute("ALTER TABLE track ADD total_track INTEGER NOT NULL DEFAULT(0)");
|
||||
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
migrateFromV17(Session& session)
|
||||
{
|
||||
// Drop colums total_disc/total_track from release
|
||||
session.getDboSession().execute(R"(
|
||||
CREATE TABLE "release_backup" (
|
||||
"id" integer primary key autoincrement,
|
||||
"version" integer not null,
|
||||
"name" text not null,
|
||||
"mbid" text not null
|
||||
))");
|
||||
session.getDboSession().execute("INSERT INTO release_backup SELECT id,version,name,mbid FROM release");
|
||||
session.getDboSession().execute("DROP TABLE release");
|
||||
session.getDboSession().execute("ALTER TABLE release_backup RENAME TO release");
|
||||
session.getDboSession().execute("INSERT INTO release_backup SELECT id,version,name,mbid FROM release");
|
||||
session.getDboSession().execute("DROP TABLE release");
|
||||
session.getDboSession().execute("ALTER TABLE release_backup RENAME TO release");
|
||||
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
else if (version == 18)
|
||||
{
|
||||
session.getDboSession().execute(R"(
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void
|
||||
migrateFromV18(Session& session)
|
||||
{
|
||||
session.getDboSession().execute(R"(
|
||||
CREATE TABLE IF NOT EXISTS "subsonic_settings" (
|
||||
"id" integer primary key autoincrement,
|
||||
"version" integer not null,
|
||||
"api_enabled" boolean not null,
|
||||
"artist_list_mode" integer not null
|
||||
))");
|
||||
}
|
||||
else if (version == 19)
|
||||
{
|
||||
session.getDboSession().execute(R"(
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
migrateFromV19(Session& session)
|
||||
{
|
||||
session.getDboSession().execute(R"(
|
||||
CREATE TABLE "user_backup" (
|
||||
"id" integer primary key autoincrement,
|
||||
"version" integer not null,
|
||||
@@ -226,67 +242,96 @@ CREATE TABLE "user_backup" (
|
||||
"repeat_all" boolean not null,
|
||||
"radio" boolean not null
|
||||
))");
|
||||
session.getDboSession().execute(std::string {"INSERT INTO user_backup SELECT id, version, type, login_name, password_salt, password_hash, last_login, "}
|
||||
+ (User::defaultSubsonicTranscodeEnable ? "1" : "0")
|
||||
+ ", " + std::to_string(static_cast<int>(User::defaultSubsonicTranscodeFormat))
|
||||
+ ", " + std::to_string(User::defaultSubsonicTranscodeBitrate)
|
||||
+ ", " + std::to_string(static_cast<int>(User::defaultSubsonicArtistListMode))
|
||||
+ ", ui_theme, cur_playing_track_pos, repeat_all, radio FROM user");
|
||||
session.getDboSession().execute("DROP TABLE user");
|
||||
session.getDboSession().execute("ALTER TABLE user_backup RENAME TO user");
|
||||
}
|
||||
else if (version == 20)
|
||||
{
|
||||
session.getDboSession().execute("DROP TABLE subsonic_settings");
|
||||
}
|
||||
else if (version == 21)
|
||||
{
|
||||
session.getDboSession().execute("ALTER TABLE track ADD track_replay_gain REAL");
|
||||
session.getDboSession().execute("ALTER TABLE track ADD release_replay_gain REAL");
|
||||
session.getDboSession().execute(std::string {"INSERT INTO user_backup SELECT id, version, type, login_name, password_salt, password_hash, last_login, "}
|
||||
+ (User::defaultSubsonicTranscodeEnable ? "1" : "0")
|
||||
+ ", " + std::to_string(static_cast<int>(User::defaultSubsonicTranscodeFormat))
|
||||
+ ", " + std::to_string(User::defaultSubsonicTranscodeBitrate)
|
||||
+ ", " + std::to_string(static_cast<int>(User::defaultSubsonicArtistListMode))
|
||||
+ ", ui_theme, cur_playing_track_pos, repeat_all, radio FROM user");
|
||||
session.getDboSession().execute("DROP TABLE user");
|
||||
session.getDboSession().execute("ALTER TABLE user_backup RENAME TO user");
|
||||
}
|
||||
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
else if (version == 22)
|
||||
{
|
||||
session.getDboSession().execute("ALTER TABLE track ADD disc_subtitle TEXT NOT NULL DEFAULT ''");
|
||||
static
|
||||
void
|
||||
migrateFromV20(Session& session)
|
||||
{
|
||||
session.getDboSession().execute("DROP TABLE subsonic_settings");
|
||||
}
|
||||
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
else if (version == 23)
|
||||
{
|
||||
// Better cover detection
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
else if (version == 24)
|
||||
{
|
||||
// User's AuthMode
|
||||
session.getDboSession().execute("ALTER TABLE user ADD auth_mode INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast<int>(/*User::defaultAuthMode*/0)) + ")");
|
||||
}
|
||||
else if (version == 25)
|
||||
{
|
||||
// Better cover detection
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
else if (version == 26)
|
||||
{
|
||||
// Composer, mixer, etc. support
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
else if (version == 27)
|
||||
{
|
||||
// Composer, mixer, etc. support, now fallback on MBID tagged entries as there is no mean to provide MBID by tags for these kinf od artists
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
else if (version == 28)
|
||||
{
|
||||
// Drop Auth mode
|
||||
session.getDboSession().execute(R"(
|
||||
static
|
||||
void
|
||||
migrateFromV21(Session& session)
|
||||
{
|
||||
session.getDboSession().execute("ALTER TABLE track ADD track_replay_gain REAL");
|
||||
session.getDboSession().execute("ALTER TABLE track ADD release_replay_gain REAL");
|
||||
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void
|
||||
migrateFromV22(Session& session)
|
||||
{
|
||||
session.getDboSession().execute("ALTER TABLE track ADD disc_subtitle TEXT NOT NULL DEFAULT ''");
|
||||
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void
|
||||
migrateFromV23(Session& session)
|
||||
{
|
||||
// Better cover detection
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
migrateFromV24(Session& session)
|
||||
{
|
||||
// User's AuthMode
|
||||
session.getDboSession().execute("ALTER TABLE user ADD auth_mode INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast<int>(/*User::defaultAuthMode*/0)) + ")");
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
migrateFromV25(Session& session)
|
||||
{
|
||||
// Better cover detection
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
migrateFromV26(Session& session)
|
||||
{
|
||||
// Composer, mixer, etc. support
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
migrateFromV27(Session& session)
|
||||
{
|
||||
// Composer, mixer, etc. support, now fallback on MBID tagged entries as there is no mean to provide MBID by tags for these kinf od artists
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
migrateFromV28(Session& session)
|
||||
{
|
||||
// Drop Auth mode
|
||||
session.getDboSession().execute(R"(
|
||||
CREATE TABLE "user_backup" (
|
||||
"id" integer primary key autoincrement,
|
||||
"version" integer not null,
|
||||
@@ -304,27 +349,33 @@ CREATE TABLE "user_backup" (
|
||||
"repeat_all" boolean not null,
|
||||
"radio" boolean not null
|
||||
))");
|
||||
session.getDboSession().execute("INSERT INTO user_backup SELECT id, version, type, login_name, password_salt, password_hash, last_login, subsonic_transcode_enable, subsonic_transcode_format, subsonic_transcode_bitrate, subsonic_artist_list_mode, ui_theme, cur_playing_track_pos, repeat_all, radio FROM user");
|
||||
session.getDboSession().execute("DROP TABLE user");
|
||||
session.getDboSession().execute("ALTER TABLE user_backup RENAME TO user");
|
||||
}
|
||||
else if (version == 29)
|
||||
{
|
||||
session.getDboSession().execute("ALTER TABLE tracklist_entry ADD date_time TEXT");
|
||||
session.getDboSession().execute("ALTER TABLE user ADD listenbrainz_token TEXT");
|
||||
session.getDboSession().execute("ALTER TABLE user ADD scrobbler INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast<int>(User::defaultScrobbler)) + ")");
|
||||
session.getDboSession().execute("ALTER TABLE track ADD recording_mbid TEXT");
|
||||
session.getDboSession().execute("INSERT INTO user_backup SELECT id, version, type, login_name, password_salt, password_hash, last_login, subsonic_transcode_enable, subsonic_transcode_format, subsonic_transcode_bitrate, subsonic_artist_list_mode, ui_theme, cur_playing_track_pos, repeat_all, radio FROM user");
|
||||
session.getDboSession().execute("DROP TABLE user");
|
||||
session.getDboSession().execute("ALTER TABLE user_backup RENAME TO user");
|
||||
}
|
||||
|
||||
session.getDboSession().execute("DELETE from tracklist WHERE name = ?").bind("__played_tracks__");
|
||||
static
|
||||
void
|
||||
migrateFromV29(Session& session)
|
||||
{
|
||||
session.getDboSession().execute("ALTER TABLE tracklist_entry ADD date_time TEXT");
|
||||
session.getDboSession().execute("ALTER TABLE user ADD listenbrainz_token TEXT");
|
||||
session.getDboSession().execute("ALTER TABLE user ADD scrobbler INTEGER NOT NULL DEFAULT(" + std::to_string(static_cast<int>(User::defaultScrobbler)) + ")");
|
||||
session.getDboSession().execute("ALTER TABLE track ADD recording_mbid TEXT");
|
||||
|
||||
// MBID changes
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
else if (version == 30)
|
||||
{
|
||||
// drop "year" and "original_year" (rescan needed to convert them into dates)
|
||||
session.getDboSession().execute(R"(
|
||||
session.getDboSession().execute("DELETE from tracklist WHERE name = ?").bind("__played_tracks__");
|
||||
|
||||
// MBID changes
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
migrateFromV30(Session& session)
|
||||
{
|
||||
// drop "year" and "original_year" (rescan needed to convert them into dates)
|
||||
session.getDboSession().execute(R"(
|
||||
CREATE TABLE "track_backup" (
|
||||
"id" integer primary key autoincrement,
|
||||
"version" integer not null,
|
||||
@@ -345,22 +396,21 @@ CREATE TABLE "track_backup" (
|
||||
"release_id" bigint, total_disc INTEGER NOT NULL DEFAULT(0), total_track INTEGER NOT NULL DEFAULT(0), track_replay_gain REAL, release_replay_gain REAL, disc_subtitle TEXT NOT NULL DEFAULT '', recording_mbid TEXT,
|
||||
constraint "fk_track_release" foreign key ("release_id") references "release" ("id") on delete cascade deferrable initially deferred
|
||||
))");
|
||||
session.getDboSession().execute("INSERT INTO track_backup SELECT id, version, scan_version, track_number, disc_number, name, duration, \"1900-01-01\", \"1900-01-01\", file_path, file_last_write, file_added, has_cover, mbid, copyright, copyright_url, release_id, total_disc, total_track, track_replay_gain, release_replay_gain, disc_subtitle, recording_mbid FROM track");
|
||||
session.getDboSession().execute("DROP TABLE track");
|
||||
session.getDboSession().execute("ALTER TABLE track_backup RENAME TO track");
|
||||
session.getDboSession().execute("INSERT INTO track_backup SELECT id, version, scan_version, track_number, disc_number, name, duration, \"1900-01-01\", \"1900-01-01\", file_path, file_last_write, file_added, has_cover, mbid, copyright, copyright_url, release_id, total_disc, total_track, track_replay_gain, release_replay_gain, disc_subtitle, recording_mbid FROM track");
|
||||
session.getDboSession().execute("DROP TABLE track");
|
||||
session.getDboSession().execute("ALTER TABLE track_backup RENAME TO track");
|
||||
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
else if (version == 31)
|
||||
{
|
||||
// new star system, using dedicated ObjectSets per scrobbler
|
||||
session.getDboSession().execute("DROP TABLE user_artist_starred");
|
||||
session.getDboSession().execute("DROP TABLE user_release_starred");
|
||||
session.getDboSession().execute("DROP TABLE user_track_starred");
|
||||
// Just increment the scan version of the settings to make the next scheduled scan rescan everything
|
||||
ScanSettings::get(session).modify()->incScanVersion();
|
||||
}
|
||||
|
||||
session.getDboSession().execute(R"(
|
||||
CREATE TABLE IF NOT EXISTS "starred_artist" (
|
||||
static
|
||||
void
|
||||
migrateFromV31(Session& session)
|
||||
{
|
||||
// new star system, using dedicated entries per scrobbler and date time
|
||||
session.getDboSession().execute(R"(
|
||||
CREATE TABLE "starred_artist" (
|
||||
"id" integer primary key autoincrement,
|
||||
"version" integer not null,
|
||||
"scrobbler" integer not null,
|
||||
@@ -371,8 +421,8 @@ CREATE TABLE IF NOT EXISTS "starred_artist" (
|
||||
constraint "fk_starred_artist_user" foreign key ("user_id") references "user" ("id") on delete cascade deferrable initially deferred
|
||||
))");
|
||||
|
||||
session.getDboSession().execute(R"(
|
||||
CREATE TABLE IF NOT EXISTS "starred_release" (
|
||||
session.getDboSession().execute(R"(
|
||||
CREATE TABLE "starred_release" (
|
||||
"id" integer primary key autoincrement,
|
||||
"version" integer not null,
|
||||
"scrobbler" integer not null,
|
||||
@@ -383,8 +433,8 @@ CREATE TABLE IF NOT EXISTS "starred_release" (
|
||||
constraint "fk_starred_release_user" foreign key ("user_id") references "user" ("id") on delete cascade deferrable initially deferred
|
||||
))");
|
||||
|
||||
session.getDboSession().execute(R"(
|
||||
CREATE TABLE IF NOT EXISTS "starred_track" (
|
||||
session.getDboSession().execute(R"(
|
||||
CREATE TABLE "starred_track" (
|
||||
"id" integer primary key autoincrement,
|
||||
"version" integer not null,
|
||||
"scrobbler" integer not null,
|
||||
@@ -395,9 +445,57 @@ CREATE TABLE IF NOT EXISTS "starred_track" (
|
||||
constraint "fk_starred_track_user" foreign key ("user_id") references "user" ("id") on delete cascade deferrable initially deferred
|
||||
))");
|
||||
|
||||
// new listen system, no longer using tracklists
|
||||
session.getDboSession().execute(R"(
|
||||
CREATE TABLE IF NOT EXISTS "listen" (
|
||||
// Can't migrate using class mapping as mapping may evolve in the future
|
||||
|
||||
// use time_t to avoid rounding issues later
|
||||
const Wt::WDateTime now {Wt::WDateTime::fromTime_t(Wt::WDateTime::currentDateTime().toTime_t())};
|
||||
|
||||
std::map<IdType::ValueType, Scrobbler> userScrobblers;
|
||||
auto getScrobbler {[&](IdType::ValueType userId)
|
||||
{
|
||||
auto itScrobbler {userScrobblers.find(userId)};
|
||||
if (itScrobbler != std::cend(userScrobblers))
|
||||
return itScrobbler->second;
|
||||
|
||||
auto query {session.getDboSession().query<Scrobbler>("SELECT scrobbler FROM user WHERE id = ?").bind(userId)};
|
||||
auto [itInserted, inserted] {userScrobblers.emplace(userId, query.resultValue())};
|
||||
assert(inserted);
|
||||
return itInserted->second;
|
||||
}};
|
||||
|
||||
auto migrateStarEntries = [&session, &getScrobbler, &now](const std::string& colName, const std::string& oldTableName, const std::string& newTableName)
|
||||
{
|
||||
using UserIdObjectId = std::tuple<IdType::ValueType, IdType::ValueType>;
|
||||
|
||||
std::vector<UserIdObjectId> starredEntries;
|
||||
auto query {session.getDboSession().query<UserIdObjectId>("SELECT user_id, " + colName + " from " + oldTableName)};
|
||||
auto results {query.resultList()};
|
||||
starredEntries.reserve(results.size());
|
||||
for (const auto& entry : results)
|
||||
starredEntries.push_back(entry);
|
||||
|
||||
LMS_LOG(DB, INFO) << "Found " << starredEntries.size() << " " << colName << " to migrate";
|
||||
|
||||
for (const auto [userId, entryId] : starredEntries)
|
||||
{
|
||||
session.getDboSession().execute("INSERT INTO " + newTableName + " ('version', 'scrobbler', 'date_time', '" + colName + "', 'user_id') VALUES (?, ?, ?, ?, ?)")
|
||||
.bind(0)
|
||||
.bind(getScrobbler(userId))
|
||||
.bind(now.toString().toUTF8())
|
||||
.bind(entryId)
|
||||
.bind(userId);
|
||||
}
|
||||
|
||||
session.getDboSession().execute("DROP TABLE " + oldTableName);
|
||||
};
|
||||
|
||||
migrateStarEntries("artist_id","user_artist_starred", "starred_artist");
|
||||
migrateStarEntries("release_id","user_release_starred", "starred_release");
|
||||
migrateStarEntries("track_id","user_track_starred", "starred_track");
|
||||
|
||||
// new listen system, no longer using tracklists
|
||||
session.getDboSession().execute(R"(
|
||||
CREATE TABLE "listen" (
|
||||
"id" integer primary key autoincrement,
|
||||
"version" integer not null,
|
||||
"date_time" text,
|
||||
@@ -408,12 +506,82 @@ CREATE TABLE IF NOT EXISTS "listen" (
|
||||
constraint "fk_listen_track" foreign key ("track_id") references "track" ("id") on delete cascade deferrable initially deferred,
|
||||
constraint "fk_listen_user" foreign key ("user_id") references "user" ("id") on delete cascade deferrable initially deferred
|
||||
))");
|
||||
}
|
||||
else
|
||||
}
|
||||
|
||||
void
|
||||
doDbMigration(Session& session)
|
||||
{
|
||||
static const std::string outdatedMsg {"Outdated database, please rebuild it (delete the .db file and restart)"};
|
||||
|
||||
ScopedNoForeignKeys noPragmaKeys {session.getDb()};
|
||||
|
||||
using MigrationFunction = std::function<void(Session&)>;
|
||||
|
||||
const std::map<unsigned, MigrationFunction> migrationFunctions
|
||||
{
|
||||
{5, migrateFromV5},
|
||||
{6, migrateFromV6},
|
||||
{7, migrateFromV7},
|
||||
{8, migrateFromV8},
|
||||
{9, migrateFromV9},
|
||||
{10, migrateFromV10},
|
||||
{11, migrateFromV11},
|
||||
{12, migrateFromV12},
|
||||
{13, migrateFromV13},
|
||||
{14, migrateFromV14},
|
||||
{15, migrateFromV15},
|
||||
{16, migrateFromV16},
|
||||
{17, migrateFromV17},
|
||||
{18, migrateFromV18},
|
||||
{19, migrateFromV19},
|
||||
{20, migrateFromV20},
|
||||
{21, migrateFromV21},
|
||||
{22, migrateFromV22},
|
||||
{23, migrateFromV23},
|
||||
{24, migrateFromV24},
|
||||
{25, migrateFromV25},
|
||||
{26, migrateFromV26},
|
||||
{27, migrateFromV27},
|
||||
{28, migrateFromV28},
|
||||
{29, migrateFromV29},
|
||||
{30, migrateFromV30},
|
||||
{31, migrateFromV31},
|
||||
};
|
||||
|
||||
while (1)
|
||||
{
|
||||
auto uniqueTransaction {session.createUniqueTransaction()};
|
||||
|
||||
Version version;
|
||||
try
|
||||
{
|
||||
LMS_LOG(DB, ERROR) << "Database version " << version << " cannot be handled using migration";
|
||||
throw LmsException { LMS_DATABASE_VERSION > version ? outdatedMsg : "Server binary outdated, please upgrade it to handle this database"};
|
||||
version = VersionInfo::getOrCreate(session)->getVersion();
|
||||
LMS_LOG(DB, INFO) << "Database version = " << version << ", LMS binary version = " << LMS_DATABASE_VERSION;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
LMS_LOG(DB, ERROR) << "Cannot get database version info: " << e.what();
|
||||
throw LmsException {outdatedMsg};
|
||||
}
|
||||
|
||||
if (version == LMS_DATABASE_VERSION)
|
||||
{
|
||||
LMS_LOG(DB, DEBUG) << "Lms database version " << LMS_DATABASE_VERSION << ": up to date!";
|
||||
return;
|
||||
}
|
||||
else if (version > LMS_DATABASE_VERSION)
|
||||
{
|
||||
throw LmsException {"Server binary outdated, please upgrade it to handle this database"};
|
||||
}
|
||||
|
||||
if (version < migrationFunctions.begin()->first)
|
||||
throw LmsException {outdatedMsg};
|
||||
|
||||
LMS_LOG(DB, INFO) << "Migrating database from version " << version << "...";
|
||||
|
||||
auto itMigrationFunc {migrationFunctions.find(version)};
|
||||
assert(itMigrationFunc != std::cend(migrationFunctions));
|
||||
itMigrationFunc->second(session);
|
||||
|
||||
VersionInfo::get(session).modify()->setVersion(++version);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user