Add a data migration to ensure that the number types are migrated to text in the db schema

This fixes a problem storing some text number formats in the db when the type is integer.
This commit is contained in:
Luis Ángel San Martín 2023-10-15 12:53:30 +02:00
parent 54fc070a2e
commit f319b00c70
5 changed files with 137 additions and 88 deletions

View File

@ -14,6 +14,7 @@ Version counting is based on semantic versioning (Major.Feature.Patch)
* Improve content reloading. Navigation and selection state is no longer reseted after content changes (e.g. library updates, tags edits, etc.)
* The app will try to move comics and folders to the trash bin when deletions are requested, if the file system used doesn't support trash bin the files will be removed permanetly.
* Add menu to choose what columns are displayed in the table comics view (do a right click on the header to show it). The view has new 3 new headers to choose from (Series, Volume and Story arc).
* Migrate `number` and `arcNumber` data types to `TEXT`. This only affects databases created before 9.13 and fixes problems with some formats of numbers (e.g. 1.10).
### YACReaderLibrary
* Add `rescan-xml-info` command.

View File

@ -160,83 +160,7 @@ bool DataBaseManagement::createTables(QSqlDatabase &database)
{
// COMIC INFO (representa la información de un cómic, cada cómic tendrá un idéntificador único formado por un hash sha1'de los primeros 512kb' + su tamaño en bytes)
QSqlQuery queryComicInfo(database);
queryComicInfo.prepare("CREATE TABLE comic_info ("
"id INTEGER PRIMARY KEY,"
"title TEXT,"
"coverPage INTEGER DEFAULT 1,"
"numPages INTEGER,"
"number TEXT," // changed to text from INTEGER (9.13)
"isBis BOOLEAN,"
"count INTEGER,"
"volume TEXT,"
"storyArc TEXT,"
"arcNumber TEXT," // changed to text from INTEGER (9.13)
"arcCount INTEGER,"
"genere TEXT,"
"writer TEXT,"
"penciller TEXT,"
"inker TEXT,"
"colorist TEXT,"
"letterer TEXT,"
"coverArtist TEXT,"
"date TEXT," // publication date dd/mm/yyyy --> se mostrará en 3 campos diferentes
"publisher TEXT,"
"format TEXT,"
"color BOOLEAN,"
"ageRating TEXT,"
"synopsis TEXT,"
"characters TEXT,"
"notes TEXT,"
"hash TEXT UNIQUE NOT NULL,"
"edited BOOLEAN DEFAULT 0,"
"read BOOLEAN DEFAULT 0,"
// new 7.0 fields
"hasBeenOpened BOOLEAN DEFAULT 0,"
"rating REAL DEFAULT 0," // changed to REAL from INTEGER (9.13)
"currentPage INTEGER DEFAULT 1, "
"bookmark1 INTEGER DEFAULT -1, "
"bookmark2 INTEGER DEFAULT -1, "
"bookmark3 INTEGER DEFAULT -1, "
"brightness INTEGER DEFAULT -1, "
"contrast INTEGER DEFAULT -1, "
"gamma INTEGER DEFAULT -1, "
// new 7.1 fields
"comicVineID TEXT,"
// new 9.5 fields
"lastTimeOpened INTEGER,"
"coverSizeRatio REAL,"
"originalCoverSize STRING," // h/w
// new 9.8 fields
"manga BOOLEAN DEFAULT 0," // deprecated 9.13
// new 9.13 fields
"added INTEGER,"
"type INTEGER DEFAULT 0," // 0 = comic, 1 = manga, 2 = manga left to right, 3 = webcomic, 4 = 4koma
"editor TEXT,"
"imprint TEXT,"
"teams TEXT,"
"locations TEXT,"
"series TEXT,"
"alternateSeries TEXT,"
"alternateNumber TEXT,"
"alternateCount INTEGER,"
"languageISO TEXT,"
"seriesGroup TEXT,"
"mainCharacterOrTeam TEXT,"
"review TEXT,"
"tags TEXT"
")");
success = success && queryComicInfo.exec();
// queryComicInfo.finish();
success = success && DataBaseManagement::createComicInfoTable(database, "comic_info");
// FOLDER (representa una carpeta en disco)
QSqlQuery queryFolder(database);
@ -284,6 +208,87 @@ bool DataBaseManagement::createTables(QSqlDatabase &database)
return success;
}
bool DataBaseManagement::createComicInfoTable(QSqlDatabase &database, QString tableName)
{
QSqlQuery queryComicInfo(database);
queryComicInfo.prepare("CREATE TABLE " + tableName + " ("
"id INTEGER PRIMARY KEY,"
"title TEXT,"
"coverPage INTEGER DEFAULT 1,"
"numPages INTEGER,"
"number TEXT," // changed to text from INTEGER (9.13)
"isBis BOOLEAN,"
"count INTEGER,"
"volume TEXT,"
"storyArc TEXT,"
"arcNumber TEXT," // changed to text from INTEGER (9.13)
"arcCount INTEGER,"
"genere TEXT,"
"writer TEXT,"
"penciller TEXT,"
"inker TEXT,"
"colorist TEXT,"
"letterer TEXT,"
"coverArtist TEXT,"
"date TEXT," // publication date dd/mm/yyyy --> se mostrará en 3 campos diferentes
"publisher TEXT,"
"format TEXT,"
"color BOOLEAN,"
"ageRating TEXT,"
"synopsis TEXT,"
"characters TEXT,"
"notes TEXT,"
"hash TEXT UNIQUE NOT NULL,"
"edited BOOLEAN DEFAULT 0,"
"read BOOLEAN DEFAULT 0,"
// new 7.0 fields
"hasBeenOpened BOOLEAN DEFAULT 0,"
"rating REAL DEFAULT 0," // changed to REAL from INTEGER (9.13)
"currentPage INTEGER DEFAULT 1, "
"bookmark1 INTEGER DEFAULT -1, "
"bookmark2 INTEGER DEFAULT -1, "
"bookmark3 INTEGER DEFAULT -1, "
"brightness INTEGER DEFAULT -1, "
"contrast INTEGER DEFAULT -1, "
"gamma INTEGER DEFAULT -1, "
// new 7.1 fields
"comicVineID TEXT,"
// new 9.5 fields
"lastTimeOpened INTEGER,"
"coverSizeRatio REAL,"
"originalCoverSize STRING," // h/w
// new 9.8 fields
"manga BOOLEAN DEFAULT 0," // deprecated 9.13
// new 9.13 fields
"added INTEGER,"
"type INTEGER DEFAULT 0," // 0 = comic, 1 = manga, 2 = manga left to right, 3 = webcomic, 4 = 4koma
"editor TEXT,"
"imprint TEXT,"
"teams TEXT,"
"locations TEXT,"
"series TEXT,"
"alternateSeries TEXT,"
"alternateNumber TEXT,"
"alternateCount INTEGER,"
"languageISO TEXT,"
"seriesGroup TEXT,"
"mainCharacterOrTeam TEXT,"
"review TEXT,"
"tags TEXT"
")");
return queryComicInfo.exec();
}
bool DataBaseManagement::createV8Tables(QSqlDatabase &database)
{
bool success = true;
@ -854,6 +859,7 @@ bool DataBaseManagement::updateToCurrentVersion(const QString &path)
bool pre9_5 = false;
bool pre9_8 = false;
bool pre9_13 = false;
bool pre9_14 = false;
QString fullPath = path + "/library.ydb";
@ -869,22 +875,15 @@ bool DataBaseManagement::updateToCurrentVersion(const QString &path)
pre9_8 = true;
if (compareVersions(DataBaseManagement::checkValidDB(fullPath), "9.13.0") < 0)
pre9_13 = true;
if (compareVersions(DataBaseManagement::checkValidDB(fullPath), "9.14.0") < 0)
pre9_14 = true;
QString connectionName = "";
bool returnValue = false;
bool returnValue = true;
{
QSqlDatabase db = loadDatabaseFromFile(fullPath);
if (db.isValid() && db.isOpen()) {
QSqlQuery updateVersion(db);
updateVersion.prepare("UPDATE db_info SET "
"version = :version");
updateVersion.bindValue(":version", DB_VERSION);
updateVersion.exec();
if (updateVersion.numRowsAffected() > 0)
returnValue = true;
if (pre7) // TODO: execute only if previous version was < 7.0
{
// new 7.0 fields
@ -1041,6 +1040,52 @@ bool DataBaseManagement::updateToCurrentVersion(const QString &path)
returnValue = returnValue && successMigratingManga;
}
}
// ensure that INTEGER types migrated to TEXT are actually changed in the table definition to avoid internal type castings, this happened in 9.13 but a migration wasn't shipped with that version.
if (pre9_14) {
{
bool pre9_14_successfulMigration = true;
QSqlQuery pragmaFKOFF(db);
pragmaFKOFF.prepare("PRAGMA foreign_keys=OFF");
pre9_14_successfulMigration = pre9_14_successfulMigration && pragmaFKOFF.exec();
db.transaction();
pre9_14_successfulMigration = pre9_14_successfulMigration && createComicInfoTable(db, "comic_info_migration");
QSqlQuery copyComicInfoToComicInfoMigration(db);
copyComicInfoToComicInfoMigration.prepare("INSERT INTO comic_info_migration SELECT * FROM comic_info");
pre9_14_successfulMigration = pre9_14_successfulMigration && copyComicInfoToComicInfoMigration.exec();
QSqlQuery dropComicInfo(db);
dropComicInfo.prepare("DROP TABLE comic_info");
pre9_14_successfulMigration = pre9_14_successfulMigration && dropComicInfo.exec();
QSqlQuery renameComicInfoMigrationToComicInfo(db);
renameComicInfoMigrationToComicInfo.prepare("ALTER TABLE comic_info_migration RENAME TO comic_info");
pre9_14_successfulMigration = pre9_14_successfulMigration && renameComicInfoMigrationToComicInfo.exec();
if (pre9_14_successfulMigration)
db.commit();
else
db.rollback();
QSqlQuery pragmaFKON1("PRAGMA foreign_keys=ON", db);
returnValue = returnValue && pre9_14_successfulMigration;
}
}
if (returnValue) {
QSqlQuery updateVersion(db);
updateVersion.prepare("UPDATE db_info SET "
"version = :version");
updateVersion.bindValue(":version", DB_VERSION);
updateVersion.exec();
returnValue = updateVersion.numRowsAffected() > 0;
}
}
connectionName = db.connectionName();
}

