Heart 1.3.848.aa44c26
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-2025 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 qCritical() << "Failed to upgrade database";
56 return false;
57 }
58
59 qDebug() << "Database loaded from: " << dbLocation();
60
61 connect(_db, &ISqlDB::sigItemChanged,
63 Qt::DirectConnection);
64
65 connect(_db, &ISqlDB::sigItemDeleted,
67 Qt::DirectConnection);
68
69 return true;
70}
71
73 return _db;
74}
75
77 if (!isSqlInited() && !initSqlDb()) {
78 return false;
79 }
80 return true;
81}
82
83bool DataBase::run(const QString &localNodeName) {
84
85 if (localNodeName.isEmpty())
86 return false;
87
89
90 if (!isSqlInited() && !initSqlDb()) {
91 return false;
92 }
93
94 return true;
95}
96
98
99 if (db()) {
100 auto writer = _db->writer();
101 _db->softDelete();
102 _db = nullptr;
103 delete writer;
104 }
105}
106
108 stop();
109}
110
112 SqlDBWriter *writer) {
113 if (!writer) {
114 writer = new AsyncSqlDBWriter();
115 }
116
117 if (!cache) {
118 cache = new SqlDB();
119 }
120
121 cache->setWriter(writer);
122 _db = cache;
123}
124
125
127 return true;
128}
129
130QStringList DataBase::SQLSources() const{
131 return {
133 };
134}
135
136QSet<QString> DataBase::systemTables() const {
137 return {"NetworkMembers", "MemberPermisions"};
138}
139
141
142}
143
144void DataBase::objectChanged(const QSharedPointer<DBObject> &) {
145
146}
147
149 return _dbPatches;
150}
151
152void DataBase::addDBPatch(const DBPatch &patch) {
153 debug_assert(patch.isValid(),
154 "Failed to initialise a Data base patch!"
155 " Patch object is invalid");
156
157
158 debug_assert(!_dbPatches[patch.versionFrom].contains(patch.versionTo),
159 "Failed to initialise a Data base patch!");
160
161 _dbPatches[patch.versionFrom][patch.versionTo] = patch;
162
163 _targetDBVersion = std::max(_targetDBVersion, patch.versionTo);
164}
165
166QString DataBase::dbLocation() const {
167 if (db() && db()->writer()) {
168 return db()->writer()->databaseLocation();
169 }
170
171 return "";
172}
173
174QString DataBase::backUp(int version) const {
175 auto&& params = defaultDbParams();
176
177 if (params.value(QH_DB_DRIVER) != "QSQLITE")
178 return {};
179
180 QString&& path = params.value(QH_DB_BACKUP_PATH).toString();
181 if (path.isEmpty()) {
182 return {};
183 }
184
185 auto file = path + "/DBv%0_" + QDateTime::currentDateTimeUtc().toString("hh:mm:ss_dd_MM_yyyy") + ".db";
186 file = file.arg(version);
187 if (db() && db()->writer() &&
188 QFile::exists(db()->writer()->databaseLocation())) {
189
190 QDir().mkpath(path);
191
192 if (!QFile::copy(db()->writer()->databaseLocation(), file)) {
193 return {};
194 }
195 }
196
197 return file;
198}
199
201 return _db;
202}
203
204bool DataBase::isForbidenTable(const QString &table) {
205 return systemTables().contains(table);
206}
207
209 if (!db())
210 return false;
211
212 DBPatchMap patchesPack = dbPatches();
213 if (!patchesPack.size()) {
214 return true;
215 }
216
217 int currentVersion = 0;
218
219 bool fsupportUpgrade = db()->doQuery("SELECT COUNT(*) FROM DataBaseAttributes", {}, true);
220
221 if (!fsupportUpgrade) {
222
223 qCritical() << "The data base of application do not support soft upgrade. "
224 "Please remove database monyaly and restart application."
225 "You can disable upgrade functions for this override the upgradeDataBase method. ";
226 return false;
227 }
228
229 currentVersion = getDBAttribute("version", 0).toInt();
230
231 if (currentVersion < _targetDBVersion)
232 onBeforeDBUpgrade(currentVersion, _targetDBVersion);
233
234 while (currentVersion < _targetDBVersion) {
235
236 QString message;
237 message = "Upgrade data base from %0 to %1 versions. %2";
238 message = message.arg(currentVersion);
239
240 auto patches = patchesPack.value(currentVersion, {});
241
242 if (!patches.size()) {
243 qCritical() << "Failed to " + message.arg("Unknown", "Required patch not found!");
244 return false;
245 }
246
247 auto patch = patches.last();
248 message = message.arg(patch.versionTo);
249
250 qInfo() << message.arg("(Begin)");
251
252 if (!patch.action(db())) {
253 qCritical() << "Failed to " + message.arg("Patch finished with error code!");
254 return false;
255 }
256
257 currentVersion = patch.versionTo;
258 if (!setDBAttribute("version", currentVersion)) {
259 return false;
260 }
261 }
262
263 return true;
264}
265
266void DataBase::onBeforeDBUpgrade(int currentVerion, int ) const {
267 backUp(currentVerion);
268}
269
270const QString &DataBase::localNodeName() const {
271 return _localNodeName;
272}
273
274void DataBase::setLocalNodeName(const QString &newLocalNodeName) {
275 _localNodeName = newLocalNodeName;
276}
277
278QVariantMap DataBase::defaultDbParams() const {
279
280 return {
281 {QH_DB_DRIVER, "QSQLITE"},
282 {QH_DB_FILE_PATH, DEFAULT_DB_PATH + "/" + localNodeName() + "/" + QCoreApplication::applicationName() + "_" + DEFAULT_DB_NAME},
283 {QH_DB_BACKUP_PATH, DEFAULT_DB_PATH + "/" + localNodeName() + "/BackUp"}
284 };
285}
286
287QVariant DataBase::getDBAttribute(const QString& key, const QVariant& defaultVal) {
288 if (!_db)
289 return defaultVal;
290
291 PKG::GetSingleValue request({"DataBaseAttributes", key}, "value", "name");
292
293 if (auto&& responce = _db->getObject(request)) {
294 if (!responce->value().isNull())
295 return responce->value();
296
297 }
298
299 return defaultVal;
300}
301
302bool DataBase::setDBAttribute(const QString& key, const QVariant& newValue) {
303 auto updateVersionRequest = QSharedPointer<PKG::SetSingleValue>::create(
304 DbAddress{"DataBaseAttributes", key},
305 "value", newValue, "name");
306
307 if (!_db->replaceObject(updateVersionRequest, true)) {
308
309 qCritical() << "Failed to update " << key << " attribute";
310 return false;
311 }
312
313 return true;
314}
315
316}
317
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:72
void stop()
stop This method stop and diskonnect the database.
Definition database.cpp:97
virtual bool upgradeDataBase()
upgradeDataBase This method upgrade data base to actyaly database version.
Definition database.cpp:208
void setLocalNodeName(const QString &newLocalNodeName)
setLocalNodeName This method sets new local name of database file.
Definition database.cpp:274
DataBase(QObject *ptr=nullptr)
Definition database.cpp:26
bool run()
run This method start and initialize the data base connection.
Definition database.cpp:76
QVariant getDBAttribute(const QString &key, const QVariant &defaultVal)
getDBAttribute This method gets value from the default of QH DB table "DataBaseAttributes".
Definition database.cpp:287
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:111
bool setDBAttribute(const QString &key, const QVariant &newValue)
setDBAttribute This method sets value for the default of QH DB table "DataBaseAttributes".
Definition database.cpp:302
virtual const DBPatchMap dbPatches() const
dbPatches This method should be return map with functions that upgrade production data base....
Definition database.cpp:148
virtual QVariantMap defaultDbParams() const
defaultDbParams This method return default database parameters for this node. Override this method fo...
Definition database.cpp:278
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:130
virtual bool welcomeAddress(AbstractNodeInfo *node)
welcomeAddress This method send to the node information about self. Override this method if you want ...
Definition database.cpp:126
const QString & localNodeName() const
localNodeName This method return local node name.
Definition database.cpp:270
virtual void objectRemoved(const DbAddress &address)
objectRemoved This method invoked when object with address removed from database. Oberride this metho...
Definition database.cpp:140
QString dbLocation() const
dbLocation This method return location of nodes or clients database.
Definition database.cpp:166
void addDBPatch(const DBPatch &patch)
addDBPatch This method add database patch to the data base object.
Definition database.cpp:152
virtual QSet< QString > systemTables() const
systemTables This method return the set of tables that forbidden for users. By default is NetworkMemb...
Definition database.cpp:136
ISqlDB * db() const
db This node return pointer to database object.
Definition database.cpp:200
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:144
virtual void onBeforeDBUpgrade(int currentVerion, int tergetVersion) const
onBeforeDBUpgrade This method will be invoked before upgrade database.
Definition database.cpp:266
QString backUp(int version) const
backUp This method make a backup of database.
Definition database.cpp:174
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:247
virtual bool init(const QString &initDbParams="")
init This method init the cache object and invoke the SqlDBWriter::initDb method.
Definition isqldb.cpp:265
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:283
bool replaceObject(const QSharedPointer< QH::PKG::DBObject > &saveObject, bool wait=false) override
Definition isqldb.cpp:233
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