4
1
mirror of https://github.com/QuasarApp/Heart.git synced 2025-05-14 10:29:43 +00:00

added db patches functionality

This commit is contained in:
Andrei Yankovich 2021-10-09 18:52:23 +03:00
parent 5c4d954a45
commit e217aadd48
11 changed files with 174 additions and 8 deletions

@ -34,6 +34,14 @@ public:
*/
using Job = std::function<bool()>;
/**
* @brief asyncLauncher This method invoke a job on the thread (using the asyncHandler method) of this object.
* @param job This is function with needed job.
* @param await This is boolean option for enable or disable wait for finish of the job function.
* @return true if the job function started correctly. If the await option is true then
* this method return result of job function.
*/
bool asyncLauncher(const Job &job, bool await = false) const;
protected:
/**
@ -66,14 +74,6 @@ protected:
*/
bool waitFor(const Job &condition, int timeout = WAIT_TIME) const;
/**
* @brief asyncLauncher This method invoke a job on the thread (using the asyncHandler method) of this object.
* @param job This is function with needed job.
* @param await This is boolean option for enable or disable wait for finish of the job function.
* @return true if the job function started correctly. If the await option is true then
* this method return result of job function.
*/
bool asyncLauncher(const Job &job, bool await = false) const;
private slots:
/**

@ -31,3 +31,11 @@ CREATE TABLE IF NOT EXISTS DefaultPermissions (
ON DELETE CASCADE
)
CREATE TABLE IF NOT EXISTS DataBaseAttributes (
name TEXT NOT NULL PRIMARY KEY,
value INT NOT NULL UNIQUE
)
INSERT INTO "DataBaseAttributes" VALUES ("version", 0);

@ -32,3 +32,10 @@ CREATE TABLE IF NOT EXISTS DefaultPermissions (
ON UPDATE CASCADE
ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS DataBaseAttributes (
name TEXT NOT NULL PRIMARY KEY,
value INT NOT NULL UNIQUE
)
INSERT INTO "DataBaseAttributes" VALUES ("version", 0);

@ -34,6 +34,8 @@
#include <sqlitedbcache.h>
#include <sqldb.h>
#include <QCryptographicHash>
#include "getsinglevalue.h"
#include "setsinglevalue.h"
#define THIS_NODE "this_node_key"
namespace QH {
@ -71,6 +73,12 @@ bool DataBaseNode::initSqlDb(QString DBparamsFile,
return false;
}
if (!upgradeDataBase()) {
QuasarAppUtils::Params::log("Failed to upgrade database",
QuasarAppUtils::Error);
return false;
}
return true;
}
@ -180,6 +188,11 @@ void DataBaseNode::objectChanged(const QSharedPointer<DBObject> &) {
}
QMap<int, std::function<bool (const iObjectProvider *)> >
DataBaseNode::dbPatches() const {
return {};
}
void DataBaseNode::handleObjectChanged(const QSharedPointer<DBObject> &item) {
notifyObjectChanged(item.staticCast<PKG::ISubscribableData>());
objectChanged(item);
@ -371,6 +384,60 @@ bool DataBaseNode::isForbidenTable(const QString &table) {
return systemTables().contains(table);
}
bool DataBaseNode::upgradeDataBase() {
auto patches = dbPatches();
int actyalyVersion = patches.cend().key();
int currentVersion = 0;
PKG::GetSingleValue request({"DataBaseAttributes", "name"}, "value");
auto responce = _db->getObject(request);
if (!responce) {
QuasarAppUtils::Params::log("The data base of application do not support soft upgrade. "
"Please remove database monyaly and restart application.",
QuasarAppUtils::Error);
return false;
}
currentVersion = responce->value().toInt();
do {
currentVersion++;
auto patch = patches.value(currentVersion);
QString message;
if (currentVersion == 0) {
message = "Initialize data base!";
} else {
message = "Upgrade data base!. from %0 to %1 versions";
}
QuasarAppUtils::Params::log(message,
QuasarAppUtils::Info);
if (!patch(db())) {
message = message.arg(currentVersion).arg(currentVersion);
QuasarAppUtils::Params::log("Failed to " + message,
QuasarAppUtils::Error);
return false;
}
auto request = QSharedPointer<PKG::SetSingleValue>::create(
DbAddress{"DataBaseAttributes", "name"},
"value", currentVersion);
if (!_db->updateObject(request, true)) {
message = message.arg(currentVersion).arg(currentVersion);
QuasarAppUtils::Params::log("Failed to update version attribute",
QuasarAppUtils::Error);
}
}
while ( currentVersion < actyalyVersion);
return true;
}
void DataBaseNode::setLocalNodeName(const QString &newLocalNodeName) {
_localNodeName = newLocalNodeName;
}

@ -27,6 +27,7 @@ class SqlDBWriter;
class WebSocketController;
class DbAddress;
class NodeId;
class iObjectProvider;
/**
@ -395,6 +396,21 @@ protected:
*/
virtual void objectChanged(const QSharedPointer<PKG::DBObject>& obj);
/**
* @brief dbPatches This method should be return map with functions that upgrade production data base.
* Eeach function shoul be can upgrade databae from preview version to own version.
* **Example**:
*
* We have 3 version of data base {0, 1, 2} each version should be contains own function for upgrade data base.
*
*
* @code{cpp}
*
* @endcode
*
* @return
*/
virtual QMap<int, std::function<bool(const iObjectProvider*)>> dbPatches() const;
private slots:
void handleObjectChanged(const QSharedPointer<PKG::DBObject> &item);
@ -415,6 +431,13 @@ private:
bool isForbidenTable(const QString& table);
/**
* @brief upgradeDataBase This method upgrade data base to actyaly database version.
* @note The last version of dbPatches is actyaly version.
* @return true if operation finished successful
*/
bool upgradeDataBase();
ISqlDBCache *_db = nullptr;
QString _localNodeName;
WebSocketController *_webSocketWorker = nullptr;