View File

@ -49,6 +49,7 @@ public:
static QSqlDatabase loadDatabase(QString path);
static QSqlDatabase loadDatabaseFromFile(QString path);
static bool createTables(QSqlDatabase &database);
static bool createComicInfoTable(QSqlDatabase &database, QString tableName);
static bool createV8Tables(QSqlDatabase &database);
static void exportComicsInfo(QString source, QString dest);

View File

@ -10,7 +10,7 @@
// Used to check if the database needs to be updated, the version is stored in the database.
// This value is only incremented when the database structure changes.
#define DB_VERSION "9.13.1"
#define DB_VERSION "9.14.0"
#define IMPORT_COMIC_INFO_XML_METADATA "IMPORT_COMIC_INFO_XML_METADATA"
#define COMPARE_MODIFIED_DATE_ON_LIBRARY_UPDATES "COMPARE_MODIFIED_DATE_ON_LIBRARY_UPDATES"

View File

@ -58,6 +58,8 @@ YACReader::WhatsNewDialog::WhatsNewDialog(QWidget *parent)
" &#8226; Improve content reloading. Navigation and selection state is no longer reseted after content changes (e.g. library updates, tags edits, etc.).<br/>"
" &#8226; The app will try to move comics and folders to the trash bin when deletions are requested, if the file system used doesn't support trash bin the files will be removed permanetly.<br/>"
" &#8226; Add menu to choose what columns are displayed in the table comics view (do a right click on the header to show it). The view has new 3 new headers to choose from (Series, Volume and Story arc).<br/>"
" &#8226; Migrate `number` and `arcNumber` data types to `TEXT`. This only affects databases created before 9.13 and it fixes problems with some formats of numbers (e.g. 1.10).<br/>"
"<br/>"
"<span style=\"font-weight:600\">YACReaderLibraryServer</span><br/>"
" &#8226; Add `rescan-xml-info` command.<br/>"
"<br/>"