From ea84f16336fc24d4e3bdea6585223a75f1199b33 Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Wed, 14 Oct 2026 18:34:17 +0200 Subject: [PATCH 001/187] Remove dead code --- YACReaderLibrary/db/comic_model.cpp | 8 -- YACReaderLibrary/db/comic_model.h | 5 - YACReaderLibrary/db/folder_item.cpp | 6 - YACReaderLibrary/db/folder_item.h | 1 - YACReaderLibrary/db/folder_model.cpp | 24 ---- YACReaderLibrary/db/folder_model.h | 2 - YACReaderLibrary/db_helper.cpp | 102 ----------------- YACReaderLibrary/db_helper.h | 6 - YACReaderLibrary/server/documentcache.h | 4 - custom_widgets/yacreader_dark_menu.cpp | 38 ------- custom_widgets/yacreader_dark_menu.h | 13 --- custom_widgets/yacreader_social_dialog.cpp | 122 --------------------- custom_widgets/yacreader_social_dialog.h | 29 ----- 13 files changed, 360 deletions(-) delete mode 100644 YACReaderLibrary/server/documentcache.h delete mode 100644 custom_widgets/yacreader_dark_menu.cpp delete mode 100644 custom_widgets/yacreader_dark_menu.h delete mode 100644 custom_widgets/yacreader_social_dialog.cpp delete mode 100644 custom_widgets/yacreader_social_dialog.h diff --git a/YACReaderLibrary/db/comic_model.cpp b/YACReaderLibrary/db/comic_model.cpp index bcaab8543..9143b0c85 100644 --- a/YACReaderLibrary/db/comic_model.cpp +++ b/YACReaderLibrary/db/comic_model.cpp @@ -796,8 +796,6 @@ void ComicModel::setModelData(QList *data, const QString &databaseP endResetModel(); - emit searchNumResults(_data.length()); - delete data; } @@ -975,12 +973,6 @@ QVector ComicModel::getReadList() } return readList; } -// TODO untested, this method is no longer used -QVector ComicModel::setAllComicsRead(YACReaderComicReadStatus read) -{ - return setComicsRead(persistentIndexList(), read); -} - QList ComicModel::getAllComics() { QList comics; diff --git a/YACReaderLibrary/db/comic_model.h b/YACReaderLibrary/db/comic_model.h index c996bd93d..beae11dc2 100644 --- a/YACReaderLibrary/db/comic_model.h +++ b/YACReaderLibrary/db/comic_model.h @@ -117,14 +117,10 @@ class ComicModel : public QAbstractItemModel ComicDB getComic(const QModelIndex &mi); //--> para la edición // ComicDB getComic(int row); QVector getReadList(); - QVector setAllComicsRead(YACReaderComicReadStatus readStatus); QList getComics(QList list); //--> recupera la información común a los comics seleccionados QList getAllComics(); QModelIndex getIndexFromId(quint64 id); QList getIndexesFromIds(const QList &comicIds); - // setcomicInfo(QModelIndex & mi); --> inserta en la base datos - // setComicInfoForAllComics(); --> inserta la información común a todos los cómics de una sola vez. - // setComicInfoForSelectedComis(QList list); -->inserta la información común para los comics seleccionados QVector setComicsRead(QList list, YACReaderComicReadStatus read); void setComicsType(QList list, FileType type); qint64 asignNumbers(QList list, int startingNumber); @@ -204,7 +200,6 @@ public slots: signals: void isEmpty(); void favoritesChanged(const QList &comicIds); - void searchNumResults(int); void resortedIndexes(QList); void newSelectedIndex(const QModelIndex &); }; diff --git a/YACReaderLibrary/db/folder_item.cpp b/YACReaderLibrary/db/folder_item.cpp index 8b539b4ab..8c5a02726 100644 --- a/YACReaderLibrary/db/folder_item.cpp +++ b/YACReaderLibrary/db/folder_item.cpp @@ -82,12 +82,6 @@ void FolderItem::removeChild(int childIndex) childItems.removeAt(childIndex); } -void FolderItem::clearChildren() -{ - qDeleteAll(childItems); - childItems.clear(); -} - QList FolderItem::children() { return childItems; diff --git a/YACReaderLibrary/db/folder_item.h b/YACReaderLibrary/db/folder_item.h index 071e0a9b4..68ea14d53 100644 --- a/YACReaderLibrary/db/folder_item.h +++ b/YACReaderLibrary/db/folder_item.h @@ -69,7 +69,6 @@ class FolderItem void addChild(FolderItem *child, int childIndex); void removeChild(FolderItem *child); void removeChild(int childIndex); - void clearChildren(); QList children(); private: diff --git a/YACReaderLibrary/db/folder_model.cpp b/YACReaderLibrary/db/folder_model.cpp index 8ade93f03..7178f02bb 100644 --- a/YACReaderLibrary/db/folder_model.cpp +++ b/YACReaderLibrary/db/folder_model.cpp @@ -799,30 +799,6 @@ void FolderModel::resetFolderCover(const QModelIndex &index) emit dataChanged(index, index); } -QStringList FolderModel::getSubfoldersNames(const QModelIndex &mi) -{ - QStringList result; - qulonglong id = 1; - if (mi.isValid()) { - auto item = static_cast(mi.internalPointer()); - id = item->id; - } - QString connectionName = ""; - { - QSqlDatabase db = DataBaseManagement::loadDatabase(_databasePath); - db.transaction(); - - result = DBHelper::loadSubfoldersNames(id, db); - - db.commit(); - connectionName = db.connectionName(); - } - QSqlDatabase::removeDatabase(connectionName); - - std::sort(result.begin(), result.end(), naturalSortLessThanCI); - return result; -} - Folder FolderModel::getRootFolder() const { if (this->rootItem == nullptr) { diff --git a/YACReaderLibrary/db/folder_model.h b/YACReaderLibrary/db/folder_model.h index 28c4b31a1..fe1b7100a 100644 --- a/YACReaderLibrary/db/folder_model.h +++ b/YACReaderLibrary/db/folder_model.h @@ -78,8 +78,6 @@ class FolderModel : public QAbstractItemModel, protected Themable void setCustomFolderCover(const QModelIndex &index, const QString &path); void resetFolderCover(const QModelIndex &index); - QStringList getSubfoldersNames(const QModelIndex &mi); - Folder getRootFolder() const; Folder getFolder(const QModelIndex &mi) const; QModelIndex getIndexFromFolderId(qulonglong folderId, const QModelIndex &parent = QModelIndex()); diff --git a/YACReaderLibrary/db_helper.cpp b/YACReaderLibrary/db_helper.cpp index e0081f9e3..cf44b26aa 100644 --- a/YACReaderLibrary/db_helper.cpp +++ b/YACReaderLibrary/db_helper.cpp @@ -86,50 +86,6 @@ QList DBHelper::getFolderComicsFromLibrary(qulonglong libraryId, return list; } -quint32 DBHelper::getNumChildrenFromFolder(qulonglong libraryId, qulonglong folderId) -{ - QString libraryPath = DBHelper::getLibraries().getPath(libraryId); - quint32 result = 0; - QString connectionName = ""; - - { - QSqlDatabase db = DataBaseManagement::loadDatabase(LibraryPaths::libraryDataPath(libraryPath)); - - QSqlQuery selectQuery(db); - selectQuery.prepare("SELECT count(*) FROM folder WHERE parentId = :parentId and id <> 1"); - selectQuery.bindValue(":parentId", folderId); - selectQuery.exec(); - - result += selectQuery.record().value(0).toULongLong(); - - selectQuery.prepare("SELECT count(*) FROM comic c WHERE c.parentId = :parentId"); - selectQuery.bindValue(":parentId", folderId); - selectQuery.exec(); - - result += selectQuery.record().value(0).toULongLong(); - connectionName = db.connectionName(); - } - - QSqlDatabase::removeDatabase(connectionName); - - return result; -} - -qulonglong DBHelper::getParentFromComicFolderId(qulonglong libraryId, qulonglong id) -{ - QString libraryPath = DBHelper::getLibraries().getPath(libraryId); - QString connectionName = ""; - Folder f; - { - QSqlDatabase db = DataBaseManagement::loadDatabase(LibraryPaths::libraryDataPath(libraryPath)); - - f = DBHelper::loadFolder(id, db); - connectionName = db.connectionName(); - } - - QSqlDatabase::removeDatabase(connectionName); - return f.parentId; -} ComicDB DBHelper::getComicInfo(qulonglong libraryId, qulonglong id) { QString libraryPath = DBHelper::getLibraries().getPath(libraryId); @@ -161,30 +117,6 @@ QList DBHelper::getSiblings(qulonglong libraryId, qulonglong parentId) return comics; } -QString DBHelper::getFolderName(qulonglong libraryId, qulonglong id) -{ - QString libraryPath = DBHelper::getLibraries().getPath(libraryId); - - QString name = ""; - QString connectionName = ""; - - { - QSqlDatabase db = DataBaseManagement::loadDatabase(LibraryPaths::libraryDataPath(libraryPath)); - QSqlQuery selectQuery(db); // TODO check - selectQuery.prepare("SELECT name FROM folder WHERE id = :id"); - selectQuery.bindValue(":id", id); - selectQuery.exec(); - - if (selectQuery.next()) { - name = selectQuery.value(0).toString(); - } - connectionName = db.connectionName(); - } - - QSqlDatabase::removeDatabase(connectionName); - return name; -} - Folder DBHelper::getFolder(qulonglong libraryId, qulonglong id) { QString libraryPath = DBHelper::getLibraries().getPath(libraryId); @@ -235,12 +167,6 @@ Folder DBHelper::getFolder(qulonglong libraryId, qulonglong id) return folder; } -QList DBHelper::getLibrariesNames() -{ - auto names = getLibraries().getNames(); - std::sort(names.begin(), names.end(), naturalSortLessThanCI); - return names; -} QString DBHelper::getLibraryName(int id) { return getLibraries().getName(id); @@ -845,18 +771,6 @@ void DBHelper::update(ComicInfo *comicInfo, QSqlDatabase &db) QLOG_INFO() << updateComicInfo.lastQuery(); } -void DBHelper::updateRead(ComicInfo *comicInfo, QSqlDatabase &db) -{ - QSqlQuery updateComicInfo(db); - updateComicInfo.prepare("UPDATE comic_info SET " - "read = :read" - " WHERE id = :id "); - - updateComicInfo.bindValue(":read", comicInfo->read ? 1 : 0); - updateComicInfo.bindValue(":id", comicInfo->id); - updateComicInfo.exec(); -} - void DBHelper::updateAdded(ComicInfo *comicInfo, QSqlDatabase &db) { QSqlQuery updateComicInfo(db); @@ -2426,22 +2340,6 @@ ComicInfo DBHelper::getComicInfoFromQuery(QSqlQuery &query, const QString &idKey return comicInfo; } -QList DBHelper::loadSubfoldersNames(qulonglong folderId, QSqlDatabase &db) -{ - QList result; - QSqlQuery selectQuery(db); - selectQuery.prepare("SELECT name FROM folder WHERE parentId = :parentId AND id <> 1"); // do not select the root folder - selectQuery.bindValue(":parentId", folderId); - selectQuery.exec(); - - int name = selectQuery.record().indexOf("name"); - - while (selectQuery.next()) { - result << selectQuery.value(name).toString(); - } - return result; -} - bool DBHelper::isFavoriteComic(qulonglong id, QSqlDatabase &db) { QSqlQuery selectQuery(db); diff --git a/YACReaderLibrary/db_helper.h b/YACReaderLibrary/db_helper.h index 7efa8f807..226aa5546 100644 --- a/YACReaderLibrary/db_helper.h +++ b/YACReaderLibrary/db_helper.h @@ -29,13 +29,9 @@ class DBHelper static QList getFolderComicsFromLibrary(qulonglong libraryId, qulonglong folderId); static QList getFolderComicsFromLibrary(qulonglong libraryId, qulonglong folderId, bool sort); static QList getFolderComicsFromLibraryForReading(qulonglong libraryId, qulonglong folderId); - static quint32 getNumChildrenFromFolder(qulonglong libraryId, qulonglong folderId); - static qulonglong getParentFromComicFolderId(qulonglong libraryId, qulonglong id); static ComicDB getComicInfo(qulonglong libraryId, qulonglong id); static QList getSiblings(qulonglong libraryId, qulonglong parentId); - static QString getFolderName(qulonglong libraryId, qulonglong id); static Folder getFolder(qulonglong libraryId, qulonglong id); - static QList getLibrariesNames(); static QString getLibraryName(int id); static QList getLabelComics(qulonglong libraryId, qulonglong labelId); static QList getFavorites(qulonglong libraryId); @@ -68,7 +64,6 @@ class DBHelper static void update(qulonglong libraryId, ComicInfo &comicInfo); static void update(ComicDB *comics, QSqlDatabase &db); static void update(ComicInfo *comicInfo, QSqlDatabase &db); - static void updateRead(ComicInfo *comicInfo, QSqlDatabase &db); static void updateAdded(ComicInfo *comicInfo, QSqlDatabase &db); static void update(const Folder &folder, QSqlDatabase &db); static void propagateFolderUpdatesToParent(const Folder &folder, QSqlDatabase &db); @@ -118,7 +113,6 @@ class DBHelper static ComicDB loadComic(QString cname, QString cpath, QString chash, QSqlDatabase &database); static ComicInfo loadComicInfo(QString hash, QSqlDatabase &db); static ComicInfo getComicInfoFromQuery(QSqlQuery &query, const QString &idKey = "id"); - static QList loadSubfoldersNames(qulonglong folderId, QSqlDatabase &db); // queries static bool isFavoriteComic(qulonglong id, QSqlDatabase &db); diff --git a/YACReaderLibrary/server/documentcache.h b/YACReaderLibrary/server/documentcache.h deleted file mode 100644 index ac344a06e..000000000 --- a/YACReaderLibrary/server/documentcache.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef DOCUMENTCACHE_H -#define DOCUMENTCACHE_H - -#endif // DOCUMENTCACHE_H diff --git a/custom_widgets/yacreader_dark_menu.cpp b/custom_widgets/yacreader_dark_menu.cpp deleted file mode 100644 index ce7e1fe6f..000000000 --- a/custom_widgets/yacreader_dark_menu.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "yacreader_dark_menu.h" - -#include -#include -#include - -YACReaderDarkMenu::YACReaderDarkMenu(QWidget *parent) - : QMenu(parent) -{ - // solid color: #454545 - QString style = "QMenu {background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #6B6B6B, stop: 1 #424242); " - "border-left: 1px solid qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #BCBCBC, stop: 1 #4C4C4C);" - "border-right: 1px solid qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #BCBCBC, stop: 1 #4C4C4C);" - "border-top: 1px solid #BCBCBC;" - "border-bottom: 1px solid #4C4C4C;" - "padding-top:5px;padding-bottom:5px;}" - "QMenu::separator {height:0px;border-top: 1px solid #292929; border-bottom:1px solid #737373; margin-left:-1px; margin-right:-1px;}" - "QMenu::item {color:#CFD1D1;padding: 5px 25px 5px 32px;}" - "QMenu::item::selected {background-color:#242424;border-top: 1px solid #151515; border-bottom:1px solid #737373;}" - "QMenu::icon {padding-left:15px;}"; - - setStyleSheet(style); - - /* - QPixmap p(":/images/icon.png"); - QLabel * l = new QLabel(); - l->setPixmap(p); - l->move(0,-10); - - //test - YACReaderDarkMenu * customMenu = new YACReaderDarkMenu(this); - customMenu->addAction(toggleFullScreenAction); - customMenu->addAction(createLibraryAction); - customMenu->addSeparator(); - customMenu->addAction(openComicAction); - customMenu->show(); - */ -} \ No newline at end of file diff --git a/custom_widgets/yacreader_dark_menu.h b/custom_widgets/yacreader_dark_menu.h deleted file mode 100644 index ccde1fe27..000000000 --- a/custom_widgets/yacreader_dark_menu.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef YACREADER_DARK_MENU_H -#define YACREADER_DARK_MENU_H - -#include - -class YACReaderDarkMenu : public QMenu -{ - Q_OBJECT -public: - YACReaderDarkMenu(QWidget *parent = 0); -}; - -#endif // YACREADER_DARK_MENU_H \ No newline at end of file diff --git a/custom_widgets/yacreader_social_dialog.cpp b/custom_widgets/yacreader_social_dialog.cpp deleted file mode 100644 index 8c0edf054..000000000 --- a/custom_widgets/yacreader_social_dialog.cpp +++ /dev/null @@ -1,122 +0,0 @@ -#include "yacreader_social_dialog.h" - -#include "comic_db.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -YACReaderSocialDialog::YACReaderSocialDialog(QWidget *parent) - : QWidget(parent) -{ - - // setWindowFlags(Qt::Window | Qt::Dialog | Qt::FramelessWindowHint); - // setModal(true); - - QToolButton *close = new QToolButton(this); - close->setIcon(QIcon(":/images/social_dialog/close.png")); - - QToolButton *facebook = new QToolButton(this); - facebook->setIcon(QIcon(":/images/social_dialog/facebook.png")); - - QToolButton *twitter = new QToolButton(this); - twitter->setIcon(QIcon(":/images/social_dialog/twitter.png")); - - QToolButton *google = new QToolButton(this); - google->setIcon(QIcon(":/images/social_dialog/google+.png")); - - QString styleSheet = "QToolButton {border:none; }"; - close->setStyleSheet(styleSheet); - facebook->setStyleSheet(styleSheet); - twitter->setStyleSheet(styleSheet); - google->setStyleSheet(styleSheet); - - QLabel *icon = new QLabel(this); - icon->setPixmap(QPixmap(":/images/social_dialog/icon.png")); - - plainText = new QTextEdit(this); - plainText->setStyleSheet("QTextEdit {border:none; padding:11px; font-size:12px; font-weight:bold; color:#525757;}"); - QTextCursor cursor(plainText->textCursor()); - QTextBlockFormat blockFormat = cursor.blockFormat(); - blockFormat.setLineHeight(12, QTextBlockFormat::SingleHeight); - cursor.setBlockFormat(blockFormat); - QLabel *sendTo = new QLabel(tr("send to:"), this); - sendTo->setStyleSheet("QLabel{color:#ABABAB; font-size:12px; font-weight:bold;}"); - - setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - - resize(sizeHint()); - - close->move(437, 5); - - QWidget *send = new QWidget(this); - QHBoxLayout *sendLayout = new QHBoxLayout; - - QPushButton *follow = new QPushButton(tr("Follow YACReader!"), this); - - follow->setStyleSheet("QPushButton{border:none; color:#FFFFFF;background:#404040; padding: 9px 25px 9px 25px; font-weight:bold; font-size:12px;}" - "QPushButton:hover{background:#E3B800;}"); - - sendLayout->setMargin(0); - sendLayout->setSpacing(0); - - sendLayout->addWidget(sendTo, 1, Qt::AlignHCenter); - sendLayout->addSpacing(11); - sendLayout->addWidget(facebook, 0, Qt::AlignHCenter); - sendLayout->addSpacing(6); - sendLayout->addWidget(twitter, 0, Qt::AlignHCenter); - sendLayout->addSpacing(6); - sendLayout->addWidget(google, 0, Qt::AlignHCenter); - - send->setLayout(sendLayout); - send->move(317, 259); - - icon->move(279, 14); - plainText->setFixedSize(291, 155); - plainText->move(169, 96); - - follow->move(230, 307); - - connect(close, SIGNAL(released()), this, SLOT(close())); -} - -void YACReaderSocialDialog::paintEvent(QPaintEvent *event) -{ - QPainter painter(this); - - // center - painter.fillRect(169, 0, 291, 369, QColor("#F0F0F0")); - painter.fillRect(169, 96, 291, 155, QColor("#FFFFFF")); - - // QPixmap cover = QPixmap("c:/temp/6.jpg").scaledToHeight(369,Qt::SmoothTransformation); - painter.drawPixmap(0, 0, 169, 369, cover, 0, 0, (169 * cover.height()) / 369, cover.height()); - - QPixmap shadow(":/images/social_dialog/shadow.png"); - painter.drawPixmap(169 - shadow.width(), 0, shadow.width(), 369, shadow); - - QPixmap separtor(":/images/social_dialog/separator.png"); - painter.drawPixmap(169, 96 - separtor.height(), separtor); - - QPen pen("#C3CAD6"); - painter.setPen(pen); - painter.drawLine(169, 251, 460, 251); - - QWidget::paintEvent(event); -} - -QSize YACReaderSocialDialog::sizeHint() const -{ - return QSize(460, 369); -} - -void YACReaderSocialDialog::setComic(ComicDB &comic, QString &basePath) -{ - this->cover = comic.info.getCover(basePath).scaledToHeight(369, Qt::SmoothTransformation); - plainText->setText(tr("I am reading %1 using YACReader.").arg(comic.path.split('/').last())); -} \ No newline at end of file diff --git a/custom_widgets/yacreader_social_dialog.h b/custom_widgets/yacreader_social_dialog.h deleted file mode 100644 index a64b3f024..000000000 --- a/custom_widgets/yacreader_social_dialog.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef YACREADER_SOCIAL_DIALOG_H -#define YACREADER_SOCIAL_DIALOG_H - -#include - -class QPixmap; -class QTextEdit; -class ComicDB; - -class YACReaderSocialDialog : public QWidget -{ - Q_OBJECT -public: - explicit YACReaderSocialDialog(QWidget *parent = 0); - QSize sizeHint() const; -signals: - -public slots: - void setComic(ComicDB &comic, QString &basePath); - -protected: - void paintEvent(QPaintEvent *); - -private: - QPixmap cover; - QTextEdit *plainText; -}; - -#endif // YACREADER_SOCIAL_DIALOG_H From 7f686e119554db934aa8680b73a87331f01ac77f Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Sun, 18 Oct 2026 12:13:56 +0200 Subject: [PATCH 002/187] Run CI on every pull request The branch filter on pull_request kept stacked PRs, which target a feature branch, from running CI. Signing and publishing steps still run only on master and develop. --- .github/workflows/build.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 22ae067c7..82f919dee 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,9 +6,6 @@ on: - master - develop pull_request: - branches: - - master - - develop env: IS_ORIGINAL_REPO: ${{ github.repository == 'YACReader/yacreader' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/develop') }} From 268288b19ee8860944e78091ccd218757bc01e9d Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Mon, 19 Oct 2026 18:55:00 +0200 Subject: [PATCH 003/187] Embed the Windows manifest as a source file so that Ninja builds link --- YACReader/CMakeLists.txt | 2 +- YACReaderLibrary/CMakeLists.txt | 2 +- YACReaderLibraryServer/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/YACReader/CMakeLists.txt b/YACReader/CMakeLists.txt index 42f512e78..ec068a800 100644 --- a/YACReader/CMakeLists.txt +++ b/YACReader/CMakeLists.txt @@ -277,7 +277,7 @@ target_link_libraries(YACReader PRIVATE if(WIN32) target_sources(YACReader PRIVATE icon.rc) if(MSVC) - target_link_options(YACReader PRIVATE "/MANIFESTINPUT:${PROJECT_SOURCE_DIR}/cmake/windows/yacreader.manifest") + target_sources(YACReader PRIVATE ${PROJECT_SOURCE_DIR}/cmake/windows/yacreader.manifest) endif() target_link_libraries(YACReader PRIVATE oleaut32 ole32 shell32 user32) endif() diff --git a/YACReaderLibrary/CMakeLists.txt b/YACReaderLibrary/CMakeLists.txt index 8641fc102..88b51d33d 100644 --- a/YACReaderLibrary/CMakeLists.txt +++ b/YACReaderLibrary/CMakeLists.txt @@ -578,7 +578,7 @@ endif() if(WIN32) target_sources(YACReaderLibrary PRIVATE icon.rc) if(MSVC) - target_link_options(YACReaderLibrary PRIVATE "/MANIFESTINPUT:${PROJECT_SOURCE_DIR}/cmake/windows/yacreader.manifest") + target_sources(YACReaderLibrary PRIVATE ${PROJECT_SOURCE_DIR}/cmake/windows/yacreader.manifest) endif() target_link_libraries(YACReaderLibrary PRIVATE oleaut32 ole32 shell32 user32) endif() diff --git a/YACReaderLibraryServer/CMakeLists.txt b/YACReaderLibraryServer/CMakeLists.txt index 8341d9d9d..0e967b16e 100644 --- a/YACReaderLibraryServer/CMakeLists.txt +++ b/YACReaderLibraryServer/CMakeLists.txt @@ -72,7 +72,7 @@ endif() # Platform-specific if(WIN32) if(MSVC) - target_link_options(YACReaderLibraryServer PRIVATE "/MANIFESTINPUT:${PROJECT_SOURCE_DIR}/cmake/windows/yacreader.manifest") + target_sources(YACReaderLibraryServer PRIVATE ${PROJECT_SOURCE_DIR}/cmake/windows/yacreader.manifest) endif() target_link_libraries(YACReaderLibraryServer PRIVATE oleaut32 ole32 shell32 user32) endif() From 67cd8e9faa470bec2ee45be683c655c17d40cba6 Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Thu, 15 Oct 2026 17:20:48 +0200 Subject: [PATCH 004/187] Extract shared descriptive comic metadata to a helper struct --- YACReaderLibrary/db_helper.cpp | 183 +--------------- common/CMakeLists.txt | 2 + common/comic_db.cpp | 39 +--- common/comic_db.h | 49 +---- common/descriptive_comic_metadata.cpp | 73 +++++++ common/descriptive_comic_metadata.h | 65 ++++++ tests/CMakeLists.txt | 1 + .../descriptive_metadata_test/CMakeLists.txt | 4 + tests/descriptive_metadata_test/main.cpp | 196 ++++++++++++++++++ 9 files changed, 349 insertions(+), 263 deletions(-) create mode 100644 common/descriptive_comic_metadata.cpp create mode 100644 common/descriptive_comic_metadata.h create mode 100644 tests/descriptive_metadata_test/CMakeLists.txt create mode 100644 tests/descriptive_metadata_test/main.cpp diff --git a/YACReaderLibrary/db_helper.cpp b/YACReaderLibrary/db_helper.cpp index cf44b26aa..f949cd873 100644 --- a/YACReaderLibrary/db_helper.cpp +++ b/YACReaderLibrary/db_helper.cpp @@ -3,6 +3,7 @@ #include "QsLog.h" #include "comic_db.h" #include "data_base_management.h" +#include "descriptive_comic_metadata.h" #include "folder.h" #include "library_item.h" #include "qnaturalsorting.h" @@ -596,40 +597,10 @@ void DBHelper::update(ComicInfo *comicInfo, QSqlDatabase &db) return; QSqlQuery updateComicInfo(db); - updateComicInfo.prepare("UPDATE comic_info SET " - "title = :title," - + updateComicInfo.prepare("UPDATE comic_info SET " + DescriptiveComicMetadata::assignments().join(",") + "," + "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," - - "synopsis = :synopsis," - "characters = :characters," - "notes = :notes," - "read = :read," "edited = :edited," // new 7.0 fields @@ -644,9 +615,6 @@ void DBHelper::update(ComicInfo *comicInfo, QSqlDatabase &db) "gamma = :gamma," "rating = :rating," - // new 7.1 fields - "comicVineID = :comicVineID," - // new 9.5 fields "lastTimeOpened = :lastTimeOpened," @@ -661,19 +629,6 @@ void DBHelper::update(ComicInfo *comicInfo, QSqlDatabase &db) // new 9.13 fields "added = :added," "type = :type," - "editor = :editor," - "imprint = :imprint," - "teams = :teams," - "locations = :locations," - "series = :series," - "alternateSeries = :alternateSeries," - "alternateNumber = :alternateNumber," - "alternateCount = :alternateCount," - "languageISO = :languageISO," - "seriesGroup = :seriesGroup," - "mainCharacterOrTeam = :mainCharacterOrTeam," - "review = :review," - "tags = :tags," // new 9.16 fields "imageFiltersJson = :imageFiltersJson," @@ -685,39 +640,11 @@ void DBHelper::update(ComicInfo *comicInfo, QSqlDatabase &db) //-- " WHERE id = :id"); - updateComicInfo.bindValue(":title", comicInfo->title); + comicInfo->bindTo(updateComicInfo); updateComicInfo.bindValue(":coverPage", comicInfo->coverPage); updateComicInfo.bindValue(":numPages", comicInfo->numPages); - updateComicInfo.bindValue(":number", comicInfo->number); - updateComicInfo.bindValue(":isBis", comicInfo->isBis); - updateComicInfo.bindValue(":count", comicInfo->count); - - updateComicInfo.bindValue(":volume", comicInfo->volume); - updateComicInfo.bindValue(":storyArc", comicInfo->storyArc); - updateComicInfo.bindValue(":arcNumber", comicInfo->arcNumber); - updateComicInfo.bindValue(":arcCount", comicInfo->arcCount); - - updateComicInfo.bindValue(":genere", comicInfo->genere); - - updateComicInfo.bindValue(":writer", comicInfo->writer); - updateComicInfo.bindValue(":penciller", comicInfo->penciller); - updateComicInfo.bindValue(":inker", comicInfo->inker); - updateComicInfo.bindValue(":colorist", comicInfo->colorist); - updateComicInfo.bindValue(":letterer", comicInfo->letterer); - updateComicInfo.bindValue(":coverArtist", comicInfo->coverArtist); - - updateComicInfo.bindValue(":date", comicInfo->date); - updateComicInfo.bindValue(":publisher", comicInfo->publisher); - updateComicInfo.bindValue(":format", comicInfo->format); - updateComicInfo.bindValue(":color", comicInfo->color); - updateComicInfo.bindValue(":ageRating", comicInfo->ageRating); - - updateComicInfo.bindValue(":synopsis", comicInfo->synopsis); - updateComicInfo.bindValue(":characters", comicInfo->characters); - updateComicInfo.bindValue(":notes", comicInfo->notes); - bool read = comicInfo->read || comicInfo->currentPage == comicInfo->numPages.toInt(); // if current page is the las page, the comic is read(completed) comicInfo->read = read; updateComicInfo.bindValue(":read", read ? 1 : 0); @@ -734,8 +661,6 @@ void DBHelper::update(ComicInfo *comicInfo, QSqlDatabase &db) updateComicInfo.bindValue(":gamma", comicInfo->gamma); updateComicInfo.bindValue(":rating", comicInfo->rating); - updateComicInfo.bindValue(":comicVineID", comicInfo->comicVineID); - updateComicInfo.bindValue(":lastTimeOpened", comicInfo->lastTimeOpened); updateComicInfo.bindValue(":coverSizeRatio", comicInfo->coverSizeRatio); @@ -744,19 +669,6 @@ void DBHelper::update(ComicInfo *comicInfo, QSqlDatabase &db) updateComicInfo.bindValue(":added", comicInfo->added); auto intType = static_cast(comicInfo->type.value()); updateComicInfo.bindValue(":type", intType); - updateComicInfo.bindValue(":editor", comicInfo->editor); - updateComicInfo.bindValue(":imprint", comicInfo->imprint); - updateComicInfo.bindValue(":teams", comicInfo->teams); - updateComicInfo.bindValue(":locations", comicInfo->locations); - updateComicInfo.bindValue(":series", comicInfo->series); - updateComicInfo.bindValue(":alternateSeries", comicInfo->alternateSeries); - updateComicInfo.bindValue(":alternateNumber", comicInfo->alternateNumber); - updateComicInfo.bindValue(":alternateCount", comicInfo->alternateCount); - updateComicInfo.bindValue(":languageISO", comicInfo->languageISO); - updateComicInfo.bindValue(":seriesGroup", comicInfo->seriesGroup); - updateComicInfo.bindValue(":mainCharacterOrTeam", comicInfo->mainCharacterOrTeam); - updateComicInfo.bindValue(":review", comicInfo->review); - updateComicInfo.bindValue(":tags", comicInfo->tags); updateComicInfo.bindValue(":imageFiltersJson", comicInfo->imageFiltersJson); updateComicInfo.bindValue(":lastTimeImageFiltersSet", comicInfo->lastTimeImageFiltersSet); @@ -2183,41 +2095,10 @@ ComicInfo DBHelper::getComicInfoFromQuery(QSqlQuery &query, const QString &idKey int rating = record.indexOf("rating"); //-- - int title = record.indexOf("title"); int numPages = record.indexOf("numPages"); int coverPage = record.indexOf("coverPage"); - int number = record.indexOf("number"); - int isBis = record.indexOf("isBis"); - int count = record.indexOf("count"); - - int volume = record.indexOf("volume"); - int storyArc = record.indexOf("storyArc"); - int arcNumber = record.indexOf("arcNumber"); - int arcCount = record.indexOf("arcCount"); - - int genere = record.indexOf("genere"); - - int writer = record.indexOf("writer"); - int penciller = record.indexOf("penciller"); - int inker = record.indexOf("inker"); - int colorist = record.indexOf("colorist"); - int letterer = record.indexOf("letterer"); - int coverArtist = record.indexOf("coverArtist"); - - int date = record.indexOf("date"); - int publisher = record.indexOf("publisher"); - int format = record.indexOf("format"); - int color = record.indexOf("color"); - int ageRating = record.indexOf("ageRating"); - - int synopsis = record.indexOf("synopsis"); - int characters = record.indexOf("characters"); - int notes = record.indexOf("notes"); - - int comicVineID = record.indexOf("comicVineID"); - int lastTimeOpened = record.indexOf("lastTimeOpened"); int coverSizeRatio = record.indexOf("coverSizeRatio"); @@ -2225,19 +2106,6 @@ ComicInfo DBHelper::getComicInfoFromQuery(QSqlQuery &query, const QString &idKey int added = record.indexOf("added"); int type = record.indexOf("type"); - int editor = record.indexOf("editor"); - int imprint = record.indexOf("imprint"); - int teams = record.indexOf("teams"); - int locations = record.indexOf("locations"); - int series = record.indexOf("series"); - int alternateSeries = record.indexOf("alternateSeries"); - int alternateNumber = record.indexOf("alternateNumber"); - int alternateCount = record.indexOf("alternateCount"); - int languageISO = record.indexOf("languageISO"); - int seriesGroup = record.indexOf("seriesGroup"); - int mainCharacterOrTeam = record.indexOf("mainCharacterOrTeam"); - int review = record.indexOf("review"); - int tags = record.indexOf("tags"); int imageFiltersJson = record.indexOf("imageFiltersJson"); int lastTimeImageFiltersSet = record.indexOf("lastTimeImageFiltersSet"); @@ -2246,6 +2114,7 @@ ComicInfo DBHelper::getComicInfoFromQuery(QSqlQuery &query, const QString &idKey int lastTimeMetadataSet = record.indexOf("lastTimeMetadataSet"); ComicInfo comicInfo; + comicInfo.loadFrom(record); comicInfo.hash = query.value(hash).toString(); comicInfo.id = query.value(id).toULongLong(); @@ -2263,41 +2132,10 @@ ComicInfo DBHelper::getComicInfoFromQuery(QSqlQuery &query, const QString &idKey comicInfo.gamma = query.value(gamma).toInt(); comicInfo.rating = query.value(rating).toInt(); //-- - comicInfo.title = query.value(title); comicInfo.numPages = query.value(numPages); comicInfo.coverPage = query.value(coverPage); - comicInfo.number = query.value(number); - comicInfo.isBis = query.value(isBis); - comicInfo.count = query.value(count); - - comicInfo.volume = query.value(volume); - comicInfo.storyArc = query.value(storyArc); - comicInfo.arcNumber = query.value(arcNumber); - comicInfo.arcCount = query.value(arcCount); - - comicInfo.genere = query.value(genere); - - comicInfo.writer = query.value(writer); - comicInfo.penciller = query.value(penciller); - comicInfo.inker = query.value(inker); - comicInfo.colorist = query.value(colorist); - comicInfo.letterer = query.value(letterer); - comicInfo.coverArtist = query.value(coverArtist); - - comicInfo.date = query.value(date); - comicInfo.publisher = query.value(publisher); - comicInfo.format = query.value(format); - comicInfo.color = query.value(color); - comicInfo.ageRating = query.value(ageRating); - - comicInfo.synopsis = query.value(synopsis); - comicInfo.characters = query.value(characters); - comicInfo.notes = query.value(notes); - - comicInfo.comicVineID = query.value(comicVineID); - // new 9.5 fields comicInfo.lastTimeOpened = query.value(lastTimeOpened); @@ -2312,19 +2150,6 @@ ComicInfo DBHelper::getComicInfoFromQuery(QSqlQuery &query, const QString &idKey // new 9.13 fields comicInfo.added = query.value(added); comicInfo.type = query.value(type); - comicInfo.editor = query.value(editor); - comicInfo.imprint = query.value(imprint); - comicInfo.teams = query.value(teams); - comicInfo.locations = query.value(locations); - comicInfo.series = query.value(series); - comicInfo.alternateSeries = query.value(alternateSeries); - comicInfo.alternateNumber = query.value(alternateNumber); - comicInfo.alternateCount = query.value(alternateCount); - comicInfo.languageISO = query.value(languageISO); - comicInfo.seriesGroup = query.value(seriesGroup); - comicInfo.mainCharacterOrTeam = query.value(mainCharacterOrTeam); - comicInfo.review = query.value(review); - comicInfo.tags = query.value(tags); //-- // new 9.16 fields diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 822540bfa..aaec0dab9 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -64,6 +64,8 @@ target_sources(worker INTERFACE add_library(common_all STATIC comic_db.h comic_db.cpp + descriptive_comic_metadata.h + descriptive_comic_metadata.cpp folder.h folder.cpp library_item.h diff --git a/common/comic_db.cpp b/common/comic_db.cpp index 04a494712..33a15c16f 100644 --- a/common/comic_db.cpp +++ b/common/comic_db.cpp @@ -368,32 +368,10 @@ ComicInfo &ComicInfo::operator=(const ComicInfo &comicInfo) contrast = comicInfo.contrast; gamma = comicInfo.gamma; - title = comicInfo.title; + DescriptiveComicMetadata::operator=(comicInfo); + coverPage = comicInfo.coverPage; numPages = comicInfo.numPages; - number = comicInfo.number; - isBis = comicInfo.isBis; - count = comicInfo.count; - volume = comicInfo.volume; - storyArc = comicInfo.storyArc; - arcNumber = comicInfo.arcNumber; - arcCount = comicInfo.arcCount; - genere = comicInfo.genere; - writer = comicInfo.writer; - penciller = comicInfo.penciller; - inker = comicInfo.inker; - colorist = comicInfo.colorist; - letterer = comicInfo.letterer; - coverArtist = comicInfo.coverArtist; - date = comicInfo.date; - publisher = comicInfo.publisher; - format = comicInfo.format; - color = comicInfo.color; - ageRating = comicInfo.ageRating; - synopsis = comicInfo.synopsis; - characters = comicInfo.characters; - notes = comicInfo.notes; - comicVineID = comicInfo.comicVineID; lastTimeOpened = comicInfo.lastTimeOpened; @@ -402,19 +380,6 @@ ComicInfo &ComicInfo::operator=(const ComicInfo &comicInfo) added = comicInfo.added; type = comicInfo.type; - editor = comicInfo.editor; - imprint = comicInfo.imprint; - teams = comicInfo.teams; - locations = comicInfo.locations; - series = comicInfo.series; - alternateSeries = comicInfo.alternateSeries; - alternateNumber = comicInfo.alternateNumber; - alternateCount = comicInfo.alternateCount; - languageISO = comicInfo.languageISO; - seriesGroup = comicInfo.seriesGroup; - mainCharacterOrTeam = comicInfo.mainCharacterOrTeam; - review = comicInfo.review; - tags = comicInfo.tags; imageFiltersJson = comicInfo.imageFiltersJson; lastTimeImageFiltersSet = comicInfo.lastTimeImageFiltersSet; diff --git a/common/comic_db.h b/common/comic_db.h index c72a01ce3..6f86356ac 100644 --- a/common/comic_db.h +++ b/common/comic_db.h @@ -1,6 +1,7 @@ #ifndef __COMICDB_H #define __COMICDB_H +#include "descriptive_comic_metadata.h" #include "library_item.h" #include @@ -9,7 +10,7 @@ #include #include -class ComicInfo : public QObject +class ComicInfo : public QObject, public DescriptiveComicMetadata { Q_OBJECT public: @@ -45,65 +46,19 @@ class ComicInfo : public QObject [[deprecated("Use imageFiltersJson")]] int gamma; //----------------- - QVariant title; // string - QVariant coverPage; // int QVariant numPages; // int - QVariant number; // string (changed in 9.13 from int) - QVariant isBis; // bool - QVariant count; // int - - QVariant volume; // string - QVariant storyArc; // string - QVariant arcNumber; // string (changed in 9.13 from int) - QVariant arcCount; // int - - QVariant genere; // string - - QVariant writer; // string - QVariant penciller; // string - QVariant inker; // string - QVariant colorist; // string - QVariant letterer; // string - QVariant coverArtist; // string - - QVariant date; // string - QVariant day; QVariant month; QVariant year; - QVariant publisher; // string - QVariant format; // string - QVariant color; // bool - QVariant ageRating; // string - - QVariant synopsis; // string - QVariant characters; // string - QVariant notes; // string - - QVariant comicVineID; // string - QVariant lastTimeOpened; // integer/date QVariant coverSizeRatio; // h/w QVariant originalCoverSize; // string "WxH" QVariant added; // integer/date QVariant type; // enum - QVariant editor; // string - QVariant imprint; // string - QVariant teams; // string/list - QVariant locations; // string/list - QVariant series; // string - QVariant alternateSeries; // string - QVariant alternateNumber; // string - QVariant alternateCount; // int - QVariant languageISO; // string - QVariant seriesGroup; // string - QVariant mainCharacterOrTeam; // string - QVariant review; // string - QVariant tags; // string/list QVariant imageFiltersJson; // string, JSON with image filters QVariant lastTimeImageFiltersSet; // integer/date, last time image filters were set diff --git a/common/descriptive_comic_metadata.cpp b/common/descriptive_comic_metadata.cpp new file mode 100644 index 000000000..7e3a5d9ba --- /dev/null +++ b/common/descriptive_comic_metadata.cpp @@ -0,0 +1,73 @@ +#include "descriptive_comic_metadata.h" + +#include +#include + +const std::array &DescriptiveComicMetadata::columns() +{ + using M = DescriptiveComicMetadata; + static const std::array columns = { { + { "title", "TEXT", &M::title }, + { "number", "TEXT", &M::number }, + { "isBis", "BOOLEAN", &M::isBis }, + { "count", "INTEGER", &M::count }, + { "volume", "TEXT", &M::volume }, + { "storyArc", "TEXT", &M::storyArc }, + { "arcNumber", "TEXT", &M::arcNumber }, + { "arcCount", "INTEGER", &M::arcCount }, + { "genere", "TEXT", &M::genere }, + { "writer", "TEXT", &M::writer }, + { "penciller", "TEXT", &M::penciller }, + { "inker", "TEXT", &M::inker }, + { "colorist", "TEXT", &M::colorist }, + { "letterer", "TEXT", &M::letterer }, + { "coverArtist", "TEXT", &M::coverArtist }, + { "date", "TEXT", &M::date }, + { "publisher", "TEXT", &M::publisher }, + { "format", "TEXT", &M::format }, + { "color", "BOOLEAN", &M::color }, + { "ageRating", "TEXT", &M::ageRating }, + { "synopsis", "TEXT", &M::synopsis }, + { "characters", "TEXT", &M::characters }, + { "notes", "TEXT", &M::notes }, + { "comicVineID", "TEXT", &M::comicVineID }, + { "editor", "TEXT", &M::editor }, + { "imprint", "TEXT", &M::imprint }, + { "teams", "TEXT", &M::teams }, + { "locations", "TEXT", &M::locations }, + { "series", "TEXT", &M::series }, + { "alternateSeries", "TEXT", &M::alternateSeries }, + { "alternateNumber", "TEXT", &M::alternateNumber }, + { "alternateCount", "INTEGER", &M::alternateCount }, + { "languageISO", "TEXT", &M::languageISO }, + { "seriesGroup", "TEXT", &M::seriesGroup }, + { "mainCharacterOrTeam", "TEXT", &M::mainCharacterOrTeam }, + { "review", "TEXT", &M::review }, + { "tags", "TEXT", &M::tags }, + } }; + return columns; +} + +QStringList DescriptiveComicMetadata::assignments() +{ + QStringList result; + for (const auto &column : columns()) { + const auto name = QString::fromLatin1(column.name); + result.append(name + " = :" + name); + } + return result; +} + +void DescriptiveComicMetadata::bindTo(QSqlQuery &query) const +{ + for (const auto &column : columns()) { + query.bindValue(":" + QString::fromLatin1(column.name), this->*column.member); + } +} + +void DescriptiveComicMetadata::loadFrom(const QSqlRecord &record) +{ + for (const auto &column : columns()) { + this->*column.member = record.value(QString::fromLatin1(column.name)); + } +} diff --git a/common/descriptive_comic_metadata.h b/common/descriptive_comic_metadata.h new file mode 100644 index 000000000..830014bf3 --- /dev/null +++ b/common/descriptive_comic_metadata.h @@ -0,0 +1,65 @@ +#ifndef DESCRIPTIVE_COMIC_METADATA_H +#define DESCRIPTIVE_COMIC_METADATA_H + +#include +#include + +#include + +class QSqlQuery; +class QSqlRecord; + +struct DescriptiveComicMetadata { + QVariant title; // string + QVariant number; // string + QVariant isBis; // bool + QVariant count; // int + QVariant volume; // string + QVariant storyArc; // string + QVariant arcNumber; // string + QVariant arcCount; // int + QVariant genere; // string + QVariant writer; // string + QVariant penciller; // string + QVariant inker; // string + QVariant colorist; // string + QVariant letterer; // string + QVariant coverArtist; // string + QVariant date; // string, dd/mm/yyyy, parts can be empty + QVariant publisher; // string + QVariant format; // string + QVariant color; // bool + QVariant ageRating; // string + QVariant synopsis; // string + QVariant characters; // string + QVariant notes; // string + QVariant comicVineID; // string + QVariant editor; // string + QVariant imprint; // string + QVariant teams; // string/list + QVariant locations; // string/list + QVariant series; // string + QVariant alternateSeries; // string + QVariant alternateNumber; // string + QVariant alternateCount; // int + QVariant languageISO; // string + QVariant seriesGroup; // string + QVariant mainCharacterOrTeam; // string + QVariant review; // string + QVariant tags; // string/list + + struct Column { + const char *name; + const char *sqlType; + QVariant DescriptiveComicMetadata::*member; + }; + + static const std::array &columns(); + + static QStringList assignments(); + + void bindTo(QSqlQuery &query) const; + void loadFrom(const QSqlRecord &record); +}; + +#endif diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index bf038fbc8..c4d146758 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -11,3 +11,4 @@ add_subdirectory(comic_files_manager_test) add_subdirectory(organize_files_test) add_subdirectory(yacreader_libraries_test) add_subdirectory(natural_sorting_test) +add_subdirectory(descriptive_metadata_test) diff --git a/tests/descriptive_metadata_test/CMakeLists.txt b/tests/descriptive_metadata_test/CMakeLists.txt new file mode 100644 index 000000000..643f311ad --- /dev/null +++ b/tests/descriptive_metadata_test/CMakeLists.txt @@ -0,0 +1,4 @@ +qt_add_executable(descriptive_metadata_test main.cpp) +yacreader_apply_build_options(descriptive_metadata_test) +target_link_libraries(descriptive_metadata_test PRIVATE Qt6::Test Qt6::Sql db_helper library_common) +add_test(NAME descriptive_metadata_test COMMAND descriptive_metadata_test) diff --git a/tests/descriptive_metadata_test/main.cpp b/tests/descriptive_metadata_test/main.cpp new file mode 100644 index 000000000..c5bb1c78c --- /dev/null +++ b/tests/descriptive_metadata_test/main.cpp @@ -0,0 +1,196 @@ +#include "comic_db.h" +#include "data_base_management.h" +#include "db_helper.h" +#include "descriptive_comic_metadata.h" +#include "yacreader_global.h" + +#include +#include +#include +#include +#include +#include + +class DescriptiveMetadataTest : public QObject +{ + Q_OBJECT +private slots: + void init(); + void cleanup(); + void columnsMatchExistingSchema(); + void descriptiveRoundTripPreservesValuesAndComicState(); + void fullComicUpdateKeepsExistingBehavior(); + void comicInfoCopyKeepsDescriptiveFields(); + void partialProjectionKeepsUnknownFieldsNull(); + +private: + QSqlDatabase db; +}; + +void DescriptiveMetadataTest::init() +{ + db = QSqlDatabase::addDatabase("QSQLITE", "descriptive_metadata_test"); + db.setDatabaseName(":memory:"); + QVERIFY(db.open()); + QVERIFY(DataBaseManagement::createComicInfoTable(db, "comic_info")); + QSqlQuery q(db); + QVERIFY(q.exec("INSERT INTO comic_info (id,hash,title,numPages,currentPage,read,hasBeenOpened,rating,coverPage,coverSizeRatio,originalCoverSize,type,usesExternalCover,lastTimeCoverSet,imageFiltersJson) VALUES (1,'real-stored-hash','Original',20,7,0,1,4,3,0.75,'600x800',1,1,123,'{}')")); +} + +void DescriptiveMetadataTest::cleanup() +{ + db.close(); + db = QSqlDatabase(); + QSqlDatabase::removeDatabase("descriptive_metadata_test"); +} + +void DescriptiveMetadataTest::columnsMatchExistingSchema() +{ + QSqlQuery q(db); + QVERIFY(q.exec("PRAGMA table_info(comic_info)")); + QMap types; + while (q.next()) + types.insert(q.value(1).toString(), q.value(2).toString()); + QCOMPARE(types.size(), 63); + QCOMPARE(DescriptiveComicMetadata::columns().size(), size_t(37)); + QSet names; + for (const auto &column : DescriptiveComicMetadata::columns()) { + const auto name = QString::fromLatin1(column.name); + QVERIFY(!names.contains(name)); + names.insert(name); + QCOMPARE(types.value(name), QString::fromLatin1(column.sqlType)); + } + for (const auto &name : { "hash", "id", "numPages", "coverPage", "read", "currentPage", "rating", "type", "usesExternalCover", "lastTimeMetadataSet" }) + QVERIFY(!names.contains(QString::fromLatin1(name))); +} + +void DescriptiveMetadataTest::descriptiveRoundTripPreservesValuesAndComicState() +{ + QSqlQuery q(db); + QVERIFY(q.exec("SELECT * FROM comic_info WHERE id=1")); + QVERIFY(q.next()); + const auto before = q.record(); + DescriptiveComicMetadata metadata; + for (const auto &column : DescriptiveComicMetadata::columns()) { + const auto type = QByteArray(column.sqlType); + metadata.*column.member = type == "TEXT" ? QVariant(QString("value:%1").arg(column.name)) : QVariant(0); + } + metadata.title = QVariant(); + metadata.notes = QString(""); + metadata.number = QString("-1.5AU"); + metadata.arcNumber = QString("01a"); + metadata.volume = QString("2024 edition"); + metadata.date = QString("//2024"); + metadata.writer = QString("First writer\nSecond writer"); + metadata.tags = QString("First tag\nSecond tag"); + metadata.isBis = false; + metadata.color = false; + QVERIFY(q.prepare("UPDATE comic_info SET " + DescriptiveComicMetadata::assignments().join(",") + " WHERE id=1")); + metadata.bindTo(q); + QVERIFY2(q.exec(), qPrintable(q.lastError().text())); + QVERIFY(q.exec("SELECT * FROM comic_info WHERE id=1")); + QVERIFY(q.next()); + const auto after = q.record(); + DescriptiveComicMetadata loaded; + loaded.loadFrom(after); + for (const auto &column : DescriptiveComicMetadata::columns()) { + const auto expected = metadata.*column.member; + const auto actual = loaded.*column.member; + QCOMPARE(actual.isNull(), expected.isNull()); + if (!expected.isNull()) { + if (QByteArray(column.sqlType) == "BOOLEAN") + QCOMPARE(actual.toBool(), expected.toBool()); + else + QCOMPARE(actual.toString(), expected.toString()); + } + } + QSet descriptive; + for (const auto &column : DescriptiveComicMetadata::columns()) + descriptive.insert(QString::fromLatin1(column.name)); + for (int i = 0; i < before.count(); ++i) { + if (!descriptive.contains(before.fieldName(i))) + QCOMPARE(after.value(i), before.value(i)); + } + QVERIFY(loaded.title.isNull()); + QVERIFY(!loaded.notes.isNull()); + QCOMPARE(loaded.notes.toString(), QString("")); + const auto comic = DBHelper::getComicInfoFromQuery(q); + const DescriptiveComicMetadata &comicMetadata = comic; + for (const auto &column : DescriptiveComicMetadata::columns()) + QCOMPARE(comicMetadata.*column.member, loaded.*column.member); + QCOMPARE(comic.number.toString(), QString("-1.5AU")); + QCOMPARE(comic.date.toString(), QString("//2024")); + QCOMPARE(comic.currentPage, 7); + QCOMPARE(comic.hash, QString("real-stored-hash")); +} + +void DescriptiveMetadataTest::fullComicUpdateKeepsExistingBehavior() +{ + QSqlQuery q(db); + QVERIFY(q.exec("SELECT * FROM comic_info WHERE id=1")); + QVERIFY(q.next()); + auto info = DBHelper::getComicInfoFromQuery(q); + info.title = QString(""); + info.synopsis = QVariant(); + info.number = QString("001a"); + info.currentPage = 20; + info.type = QVariant::fromValue(YACReader::FileType::WebComic); + DBHelper::update(&info, db); + QVERIFY(q.exec("SELECT * FROM comic_info WHERE id=1")); + QVERIFY(q.next()); + const auto loaded = DBHelper::getComicInfoFromQuery(q); + QVERIFY(!loaded.title.isNull()); + QVERIFY(loaded.synopsis.isNull()); + QCOMPARE(loaded.number.toString(), QString("001a")); + QVERIFY(loaded.read); + QVERIFY(loaded.hasBeenOpened); + QCOMPARE(loaded.currentPage, 20); + QCOMPARE(loaded.rating, 4); + QCOMPARE(loaded.coverPage.toInt(), 3); + QCOMPARE(loaded.originalCoverSize.toString(), QString("600x800")); + QCOMPARE(loaded.usesExternalCover.toBool(), true); + QCOMPARE(loaded.lastTimeCoverSet.toInt(), 123); + QCOMPARE(loaded.type.toInt(), static_cast(YACReader::FileType::WebComic)); + QCOMPARE(loaded.hash, QString("real-stored-hash")); +} + +void DescriptiveMetadataTest::comicInfoCopyKeepsDescriptiveFields() +{ + ComicInfo info; + info.hash = "keep-hash"; + info.currentPage = 9; + info.title = QString("Title"); + info.number = QString("1/2"); + info.synopsis = QVariant(); + info.notes = QString(""); + info.color = false; + info.tags = QString("First tag\nSecond tag"); + + ComicInfo copy(info); + ComicInfo assigned; + assigned = info; + + for (const ComicInfo *result : { ©, &assigned }) { + for (const auto &column : DescriptiveComicMetadata::columns()) + QCOMPARE(result->*column.member, info.*column.member); + QVERIFY(result->synopsis.isNull()); + QVERIFY(!result->notes.isNull()); + QCOMPARE(result->hash, QString("keep-hash")); + QCOMPARE(result->currentPage, 9); + } +} + +void DescriptiveMetadataTest::partialProjectionKeepsUnknownFieldsNull() +{ + QSqlQuery q(db); + QVERIFY(q.exec("SELECT id AS metadata_id,title FROM comic_info WHERE id=1")); + QVERIFY(q.next()); + const auto info = DBHelper::getComicInfoFromQuery(q, "metadata_id"); + QCOMPARE(info.id, qulonglong(1)); + QCOMPARE(info.title.toString(), QString("Original")); + QVERIFY(info.number.isNull()); + QVERIFY(info.comicVineID.isNull()); +} + +QTEST_GUILESS_MAIN(DescriptiveMetadataTest) +#include "main.moc" From e769ea5fb52c66e1a676cedea731efbad17f8d5f Mon Sep 17 00:00:00 2001 From: luisangelsm Date: Thu, 15 Oct 2026 17:38:35 +0200 Subject: [PATCH 005/187] Add typed ids and table projections for comic files, reading lists and labels --- YACReaderLibrary/db/reading_list.cpp | 60 ++-- YACReaderLibrary/db/reading_list.h | 48 +-- YACReaderLibrary/db_helper.cpp | 34 +-- .../server/yacreader_server_data_helper.cpp | 10 +- common/CMakeLists.txt | 5 + common/comic_file.cpp | 33 +++ common/comic_file.h | 24 ++ common/library_ids.h | 36 +++ common/table_projection.cpp | 50 ++++ common/table_projection.h | 22 ++ tests/CMakeLists.txt | 1 + tests/table_projection_test/CMakeLists.txt | 4 + tests/table_projection_test/main.cpp | 280 ++++++++++++++++++ 13 files changed, 538 insertions(+), 69 deletions(-) create mode 100644 common/comic_file.cpp create mode 100644 common/comic_file.h create mode 100644 common/library_ids.h create mode 100644 common/table_projection.cpp create mode 100644 common/table_projection.h create mode 100644 tests/table_projection_test/CMakeLists.txt create mode 100644 tests/table_projection_test/main.cpp diff --git a/YACReaderLibrary/db/reading_list.cpp b/YACReaderLibrary/db/reading_list.cpp index 4b9d0279d..b43507ed8 100644 --- a/YACReaderLibrary/db/reading_list.cpp +++ b/YACReaderLibrary/db/reading_list.cpp @@ -1,41 +1,61 @@ #include "reading_list.h" -ReadingList::ReadingList(const QString &name, qulonglong id, int ordering) - : name(name), id(id), ordering(ordering) -{ -} +#include "table_projection.h" -qulonglong ReadingList::getId() const -{ - return id; -} +#include +#include + +using TableProjection::value; -QString ReadingList::getName() const +const QStringList &ReadingList::columns() { - return name; + static const QStringList columns = { "parentId", "ordering", "name", "finished", "completed" }; + return columns; } -int ReadingList::getOrdering() const +ReadingList ReadingList::fromRecord(const QSqlRecord &record, const QString &alias) { - return ordering; + ReadingList list; + list.id = ReadingListId(value(record, alias, "id").toULongLong()); + const auto parentId = value(record, alias, "parentId"); + if (!parentId.isNull()) { + list.parentId = ReadingListId(parentId.toULongLong()); + } + list.ordering = value(record, alias, "ordering").toInt(); + list.name = value(record, alias, "name").toString(); + list.finished = value(record, alias, "finished").toBool(); + list.completed = value(record, alias, "completed").toBool(); + return list; } -Label::Label(const QString &name, qulonglong id, YACReader::LabelColors colorid) - : name(name), id(id), colorid(colorid) +void ReadingList::bindTo(QSqlQuery &query) const { + query.bindValue(":parentId", parentId ? QVariant(parentId->value()) : QVariant()); + query.bindValue(":ordering", ordering); + query.bindValue(":name", name); + query.bindValue(":finished", finished); + query.bindValue(":completed", completed); } -YACReader::LabelColors Label::getColorID() const +const QStringList &Label::columns() { - return colorid; + static const QStringList columns = { "name", "color", "ordering" }; + return columns; } -QString Label::getName() const +Label Label::fromRecord(const QSqlRecord &record, const QString &alias) { - return name; + Label label; + label.id = LabelId(value(record, alias, "id").toULongLong()); + label.name = value(record, alias, "name").toString(); + label.color = value(record, alias, "color").toString(); + label.ordering = value(record, alias, "ordering").toInt(); + return label; } -qulonglong Label::getId() const +void Label::bindTo(QSqlQuery &query) const { - return id; + query.bindValue(":name", name); + query.bindValue(":color", color); + query.bindValue(":ordering", ordering); } diff --git a/YACReaderLibrary/db/reading_list.h b/YACReaderLibrary/db/reading_list.h index d60e8e173..72b3821ac 100644 --- a/YACReaderLibrary/db/reading_list.h +++ b/YACReaderLibrary/db/reading_list.h @@ -1,36 +1,38 @@ #ifndef READING_LIST_H #define READING_LIST_H -#include "yacreader_global.h" +#include "library_ids.h" -class ReadingList -{ -public: - ReadingList(const QString &name, qulonglong id, int ordering); +#include +#include - qulonglong getId() const; - QString getName() const; - int getOrdering() const; +#include -private: - QString name; - qulonglong id; - int ordering; -}; +class QSqlQuery; +class QSqlRecord; -class Label -{ -public: - Label(const QString &name, qulonglong id, YACReader::LabelColors colorid); +struct ReadingList { + ReadingListId id; + std::optional parentId; + int ordering = 0; + QString name; + bool finished = false; + bool completed = true; - YACReader::LabelColors getColorID() const; - QString getName() const; - qulonglong getId() const; + static const QStringList &columns(); + static ReadingList fromRecord(const QSqlRecord &record, const QString &alias); + void bindTo(QSqlQuery &query) const; +}; -private: +struct Label { + LabelId id; QString name; - qulonglong id; - YACReader::LabelColors colorid; + QString color; + int ordering = 0; + + static const QStringList &columns(); + static Label fromRecord(const QSqlRecord &record, const QString &alias); + void bindTo(QSqlQuery &query) const; }; #endif // READING_LIST_H diff --git a/YACReaderLibrary/db_helper.cpp b/YACReaderLibrary/db_helper.cpp index f949cd873..85711a2da 100644 --- a/YACReaderLibrary/db_helper.cpp +++ b/YACReaderLibrary/db_helper.cpp @@ -8,6 +8,7 @@ #include "library_item.h" #include "qnaturalsorting.h" #include "reading_list.h" +#include "table_projection.h" #include "yacreader_global.h" #include "yacreader_libraries.h" @@ -341,24 +342,20 @@ QList DBHelper::getReadingLists(qulonglong libraryId) { QSqlDatabase db = DataBaseManagement::loadDatabase(LibraryPaths::libraryDataPath(libraryPath)); - QSqlQuery selectQuery("SELECT * from reading_list WHERE parentId IS NULL ORDER BY name DESC", db); + QSqlQuery selectQuery("SELECT " + TableProjection::selectList("rl", ReadingList::columns()) + + " FROM reading_list rl WHERE rl.parentId IS NULL ORDER BY rl.name DESC", + db); selectQuery.exec(); - QSqlRecord record = selectQuery.record(); - - int name = record.indexOf("name"); - int id = record.indexOf("id"); - int ordering = record.indexOf("ordering"); - while (selectQuery.next()) { - ReadingList item(selectQuery.value(name).toString(), selectQuery.value(id).toLongLong(), selectQuery.value(ordering).toInt()); + const auto item = ReadingList::fromRecord(selectQuery.record(), "rl"); if (list.isEmpty()) { list.append(item); } else { int i = 0; - while (i < list.length() && naturalSortLessThanCI(list.at(i).getName(), item.getName())) + while (i < list.length() && naturalSortLessThanCI(list.at(i).name, item.name)) i++; list.insert(i, item); } @@ -1768,30 +1765,25 @@ QList