From 4784baad48e679ddafe7fd8b0cce41ae59159af8 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Mon, 12 Jun 2023 07:44:08 +0200 Subject: [PATCH] much faster label menu showing --- src/librssguard/database/databasequeries.cpp | 69 +++++++++++++++++++ src/librssguard/database/databasequeries.h | 4 ++ src/librssguard/gui/reusable/labelsmenu.cpp | 16 +++-- .../services/abstract/labelsnode.cpp | 5 ++ 4 files changed, 87 insertions(+), 7 deletions(-) diff --git a/src/librssguard/database/databasequeries.cpp b/src/librssguard/database/databasequeries.cpp index 61301f459..3ce6739ce 100644 --- a/src/librssguard/database/databasequeries.cpp +++ b/src/librssguard/database/databasequeries.cpp @@ -709,6 +709,75 @@ QMap DatabaseQueries::getMessageCountsForAllLabels(const return counts; } +QMap DatabaseQueries::getCountOfAssignedLabelsToMessages(const QSqlDatabase& db, + const QList& messages, + int account_id, + bool* ok) { + QMap counts; + QSqlQuery q(db); + + q.setForwardOnly(true); + + auto msgs_std = boolinq::from(messages) + .select([](const Message& msg) { + return QSL("m.custom_id = '%1'").arg(msg.m_customId); + }) + .toStdList(); + + QStringList msgs_lst = FROM_STD_LIST(QStringList, msgs_std); + auto msgs = msgs_lst.join(QSL(" OR ")); + + if (db.driverName() == QSL(APP_DB_MYSQL_DRIVER)) { + q.prepare(QSL("SELECT l.custom_id, CONCAT('%.', l.id,'.%') pid, SUM(m.is_read), COUNT(*) FROM Labels l " + "INNER JOIN Messages m " + " ON m.account_id = l.account_id AND m.labels LIKE pid " + "WHERE " + " m.is_deleted = 0 AND " + " m.is_pdeleted = 0 AND " + " m.account_id = :account_id AND " + " (%1) " + "GROUP BY pid;") + .arg(msgs)); + } + else { + q.prepare(QSL("SELECT l.custom_id, ('%.' || l.id || '.%') pid, SUM(m.is_read), COUNT(*) FROM Labels l " + "INNER JOIN Messages m " + " ON m.account_id = l.account_id AND m.labels LIKE pid " + "WHERE " + " m.is_deleted = 0 AND " + " m.is_pdeleted = 0 AND " + " m.account_id = :account_id AND " + " (%1) " + "GROUP BY pid;") + .arg(msgs)); + } + + q.bindValue(QSL(":account_id"), account_id); + + if (q.exec()) { + while (q.next()) { + QString lbl_custom_id = q.value(0).toString(); + ArticleCounts ac; + + ac.m_total = q.value(3).toInt(); + ac.m_unread = ac.m_total - q.value(2).toInt(); + + counts.insert(lbl_custom_id, ac); + } + + if (ok != nullptr) { + *ok = true; + } + } + else { + if (ok != nullptr) { + *ok = false; + } + } + + return counts; +} + ArticleCounts DatabaseQueries::getImportantMessageCounts(const QSqlDatabase& db, int account_id, bool* ok) { QSqlQuery q(db); diff --git a/src/librssguard/database/databasequeries.h b/src/librssguard/database/databasequeries.h index 0c1f281e1..e75adb316 100644 --- a/src/librssguard/database/databasequeries.h +++ b/src/librssguard/database/databasequeries.h @@ -93,6 +93,10 @@ class DatabaseQueries { static QMap getMessageCountsForAllLabels(const QSqlDatabase& db, int account_id, bool* ok = nullptr); + static QMap getCountOfAssignedLabelsToMessages(const QSqlDatabase& db, + const QList& messages, + int account_id, + bool* ok = nullptr); static ArticleCounts getImportantMessageCounts(const QSqlDatabase& db, int account_id, bool* ok = nullptr); static int getUnreadMessageCounts(const QSqlDatabase& db, int account_id, bool* ok = nullptr); diff --git a/src/librssguard/gui/reusable/labelsmenu.cpp b/src/librssguard/gui/reusable/labelsmenu.cpp index fc486137d..04c7f131a 100644 --- a/src/librssguard/gui/reusable/labelsmenu.cpp +++ b/src/librssguard/gui/reusable/labelsmenu.cpp @@ -23,6 +23,12 @@ LabelsMenu::LabelsMenu(const QList& messages, const QList& labe } else { QSqlDatabase db = qApp->database()->driver()->connection(QSL("LabelsMenu")); + QMap assignments = + labels.isEmpty() + ? QMap() + : DatabaseQueries::getCountOfAssignedLabelsToMessages(db, + messages, + labels.first()->getParentServiceRoot()->accountId()); for (Label* label : boolinq::from(labels) .orderBy([](const Label* label) { @@ -30,17 +36,13 @@ LabelsMenu::LabelsMenu(const QList& messages, const QList& labe }) .toStdList()) { - auto count = boolinq::from(messages).count([&db, label](const Message& msg) { - // TODO: slow - return DatabaseQueries::isLabelAssignedToMessage(db, label, msg); - }); - + auto count = assignments.value(label->customId()); Qt::CheckState state = Qt::CheckState::Unchecked; - if (count == messages.size()) { + if (count.m_total == messages.size()) { state = Qt::CheckState::Checked; } - else if (count > 0) { + else if (count.m_total > 0) { state = Qt::CheckState::PartiallyChecked; } diff --git a/src/librssguard/services/abstract/labelsnode.cpp b/src/librssguard/services/abstract/labelsnode.cpp index a343e0e84..949bc6b1e 100644 --- a/src/librssguard/services/abstract/labelsnode.cpp +++ b/src/librssguard/services/abstract/labelsnode.cpp @@ -61,6 +61,11 @@ int LabelsNode::countOfAllMessages() const { } void LabelsNode::updateCounts(bool including_total_count) { + // TODO: This is still rather slow because this is automatically + // called when message is marked (un)read or starred. + // It would be enought if only labels which are assigned to article + // are recounted, not all. + QSqlDatabase database = qApp->database()->driver()->threadSafeConnection(metaObject()->className()); int account_id = getParentServiceRoot()->accountId(); auto acc = DatabaseQueries::getMessageCountsForAllLabels(database, account_id);