diff --git a/YACReaderLibrary/YACReaderLibrary.pro b/YACReaderLibrary/YACReaderLibrary.pro index 9a0e4bf29..b111749c6 100644 --- a/YACReaderLibrary/YACReaderLibrary.pro +++ b/YACReaderLibrary/YACReaderLibrary.pro @@ -92,6 +92,7 @@ HEADERS += comic_flow.h \ import_comics_info_dialog.h \ server_config_dialog.h \ comic_flow_widget.h \ + database_helper.h \ db_helper.h \ ./db/data_base_management.h \ ./db/folder_item.h \ @@ -171,6 +172,7 @@ SOURCES += comic_flow.cpp \ import_comics_info_dialog.cpp \ server_config_dialog.cpp \ comic_flow_widget.cpp \ + database_helper.cpp \ db_helper.cpp \ ./db/data_base_management.cpp \ ./db/folder_item.cpp \ diff --git a/YACReaderLibrary/database_helper.cpp b/YACReaderLibrary/database_helper.cpp new file mode 100644 index 000000000..0a5844c29 --- /dev/null +++ b/YACReaderLibrary/database_helper.cpp @@ -0,0 +1,33 @@ +#include "database_helper.h" + +#include "data_base_management.h" + +#include "QsLog.h" + +using namespace YACReader; + +DatabaseHolder::DatabaseHolder(const QString &path) + : DatabaseHolder { DataBaseManagement::loadDatabase(path) } +{ +} + +DatabaseHolder::DatabaseHolder(const QSqlDatabase &db) + : db { db } +{ + remover.setDb(this->db); +} + +void DatabaseHolder::Remover::setDb(const QSqlDatabase &db) +{ + connectionName = db.connectionName(); + Q_ASSERT(!connectionName.isEmpty()); +} + +DatabaseHolder::Remover::~Remover() +{ + if (connectionName.isEmpty()) { + QLOG_WARN() << "DatabaseHolder::Remover cannot remove a database: empty connection name."; + return; + } + QSqlDatabase::removeDatabase(connectionName); +} diff --git a/YACReaderLibrary/database_helper.h b/YACReaderLibrary/database_helper.h new file mode 100644 index 000000000..5430dfd6b --- /dev/null +++ b/YACReaderLibrary/database_helper.h @@ -0,0 +1,124 @@ +#ifndef DATABASE_HELPER_H +#define DATABASE_HELPER_H + +#include "comic_db.h" +#include "db_helper.h" +#include "folder.h" + +#include +#include +#include + +#include + +namespace YACReader { + +//! A RAII class that adds or adopts a QSqlDatabase connection in its constructors +//! and removes this connection via QSqlDatabase::removeDatabase() in the destructor. +class DatabaseHolder +{ +#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) + Q_DISABLE_COPY_MOVE(DatabaseHolder) +#else + Q_DISABLE_COPY(DatabaseHolder) +#endif +public: + explicit DatabaseHolder(const QString &path); + explicit DatabaseHolder(const QSqlDatabase &db); + + QSqlDatabase &operator*() { return db; } + QSqlDatabase *operator->() { return &db; } + +private: + class Remover + { + public: + void setDb(const QSqlDatabase &db); + ~Remover(); + + private: + QString connectionName; + }; + + // The order of the data members is important: remover must be destroyed after + // db to avoid the Qt warning in log - "QSqlDatabasePrivate::removeDatabase: + // connection '' is still in use, all queries will cease to work." + Remover remover; + QSqlDatabase db; +}; + +//! A wrapper around DatabaseHolder that makes access to the managed QSqlDatabase +//! object a bit more verbose, but provides convenience forwarding functions for +//! all DBHelper's member functions that take a QSqlDatabase & argument. +class DatabaseHelper +{ +public: + //! @note Access to DatabaseHolder(const QSqlDatabase &db) is intentionally + //! restricted to prevent its use by mistake. The QString constructor + //! overload is much more common and should be used most of the time. Use + //! DatabaseHolder directly if you need to load a database differently. + explicit DatabaseHelper(const QString &path) + : holder(path) { } + + QSqlDatabase &db() { return *holder; } + + // All public member functions below simply forward their arguments and db() to DBHelper. + + //objects management + //deletes + void removeFromDB(LibraryItem *item) { DBHelper::removeFromDB(item, db()); } + void removeFromDB(Folder *folder) { DBHelper::removeFromDB(folder, db()); } + void removeFromDB(ComicDB *comic) { DBHelper::removeFromDB(comic, db()); } + void removeLabelFromDB(qulonglong id) { DBHelper::removeLabelFromDB(id, db()); } + void removeListFromDB(qulonglong id) { DBHelper::removeListFromDB(id, db()); } + //logic deletes + void deleteComicsFromFavorites(const QList &comicsList) { DBHelper::deleteComicsFromFavorites(comicsList, db()); } + void deleteComicsFromLabel(const QList &comicsList, qulonglong labelId) { DBHelper::deleteComicsFromLabel(comicsList, labelId, db()); } + void deleteComicsFromReadingList(const QList &comicsList, qulonglong readingListId) { DBHelper::deleteComicsFromReadingList(comicsList, readingListId, db()); } + //inserts + qulonglong insert(Folder *folder) { return DBHelper::insert(folder, db()); } + qulonglong insert(ComicDB *comic) { return DBHelper::insert(comic, db()); } + qulonglong insertLabel(const QString &name, YACReader::LabelColors color) { return DBHelper::insertLabel(name, color, db()); } + qulonglong insertReadingList(const QString &name) { return DBHelper::insertReadingList(name, db()); } + qulonglong insertReadingSubList(const QString &name, qulonglong parentId, int ordering) { return DBHelper::insertReadingSubList(name, parentId, ordering, db()); } + void insertComicsInFavorites(const QList &comicsList) { DBHelper::insertComicsInFavorites(comicsList, db()); } + void insertComicsInLabel(const QList &comicsList, qulonglong labelId) { DBHelper::insertComicsInLabel(comicsList, labelId, db()); } + void insertComicsInReadingList(const QList &comicsList, qulonglong readingListId) { DBHelper::insertComicsInReadingList(comicsList, readingListId, db()); } + //updates + void update(ComicDB *comics) { DBHelper::update(comics, db()); } + void update(ComicInfo *comicInfo) { DBHelper::update(comicInfo, db()); } + void updateRead(ComicInfo *comicInfo) { DBHelper::updateRead(comicInfo, db()); } + void update(const Folder &folder) { DBHelper::update(folder, db()); } + void updateChildrenInfo(const Folder &folder) { DBHelper::updateChildrenInfo(folder, db()); } + void updateChildrenInfo(qulonglong folderId) { DBHelper::updateChildrenInfo(folderId, db()); } + void updateChildrenInfo() { DBHelper::updateChildrenInfo(db()); } + void updateReadingRemoteProgress(const ComicInfo &comicInfo) { DBHelper::updateReadingRemoteProgress(comicInfo, db()); } + void renameLabel(qulonglong id, const QString &name) { DBHelper::renameLabel(id, name, db()); } + void renameList(qulonglong id, const QString &name) { DBHelper::renameList(id, name, db()); } + void reassignOrderToSublists(const QList &ids) { DBHelper::reassignOrderToSublists(ids, db()); } + void reassignOrderToComicsInFavorites(const QList &comicIds) { DBHelper::reassignOrderToComicsInFavorites(comicIds, db()); } + void reassignOrderToComicsInLabel(qulonglong labelId, const QList &comicIds) { DBHelper::reassignOrderToComicsInLabel(labelId, comicIds, db()); } + void reassignOrderToComicsInReadingList(qulonglong readingListId, const QList &comicIds) { DBHelper::reassignOrderToComicsInReadingList(readingListId, comicIds, db()); } + + QList getFoldersFromParent(qulonglong parentId, bool sort = true) { return DBHelper::getFoldersFromParent(parentId, db(), sort); } + QList getSortedComicsFromParent(qulonglong parentId) { return DBHelper::getSortedComicsFromParent(parentId, db()); } + QList getComicsFromParent(qulonglong parentId, bool sort = true) { return DBHelper::getComicsFromParent(parentId, db(), sort); } + + void updateFolderTreeManga(qulonglong id, bool manga) { DBHelper::updateFolderTreeManga(id, manga, db()); } + + //load + Folder loadFolder(qulonglong id) { return DBHelper::loadFolder(id, db()); } + Folder loadFolder(const QString &folderName, qulonglong parentId) { return DBHelper::loadFolder(folderName, parentId, db()); } + ComicDB loadComic(qulonglong id) { return DBHelper::loadComic(id, db()); } + ComicDB loadComic(QString cname, QString cpath, const QString &chash) { return DBHelper::loadComic(std::move(cname), std::move(cpath), chash, db()); } + ComicInfo loadComicInfo(const QString &hash) { return DBHelper::loadComicInfo(hash, db()); } + QList loadSubfoldersNames(qulonglong folderId) { return DBHelper::loadSubfoldersNames(folderId, db()); } + //queries + bool isFavoriteComic(qulonglong id) { return DBHelper::isFavoriteComic(id, db()); } + +private: + DatabaseHolder holder; +}; +} // namespace YACReader + +#endif // DATABASE_HELPER_H diff --git a/YACReaderLibrary/db/comic_model.cpp b/YACReaderLibrary/db/comic_model.cpp index da6c8a46a..bd53a1057 100644 --- a/YACReaderLibrary/db/comic_model.cpp +++ b/YACReaderLibrary/db/comic_model.cpp @@ -158,13 +158,13 @@ bool ComicModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); switch (mode) { case Favorites: - DBHelper::reasignOrderToComicsInFavorites(allComicIds, db); + DBHelper::reassignOrderToComicsInFavorites(allComicIds, db); break; case Label: - DBHelper::reasignOrderToComicsInLabel(sourceId, allComicIds, db); + DBHelper::reassignOrderToComicsInLabel(sourceId, allComicIds, db); break; case ReadingList: - DBHelper::reasignOrderToComicsInReadingList(sourceId, allComicIds, db); + DBHelper::reassignOrderToComicsInReadingList(sourceId, allComicIds, db); break; default: break; diff --git a/YACReaderLibrary/db/comic_model.h b/YACReaderLibrary/db/comic_model.h index 4d9c05948..1203c02b5 100644 --- a/YACReaderLibrary/db/comic_model.h +++ b/YACReaderLibrary/db/comic_model.h @@ -5,7 +5,6 @@ #include #include #include -#include #include #include "yacreader_global_gui.h" diff --git a/YACReaderLibrary/db/comic_query_result_processor.cpp b/YACReaderLibrary/db/comic_query_result_processor.cpp index d00ddebbe..d76c75a98 100644 --- a/YACReaderLibrary/db/comic_query_result_processor.cpp +++ b/YACReaderLibrary/db/comic_query_result_processor.cpp @@ -9,6 +9,10 @@ #include "QsLog.h" +#include +#include +#include + QString getLastExecutedQuery(const QSqlQuery &query) { QString str = query.lastQuery(); diff --git a/YACReaderLibrary/db/data_base_management.cpp b/YACReaderLibrary/db/data_base_management.cpp index 3e41d77df..f93f773fe 100644 --- a/YACReaderLibrary/db/data_base_management.cpp +++ b/YACReaderLibrary/db/data_base_management.cpp @@ -1,12 +1,16 @@ #include "data_base_management.h" -#include #include "library_creator.h" #include "check_new_version.h" +#include "database_helper.h" #include "db_helper.h" #include "QsLog.h" +#include +#include +#include + static QString fields = "title ," "coverPage," @@ -44,27 +48,12 @@ static QString fields = "title ," "hash"; -DataBaseManagement::DataBaseManagement() - : QObject(), dataBasesList() -{ -} - -/*TreeModel * DataBaseManagement::newTreeModel(QString path) -{ - //la consulta se ejecuta... - QSqlQuery selectQuery(loadDatabase(path)); - selectQuery.setForwardOnly(true); - selectQuery.exec("select * from folder order by parentId,name"); - //selectQuery.finish(); - return new TreeModel(selectQuery); -}*/ - -QSqlDatabase DataBaseManagement::createDatabase(QString name, QString path) +QSqlDatabase DataBaseManagement::createDatabase(const QString &name, const QString &path) { return createDatabase(QDir::cleanPath(path) + "/" + name + ".ydb"); } -QSqlDatabase DataBaseManagement::createDatabase(QString dest) +QSqlDatabase DataBaseManagement::createDatabase(const QString &dest) { QString threadId = QString::number((long long)QThread::currentThreadId(), 16); QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", dest + threadId); @@ -90,7 +79,7 @@ QSqlDatabase DataBaseManagement::createDatabase(QString dest) return db; } -QSqlDatabase DataBaseManagement::loadDatabase(QString path) +QSqlDatabase DataBaseManagement::loadDatabase(const QString &path) { //TODO check path QString threadId = QString::number((long long)QThread::currentThreadId(), 16); @@ -104,7 +93,7 @@ QSqlDatabase DataBaseManagement::loadDatabase(QString path) return db; } -QSqlDatabase DataBaseManagement::loadDatabaseFromFile(QString filePath) +QSqlDatabase DataBaseManagement::loadDatabaseFromFile(const QString &filePath) { //TODO check path QString threadId = QString::number((long long)QThread::currentThreadId(), 16); @@ -319,240 +308,218 @@ bool DataBaseManagement::createV8Tables(QSqlDatabase &database) return success; } -void DataBaseManagement::exportComicsInfo(QString source, QString dest) +void DataBaseManagement::exportComicsInfo(const QString &source, const QString &dest) { - QString connectionName = ""; - { - QSqlDatabase destDB = loadDatabaseFromFile(dest); + YACReader::DatabaseHolder destDB(loadDatabaseFromFile(dest)); - QSqlQuery attach(destDB); - attach.prepare("ATTACH DATABASE '" + QDir().toNativeSeparators(dest) + "' AS dest;"); - attach.exec(); + QSqlQuery attach(*destDB); + attach.prepare("ATTACH DATABASE '" + QDir().toNativeSeparators(dest) + "' AS dest;"); + attach.exec(); - QSqlQuery attach2(destDB); - attach2.prepare("ATTACH DATABASE '" + QDir().toNativeSeparators(source) + "' AS source;"); - attach2.exec(); + QSqlQuery attach2(*destDB); + attach2.prepare("ATTACH DATABASE '" + QDir().toNativeSeparators(source) + "' AS source;"); + attach2.exec(); - QSqlQuery queryDBInfo(destDB); - queryDBInfo.prepare("CREATE TABLE dest.db_info (version TEXT NOT NULL)"); - queryDBInfo.exec(); + QSqlQuery queryDBInfo(*destDB); + queryDBInfo.prepare("CREATE TABLE dest.db_info (version TEXT NOT NULL)"); + queryDBInfo.exec(); - QSqlQuery query("INSERT INTO dest.db_info (version) " - "VALUES ('" VERSION "')", - destDB); + QSqlQuery query("INSERT INTO dest.db_info (version) " + "VALUES ('" VERSION "')", + *destDB); - QSqlQuery exportData(destDB); - exportData.prepare("create table dest.comic_info as select " + fields + - " from source.comic_info where source.comic_info.edited = 1"); - exportData.exec(); - connectionName = destDB.connectionName(); - } - - QSqlDatabase::removeDatabase(connectionName); + QSqlQuery exportData(*destDB); + exportData.prepare("create table dest.comic_info as select " + fields + + " from source.comic_info where source.comic_info.edited = 1"); + exportData.exec(); } -bool DataBaseManagement::importComicsInfo(QString source, QString dest) +void DataBaseManagement::importComicsInfo(const QString &source, const QString &dest) { - QString error; - QString driver; QStringList hashes; - bool b = false; + YACReader::DatabaseHolder sourceDB(loadDatabaseFromFile(source)); + YACReader::DatabaseHolder destDB(loadDatabaseFromFile(dest)); - QString sourceDBconnection = ""; - QString destDBconnection = ""; + QSqlQuery pragma("PRAGMA synchronous=OFF", *destDB); + QSqlQuery newInfo(*sourceDB); + newInfo.prepare("SELECT * FROM comic_info"); + newInfo.exec(); + destDB->transaction(); + int cp; + while (newInfo.next()) //cada tupla deberá ser insertada o actualizada { - QSqlDatabase sourceDB = loadDatabaseFromFile(source); - QSqlDatabase destDB = loadDatabaseFromFile(dest); - - QSqlQuery pragma("PRAGMA synchronous=OFF", destDB); - - QSqlQuery newInfo(sourceDB); - newInfo.prepare("SELECT * FROM comic_info"); - newInfo.exec(); - destDB.transaction(); - int cp; - while (newInfo.next()) //cada tupla deberá ser insertada o actualizada - { - QSqlQuery update(destDB); - update.prepare("UPDATE comic_info SET " - "title = :title," - - "coverPage = :coverPage," - "numPages = :numPages," - - "number = :number," - "isBis = :isBis," - "count = :count," - - "volume = :volume," - "storyArc = :storyArc," - "arcNumber = :arcNumber," - "arcCount = :arcCount," - - "genere = :genere," - - "writer = :writer," - "penciller = :penciller," - "inker = :inker," - "colorist = :colorist," - "letterer = :letterer," - "coverArtist = :coverArtist," - - "date = :date," - "publisher = :publisher," - "format = :format," - "color = :color," - "ageRating = :ageRating," - "manga = :manga" - - "synopsis = :synopsis," - "characters = :characters," - "notes = :notes," - - "edited = :edited," - - "comicVineID = :comicVineID," - - "lastTimeOpened = :lastTimeOpened," - - "coverSizeRatio = :coverSizeRatio," - "originalCoverSize = :originalCoverSize" - - " WHERE hash = :hash "); - - QSqlQuery insert(destDB); - insert.prepare("INSERT INTO comic_info " - "(title," - "coverPage," - "numPages," - "number," - "isBis," - "count," - "volume," - "storyArc," - "arcNumber," - "arcCount," - "genere," - "writer," - "penciller," - "inker," - "colorist," - "letterer," - "coverArtist," - "date," - "publisher," - "format," - "color," - "ageRating," - "synopsis," - "characters," - "notes," - "read," - "edited," - "comicVineID," - "lastTimeOpened," - "coverSizeRatio," - "hash)" - - "VALUES (:title," - ":coverPage," - ":numPages," - ":number," - ":isBis," - ":count," - - ":volume," - ":storyArc," - ":arcNumber," - ":arcCount," - - ":genere," - - ":writer," - ":penciller," - ":inker," - ":colorist," - ":letterer," - ":coverArtist," - - ":date," - ":publisher," - ":format," - ":color," - ":ageRating," - ":manga," - - ":synopsis," - ":characters," - ":notes," - - ":read," - ":edited," - ":comicVineID," - - ":lastTimeOpened," - - ":coverSizeRatio," - ":originalCoverSize," - - ":hash )"); - - QSqlRecord record = newInfo.record(); - cp = record.value("coverPage").toInt(); - if (cp > 1) { - QSqlQuery checkCoverPage(destDB); - checkCoverPage.prepare("SELECT coverPage FROM comic_info where hash = :hash"); - checkCoverPage.bindValue(":hash", record.value("hash").toString()); - checkCoverPage.exec(); - bool extract = false; - if (checkCoverPage.next()) { - extract = checkCoverPage.record().value("coverPage").toInt() != cp; - } - if (extract) - hashes.append(record.value("hash").toString()); + QSqlQuery update(*destDB); + update.prepare("UPDATE comic_info SET " + "title = :title," + + "coverPage = :coverPage," + "numPages = :numPages," + + "number = :number," + "isBis = :isBis," + "count = :count," + + "volume = :volume," + "storyArc = :storyArc," + "arcNumber = :arcNumber," + "arcCount = :arcCount," + + "genere = :genere," + + "writer = :writer," + "penciller = :penciller," + "inker = :inker," + "colorist = :colorist," + "letterer = :letterer," + "coverArtist = :coverArtist," + + "date = :date," + "publisher = :publisher," + "format = :format," + "color = :color," + "ageRating = :ageRating," + "manga = :manga" + + "synopsis = :synopsis," + "characters = :characters," + "notes = :notes," + + "edited = :edited," + + "comicVineID = :comicVineID," + + "lastTimeOpened = :lastTimeOpened," + + "coverSizeRatio = :coverSizeRatio," + "originalCoverSize = :originalCoverSize" + + " WHERE hash = :hash "); + + QSqlQuery insert(*destDB); + insert.prepare("INSERT INTO comic_info " + "(title," + "coverPage," + "numPages," + "number," + "isBis," + "count," + "volume," + "storyArc," + "arcNumber," + "arcCount," + "genere," + "writer," + "penciller," + "inker," + "colorist," + "letterer," + "coverArtist," + "date," + "publisher," + "format," + "color," + "ageRating," + "synopsis," + "characters," + "notes," + "read," + "edited," + "comicVineID," + "lastTimeOpened," + "coverSizeRatio," + "hash)" + + "VALUES (:title," + ":coverPage," + ":numPages," + ":number," + ":isBis," + ":count," + + ":volume," + ":storyArc," + ":arcNumber," + ":arcCount," + + ":genere," + + ":writer," + ":penciller," + ":inker," + ":colorist," + ":letterer," + ":coverArtist," + + ":date," + ":publisher," + ":format," + ":color," + ":ageRating," + ":manga," + + ":synopsis," + ":characters," + ":notes," + + ":read," + ":edited," + ":comicVineID," + + ":lastTimeOpened," + + ":coverSizeRatio," + ":originalCoverSize," + + ":hash )"); + + QSqlRecord record = newInfo.record(); + cp = record.value("coverPage").toInt(); + if (cp > 1) { + QSqlQuery checkCoverPage(*destDB); + checkCoverPage.prepare("SELECT coverPage FROM comic_info where hash = :hash"); + checkCoverPage.bindValue(":hash", record.value("hash").toString()); + checkCoverPage.exec(); + bool extract = false; + if (checkCoverPage.next()) { + extract = checkCoverPage.record().value("coverPage").toInt() != cp; } + if (extract) + hashes.append(record.value("hash").toString()); + } - bindValuesFromRecord(record, update); + bindValuesFromRecord(record, update); - update.bindValue(":edited", 1); + update.bindValue(":edited", 1); - update.exec(); + update.exec(); - if (update.numRowsAffected() == 0) { + if (update.numRowsAffected() == 0) { - bindValuesFromRecord(record, insert); - insert.bindValue(":edited", 1); - insert.bindValue(":read", 0); + bindValuesFromRecord(record, insert); + insert.bindValue(":edited", 1); + insert.bindValue(":read", 0); - insert.exec(); - } + insert.exec(); } + } - destDB.commit(); - QString hash; - foreach (hash, hashes) { - QSqlQuery getComic(destDB); - getComic.prepare("SELECT c.path,ci.coverPage FROM comic c INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) where ci.hash = :hash"); - getComic.bindValue(":hash", hash); - getComic.exec(); - if (getComic.next()) { - QString basePath = QString(dest).remove("/.yacreaderlibrary/library.ydb"); - QString path = basePath + getComic.record().value("path").toString(); - int coverPage = getComic.record().value("coverPage").toInt(); - ThumbnailCreator tc(path, basePath + "/.yacreaderlibrary/covers/" + hash + ".jpg", coverPage); - tc.create(); - } + destDB->commit(); + QString hash; + foreach (hash, hashes) { + QSqlQuery getComic(*destDB); + getComic.prepare("SELECT c.path,ci.coverPage FROM comic c INNER JOIN comic_info ci ON (c.comicInfoId = ci.id) where ci.hash = :hash"); + getComic.bindValue(":hash", hash); + getComic.exec(); + if (getComic.next()) { + QString basePath = QString(dest).remove("/.yacreaderlibrary/library.ydb"); + QString path = basePath + getComic.record().value("path").toString(); + int coverPage = getComic.record().value("coverPage").toInt(); + ThumbnailCreator tc(path, basePath + "/.yacreaderlibrary/covers/" + hash + ".jpg", coverPage); + tc.create(); } - sourceDBconnection = sourceDB.connectionName(); - destDBconnection = sourceDB.connectionName(); } - - QSqlDatabase::removeDatabase(sourceDBconnection); - QSqlDatabase::removeDatabase(destDBconnection); - - return b; } //TODO fix these bindings void DataBaseManagement::bindValuesFromRecord(const QSqlRecord &record, QSqlQuery &query) @@ -656,25 +623,15 @@ void DataBaseManagement::bindDouble(const QString &name, const QSqlRecord &recor QString DataBaseManagement::checkValidDB(const QString &fullPath) { - QString versionString = ""; - QString connectionName = ""; - { - QSqlDatabase db = loadDatabaseFromFile(fullPath); - - if (db.isValid() && db.isOpen()) { - QSqlQuery version(db); - version.prepare("SELECT * FROM db_info"); - version.exec(); - - if (version.next()) - versionString = version.record().value("version").toString(); - } - connectionName = db.connectionName(); + YACReader::DatabaseHolder db(loadDatabaseFromFile(fullPath)); + if (db->isValid() && db->isOpen()) { + QSqlQuery version(*db); + version.prepare("SELECT * FROM db_info"); + version.exec(); + if (version.next()) + return version.record().value("version").toString(); } - - QSqlDatabase::removeDatabase(connectionName); - - return versionString; + return QString(); } int DataBaseManagement::compareVersions(const QString &v1, const QString v2) @@ -728,135 +685,130 @@ bool DataBaseManagement::updateToCurrentVersion(const QString &path) if (compareVersions(DataBaseManagement::checkValidDB(fullPath), "9.8.0") < 0) pre9_8 = true; - QString connectionName = ""; bool returnValue = false; - { - QSqlDatabase db = loadDatabaseFromFile(fullPath); - if (db.isValid() && db.isOpen()) { - QSqlQuery updateVersion(db); - updateVersion.prepare("UPDATE db_info SET " - "version = :version"); - updateVersion.bindValue(":version", VERSION); - updateVersion.exec(); - - if (updateVersion.numRowsAffected() > 0) - returnValue = true; - - if (pre7) //TODO: execute only if previous version was < 7.0 + YACReader::DatabaseHolder db(loadDatabaseFromFile(fullPath)); + if (db->isValid() && db->isOpen()) { + QSqlQuery updateVersion(*db); + updateVersion.prepare("UPDATE db_info SET " + "version = :version"); + updateVersion.bindValue(":version", VERSION); + updateVersion.exec(); + + if (updateVersion.numRowsAffected() > 0) + returnValue = true; + + if (pre7) //TODO: execute only if previous version was < 7.0 + { + //new 7.0 fields + QStringList columnDefs; + columnDefs << "hasBeenOpened BOOLEAN DEFAULT 0" + << "rating INTEGER DEFAULT 0" + << "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"; + + bool successAddingColumns = addColumns("comic_info", columnDefs, *db); + returnValue = returnValue && successAddingColumns; + } + //TODO update hasBeenOpened value + + if (pre7_1) { { - //new 7.0 fields QStringList columnDefs; - columnDefs << "hasBeenOpened BOOLEAN DEFAULT 0" - << "rating INTEGER DEFAULT 0" - << "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"; - - bool successAddingColumns = addColumns("comic_info", columnDefs, db); + columnDefs << "finished BOOLEAN DEFAULT 0" + << "completed BOOLEAN DEFAULT 1"; + bool successAddingColumns = addColumns("folder", columnDefs, *db); returnValue = returnValue && successAddingColumns; } - //TODO update hasBeenOpened value - - if (pre7_1) { - { - QStringList columnDefs; - columnDefs << "finished BOOLEAN DEFAULT 0" - << "completed BOOLEAN DEFAULT 1"; - bool successAddingColumns = addColumns("folder", columnDefs, db); - returnValue = returnValue && successAddingColumns; - } - { //comic_info - QStringList columnDefs; - columnDefs << "comicVineID TEXT DEFAULT NULL"; - bool successAddingColumns = addColumns("comic_info", columnDefs, db); - returnValue = returnValue && successAddingColumns; - } + { //comic_info + QStringList columnDefs; + columnDefs << "comicVineID TEXT DEFAULT NULL"; + bool successAddingColumns = addColumns("comic_info", columnDefs, *db); + returnValue = returnValue && successAddingColumns; } + } - if (pre8) { - bool successCreatingNewTables = createV8Tables(db); - returnValue = returnValue && successCreatingNewTables; - } + if (pre8) { + bool successCreatingNewTables = createV8Tables(*db); + returnValue = returnValue && successCreatingNewTables; + } - if (pre9_5) { - { //folder - QStringList columnDefs; - //a full library update is needed after updating the table - columnDefs << "numChildren INTEGER"; - columnDefs << "firstChildHash TEXT"; - columnDefs << "customImage TEXT"; - bool successAddingColumns = addColumns("folder", columnDefs, db); - returnValue = returnValue && successAddingColumns; - } + if (pre9_5) { + { //folder + QStringList columnDefs; + //a full library update is needed after updating the table + columnDefs << "numChildren INTEGER"; + columnDefs << "firstChildHash TEXT"; + columnDefs << "customImage TEXT"; + bool successAddingColumns = addColumns("folder", columnDefs, *db); + returnValue = returnValue && successAddingColumns; + } - { //comic_info - QStringList columnDefs; - columnDefs << "lastTimeOpened INTEGER"; - columnDefs << "coverSizeRatio REAL"; - columnDefs << "originalCoverSize TEXT"; - bool successAddingColumns = addColumns("comic_info", columnDefs, db); - returnValue = returnValue && successAddingColumns; - - QSqlQuery queryIndexLastTimeOpened(db); - bool successCreatingIndex = queryIndexLastTimeOpened.exec("CREATE INDEX last_time_opened_index ON comic_info (lastTimeOpened)"); - returnValue = returnValue && successCreatingIndex; - } + { //comic_info + QStringList columnDefs; + columnDefs << "lastTimeOpened INTEGER"; + columnDefs << "coverSizeRatio REAL"; + columnDefs << "originalCoverSize TEXT"; + bool successAddingColumns = addColumns("comic_info", columnDefs, *db); + returnValue = returnValue && successAddingColumns; - //update folders info - { - DBHelper::updateChildrenInfo(db); - } + QSqlQuery queryIndexLastTimeOpened(*db); + bool successCreatingIndex = queryIndexLastTimeOpened.exec("CREATE INDEX last_time_opened_index ON comic_info (lastTimeOpened)"); + returnValue = returnValue && successCreatingIndex; + } - { - QSqlQuery selectQuery(db); - selectQuery.prepare("SELECT id, hash FROM comic_info"); - selectQuery.exec(); + //update folders info + { + DBHelper::updateChildrenInfo(*db); + } - db.transaction(); + { + QSqlQuery selectQuery(*db); + selectQuery.prepare("SELECT id, hash FROM comic_info"); + selectQuery.exec(); - QSqlQuery updateCoverInfo(db); - updateCoverInfo.prepare("UPDATE comic_info SET coverSizeRatio = :coverSizeRatio WHERE id = :id"); + db->transaction(); - QImageReader thumbnail; - while (selectQuery.next()) { - thumbnail.setFileName(path % "/covers/" % selectQuery.value(1).toString() % ".jpg"); + QSqlQuery updateCoverInfo(*db); + updateCoverInfo.prepare("UPDATE comic_info SET coverSizeRatio = :coverSizeRatio WHERE id = :id"); - float coverSizeRatio = static_cast(thumbnail.size().width()) / thumbnail.size().height(); - updateCoverInfo.bindValue(":coverSizeRatio", coverSizeRatio); - updateCoverInfo.bindValue(":id", selectQuery.value(0)); + QImageReader thumbnail; + while (selectQuery.next()) { + thumbnail.setFileName(path % "/covers/" % selectQuery.value(1).toString() % ".jpg"); - updateCoverInfo.exec(); - } + float coverSizeRatio = static_cast(thumbnail.size().width()) / thumbnail.size().height(); + updateCoverInfo.bindValue(":coverSizeRatio", coverSizeRatio); + updateCoverInfo.bindValue(":id", selectQuery.value(0)); - db.commit(); + updateCoverInfo.exec(); } + + db->commit(); } + } - if (pre9_8) { - { //comic_info - QStringList columnDefs; - columnDefs << "manga BOOLEAN DEFAULT 0"; - bool successAddingColumns = addColumns("comic_info", columnDefs, db); - returnValue = returnValue && successAddingColumns; - } - { //folder - QStringList columnDefs; - columnDefs << "manga BOOLEAN DEFAULT 0"; - bool successAddingColumns = addColumns("folder", columnDefs, db); - returnValue = returnValue && successAddingColumns; - } + if (pre9_8) { + { //comic_info + QStringList columnDefs; + columnDefs << "manga BOOLEAN DEFAULT 0"; + bool successAddingColumns = addColumns("comic_info", columnDefs, *db); + returnValue = returnValue && successAddingColumns; + } + { //folder + QStringList columnDefs; + columnDefs << "manga BOOLEAN DEFAULT 0"; + bool successAddingColumns = addColumns("folder", columnDefs, *db); + returnValue = returnValue && successAddingColumns; } } - connectionName = db.connectionName(); } - QSqlDatabase::removeDatabase(connectionName); return returnValue; } diff --git a/YACReaderLibrary/db/data_base_management.h b/YACReaderLibrary/db/data_base_management.h index 3eac4a404..06ea19ef8 100644 --- a/YACReaderLibrary/db/data_base_management.h +++ b/YACReaderLibrary/db/data_base_management.h @@ -1,11 +1,13 @@ #ifndef __DATA_BASE_MANAGEMENT_H #define __DATA_BASE_MANAGEMENT_H -#include -#include #include - -#include "folder_model.h" +#include +#include +#include +#include +#include +#include class ComicsInfoExporter : public QThread { @@ -29,11 +31,9 @@ class ComicsInfoImporter : public QThread void run() override; }; -class DataBaseManagement : public QObject +class DataBaseManagement { - Q_OBJECT private: - QList dataBasesList; static void bindString(const QString &name, const QSqlRecord &record, QSqlQuery &query); static void bindInt(const QString &name, const QSqlRecord &record, QSqlQuery &query); static void bindDouble(const QString &name, const QSqlRecord &record, QSqlQuery &query); @@ -43,19 +43,17 @@ class DataBaseManagement : public QObject static bool addConstraint(const QString &tableName, const QString &constraint, const QSqlDatabase &db); public: - DataBaseManagement(); - //TreeModel * newTreeModel(QString path); //crea una base de datos y todas sus tablas - static QSqlDatabase createDatabase(QString name, QString path); - static QSqlDatabase createDatabase(QString dest); + static QSqlDatabase createDatabase(const QString &name, const QString &path); + static QSqlDatabase createDatabase(const QString &dest); //carga una base de datos desde la ruta path - static QSqlDatabase loadDatabase(QString path); - static QSqlDatabase loadDatabaseFromFile(QString path); + static QSqlDatabase loadDatabase(const QString &path); + static QSqlDatabase loadDatabaseFromFile(const QString &path); static bool createTables(QSqlDatabase &database); static bool createV8Tables(QSqlDatabase &database); - static void exportComicsInfo(QString source, QString dest); - static bool importComicsInfo(QString source, QString dest); + static void exportComicsInfo(const QString &source, const QString &dest); + static void importComicsInfo(const QString &source, const QString &dest); static QString checkValidDB(const QString &fullPath); //retorna "" si la DB es inválida ó la versión si es válida. static int compareVersions(const QString &v1, const QString v2); //retorna <0 si v1 < v2, 0 si v1 = v2 y >0 si v1 > v2 diff --git a/YACReaderLibrary/db/folder_model.cpp b/YACReaderLibrary/db/folder_model.cpp index 35271125a..5a9616fb9 100644 --- a/YACReaderLibrary/db/folder_model.cpp +++ b/YACReaderLibrary/db/folder_model.cpp @@ -385,7 +385,7 @@ void FolderModel::updateFolderManga(const QModelIndexList &list, bool manga) setManga(item, manga); - DBHelper::updateFolderTreeManga(item->id, db, manga); + DBHelper::updateFolderTreeManga(item->id, manga, db); } db.commit(); connectionName = db.connectionName(); diff --git a/YACReaderLibrary/db/folder_model.h b/YACReaderLibrary/db/folder_model.h index 8eb19af17..fdd1cc2ae 100644 --- a/YACReaderLibrary/db/folder_model.h +++ b/YACReaderLibrary/db/folder_model.h @@ -6,7 +6,6 @@ #include #include #include -#include #include "yacreader_global.h" #include "folder_query_result_processor.h" diff --git a/YACReaderLibrary/db/folder_query_result_processor.cpp b/YACReaderLibrary/db/folder_query_result_processor.cpp index 3cbde4547..fd7f41a09 100644 --- a/YACReaderLibrary/db/folder_query_result_processor.cpp +++ b/YACReaderLibrary/db/folder_query_result_processor.cpp @@ -9,8 +9,10 @@ #include "QsLog.h" -#include #include +#include +#include +#include //Copy/pasted from "folder_model.cpp" #define ROOT 1 diff --git a/YACReaderLibrary/db/reading_list_model.cpp b/YACReaderLibrary/db/reading_list_model.cpp index 5f3012572..bcb989c46 100644 --- a/YACReaderLibrary/db/reading_list_model.cpp +++ b/YACReaderLibrary/db/reading_list_model.cpp @@ -4,6 +4,7 @@ #include "data_base_management.h" #include "qnaturalsorting.h" +#include "database_helper.h" #include "db_helper.h" #include "QsLog.h" @@ -352,20 +353,20 @@ void ReadingListModel::setupReadingListsData(QString path) cleanAll(); _databasePath = path; - QSqlDatabase db = DataBaseManagement::loadDatabase(path); + YACReader::DatabaseHolder db(path); //setup special lists - specialLists = setupSpecialLists(db); + specialLists = setupSpecialLists(*db); //separator-------------------------------------------- //setup labels - setupLabels(db); + setupLabels(*db); //separator-------------------------------------------- //setup reading list - setupReadingLists(db); + setupReadingLists(*db); endResetModel(); } @@ -476,65 +477,55 @@ void ReadingListModel::rename(const QModelIndex &mi, const QString &name) { if (!isEditable(mi)) return; - QString connectionName = ""; - { - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - - auto item = static_cast(mi.internalPointer()); + YACReader::DatabaseHelper dbh(_databasePath); - if (typeid(*item) == typeid(ReadingListItem)) { - auto rli = static_cast(item); - rli->setName(name); - DBHelper::renameList(item->getId(), name, db); - - if (rli->parent->getId() != 0) { - //TODO - //move row depending on the name - } else - emit dataChanged(index(mi.row(), 0), index(mi.row(), 0)); - } else if (typeid(*item) == typeid(LabelItem)) { - auto li = static_cast(item); - li->setName(name); - DBHelper::renameLabel(item->getId(), name, db); + auto item = static_cast(mi.internalPointer()); + if (typeid(*item) == typeid(ReadingListItem)) { + auto rli = static_cast(item); + rli->setName(name); + dbh.renameList(item->getId(), name); + + if (rli->parent->getId() != 0) { + //TODO + //move row depending on the name + } else emit dataChanged(index(mi.row(), 0), index(mi.row(), 0)); - } - connectionName = db.connectionName(); + } else if (typeid(*item) == typeid(LabelItem)) { + auto li = static_cast(item); + li->setName(name); + dbh.renameLabel(item->getId(), name); + emit dataChanged(index(mi.row(), 0), index(mi.row(), 0)); } - QSqlDatabase::removeDatabase(connectionName); } void ReadingListModel::deleteItem(const QModelIndex &mi) { - if (isEditable(mi)) { - QLOG_DEBUG() << "parent row :" << mi.parent().data() << "-" << mi.row(); - beginRemoveRows(mi.parent(), mi.row(), mi.row()); - QString connectionName = ""; - { - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - - auto item = static_cast(mi.internalPointer()); - - if (typeid(*item) == typeid(ReadingListItem)) { - auto rli = static_cast(item); - QLOG_DEBUG() << "num children : " << rli->parent->childCount(); - rli->parent->removeChild(rli); - QLOG_DEBUG() << "num children : " << rli->parent->childCount(); - DBHelper::removeListFromDB(item->getId(), db); - if (rli->parent->getId() != 0) { - reorderingChildren(rli->parent->children()); - } - QLOG_DEBUG() << "num children : " << rli->parent->childCount(); - } else if (typeid(*item) == typeid(LabelItem)) { - auto li = static_cast(item); - labels.removeOne(li); - DBHelper::removeLabelFromDB(item->getId(), db); - } - connectionName = db.connectionName(); - } - QSqlDatabase::removeDatabase(connectionName); + if (!isEditable(mi)) + return; + + QLOG_DEBUG() << "parent row :" << mi.parent().data() << "-" << mi.row(); + beginRemoveRows(mi.parent(), mi.row(), mi.row()); - endRemoveRows(); + YACReader::DatabaseHelper dbh(_databasePath); + + auto item = static_cast(mi.internalPointer()); + if (typeid(*item) == typeid(ReadingListItem)) { + auto rli = static_cast(item); + QLOG_DEBUG() << "num children : " << rli->parent->childCount(); + rli->parent->removeChild(rli); + QLOG_DEBUG() << "num children : " << rli->parent->childCount(); + dbh.removeListFromDB(item->getId()); + if (rli->parent->getId() != 0) { + reorderingChildren(rli->parent->children()); + } + QLOG_DEBUG() << "num children : " << rli->parent->childCount(); + } else if (typeid(*item) == typeid(LabelItem)) { + auto li = static_cast(item); + labels.removeOne(li); + dbh.removeLabelFromDB(item->getId()); } + + endRemoveRows(); } const QList ReadingListModel::getLabels() @@ -708,13 +699,8 @@ void ReadingListModel::reorderingChildren(QList children) item->setOrdering(i++); childrenIds << item->getId(); } - QString connectionName = ""; - { - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - DBHelper::reasignOrderToSublists(childrenIds, db); - connectionName = db.connectionName(); - } - QSqlDatabase::removeDatabase(connectionName); + YACReader::DatabaseHelper dbh(_databasePath); + dbh.reassignOrderToSublists(childrenIds); } bool ReadingListModel::rowIsSpecialList(int row, const QModelIndex &parent) const diff --git a/YACReaderLibrary/db_helper.cpp b/YACReaderLibrary/db_helper.cpp index 3a0107560..132c6cea8 100644 --- a/YACReaderLibrary/db_helper.cpp +++ b/YACReaderLibrary/db_helper.cpp @@ -9,11 +9,12 @@ #include #include #include +#include #include #include #include -#include +#include #include "reading_list.h" #include "library_item.h" @@ -1003,7 +1004,7 @@ void DBHelper::renameList(qulonglong id, const QString &name, QSqlDatabase &db) renameLabelQuery.exec(); } -void DBHelper::reasignOrderToSublists(QList ids, QSqlDatabase &db) +void DBHelper::reassignOrderToSublists(const QList &ids, QSqlDatabase &db) { QSqlQuery updateOrdering(db); updateOrdering.prepare("UPDATE reading_list SET " @@ -1011,7 +1012,7 @@ void DBHelper::reasignOrderToSublists(QList ids, QSqlDatabase &db) "WHERE id = :id"); db.transaction(); int order = 0; - foreach (qulonglong id, ids) { + for (auto id : ids) { updateOrdering.bindValue(":ordering", order++); updateOrdering.bindValue(":id", id); updateOrdering.exec(); @@ -1020,7 +1021,7 @@ void DBHelper::reasignOrderToSublists(QList ids, QSqlDatabase &db) db.commit(); } -void DBHelper::reasignOrderToComicsInFavorites(QList comicIds, QSqlDatabase &db) +void DBHelper::reassignOrderToComicsInFavorites(const QList &comicIds, QSqlDatabase &db) { QSqlQuery updateOrdering(db); updateOrdering.prepare("UPDATE comic_default_reading_list SET " @@ -1028,7 +1029,7 @@ void DBHelper::reasignOrderToComicsInFavorites(QList comicIds, QSqlD "WHERE comic_id = :comic_id AND default_reading_list_id = 1"); db.transaction(); int order = 0; - foreach (qulonglong id, comicIds) { + for (auto id : comicIds) { updateOrdering.bindValue(":ordering", order++); updateOrdering.bindValue(":comic_id", id); updateOrdering.exec(); @@ -1037,7 +1038,7 @@ void DBHelper::reasignOrderToComicsInFavorites(QList comicIds, QSqlD db.commit(); } -void DBHelper::reasignOrderToComicsInLabel(qulonglong labelId, QList comicIds, QSqlDatabase &db) +void DBHelper::reassignOrderToComicsInLabel(qulonglong labelId, const QList &comicIds, QSqlDatabase &db) { QSqlQuery updateOrdering(db); updateOrdering.prepare("UPDATE comic_label SET " @@ -1045,7 +1046,7 @@ void DBHelper::reasignOrderToComicsInLabel(qulonglong labelId, QList "WHERE comic_id = :comic_id AND label_id = :label_id"); db.transaction(); int order = 0; - foreach (qulonglong id, comicIds) { + for (auto id : comicIds) { updateOrdering.bindValue(":ordering", order++); updateOrdering.bindValue(":comic_id", id); updateOrdering.bindValue(":label_id", labelId); @@ -1055,7 +1056,7 @@ void DBHelper::reasignOrderToComicsInLabel(qulonglong labelId, QList db.commit(); } -void DBHelper::reasignOrderToComicsInReadingList(qulonglong readingListId, QList comicIds, QSqlDatabase &db) +void DBHelper::reassignOrderToComicsInReadingList(qulonglong readingListId, const QList &comicIds, QSqlDatabase &db) { QSqlQuery updateOrdering(db); updateOrdering.prepare("UPDATE comic_reading_list SET " @@ -1063,7 +1064,7 @@ void DBHelper::reasignOrderToComicsInReadingList(qulonglong readingListId, QList "WHERE comic_id = :comic_id AND reading_list_id = :reading_list_id"); db.transaction(); int order = 0; - foreach (qulonglong id, comicIds) { + for (auto id : comicIds) { updateOrdering.bindValue(":ordering", order++); updateOrdering.bindValue(":comic_id", id); updateOrdering.bindValue(":reading_list_id", readingListId); @@ -1519,7 +1520,7 @@ QList