Verified Commit abd7b515 authored by Linus Jahn's avatar Linus Jahn 🔌
Browse files

Refactor RosterDb to use QFutures

parent 7fbe011c
Pipeline #82663 passed with stage
in 7 minutes and 12 seconds
......@@ -48,10 +48,6 @@ RosterDb::RosterDb(Database *db, QObject *parent)
{
Q_ASSERT(!RosterDb::s_instance);
s_instance = this;
connect(this, &RosterDb::fetchItemsRequested, this, &RosterDb::fetchItems);
connect(this, &RosterDb::updateItemRequested, this, &RosterDb::updateItem);
connect(this, &RosterDb::removeItemsRequested, this, &RosterDb::removeItems);
}
RosterDb::~RosterDb()
......@@ -96,148 +92,161 @@ QSqlRecord RosterDb::createUpdateRecord(const RosterItem &oldItem, const RosterI
return rec;
}
void RosterDb::addItem(const RosterItem &item)
QFuture<void> RosterDb::addItem(const RosterItem &item)
{
addItems(QVector<RosterItem>() << item);
return addItems({item});
}
void RosterDb::addItems(const QVector<RosterItem> &items)
QFuture<void> RosterDb::addItems(const QVector<RosterItem> &items)
{
auto query = createQuery();
transaction();
Utils::prepareQuery(query, sqlDriver().sqlStatement(
QSqlDriver::InsertStatement,
DB_TABLE_ROSTER,
sqlRecord(DB_TABLE_ROSTER),
true
));
for (const auto &item : items) {
query.addBindValue(item.jid());
query.addBindValue(item.name());
query.addBindValue(QStringLiteral("")); // lastExchanged (NOT NULL)
query.addBindValue(item.unreadMessages());
query.addBindValue(QString()); // lastMessage
Utils::execQuery(query);
}
return run([this, items]() {
auto query = createQuery();
transaction();
Utils::prepareQuery(query, sqlDriver().sqlStatement(
QSqlDriver::InsertStatement,
DB_TABLE_ROSTER,
sqlRecord(DB_TABLE_ROSTER),
true
));
for (const auto &item : items) {
query.addBindValue(item.jid());
query.addBindValue(item.name());
query.addBindValue(QStringLiteral("")); // lastExchanged (NOT NULL)
query.addBindValue(item.unreadMessages());
query.addBindValue(QString()); // lastMessage
Utils::execQuery(query);
}
commit();
commit();
});
}
void RosterDb::updateItem(const QString &jid,
QFuture<void> RosterDb::updateItem(const QString &jid,
const std::function<void (RosterItem &)> &updateItem)
{
// load current roster item from db
auto query = createQuery();
Utils::execQuery(
query,
"SELECT * FROM Roster WHERE jid = ? LIMIT 1",
QVector<QVariant>() << jid
);
QVector<RosterItem> items;
parseItemsFromQuery(query, items);
// update loaded item
if (!items.isEmpty()) {
RosterItem item = items.first();
updateItem(item);
// replace old item with updated one, if item has changed
if (items.first() != item) {
// create an SQL record with only the differences
QSqlRecord rec = createUpdateRecord(items.first(), item);
if (rec.isEmpty())
return;
updateItemByRecord(jid, rec);
return run([this, jid, updateItem]() {
// load current roster item from db
auto query = createQuery();
Utils::execQuery(
query,
"SELECT * FROM Roster WHERE jid = ? LIMIT 1",
QVector<QVariant>() << jid
);
QVector<RosterItem> items;
parseItemsFromQuery(query, items);
// update loaded item
if (!items.isEmpty()) {
RosterItem item = items.first();
updateItem(item);
// replace old item with updated one, if item has changed
if (items.first() != item) {
// create an SQL record with only the differences
QSqlRecord rec = createUpdateRecord(items.first(), item);
if (rec.isEmpty())
return;
updateItemByRecord(jid, rec);
}
}
}
});
}
void RosterDb::replaceItems(const QHash<QString, RosterItem> &items)
QFuture<void> RosterDb::replaceItems(const QHash<QString, RosterItem> &items)
{
// load current items
auto query = createQuery();
Utils::execQuery(query, "SELECT * FROM Roster");
QVector<RosterItem> currentItems;
parseItemsFromQuery(query, currentItems);
transaction();
QList<QString> keys = items.keys();
QSet<QString> newJids = QSet<QString>(keys.begin(), keys.end());
for (const auto &oldItem : qAsConst(currentItems)) {
// We will remove the already existing JIDs, so we get a set of JIDs that
// are completely new.
//
// By calling remove(), we also find out whether the JID is already
// existing or not.
if (newJids.remove(oldItem.jid())) {
// item is also included in newJids -> update
// name is (currently) the only attribute that is defined by the
// XMPP roster and so could cause a change
if (oldItem.name() != items[oldItem.jid()].name())
setItemName(oldItem.jid(), items[oldItem.jid()].name());
} else {
// item is not included in newJids -> delete
removeItems({}, oldItem.jid());
return run([this, items]() {
// load current items
auto query = createQuery();
Utils::execQuery(query, "SELECT * FROM Roster");
QVector<RosterItem> currentItems;
parseItemsFromQuery(query, currentItems);
transaction();
QList<QString> keys = items.keys();
QSet<QString> newJids = QSet<QString>(keys.begin(), keys.end());
for (const auto &oldItem : qAsConst(currentItems)) {
// We will remove the already existing JIDs, so we get a set of JIDs that
// are completely new.
//
// By calling remove(), we also find out whether the JID is already
// existing or not.
if (newJids.remove(oldItem.jid())) {
// item is also included in newJids -> update
// name is (currently) the only attribute that is defined by the
// XMPP roster and so could cause a change
if (oldItem.name() != items[oldItem.jid()].name())
setItemName(oldItem.jid(), items[oldItem.jid()].name());
} else {
// item is not included in newJids -> delete
removeItems({}, oldItem.jid());
}
}
}
// now add the completely new JIDs
for (const QString &jid : newJids)
addItem(items[jid]);
// now add the completely new JIDs
for (const QString &jid : newJids) {
addItem(items[jid]);
}
commit();
commit();
});
}
void RosterDb::removeItems(const QString &, const QString &)
QFuture<void> RosterDb::removeItems(const QString &, const QString &)
{
auto query = createQuery();
Utils::execQuery(query, "DELETE FROM Roster");
return run([this]() {
auto query = createQuery();
Utils::execQuery(query, "DELETE FROM Roster");
});
}
void RosterDb::setItemName(const QString &jid, const QString &name)
QFuture<void> RosterDb::setItemName(const QString &jid, const QString &name)
{
auto query = createQuery();
auto &driver = sqlDriver();
QSqlRecord rec;
rec.append(Utils::createSqlField("name", name));
Utils::execQuery(
query,
driver.sqlStatement(
QSqlDriver::UpdateStatement,
DB_TABLE_ROSTER,
rec,
false
) +
Utils::simpleWhereStatement(&driver, "jid", jid)
);
return run([this, jid, name]() {
auto query = createQuery();
auto &driver = sqlDriver();
QSqlRecord rec;
rec.append(Utils::createSqlField("name", name));
Utils::execQuery(
query,
driver.sqlStatement(
QSqlDriver::UpdateStatement,
DB_TABLE_ROSTER,
rec,
false
) +
Utils::simpleWhereStatement(&driver, "jid", jid)
);
});
}
void RosterDb::fetchItems(const QString &accountId)
QFuture<QVector<RosterItem>> RosterDb::fetchItems(const QString &accountId)
{
auto query = createQuery();
Utils::execQuery(query, "SELECT * FROM Roster");
return run([this, accountId]() {
auto query = createQuery();
Utils::execQuery(query, "SELECT * FROM Roster");
QVector<RosterItem> items;
parseItemsFromQuery(query, items);
QVector<RosterItem> items;
parseItemsFromQuery(query, items);
for (auto &item : items) {
Message lastMessage = MessageDb::instance()->fetchLastMessage(accountId, item.jid());
item.setLastExchanged(lastMessage.stamp());
item.setLastMessage(lastMessage.previewText());
}
for (auto &item : items) {
Message lastMessage = MessageDb::instance()->fetchLastMessage(accountId, item.jid());
item.setLastExchanged(lastMessage.stamp());
item.setLastMessage(lastMessage.previewText());
}
emit itemsFetched(items);
return items;
});
}
void RosterDb::updateItemByRecord(const QString &jid, const QSqlRecord &record)
......
......@@ -55,27 +55,11 @@ public:
static QSqlRecord createUpdateRecord(const RosterItem &oldItem,
const RosterItem &newItem);
signals:
void fetchItemsRequested(const QString &accountId);
void itemsFetched(const QVector<RosterItem> &items);
void updateItemRequested(const QString &jid,
const std::function<void (RosterItem &)> &updateItem);
void clearAllRequested();
/**
* Emitted to remove all roster items of an account or a specific roster item.
*
* @param accountJid JID of the account whose roster items are being removed
* @param jid JID of the roster item being removed (optional)
*/
void removeItemsRequested(const QString &accountJid, const QString &jid = {});
public slots:
void addItem(const RosterItem &item);
void addItems(const QVector<RosterItem> &items);
void updateItem(const QString &jid,
QFuture<void> addItem(const RosterItem &item);
QFuture<void> addItems(const QVector<RosterItem> &items);
QFuture<void> updateItem(const QString &jid,
const std::function<void (RosterItem &)> &updateItem);
void replaceItems(const QHash<QString, RosterItem> &items);
QFuture<void> replaceItems(const QHash<QString, RosterItem> &items);
/**
* Removes all roster items of an account or a specific roster item.
......@@ -83,12 +67,9 @@ public slots:
* @param accountJid JID of the account whose roster items are being removed
* @param jid JID of the roster item being removed (optional)
*/
void removeItems(const QString &accountJid, const QString &jid = {});
void setItemName(const QString &jid, const QString &name);
private slots:
void fetchItems(const QString &accountId);
QFuture<void> removeItems(const QString &accountJid, const QString &jid = {});
QFuture<void> setItemName(const QString &jid, const QString &name);
QFuture<QVector<RosterItem>> fetchItems(const QString &accountId);
private:
void updateItemByRecord(const QString &jid, const QSqlRecord &record);
......
......@@ -32,6 +32,7 @@
// Kaidan
#include "AccountManager.h"
#include "FutureUtils.h"
#include "Kaidan.h"
#include "MessageDb.h"
#include "MessageModel.h"
......@@ -54,9 +55,6 @@ RosterModel::RosterModel(QObject *parent)
Q_ASSERT(!s_instance);
s_instance = this;
connect(RosterDb::instance(), &RosterDb::itemsFetched,
this, &RosterModel::handleItemsFetched);
connect(this, &RosterModel::addItemRequested, this, &RosterModel::addItem);
connect(this, &RosterModel::addItemRequested, RosterDb::instance(), &RosterDb::addItem);
......@@ -76,12 +74,13 @@ RosterModel::RosterModel(QObject *parent)
m_items.clear();
endResetModel();
emit RosterDb::instance()->fetchItemsRequested(AccountManager::instance()->jid());
await(RosterDb::instance()->fetchItems(AccountManager::instance()->jid()), this, [this](QVector<RosterItem> items) {
handleItemsFetched(items);
});
});
connect(this, &RosterModel::removeItemsRequested, this, [=](const QString &accountJid, const QString &chatJid) {
emit RosterDb::instance()->removeItemsRequested(accountJid, chatJid);
RosterDb::instance()->removeItems(accountJid, chatJid);
removeItems(accountJid, chatJid);
if (accountJid == MessageModel::instance()->currentAccountJid() && chatJid == MessageModel::instance()->currentChatJid())
......@@ -335,7 +334,7 @@ void RosterModel::handleMessageAdded(const Message &message, MessageOrigin origi
itr->setUnreadMessages(*newUnreadMessages);
changedRoles << int(UnreadMessagesRole);
emit RosterDb::instance()->updateItemRequested(contactJid, [=](RosterItem &item) {
RosterDb::instance()->updateItem(contactJid, [=](RosterItem &item) {
item.setUnreadMessages(*newUnreadMessages);
});
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment