Heart 1.3.842.34c2ab5
Heart is base back end library for your c++ Qt projects.
database.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2018-2024 QuasarApp.
3 * Distributed under the lgplv3 software license, see the accompanying
4 * Everyone is permitted to copy and distribute verbatim copies
5 * of this license document, but changing it is not allowed.
6*/
7
8#include "database.h"
9#include "sqldbwriter.h"
10#include "asyncsqldbwriter.h"
11
12#include <quasarapp.h>
13#include <QCoreApplication>
14#include <deleteobject.h>
15#include <QSet>
16#include <itoken.h>
17#include <sqlitedbcache.h>
18#include <sqldb.h>
19#include "getsinglevalue.h"
20#include "setsinglevalue.h"
21#include <qaglobalutils.h>
22
23namespace QH {
24using namespace PKG;
25
26DataBase::DataBase(QObject *ptr): QObject(ptr) {
27 qRegisterMetaType<QSharedPointer<QH::PKG::DBObject>>();
28}
29
30bool DataBase::initSqlDb(QString DBparamsFile,
31 ISqlDB *cache,
32 SqlDBWriter *writer) {
33
34 initDefaultDbObjects(cache, writer);
35
36 QVariantMap params;
38
39 if (DBparamsFile.isEmpty()) {
40 params = defaultDbParams();
41
42 if (!_db->init(params)) {
43 return false;
44 }
45
46 } else {
47
48 if (!_db->init(DBparamsFile)) {
49 return false;
50 }
51
52 }
53
54 if (!upgradeDataBase()) {
55 QuasarAppUtils::Params::log("Failed to upgrade database",
56 QuasarAppUtils::Error);
57 return false;
58 }
59
60 QuasarAppUtils::Params::log(QString("Database loaded from: %0").arg(dbLocation()),
61 QuasarAppUtils::Debug);
62
63 connect(_db, &ISqlDB::sigItemChanged,
65 Qt::DirectConnection);
66
67 connect(_db, &ISqlDB::sigItemDeleted,
69 Qt::DirectConnection);
70
71 return true;
72}
73
75 return _db;
76}
77
79 if (!isSqlInited() && !initSqlDb()) {
80 return false;
81 }
82 return true;
83}
84
85bool DataBase::run(const QString &localNodeName) {
86
87 if (localNodeName.isEmpty())
88 return false;
89
91
92 if (!isSqlInited() && !initSqlDb()) {
93 return false;
94 }
95
96 return true;
97}
98
100
101 if (db()) {
102 auto writer = _db->writer();
103 _db->softDelete();
104 _db = nullptr;
105 delete writer;
106 }
107}
108
110 stop();
111}
112
114 SqlDBWriter *writer) {
115 if (!writer) {
116 writer = new AsyncSqlDBWriter();
117 }
118
119 if (!cache) {
120 cache = new SqlDB();
121 }
122
123 cache->setWriter(writer);
124 _db = cache;
125}
126
127
129 return true;
130}
131
132QStringList DataBase::SQLSources() const{
133 return {
135 };
136}
137
138QSet<QString> DataBase::systemTables() const {
139 return {"NetworkMembers", "MemberPermisions"};
140}
141
143
144}
145
146void DataBase::objectChanged(const QSharedPointer<DBObject> &) {
147
148}
149
151 return _dbPatches;
152}
153
154void DataBase::addDBPatch(const DBPatch &patch) {
155 debug_assert(patch.isValid(),
156 "Failed to initialise a Data base patch!"
157 " Patch object is invalid");
158
159
160 debug_assert(!_dbPatches[patch.versionFrom].contains(patch.versionTo),
161 "Failed to initialise a Data base patch!");
162
163 _dbPatches[patch.versionFrom][patch.versionTo] = patch;
164
165 _targetDBVersion = std::max(_targetDBVersion, patch.versionTo);
166}
167
168QString DataBase::dbLocation() const {
169 if (db() && db()->writer()) {
170 return db()->writer()->databaseLocation();
171 }
172
173 return "";
174}
175
176QString DataBase::backUp(int version) const {
177 auto&& params = defaultDbParams();
178
179 if (params.value(QH_DB_DRIVER) != "QSQLITE")
180 return {};
181
182 QString&& path = params.value(QH_DB_BACKUP_PATH).toString();
183 if (path.isEmpty()) {
184 return {};
185 }
186
187 auto file = path + "/DBv%0_" + QDateTime::currentDateTimeUtc().toString("hh:mm:ss_dd_MM_yyyy") + ".db";
188 file = file.arg(version);
189 if (db() && db()->writer() &&
190 QFile::exists(db()->writer()->databaseLocation())) {
191
192 QDir().mkpath(path);
193
194 if (!QFile::copy(db()->writer()->databaseLocation(), file)) {
195 return {};
196 }
197 }
198
199 return file;
200}
201
203 return _db;
204}
205
206bool DataBase::isForbidenTable(const QString &table) {
207 return systemTables().contains(table);
208}
209
211 if (!db())
212 return false;
213
214 DBPatchMap patchesPack = dbPatches();
215 if (!patchesPack.size()) {
216 return true;
217 }
218
219 int currentVersion = 0;
220
221 bool fsupportUpgrade = db()->doQuery("SELECT COUNT(*) FROM DataBaseAttributes", {}, true);
222
223 if (!fsupportUpgrade) {
224
225 QuasarAppUtils::Params::log("The data base of application do not support soft upgrade. "
226 "Please remove database monyaly and restart application."
227 "You can disable upgrade functions for this override the upgradeDataBase method. ",
228 QuasarAppUtils::Error);
229 return false;
230 }
231
232 currentVersion = getDBAttribute("version", 0).toInt();
233
234 if (currentVersion < _targetDBVersion)
235 onBeforeDBUpgrade(currentVersion, _targetDBVersion);
236
237 while (currentVersion < _targetDBVersion) {
238
239 QString message;
240 message = "Upgrade data base from %0 to %1 versions. %2";
241 message = message.arg(currentVersion);
242
243 auto patches = patchesPack.value(currentVersion, {});
244
245 if (!patches.size()) {
246 QuasarAppUtils::Params::log("Failed to " + message.arg("Unknown", "Required patch not found!"),
247 QuasarAppUtils::Error);
248 return false;
249 }
250
251 auto patch = patches.last();
252 message = message.arg(patch.versionTo);
253
254 QuasarAppUtils::Params::log(message.arg("(Begin)"),
255 QuasarAppUtils::Info);
256
257 if (!patch.action(db())) {
258 QuasarAppUtils::Params::log("Failed to " + message.arg("Patch finished with error code!"),
259 QuasarAppUtils::Error);
260 return false;
261 }
262
263 currentVersion = patch.versionTo;
264 if (!setDBAttribute("version", currentVersion)) {
265 return false;
266 }
267 }
268
269 return true;
270}
271
272void DataBase::onBeforeDBUpgrade(int currentVerion, int ) const {
273 backUp(currentVerion);
274}
275
276const QString &DataBase::localNodeName() const {
277 return _localNodeName;
278}
279
280void DataBase::setLocalNodeName(const QString &newLocalNodeName) {
281 _localNodeName = newLocalNodeName;
282}
283
284QVariantMap DataBase::defaultDbParams() const {
285
286 return {
287 {QH_DB_DRIVER, "QSQLITE"},
288 {QH_DB_FILE_PATH, DEFAULT_DB_PATH + "/" + localNodeName() + "/" + QCoreApplication::applicationName() + "_" + DEFAULT_DB_NAME},
289 {QH_DB_BACKUP_PATH, DEFAULT_DB_PATH + "/" + localNodeName() + "/BackUp"}
290 };
291}
292
293QVariant DataBase::getDBAttribute(const QString& key, const QVariant& defaultVal) {
294 if (!_db)
295 return defaultVal;
296
297 PKG::GetSingleValue request({"DataBaseAttributes", key}, "value", "name");
298
299 if (auto&& responce = _db->getObject(request)) {
300 if (!responce->value().isNull())
301 return responce->value();
302
303 }
304
305 return defaultVal;
306}
307
308bool DataBase::setDBAttribute(const QString& key, const QVariant& newValue) {
309 auto updateVersionRequest = QSharedPointer<PKG::SetSingleValue>::create(
310 DbAddress{"DataBaseAttributes", key},
311 "value", newValue, "name");
312
313 if (!_db->replaceObject(updateVersionRequest, true)) {
314 QuasarAppUtils::Params::log(QString("Failed to update %0 attribute").arg(key),
315 QuasarAppUtils::Error);
316 return false;
317 }
318
319 return true;
320}
321
322}
323
The AbstractNodeInfo class contains information about client or server connection and tcp socket of n...
The AsyncSqlDbWriter class is some as SqlDBWriter but run all command in own thread....
void sigObjectChanged(const QSharedPointer< QH::PKG::DBObject > &obj)
sigItemChanged This signal emitted when database object is changed.
bool isSqlInited() const
isSqlInited This method return true if database initialized successful.
Definition database.cpp:74
void stop()
stop This method stop and diskonnect the database.
Definition database.cpp:99
virtual bool upgradeDataBase()
upgradeDataBase This method upgrade data base to actyaly database version.
Definition database.cpp:210
void setLocalNodeName(const QString &newLocalNodeName)
setLocalNodeName This method sets new local name of database file.
Definition database.cpp:280
DataBase(QObject *ptr=nullptr)
Definition database.cpp:26
bool run()
run This method start and initialize the data base connection.
Definition database.cpp:78
QVariant getDBAttribute(const QString &key, const QVariant &defaultVal)
getDBAttribute This method gets value from the default of QH DB table "DataBaseAttributes".
Definition database.cpp:293
virtual void initDefaultDbObjects(ISqlDB *cache, SqlDBWriter *writer)
initDefaultDbObjects This method create a default cache and database writer objects if the input poin...
Definition database.cpp:113
bool setDBAttribute(const QString &key, const QVariant &newValue)
setDBAttribute This method sets value for the default of QH DB table "DataBaseAttributes".
Definition database.cpp:308
virtual const DBPatchMap dbPatches() const
dbPatches This method should be return map with functions that upgrade production data base....
Definition database.cpp:150
virtual QVariantMap defaultDbParams() const
defaultDbParams This method return default database parameters for this node. Override this method fo...
Definition database.cpp:284
void sigObjectDeleted(const QH::DbAddress &obj)
sigItemDeleted This signal emitted when database object is deleted.
virtual QStringList SQLSources() const
SQLSources This method contains list of sqldatabase sources. This method will be invoked into initial...
Definition database.cpp:132
virtual bool welcomeAddress(AbstractNodeInfo *node)
welcomeAddress This method send to the node information about self. Override this method if you want ...
Definition database.cpp:128
const QString & localNodeName() const
localNodeName This method return local node name.
Definition database.cpp:276
virtual void objectRemoved(const DbAddress &address)
objectRemoved This method invoked when object with address removed from database. Oberride this metho...
Definition database.cpp:142
QString dbLocation() const
dbLocation This method return location of nodes or clients database.
Definition database.cpp:168
void addDBPatch(const DBPatch &patch)
addDBPatch This method add database patch to the data base object.
Definition database.cpp:154
virtual QSet< QString > systemTables() const
systemTables This method return the set of tables that forbidden for users. By default is NetworkMemb...
Definition database.cpp:138
ISqlDB * db() const
db This node return pointer to database object.
Definition database.cpp:202
virtual void objectChanged(const QSharedPointer< PKG::DBObject > &obj)
objectChanged This method invoked when object with address changed in database. Override this method ...
Definition database.cpp:146
virtual void onBeforeDBUpgrade(int currentVerion, int tergetVersion) const
onBeforeDBUpgrade This method will be invoked before upgrade database.
Definition database.cpp:272
QString backUp(int version) const
backUp This method make a backup of database.
Definition database.cpp:176
virtual bool initSqlDb(QString DBparamsFile="", ISqlDB *cache=nullptr, SqlDBWriter *writer=nullptr)
intSqlDb This method initalize database of this node or server.
Definition database.cpp:30
The DbAddress class use to work with database addresses. Database Address it is structure with 2 valu...
Definition dbaddress.h:24
The ISqlDB class it is db cache and bridge for DbWriters. Work Scheme of the database cache:
Definition isqldb.h:73
void setWriter(SqlDBWriter *writer)
setWriter This method set new writer for this cache.
Definition isqldb.cpp:154
SqlDBWriter * writer() const
writer This method return is database writer object. For more inforamation about writer see the SqlDB...
Definition isqldb.cpp:150
bool doQuery(const QString &query, const QVariantMap &bindValues, bool wait=false, QSqlQuery *result=nullptr) const override
doQuery This method execute a query in this database.
Definition isqldb.cpp:249
virtual bool init(const QString &initDbParams="")
init This method init the cache object and invoke the SqlDBWriter::initDb method.
Definition isqldb.cpp:267
void sigItemChanged(const QSharedPointer< QH::PKG::DBObject > &obj)
sigItemChanged This signal emitted when database object is changed.
void sigItemDeleted(const QH::DbAddress &obj)
sigItemDeleted This signal emitted when database object is deleted.
void setSQLSources(const QStringList &list) override
setSQLSources This method set sql sources for deployed database.
Definition isqldb.cpp:285
bool replaceObject(const QSharedPointer< QH::PKG::DBObject > &saveObject, bool wait=false) override
Definition isqldb.cpp:235
The GetSingleValue class is intended for get a single value from database. The value is selected by p...
QVariant value() const
value This method return Maximum value of a sql tables field.
void softDelete()
softDelete This method remove this object and save all changes into database.
The SqlDBWriter class. This class write and read objects from database (hard level)....
Definition sqldbwriter.h:36
QString databaseLocation() const
databaseLocation This method return location of database. If it is sqlite then return path to db file...
The SqlDB class This is base implementation fo datatbase. The SqlDB do not use caches,...
Definition sqldb.h:18
QSharedPointer< TYPE > getObject(const TYPE &templateVal)
getObject this method return a strong pointer to DBObject created by select method of the template ob...
#define DEFAULT_DB_PATH
Definition config.h:27
#define QH_DB_DRIVER
Definition config.h:32
#define DEFAULT_DB_NAME
Definition config.h:26
#define QH_DB_BACKUP_PATH
Definition config.h:39
#define DEFAULT_DB_INIT_FILE_PATH
Definition config.h:28
#define QH_DB_FILE_PATH
Definition config.h:33
The QH namespace - QuasarApp Heart namespace. This namespace contains all classes of the Heart librar...
Definition heart.cpp:13
QMap< unsigned short, QMap< unsigned short, DBPatch > > DBPatchMap
DBPatchMap This is 2 depch map of the DBPatch structure when the first key it is version (from) and s...
Definition dbpatch.h:49
DBPatch This is function that should be upgrade database.
Definition dbpatch.h:25
unsigned short versionFrom
Definition dbpatch.h:28
bool isValid() const
isValid This method check this oject to valid.
Definition dbpatch.cpp:12
unsigned short versionTo
Definition dbpatch.h:32