provide local IDs

This commit is contained in:
Martin Rotter 2021-07-14 14:46:45 +02:00
parent 465f5d254f
commit fd251a1e78
19 changed files with 185 additions and 21 deletions

View File

@ -5,6 +5,7 @@
#include "3rd-party/boolinq/boolinq.h"
#include "core/feedsmodel.h"
#include "core/messagefilter.h"
#include "database/databasequeries.h"
#include "definitions/definitions.h"
#include "exceptions/feedfetchexception.h"
#include "exceptions/filteringexception.h"
@ -122,7 +123,36 @@ void FeedDownloader::updateOneFeed(Feed* feed) {
QElapsedTimer tmr; tmr.start();
try {
QList<Message> msgs = feed->getParentServiceRoot()->obtainNewMessages({ feed });
bool is_main_thread = QThread::currentThread() == qApp->thread();
QSqlDatabase database = is_main_thread ?
qApp->database()->driver()->connection(metaObject()->className()) :
qApp->database()->driver()->connection(QSL("feed_upd"));
QHash<ServiceRoot::BagOfMessages, QStringList> stated_messages;
QHash<QString, QStringList> tagged_messages;
if (feed->getParentServiceRoot()->wantsBaggedIdsOfExistingMessages()) {
// This account has activated intelligent downloading of messages.
// Prepare bags.
stated_messages.insert(ServiceRoot::BagOfMessages::Read,
DatabaseQueries::bagOfMessages(database,
ServiceRoot::BagOfMessages::Read,
{ feed }));
stated_messages.insert(ServiceRoot::BagOfMessages::Unread,
DatabaseQueries::bagOfMessages(database,
ServiceRoot::BagOfMessages::Unread,
{ feed }));
stated_messages.insert(ServiceRoot::BagOfMessages::Starred,
DatabaseQueries::bagOfMessages(database,
ServiceRoot::BagOfMessages::Starred,
{ feed }));
tagged_messages = DatabaseQueries::bagsOfMessages(database,
feed->getParentServiceRoot()->labelsNode()->labels());
}
QList<Message> msgs = feed->getParentServiceRoot()->obtainNewMessages({ feed },
stated_messages,
tagged_messages);
qDebugNN << LOGSEC_FEEDDOWNLOADER << "Downloaded " << msgs.size() << " messages for feed ID '"
<< feed->customId() << "' URL: '" << feed->source() << "' title: '" << feed->title() << "' in thread: '"
@ -137,11 +167,6 @@ void FeedDownloader::updateOneFeed(Feed* feed) {
if (!feed->messageFilters().isEmpty()) {
tmr.restart();
bool is_main_thread = QThread::currentThread() == qApp->thread();
QSqlDatabase database = is_main_thread ?
qApp->database()->driver()->connection(metaObject()->className()) :
qApp->database()->driver()->connection(QSL("feed_upd"));
// Perform per-message filtering.
QJSEngine filter_engine;

View File

@ -958,6 +958,72 @@ QList<Message> DatabaseQueries::getUndeletedMessagesForAccount(const QSqlDatabas
return messages;
}
QStringList DatabaseQueries::bagOfMessages(const QSqlDatabase& db, ServiceRoot::BagOfMessages bag, const QList<Feed*>& feeds) {
QStringList ids;
QSqlQuery q(db);
QString query;
q.setForwardOnly(true);
switch (bag) {
case ServiceRoot::BagOfMessages::Unread:
query = QSL("is_read = 0");
break;
case ServiceRoot::BagOfMessages::Starred:
query = QSL("is_important = 1");
break;
case ServiceRoot::BagOfMessages::Read:
default:
query = QSL("is_read = 1");
break;
}
q.prepare(QSL("SELECT custom_id "
"FROM Messages "
"WHERE %1 AND account_id = :account_id;").arg(query));
for (Feed* feed: feeds) {
q.bindValue(QSL(":account_id"), feed->getParentServiceRoot()->accountId());
q.exec();
while (q.next()) {
ids.append(q.value(0).toString());
}
}
return ids;
}
QHash<QString, QStringList> DatabaseQueries::bagsOfMessages(const QSqlDatabase& db, const QList<Label*>& labels) {
QHash<QString, QStringList> ids;
QSqlQuery q(db);
QString query;
q.setForwardOnly(true);
q.prepare(QSL("SELECT message "
"FROM LabelsInMessages "
"WHERE label = :label AND account_id = :account_id;").arg(query));
for (const Label* lbl :labels) {
q.bindValue(QSL(":label"), lbl->customId());
q.bindValue(QSL(":account_id"), lbl->getParentServiceRoot()->accountId());
q.exec();
QStringList ids_one_label;
while (q.next()) {
ids_one_label.append(q.value(0).toString());
}
ids.insert(lbl->customId(), ids_one_label);
}
return ids;
}
QPair<int, int> DatabaseQueries::updateMessages(QSqlDatabase db,
const QList<Message>& messages,
const QString& feed_custom_id,

View File

@ -93,6 +93,8 @@ class DatabaseQueries {
static QList<Message> getUndeletedMessagesForAccount(const QSqlDatabase& db, int account_id, bool* ok = nullptr);
// Custom ID accumulators.
static QStringList bagOfMessages(const QSqlDatabase& db, ServiceRoot::BagOfMessages bag, const QList<Feed*>& feeds);
static QHash<QString, QStringList> bagsOfMessages(const QSqlDatabase& db, const QList<Label*>& labels);
static QStringList customIdsOfMessagesFromLabel(const QSqlDatabase& db, Label* label, bool* ok = nullptr);
static QStringList customIdsOfImportantMessages(const QSqlDatabase& db, int account_id, bool* ok = nullptr);
static QStringList customIdsOfUnreadMessages(const QSqlDatabase& db, int account_id, bool* ok = nullptr);

View File

@ -311,6 +311,10 @@ void ServiceRoot::setCustomDatabaseData(const QVariantHash& data) {
Q_UNUSED(data)
}
bool ServiceRoot::wantsBaggedIdsOfExistingMessages() const {
return false;
}
void ServiceRoot::itemChanged(const QList<RootItem*>& items) {
emit dataChanged(items);
}

View File

@ -36,6 +36,12 @@ class ServiceRoot : public RootItem {
Deleting = 4
};
enum class BagOfMessages {
Read,
Unread,
Starred
};
public:
explicit ServiceRoot(RootItem* parent = nullptr);
virtual ~ServiceRoot();
@ -58,6 +64,7 @@ class ServiceRoot : public RootItem {
virtual void saveAccountDataToDatabase();
virtual QVariantHash customDatabaseData() const;
virtual void setCustomDatabaseData(const QVariantHash& data);
virtual bool wantsBaggedIdsOfExistingMessages() const;
// Returns list of specific actions for "Add new item" main window menu.
// So typical list of returned actions could look like:
@ -94,7 +101,9 @@ class ServiceRoot : public RootItem {
// Obtains list of messages.
// Throws exception subclassed from ApplicationException, preferably FeedFetchException
// if any problems arise.
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds) = 0;
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds,
const QHash<ServiceRoot::BagOfMessages, QStringList>& stated_messages,
const QHash<QString, QStringList>& tagged_messages) = 0;
// This method should prepare messages for given "item" (download them maybe?)
// into predefined "Messages" table
@ -266,6 +275,10 @@ class ServiceRoot : public RootItem {
QNetworkProxy m_networkProxy;
};
inline uint qHash(ServiceRoot::BagOfMessages key, uint seed) {
return ::qHash(static_cast<uint>(key), seed);
}
ServiceRoot::LabelOperation operator|(ServiceRoot::LabelOperation lhs, ServiceRoot::LabelOperation rhs);
ServiceRoot::LabelOperation operator&(ServiceRoot::LabelOperation lhs, ServiceRoot::LabelOperation rhs);

View File

@ -72,7 +72,12 @@ void FeedlyServiceRoot::setCustomDatabaseData(const QVariantHash& data) {
m_network->setDownloadOnlyUnreadMessages(data["download_only_unread"].toBool());
}
QList<Message> FeedlyServiceRoot::obtainNewMessages(const QList<Feed*>& feeds) {
QList<Message> FeedlyServiceRoot::obtainNewMessages(const QList<Feed*>& feeds,
const QHash<BagOfMessages, QStringList>& stated_messages,
const QHash<QString, QStringList>& tagged_messages) {
Q_UNUSED(stated_messages)
Q_UNUSED(tagged_messages)
QList<Message> messages;
for (Feed* feed : feeds) {

View File

@ -23,7 +23,9 @@ class FeedlyServiceRoot : public ServiceRoot, public CacheForServiceRoot {
virtual LabelOperation supportedLabelOperations() const;
virtual QVariantHash customDatabaseData() const;
virtual void setCustomDatabaseData(const QVariantHash& data);
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds);
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds,
const QHash<ServiceRoot::BagOfMessages, QStringList>& stated_messages,
const QHash<QString, QStringList>& tagged_messages);
FeedlyNetwork* network() const;

View File

@ -74,7 +74,12 @@ void GmailServiceRoot::setCustomDatabaseData(const QVariantHash& data) {
m_network->oauth()->setRedirectUrl(data["redirect_uri"].toString());
}
QList<Message> GmailServiceRoot::obtainNewMessages(const QList<Feed*>& feeds) {
QList<Message> GmailServiceRoot::obtainNewMessages(const QList<Feed*>& feeds,
const QHash<BagOfMessages, QStringList>& stated_messages,
const QHash<QString, QStringList>& tagged_messages) {
Q_UNUSED(stated_messages)
Q_UNUSED(tagged_messages)
QList<Message> messages;
for (Feed* feed : feeds) {

View File

@ -31,7 +31,9 @@ class GmailServiceRoot : public ServiceRoot, public CacheForServiceRoot {
virtual void saveAllCachedData(bool ignore_errors);
virtual QVariantHash customDatabaseData() const;
virtual void setCustomDatabaseData(const QVariantHash& data);
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds);
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds,
const QHash<ServiceRoot::BagOfMessages, QStringList>& stated_messages,
const QHash<QString, QStringList>& tagged_messages);
protected:
virtual RootItem* obtainNewTreeForSyncIn() const;

View File

@ -57,7 +57,12 @@ void GreaderServiceRoot::setCustomDatabaseData(const QVariantHash& data) {
m_network->setDownloadOnlyUnreadMessages(data["download_only_unread"].toBool());
}
QList<Message> GreaderServiceRoot::obtainNewMessages(const QList<Feed*>& feeds) {
QList<Message> GreaderServiceRoot::obtainNewMessages(const QList<Feed*>& feeds,
const QHash<BagOfMessages, QStringList>& stated_messages,
const QHash<QString, QStringList>& tagged_messages) {
Q_UNUSED(stated_messages)
Q_UNUSED(tagged_messages)
QList<Message> messages;
for (Feed* feed : feeds) {
@ -73,6 +78,10 @@ QList<Message> GreaderServiceRoot::obtainNewMessages(const QList<Feed*>& feeds)
return messages;
}
bool GreaderServiceRoot::wantsBaggedIdsOfExistingMessages() const {
return true;
}
void GreaderServiceRoot::start(bool freshly_activated) {
if (!freshly_activated) {
DatabaseQueries::loadFromDatabase<Category, Feed>(this);

View File

@ -31,7 +31,10 @@ class GreaderServiceRoot : public ServiceRoot, public CacheForServiceRoot {
virtual LabelOperation supportedLabelOperations() const;
virtual QVariantHash customDatabaseData() const;
virtual void setCustomDatabaseData(const QVariantHash& data);
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds);
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds,
const QHash<ServiceRoot::BagOfMessages, QStringList>& stated_messages,
const QHash<QString, QStringList>& tagged_messages);
virtual bool wantsBaggedIdsOfExistingMessages() const;
GreaderNetwork* network() const;

View File

@ -56,7 +56,12 @@ void InoreaderServiceRoot::setCustomDatabaseData(const QVariantHash& data) {
m_network->oauth()->setRedirectUrl(data["redirect_uri"].toString());
}
QList<Message> InoreaderServiceRoot::obtainNewMessages(const QList<Feed*>& feeds) {
QList<Message> InoreaderServiceRoot::obtainNewMessages(const QList<Feed*>& feeds,
const QHash<BagOfMessages, QStringList>& stated_messages,
const QHash<QString, QStringList>& tagged_messages) {
Q_UNUSED(stated_messages)
Q_UNUSED(tagged_messages)
QList<Message> messages;
for (Feed* feed : feeds) {

View File

@ -29,7 +29,9 @@ class InoreaderServiceRoot : public ServiceRoot, public CacheForServiceRoot {
virtual void saveAllCachedData(bool ignore_errors);
virtual QVariantHash customDatabaseData() const;
virtual void setCustomDatabaseData(const QVariantHash& data);
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds);
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds,
const QHash<ServiceRoot::BagOfMessages, QStringList>& stated_messages,
const QHash<QString, QStringList>& tagged_messages);
protected:
virtual RootItem* obtainNewTreeForSyncIn() const;

View File

@ -150,7 +150,12 @@ void OwnCloudServiceRoot::setCustomDatabaseData(const QVariantHash& data) {
m_network->setDownloadOnlyUnreadMessages(data["download_only_unread"].toBool());
}
QList<Message> OwnCloudServiceRoot::obtainNewMessages(const QList<Feed*>& feeds) {
QList<Message> OwnCloudServiceRoot::obtainNewMessages(const QList<Feed*>& feeds,
const QHash<BagOfMessages, QStringList>& stated_messages,
const QHash<QString, QStringList>& tagged_messages) {
Q_UNUSED(stated_messages)
Q_UNUSED(tagged_messages)
QList<Message> msgs;
for (Feed* feed : feeds) {

View File

@ -28,7 +28,9 @@ class OwnCloudServiceRoot : public ServiceRoot, public CacheForServiceRoot {
virtual void saveAllCachedData(bool ignore_errors);
virtual QVariantHash customDatabaseData() const;
virtual void setCustomDatabaseData(const QVariantHash& data);
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds);
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds,
const QHash<ServiceRoot::BagOfMessages, QStringList>& stated_messages,
const QHash<QString, QStringList>& tagged_messages);
OwnCloudNetworkFactory* network() const;

View File

@ -144,7 +144,12 @@ Qt::ItemFlags StandardServiceRoot::additionalFlags() const {
return Qt::ItemFlag::ItemIsDropEnabled;
}
QList<Message> StandardServiceRoot::obtainNewMessages(const QList<Feed*>& feeds) {
QList<Message> StandardServiceRoot::obtainNewMessages(const QList<Feed*>& feeds,
const QHash<BagOfMessages, QStringList>& stated_messages,
const QHash<QString, QStringList>& tagged_messages) {
Q_UNUSED(stated_messages)
Q_UNUSED(tagged_messages)
QList<Message> msgs;
for (Feed* f : feeds) {

View File

@ -32,7 +32,9 @@ class StandardServiceRoot : public ServiceRoot {
virtual bool supportsFeedAdding() const;
virtual bool supportsCategoryAdding() const;
virtual Qt::ItemFlags additionalFlags() const;
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds);
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds,
const QHash<ServiceRoot::BagOfMessages, QStringList>& stated_messages,
const QHash<QString, QStringList>& tagged_messages);
QList<QAction*> serviceMenu();
QList<QAction*> getContextMenuForFeed(StandardFeed* feed);

View File

@ -214,7 +214,12 @@ void TtRssServiceRoot::setCustomDatabaseData(const QVariantHash& data) {
m_network->setDownloadOnlyUnreadMessages(data["download_only_unread"].toBool());
}
QList<Message> TtRssServiceRoot::obtainNewMessages(const QList<Feed*>& feeds) {
QList<Message> TtRssServiceRoot::obtainNewMessages(const QList<Feed*>& feeds,
const QHash<BagOfMessages, QStringList>& stated_messages,
const QHash<QString, QStringList>& tagged_messages) {
Q_UNUSED(stated_messages)
Q_UNUSED(tagged_messages)
QList<Message> messages;
for (Feed* feed : feeds) {

View File

@ -33,7 +33,9 @@ class TtRssServiceRoot : public ServiceRoot, public CacheForServiceRoot {
virtual void saveAllCachedData(bool ignore_errors);
virtual QVariantHash customDatabaseData() const;
virtual void setCustomDatabaseData(const QVariantHash& data);
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds);
virtual QList<Message> obtainNewMessages(const QList<Feed*>& feeds,
const QHash<ServiceRoot::BagOfMessages, QStringList>& stated_messages,
const QHash<QString, QStringList>& tagged_messages);
// Access to network.
TtRssNetworkFactory* network() const;