diff --git a/src/MessageDb.cpp b/src/MessageDb.cpp
index a5f21e0..3a8c169 100644
--- a/src/MessageDb.cpp
+++ b/src/MessageDb.cpp
@@ -1,301 +1,316 @@
/*
* Kaidan - A user-friendly XMPP client for every device!
*
* Copyright (C) 2016-2020 Kaidan developers and contributors
* (see the LICENSE file for a full list of copyright authors)
*
* Kaidan is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* In addition, as a special exception, the author of Kaidan gives
* permission to link the code of its release with the OpenSSL
* project's "OpenSSL" library (or with modified versions of it that
* use the same license as the "OpenSSL" library), and distribute the
* linked executables. You must obey the GNU General Public License in
* all respects for all of the code used other than "OpenSSL". If you
* modify this file, you may extend this exception to your version of
* the file, but you are not obligated to do so. If you do not wish to
* do so, delete this exception statement from your version.
*
* Kaidan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Kaidan. If not, see .
*/
#include "MessageDb.h"
// Kaidan
#include "Globals.h"
#include "Message.h"
#include "Utils.h"
// Qt
#include
#include
#include
#include
#include
+MessageDb *MessageDb::s_instance = nullptr;
+
MessageDb::MessageDb(QObject *parent)
: QObject(parent)
{
+ Q_ASSERT(!MessageDb::s_instance);
+ s_instance = this;
+
connect(this, &MessageDb::fetchMessagesRequested,
this, &MessageDb::fetchMessages);
}
+MessageDb::~MessageDb()
+{
+ s_instance = nullptr;
+}
+
+MessageDb *MessageDb::instance()
+{
+ return s_instance;
+}
+
void MessageDb::parseMessagesFromQuery(QSqlQuery &query, QVector &msgs)
{
// get indexes of attributes
QSqlRecord rec = query.record();
int idxFrom = rec.indexOf("author");
int idxTo = rec.indexOf("recipient");
int idxStamp = rec.indexOf("timestamp");
int idxId = rec.indexOf("id");
int idxBody = rec.indexOf("message");
int idxIsSent = rec.indexOf("isSent");
int idxIsDelivered = rec.indexOf("isDelivered");
int idxMediaType = rec.indexOf("type");
int idxOutOfBandUrl = rec.indexOf("mediaUrl");
int idxMediaContentType = rec.indexOf("mediaContentType");
int idxMediaLocation = rec.indexOf("mediaLocation");
int idxMediaSize = rec.indexOf("mediaSize");
int idxMediaLastModified = rec.indexOf("mediaLastModified");
int idxIsEdited = rec.indexOf("edited");
int idxSpoilerHint = rec.indexOf("spoilerHint");
int idxIsSpoiler = rec.indexOf("isSpoiler");
while (query.next()) {
Message msg;
msg.setFrom(query.value(idxFrom).toString());
msg.setTo(query.value(idxTo).toString());
msg.setStamp(QDateTime::fromString(
query.value(idxStamp).toString(),
Qt::ISODate
));
msg.setId(query.value(idxId).toString());
msg.setBody(query.value(idxBody).toString());
msg.setIsSent(query.value(idxIsSent).toBool());
msg.setIsDelivered(query.value(idxIsDelivered).toBool());
msg.setMediaType(static_cast(query.value(idxMediaType).toInt()));
msg.setOutOfBandUrl(query.value(idxOutOfBandUrl).toString());
msg.setMediaContentType(query.value(idxMediaContentType).toString());
msg.setMediaLocation(query.value(idxMediaLocation).toString());
msg.setMediaSize(query.value(idxMediaSize).toLongLong());
msg.setMediaLastModified(QDateTime::fromMSecsSinceEpoch(
query.value(idxMediaLastModified).toLongLong()
));
msg.setIsEdited(query.value(idxIsEdited).toBool());
msg.setSpoilerHint(query.value(idxSpoilerHint).toString());
msg.setIsSpoiler(query.value(idxIsSpoiler).toBool());
msgs << msg;
}
}
QSqlRecord MessageDb::createUpdateRecord(const Message &oldMsg, const Message &newMsg)
{
QSqlRecord rec;
if (oldMsg.from() != newMsg.from())
rec.append(Utils::createSqlField("author", newMsg.from()));
if (oldMsg.to() != newMsg.to())
rec.append(Utils::createSqlField("recipient", newMsg.to()));
if (oldMsg.stamp() != newMsg.stamp())
rec.append(Utils::createSqlField(
"timestamp",
newMsg.stamp().toString(Qt::ISODate)
));
if (oldMsg.id() != newMsg.id()) {
// TODO: remove as soon as 'NOT NULL' was removed from id column
if (newMsg.id().isEmpty())
rec.append(Utils::createSqlField("id", QStringLiteral(" ")));
else
rec.append(Utils::createSqlField("id", newMsg.id()));
}
if (oldMsg.body() != newMsg.body())
rec.append(Utils::createSqlField("message", newMsg.body()));
if (oldMsg.isSent() != newMsg.isSent())
rec.append(Utils::createSqlField("isSent", newMsg.isSent()));
if (oldMsg.isDelivered() != newMsg.isDelivered())
rec.append(Utils::createSqlField("isDelivered", newMsg.isDelivered()));
if (oldMsg.mediaType() != newMsg.mediaType())
rec.append(Utils::createSqlField("type", int(newMsg.mediaType())));
if (oldMsg.outOfBandUrl() != newMsg.outOfBandUrl())
rec.append(Utils::createSqlField("mediaUrl", newMsg.outOfBandUrl()));
if (oldMsg.mediaContentType() != newMsg.mediaContentType())
rec.append(Utils::createSqlField(
"mediaContentType",
newMsg.mediaContentType()
));
if (oldMsg.mediaLocation() != newMsg.mediaLocation())
rec.append(Utils::createSqlField(
"mediaLocation",
newMsg.mediaLocation()
));
if (oldMsg.mediaSize() != newMsg.mediaSize())
rec.append(Utils::createSqlField("mediaSize", newMsg.mediaSize()));
if (oldMsg.mediaLastModified() != newMsg.mediaLastModified())
rec.append(Utils::createSqlField(
"mediaLastModified",
newMsg.mediaLastModified().toMSecsSinceEpoch()
));
if (oldMsg.isEdited() != newMsg.isEdited())
rec.append(Utils::createSqlField("edited", newMsg.isEdited()));
if (oldMsg.spoilerHint() != newMsg.spoilerHint())
rec.append(Utils::createSqlField("spoilerHint", newMsg.spoilerHint()));
if (oldMsg.isSpoiler() != newMsg.isSpoiler())
rec.append(Utils::createSqlField("isSpoiler", newMsg.isSpoiler()));
return rec;
}
void MessageDb::fetchMessages(const QString &user1, const QString &user2, int index)
{
QSqlQuery query(QSqlDatabase::database(DB_CONNECTION));
query.setForwardOnly(true);
QMap bindValues;
bindValues[":user1"] = user1;
bindValues[":user2"] = user2;
bindValues[":index"] = index;
bindValues[":limit"] = DB_MSG_QUERY_LIMIT;
Utils::execQuery(
query,
"SELECT * FROM Messages "
"WHERE (author = :user1 AND recipient = :user2) OR "
"(author = :user2 AND recipient = :user1) "
"ORDER BY timestamp DESC "
"LIMIT :index, :limit",
bindValues
);
QVector messages;
parseMessagesFromQuery(query, messages);
emit messagesFetched(messages);
}
void MessageDb::addMessage(const Message &msg)
{
QSqlDatabase db = QSqlDatabase::database(DB_CONNECTION);
QSqlRecord record = db.record(DB_TABLE_MESSAGES);
record.setValue("author", msg.from());
record.setValue("recipient", msg.to());
record.setValue("timestamp", msg.stamp().toString(Qt::ISODate));
record.setValue("message", msg.body());
record.setValue("id", msg.id().isEmpty() ? " " : msg.id());
record.setValue("isSent", msg.isSent());
record.setValue("isDelivered", msg.isDelivered());
record.setValue("type", int(msg.mediaType()));
record.setValue("edited", msg.isEdited());
record.setValue("isSpoiler", msg.isSpoiler());
record.setValue("spoilerHint", msg.spoilerHint());
record.setValue("mediaUrl", msg.outOfBandUrl());
record.setValue("mediaContentType", msg.mediaContentType());
record.setValue("mediaLocation", msg.mediaLocation());
record.setValue("mediaSize", msg.mediaSize());
record.setValue("mediaLastModified", msg.mediaLastModified().toMSecsSinceEpoch());
QSqlQuery query(db);
Utils::execQuery(query, db.driver()->sqlStatement(
QSqlDriver::InsertStatement,
DB_TABLE_MESSAGES,
record,
false
));
}
void MessageDb::removeMessage(const QString &id)
{
QSqlQuery query(QSqlDatabase::database(DB_CONNECTION));
Utils::execQuery(
query,
"DELETE FROM Messages WHERE id = ?",
QVector() << id
);
}
void MessageDb::removeAllMessages()
{
QSqlQuery query(QSqlDatabase::database(DB_CONNECTION));
Utils::execQuery(query, "DELETE FROM Messages");
}
void MessageDb::updateMessage(const QString &id,
const std::function &updateMsg)
{
// load current message item from db
QSqlDatabase db = QSqlDatabase::database(DB_CONNECTION);
QSqlQuery query(db);
query.setForwardOnly(true);
Utils::execQuery(
query,
"SELECT * FROM Messages WHERE id = ? LIMIT 1",
QVector() << id
);
QVector msgs;
parseMessagesFromQuery(query, msgs);
// update loaded item
if (!msgs.isEmpty()) {
Message msg = msgs.first();
updateMsg(msg);
// replace old message with updated one, if message has changed
if (msgs.first() != msg) {
// create an SQL record with only the differences
QSqlRecord rec = createUpdateRecord(msgs.first(), msg);
Utils::execQuery(
query,
db.driver()->sqlStatement(
QSqlDriver::UpdateStatement,
DB_TABLE_MESSAGES,
rec,
false
) +
Utils::simpleWhereStatement(db.driver(), "id", id)
);
}
}
}
void MessageDb::updateMessageRecord(const QString &id,
const QSqlRecord &updateRecord)
{
QSqlDatabase db = QSqlDatabase::database(DB_CONNECTION);
QSqlQuery query(db);
Utils::execQuery(
query,
db.driver()->sqlStatement(
QSqlDriver::UpdateStatement,
DB_TABLE_MESSAGES,
updateRecord,
false
) +
Utils::simpleWhereStatement(db.driver(), "id", id)
);
}
void MessageDb::setMessageAsSent(const QString &msgId)
{
QSqlRecord rec;
rec.append(Utils::createSqlField("isSent", true));
updateMessageRecord(msgId, rec);
}
void MessageDb::setMessageAsDelivered(const QString &msgId)
{
QSqlRecord rec;
rec.append(Utils::createSqlField("isDelivered", true));
updateMessageRecord(msgId, rec);
}
diff --git a/src/MessageDb.h b/src/MessageDb.h
index 38ae239..f14841e 100644
--- a/src/MessageDb.h
+++ b/src/MessageDb.h
@@ -1,138 +1,144 @@
/*
* Kaidan - A user-friendly XMPP client for every device!
*
* Copyright (C) 2016-2020 Kaidan developers and contributors
* (see the LICENSE file for a full list of copyright authors)
*
* Kaidan is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* In addition, as a special exception, the author of Kaidan gives
* permission to link the code of its release with the OpenSSL
* project's "OpenSSL" library (or with modified versions of it that
* use the same license as the "OpenSSL" library), and distribute the
* linked executables. You must obey the GNU General Public License in
* all respects for all of the code used other than "OpenSSL". If you
* modify this file, you may extend this exception to your version of
* the file, but you are not obligated to do so. If you do not wish to
* do so, delete this exception statement from your version.
*
* Kaidan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Kaidan. If not, see .
*/
#ifndef MESSAGEDB_H
#define MESSAGEDB_H
#include
#include
class Message;
class QSqlQuery;
class QSqlRecord;
/**
* @class The MessageDb is used to query the 'messages' database table. It's used by the
* MessageModel to load messages and by the MessageHandler to insert messages.
*
* All queries must be executed only after the Kaidan SQL connection has been opened in
* the Database class.
*/
class MessageDb : public QObject
{
Q_OBJECT
public:
explicit MessageDb(QObject *parent = nullptr);
+ ~MessageDb();
+
+ static MessageDb *instance();
/**
* Parses a list of messages from a SELECT query.
*/
static void parseMessagesFromQuery(QSqlQuery &query, QVector &msgs);
/**
* Creates an @c QSqlRecord for updating an old message to a new message.
*
* @param oldMsg Full message as it is currently saved
* @param newMsg Full message as it should be after the update query ran.
*/
static QSqlRecord createUpdateRecord(const Message &oldMsg,
const Message &newMsg);
signals:
/**
* Can be used to triggerd fetchMessages()
*/
void fetchMessagesRequested(const QString &user1,
const QString &user2,
int index);
/**
* Emitted, when new messages have been fetched
*/
void messagesFetched(const QVector &messages);
public slots:
/**
* @brief Fetches more entries from the database and emits messagesFetched() with
* the results.
*
* @param user1 Messages are from or to this JID.
* @param user2 Messages are from or to this JID.
* @param index Number of entries to be skipped, used for paging.
*/
void fetchMessages(const QString &user1,
const QString &user2,
int index);
/**
* Adds a message to the database.
*/
void addMessage(const Message &msg);
/**
* Deletes a message from the database.
*/
void removeMessage(const QString &id);
/**
* Removes all messages from the database.
*/
void removeAllMessages();
/**
* Loads a message, runs the update lambda and writes it to the DB again.
*
* @param updateMsg Function that changes the message
*/
void updateMessage(const QString &id,
const std::function &updateMsg);
/**
* Updates message by @c UPDATE record: This means it doesn't load the message
* from the database and writes it again, but executes an UPDATE query.
*
* @param updateRecord
*/
void updateMessageRecord(const QString &id,
const QSqlRecord &updateRecord);
/**
* Marks a message as sent using an UPDATE query.
*/
void setMessageAsSent(const QString &msgId);
/**
* Marks a message as delivered using an UPDATE query.
*/
void setMessageAsDelivered(const QString &msgId);
+
+private:
+ static MessageDb *s_instance;
};
#endif // MESSAGEDB_H
diff --git a/src/RosterDb.cpp b/src/RosterDb.cpp
index 1c4fa7e..e29957c 100644
--- a/src/RosterDb.cpp
+++ b/src/RosterDb.cpp
@@ -1,256 +1,271 @@
/*
* Kaidan - A user-friendly XMPP client for every device!
*
* Copyright (C) 2016-2020 Kaidan developers and contributors
* (see the LICENSE file for a full list of copyright authors)
*
* Kaidan is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* In addition, as a special exception, the author of Kaidan gives
* permission to link the code of its release with the OpenSSL
* project's "OpenSSL" library (or with modified versions of it that
* use the same license as the "OpenSSL" library), and distribute the
* linked executables. You must obey the GNU General Public License in
* all respects for all of the code used other than "OpenSSL". If you
* modify this file, you may extend this exception to your version of
* the file, but you are not obligated to do so. If you do not wish to
* do so, delete this exception statement from your version.
*
* Kaidan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Kaidan. If not, see .
*/
#include "RosterDb.h"
// Kaidan
#include "Database.h"
#include "Globals.h"
#include "Utils.h"
// Qt
#include
#include
#include
#include
#include
+RosterDb *RosterDb::s_instance = nullptr;
+
RosterDb::RosterDb(Database *db, QObject *parent)
: QObject(parent),
m_db(db)
{
+ Q_ASSERT(!RosterDb::s_instance);
+ s_instance = this;
+
connect(this, &RosterDb::fetchItemsRequested, this, &RosterDb::fetchItems);
}
+RosterDb::~RosterDb()
+{
+ s_instance = nullptr;
+}
+
+RosterDb *RosterDb::instance()
+{
+ return s_instance;
+}
+
void RosterDb::parseItemsFromQuery(QSqlQuery &query, QVector &items)
{
QSqlRecord rec = query.record();
int idxJid = rec.indexOf("jid");
int idxName = rec.indexOf("name");
int idxLastExchanged = rec.indexOf("lastExchanged");
int idxUnreadMessages = rec.indexOf("unreadMessages");
int idxLastMessage = rec.indexOf("lastMessage");
while (query.next()) {
RosterItem item;
item.setJid(query.value(idxJid).toString());
item.setName(query.value(idxName).toString());
item.setLastExchanged(QDateTime::fromString(
query.value(idxLastExchanged).toString(),
Qt::ISODateWithMs
));
item.setUnreadMessages(query.value(idxUnreadMessages).toInt());
item.setLastMessage(query.value(idxLastMessage).toString());
items << item;
}
}
QSqlRecord RosterDb::createUpdateRecord(const RosterItem &oldItem, const RosterItem &newItem)
{
QSqlRecord rec;
if (oldItem.jid() != newItem.jid())
rec.append(Utils::createSqlField("jid", newItem.jid()));
if (oldItem.name() != newItem.name())
rec.append(Utils::createSqlField("name", oldItem.name()));
if (oldItem.lastMessage() != newItem.lastMessage())
rec.append(Utils::createSqlField("lastMessage", newItem.lastMessage()));
if (oldItem.lastExchanged() != newItem.lastExchanged())
rec.append(Utils::createSqlField(
"lastExchanged",
newItem.lastExchanged().toString(Qt::ISODateWithMs)
));
if (oldItem.unreadMessages() != newItem.unreadMessages())
rec.append(Utils::createSqlField(
"unreadMessages",
newItem.unreadMessages()
));
return rec;
}
void RosterDb::addItem(const RosterItem &item)
{
addItems(QVector() << item);
}
void RosterDb::addItems(const QVector &items)
{
QSqlDatabase db = QSqlDatabase::database(DB_CONNECTION);
m_db->transaction();
QSqlQuery query(db);
Utils::prepareQuery(query, db.driver()->sqlStatement(
QSqlDriver::InsertStatement,
DB_TABLE_ROSTER,
db.record(DB_TABLE_ROSTER),
true
));
for (const auto &item : items) {
query.addBindValue(item.jid());
query.addBindValue(item.name());
query.addBindValue(item.lastExchanged().toString(Qt::ISODateWithMs));
query.addBindValue(item.unreadMessages());
query.addBindValue(item.lastMessage());
Utils::execQuery(query);
}
m_db->commit();
}
void RosterDb::removeItem(const QString &jid)
{
QSqlDatabase db = QSqlDatabase::database(DB_CONNECTION);
QSqlQuery query(db);
Utils::execQuery(
query,
"DELETE FROM Roster WHERE jid = ?",
QVector() << jid
);
}
void RosterDb::updateItem(const QString &jid,
const std::function &updateItem)
{
// load current roster item from db
QSqlDatabase db = QSqlDatabase::database(DB_CONNECTION);
QSqlQuery query(db);
query.setForwardOnly(true);
Utils::execQuery(
query,
"SELECT * FROM Roster WHERE jid = ? LIMIT 1",
QVector() << jid
);
QVector 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);
Utils::execQuery(
query,
db.driver()->sqlStatement(
QSqlDriver::UpdateStatement,
DB_TABLE_ROSTER,
rec,
false
) +
Utils::simpleWhereStatement(db.driver(), "jid", jid)
);
}
}
}
void RosterDb::replaceItems(const QHash &items)
{
// load current items
QSqlDatabase db = QSqlDatabase::database(DB_CONNECTION);
QSqlQuery query(db);
query.setForwardOnly(true);
Utils::execQuery(query, "SELECT * FROM Roster");
QVector currentItems;
parseItemsFromQuery(query, currentItems);
m_db->transaction();
QSet newJids = items.keys().toSet();
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
removeItem(oldItem.jid());
}
}
// now add the completely new JIDs
for (const QString &jid : newJids)
addItem(items[jid]);
m_db->commit();
}
void RosterDb::setItemName(const QString &jid, const QString &name)
{
QSqlDatabase db = QSqlDatabase::database(DB_CONNECTION);
QSqlQuery query(db);
QSqlRecord rec;
rec.append(Utils::createSqlField("name", name));
Utils::execQuery(
query,
db.driver()->sqlStatement(
QSqlDriver::UpdateStatement,
DB_TABLE_ROSTER,
rec,
false
) +
Utils::simpleWhereStatement(db.driver(), "jid", jid)
);
}
void RosterDb::clearAll()
{
QSqlQuery query(QSqlDatabase::database(DB_CONNECTION));
Utils::execQuery(query, "DELETE FROM Roster");
}
void RosterDb::fetchItems()
{
QSqlQuery query(QSqlDatabase::database(DB_CONNECTION));
query.setForwardOnly(true);
Utils::execQuery(query, "SELECT * FROM Roster");
QVector items;
parseItemsFromQuery(query, items);
emit itemsFetched(items);
}
diff --git a/src/RosterDb.h b/src/RosterDb.h
index 2afcedc..85c0aad 100644
--- a/src/RosterDb.h
+++ b/src/RosterDb.h
@@ -1,82 +1,88 @@
/*
* Kaidan - A user-friendly XMPP client for every device!
*
* Copyright (C) 2016-2020 Kaidan developers and contributors
* (see the LICENSE file for a full list of copyright authors)
*
* Kaidan is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* In addition, as a special exception, the author of Kaidan gives
* permission to link the code of its release with the OpenSSL
* project's "OpenSSL" library (or with modified versions of it that
* use the same license as the "OpenSSL" library), and distribute the
* linked executables. You must obey the GNU General Public License in
* all respects for all of the code used other than "OpenSSL". If you
* modify this file, you may extend this exception to your version of
* the file, but you are not obligated to do so. If you do not wish to
* do so, delete this exception statement from your version.
*
* Kaidan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Kaidan. If not, see .
*/
#ifndef ROSTERDB_H
#define ROSTERDB_H
// C++
#include
// Qt
#include
class QSqlQuery;
class QSqlRecord;
// Kaidan
#include "RosterItem.h"
class Database;
class RosterDb : public QObject
{
Q_OBJECT
+
public:
RosterDb(Database *db, QObject *parent = nullptr);
+ ~RosterDb();
+
+ static RosterDb *instance();
static void parseItemsFromQuery(QSqlQuery &query, QVector &items);
/**
* Creates an @c QSqlRecord for updating an old item to a new item.
*
* @param oldMsg Full item as it is currently saved
* @param newMsg Full item as it should be after the update query ran.
*/
static QSqlRecord createUpdateRecord(const RosterItem &oldItem,
const RosterItem &newItem);
signals:
void fetchItemsRequested();
void itemsFetched(const QVector &items);
public slots:
void addItem(const RosterItem &item);
void addItems(const QVector &items);
void removeItem(const QString &jid);
void updateItem(const QString &jid,
const std::function &updateItem);
void replaceItems(const QHash &items);
void setItemName(const QString &jid, const QString &name);
void clearAll();
private slots:
void fetchItems();
private:
Database *m_db;
+
+ static RosterDb *s_instance;
};
#endif // ROSTERDB_H