@ -121,6 +121,14 @@ public:
bool wait = true);
/**
* @brief doQuery This method execute a @a query in this database.
* @param query This is query that will be executed.
* @return true if the query finished successful
*/
virtual bool doQuery(const QString& query, bool wait = false) const = 0;
};
}

@ -214,6 +214,15 @@ bool ISqlDBCache::insertObject(const QSharedPointer<DBObject> &saveObject, bool
return true;
}
bool ISqlDBCache::doQuery(const QString &query, bool wait) const {
if (!_writer) {
return false;
}
return _writer->doQuery(query, wait);
}
bool ISqlDBCache::init(const QString &initDbParams) {
if (!_writer) {

@ -107,6 +107,8 @@ public:
bool insertObject(const QSharedPointer<QH::PKG::DBObject>& saveObject,
bool wait = false) override;
bool doQuery(const QString &query, bool wait) const override;
/**
* @brief changeObjects This method change object of the database.
* @param templateObject This is template for get objects from database.
@ -258,6 +260,7 @@ signals:
*/
void sigItemDeleted(const DbAddress& obj);
};
/**

@ -131,6 +131,22 @@ bool SqlDBWriter::initDbPrivate(const QVariantMap &params) {
return initSuccessful;
}
bool SqlDBWriter::doQueryPrivate(const QString &query) const {
if (!db()) {
return false;
}
QSqlQuery q(query, *db());
if (!q.exec()) {
QuasarAppUtils::Params::log("request error : " + q.lastError().text());
return false;
}
return true;
}
bool SqlDBWriter::enableFK() {
if (!db()) {
return false;
@ -317,6 +333,17 @@ bool SqlDBWriter::insertQuery(const QSharedPointer<DBObject> &ptr) const {
return workWithQuery(q, prepare, cb, ptr->printError());
}
bool SqlDBWriter::doQuery(const QString &query,
bool wait) const {
Async::Job job = [this, query]() {
return doQueryPrivate(query);
};
return asyncLauncher(job, wait);
}
bool SqlDBWriter::selectQuery(const DBObject& requestObject,
QList<QSharedPointer<QH::PKG::DBObject>> &result) {

@ -69,6 +69,7 @@ public:
bool deleteObject(const QSharedPointer<PKG::DBObject> &ptr, bool wait = false) override;
bool insertObject(const QSharedPointer<PKG::DBObject> &ptr, bool wait = false) override;
void setSQLSources(const QStringList &list) override;
bool doQuery(const QString& query, bool wait = false) const override;
/**
* @brief databaseLocation This method return location of database.
@ -213,6 +214,13 @@ private:
*/
bool initDbPrivate(const QVariantMap &params);
/**
* @brief doQueryPrivate This method execute a @a query in this database.
* @param query This is query that will be executed.
* @return true if the query finished successful
*/
bool doQueryPrivate(const QString& query) const;
bool initSuccessful = false;
QVariantMap _config;
QStringList _SQLSources;

@ -36,8 +36,14 @@ protected:
_ping.setAnsver(ping->ansver());
}
QMap<int, std::function<bool (const QH::iObjectProvider *)> > dbPatches() const override{
return {};
};
private:
QH::PKG::Ping _ping;
};
class BadTstClient: public QH::DataBaseNode {