Heart 1.3.842.34c2ab5
Heart is base back end library for your c++ Qt projects.
sqldbwriter.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 "sqldbwriter.h"
9
10#include <QRegularExpression>
11#include <QSqlDatabase>
12#include <QSqlQuery>
13#include <QDebug>
14#include <QSqlError>
15#include <quasarapp.h>
16#include <QJsonDocument>
17#include <QJsonObject>
18#include <QHash>
19#include <dbobject.h>
20#include <QSqlRecord>
21#include <QStandardPaths>
22#include <QCoreApplication>
23
24namespace QH {
25using namespace PKG;
26
27bool SqlDBWriter::exec(QSqlQuery *sq, const QString& sqlFile) const {
28 QFile f(sqlFile);
29 bool result = true;
30 if (f.open(QIODevice::ReadOnly)) {
31
32 QString temp, delimiter = ";";
33 QTextStream stream(&f);
34#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
35 stream.setCodec("UTF8");
36#endif
37 int lineNumber = 0;
38 while(!stream.atEnd()) {
39 QString line = stream.readLine();
40 lineNumber++;
41 int linedelimiterIndex = line.lastIndexOf(delimiter, -1, Qt::CaseInsensitive);
42 int delimiterIndex = temp.size() + linedelimiterIndex;
43
44 if (line.contains("--"))
45 continue;
46
47 temp += line;
48
49 if (linedelimiterIndex > -1) {
50 result = result && sq->exec(temp.left(delimiterIndex));
51 temp = temp.remove(0, delimiterIndex + 1);
52
53 if (!result) {
54 QuasarAppUtils::Params::log(QString("Exec database error. File: %0. Line:%1: %2").
55 arg(sqlFile).arg(lineNumber).arg(sq->lastError().text()),
56 QuasarAppUtils::Error);
57 f.close();
58 return false;
59 }
60 }
61 }
62
63 f.close();
64 return result;
65 }
66
67 QuasarAppUtils::Params::log("sql source file is not open: " + sqlFile,
68 QuasarAppUtils::Error);
69
70 return false;
71}
72
73bool SqlDBWriter::initDbPrivate(const QVariantMap &params) {
74 _config = params;
75
76 if (_db)
77 delete _db;
78
79 _db = new QSqlDatabase(initSqlDataBasse(_config["DBDriver"].toString(),
80 _config["DBFilePath"].toString()));
81
82 if (_config.contains("DBFilePath")) {
83
84 auto path = QFileInfo(_config["DBFilePath"].toString());
85 if (!QDir("").mkpath(path.absolutePath())) {
86 return false;
87 }
88
89 _db->setDatabaseName(path.absoluteFilePath());
90 }
91
92 if (_config.contains("DBLogin")) {
93 _db->setPassword(_config["DBLogin"].toString());
94 }
95
96 if (_config.contains("DBPass")) {
97 _db->setPassword(_config["DBPass"].toString());
98 }
99
100 if (_config.contains("DBHost")) {
101 _db->setHostName(_config["DBHost"].toString());
102 }
103
104 if (_config.contains("DBPort")) {
105 _db->setPort(_config["DBPort"].toInt());
106 }
107
108 if (!_db->open()) {
109 QuasarAppUtils::Params::log(_db->lastError().text(),
110 QuasarAppUtils::Error);
111 return false;
112 }
113
114 for (const QString& sqlFile : std::as_const(_SQLSources)) {
115 QSqlQuery query(*_db);
116 if (!exec(&query, sqlFile)) {
117 return false;
118 }
119 }
120
121 if (_config.contains("DBInitFile")) {
122 auto path = QFileInfo(_config["DBInitFile"].toString()).absoluteFilePath();
123
124 QSqlQuery query(*_db);
125 if (!exec(&query, path)) {
126 return false;
127 }
128 }
129
130 initSuccessful = _db->isValid();
131 return initSuccessful;
132}
133
134bool SqlDBWriter::doQueryPrivate(const QString &query, const QVariantMap &bindValues, QSqlQuery* result) const {
135
136 if (!db()) {
137 return false;
138 }
139
140 QSqlQuery q(*db());
141 if (bindValues.size()) {
142 if (!q.prepare(query)) {
143 QuasarAppUtils::Params::log("request error : " + q.lastError().text(),
144 QuasarAppUtils::Error);
145 return false;
146 }
147
148 for (auto it = bindValues.begin(); it != bindValues.end(); ++it) {
149 q.bindValue(it.key(), it.value());
150 }
151
152 if (!q.exec()) {
153 QuasarAppUtils::Params::log("request error : " + q.lastError().text(),
154 QuasarAppUtils::Error);
155 return false;
156 }
157 } else {
158 if (!q.exec(query)) {
159 QuasarAppUtils::Params::log("request error : " + q.lastError().text(),
160 QuasarAppUtils::Error);
161 return false;
162 }
163 }
164
165 if (result) {
166 *result = std::move(q);
167 }
168
169 return true;
170
171}
172
173bool SqlDBWriter::doSqlPrivate(const QString &sqlFile) const {
174 QSqlQuery query(*_db);
175 if (!exec(&query, sqlFile)) {
176 return false;
177 }
178
179 return true;
180}
181
183 if (!db()) {
184 return false;
185 }
186
187 QSqlQuery query(*db());
188 QString request = QString("PRAGMA foreign_keys = ON");
189 if (!query.exec(request)) {
190 QuasarAppUtils::Params::log("request error : " + query.lastError().text());
191 return false;
192 }
193
194 return true;
195}
196
198
199 if (!db()) {
200 return false;
201 }
202
203 QSqlQuery query(*db());
204 QString request = QString("PRAGMA foreign_keys = OFF");
205 if (!query.exec(request)) {
206 QuasarAppUtils::Params::log("request error : " + query.lastError().text());
207 return false;
208 }
209
210 return true;
211
212}
213
214QVariantMap SqlDBWriter::getInitParams(const QString &initFile) const {
215 QFile file(initFile);
216 QVariantMap res;
217
218 if (file.open(QIODevice::ReadOnly)) {
219 QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
220 file.close();
221
222 if (!doc.isObject()) {
223 return res;
224 }
225
226 QJsonObject obj = doc.object();
227 return obj.toVariantMap();
228 }
229
230 return res;
231}
232
233/*
234 * about driver see https://doc.qt.io/qt-5/sql-driver.html
235 */
237 QVariantMap params;
238 params["DBDriver"] = "QSQLITE";
239 params["DBFile"] = DEFAULT_DB_PATH;
240 return params;
241}
242
243QSqlDatabase SqlDBWriter::initSqlDataBasse(const QString& driverName,
244 const QString& name) {
245
246 return QSqlDatabase::addDatabase(driverName,
247 QFileInfo(name).fileName());
248}
249
250QSqlDatabase *SqlDBWriter::db() {
251 return _db;
252}
253
254const QSqlDatabase *SqlDBWriter::db() const {
255 return _db;
256}
257
258SqlDBWriter::SqlDBWriter(QThread *thread, QObject* ptr):
259 Async(thread, ptr) {
260}
261
262bool SqlDBWriter::initDb(const QString &initDbParams) {
263 QVariantMap params;
264
265 if (initDbParams.isEmpty()) {
266 params = defaultInitPararm();
267 } else {
268 params = getInitParams(initDbParams);
269 }
270
271 return initDb(params);
272}
273
274bool SqlDBWriter::initDb(const QVariantMap &params) {
275 auto handleInitDb = [&params, this]() {
276 return initDbPrivate(params);
277 };
278
279 return asyncLauncher(handleInitDb, true);
280}
281
283 return db() && db()->isValid() && db()->isOpen() && initSuccessful;
284}
285
286bool SqlDBWriter::getAllObjects(const DBObject &templateObject,
287 QList<QSharedPointer<DBObject>> &result) {
288
289 auto getAll = [&templateObject, &result, this]() {
290 return SqlDBWriter::selectQuery(templateObject, result);
291 };
292
293 return asyncLauncher(getAll, true);
294}
295
296bool SqlDBWriter::updateObject(const QSharedPointer<DBObject> &ptr, bool wait) {
297
298 Async::Job job = [this, ptr]() {
299 return updateQuery(ptr);
300 };
301
302 return asyncLauncher(job, wait);
303}
304
305bool SqlDBWriter::deleteObject(const QSharedPointer<DBObject> &ptr, bool wait) {
306
307 Async::Job job = [this, ptr]() {
308 return deleteQuery(ptr);
309 };
310
311 return asyncLauncher(job, wait);
312}
313
314bool SqlDBWriter::insertObject(const QSharedPointer<DBObject> &ptr,
315 bool wait,
316 const QWeakPointer<unsigned int>& autoincrementIdResult) {
317
318 if (wait) {
319 auto resultId = QSharedPointer<int>::create();
320 Async::Job job = [this, ptr, autoincrementIdResult]() {
321 return insertQuery(ptr, autoincrementIdResult);
322 };
323
324 return asyncLauncher(job, wait);
325 } else {
326 Async::Job job = [this, ptr]() {
327 return insertQuery(ptr);
328 };
329
330 return asyncLauncher(job, wait);
331 }
332}
333
334bool SqlDBWriter::replaceObject(const QSharedPointer<PKG::DBObject> &ptr, bool wait) {
335 Async::Job job = [this, ptr]() {
336 return replaceQuery(ptr);
337 };
338
339 return asyncLauncher(job, wait);
340}
341
342void SqlDBWriter::setSQLSources(const QStringList &list) {
343 _SQLSources = list;
344}
345
347 if (!db())
348 return "";
349
350 return db()->databaseName();
351}
352
354 if (_db) {
355 _db->close();
356
357 QString connectionName = _db->connectionName();
358
359 delete _db;
360 _db = nullptr;
361
362 QSqlDatabase::removeDatabase(connectionName);
363 }
364
365}
366
367bool SqlDBWriter::insertQuery(const QSharedPointer<DBObject> &ptr,
368 const QWeakPointer<unsigned int>& autoincrementIdResult) const {
369 if (!ptr)
370 return false;
371
372 if (!db()) {
373 return false;
374 }
375
376 QSqlQuery q(*db());
377
378 auto prepare = [ptr](QSqlQuery&q) {
379 return ptr->prepareInsertQuery(q, false);
380 };
381
382 auto cb = [&q, autoincrementIdResult]() {
383
384 if (auto&& ptr = autoincrementIdResult.lock()) {
385 *ptr = q.lastInsertId().toInt();
386 }
387
388 return true;
389 };
390
391 return workWithQuery(q, prepare, cb);
392}
393
394bool SqlDBWriter::replaceQuery(const QSharedPointer<PKG::DBObject> &ptr) const {
395 if (!ptr)
396 return false;
397
398 if (!db()) {
399 return false;
400 }
401
402 QSqlQuery q(*db());
403
404 auto prepare = [ptr](QSqlQuery&q) {
405 return ptr->prepareInsertQuery(q, true);
406 };
407
408 auto cb = [](){return true;};
409
410 return workWithQuery(q, prepare, cb);
411}
412
413bool SqlDBWriter::doQuery(const QString &query, const QVariantMap &bindValues,
414 bool wait, QSqlQuery* result) const {
415
416 wait = result || wait;
417
418 Async::Job job = [this, query, bindValues, result]() {
419 return doQueryPrivate(query, bindValues, result);
420 };
421
422 return asyncLauncher(job, wait);
423}
424
425bool SqlDBWriter::doSql(const QString &sqlFile, bool wait) const {
426
427 Async::Job job = [this, sqlFile]() {
428 return doSqlPrivate(sqlFile);
429 };
430
431 return asyncLauncher(job, wait);
432
433}
434
435bool SqlDBWriter::selectQuery(const DBObject& requestObject,
436 QList<QSharedPointer<QH::PKG::DBObject>> &result) {
437
438 if (!db()) {
439 return false;
440 }
441
442 QSqlQuery q(*db());
443 auto prepare = [&requestObject](QSqlQuery&q) {
444 return requestObject.prepareSelectQuery(q);
445 };
446
447 auto cb = [&q, &requestObject, &result]() -> bool {
448
449 if (requestObject.isBundle()) {
450 auto newObject = QSharedPointer<QH::PKG::DBObject>(requestObject.createDBObject());
451
452 if (!newObject)
453 return false;
454
455 while (q.next()) {
456 if (!newObject->fromSqlRecord(q.record())) {
457 QuasarAppUtils::Params::log("Select query finished successful but, "
458 "the fromSqlRecord method return false." +
459 newObject->toString(),
460 QuasarAppUtils::Error);
461 return false;
462 }
463 }
464
465 result.push_back(newObject);
466
467 } else {
468 while (q.next()) {
469 auto newObject = QSharedPointer<QH::PKG::DBObject>(requestObject.createDBObject());
470
471 if (!newObject)
472 return false;
473
474 if (!newObject->fromSqlRecord(q.record())) {
475 QuasarAppUtils::Params::log("Init sql object error.",
476 QuasarAppUtils::Error);
477 return false;
478 }
479 result.push_back(newObject);
480 }
481
482 return true;
483 }
484
485 return result.size();
486 };
487
488 return workWithQuery(q, prepare, cb);
489}
490
491bool SqlDBWriter::deleteQuery(const QSharedPointer<DBObject> &deleteObject) const {
492 if (!deleteObject)
493 return false;
494
495 QSqlQuery q(*db());
496
497 auto prepare = [deleteObject](QSqlQuery&q) {
498 return deleteObject->prepareRemoveQuery(q);
499 };
500
501 auto cb = []() -> bool {
502 return true;
503 };
504
505
506 return workWithQuery(q, prepare, cb);
507}
508
509bool SqlDBWriter::updateQuery(const QSharedPointer<DBObject> &ptr) const {
510 if (!ptr)
511 return false;
512
513 QSqlQuery q(*db());
514
515 auto prepare = [ptr](QSqlQuery&q) {
516 return ptr->prepareUpdateQuery(q);
517 };
518
519 auto cb = [](){return true;};
520
521 return workWithQuery(q, prepare, cb);
522}
523
524bool SqlDBWriter::workWithQuery(QSqlQuery &q,
525 const std::function< PrepareResult (QSqlQuery &)> &prepareFunc,
526 const std::function<bool ()> &cb) const {
527
528 auto printError = [](const QSqlQuery &q) {
529
530 QuasarAppUtils::Params::log("prepare sql error: " + q.executedQuery(),
531 QuasarAppUtils::Debug);
532
533 QuasarAppUtils::Params::log("exec sql error: " + q.lastError().text(),
534 QuasarAppUtils::Error);
535
536 };
537
538
539 switch (prepareFunc(q)) {
540 case PrepareResult::Success: {
541
542 if (!q.exec()) {
543 printError(q);
544 return false;
545 }
546
547#ifdef HEART_PRINT_SQL_QUERIES
548 QuasarAppUtils::Params::log(QString("Query executed successfull into %0\n"
549 "query: %1").
550 arg(_db->databaseName(), q.executedQuery()),
551 QuasarAppUtils::Debug);
552#endif
553
554 return cb();
555 }
556 case PrepareResult::Disabled: {
557 QuasarAppUtils::Params::log("call disabled operator! ",
558 QuasarAppUtils::Warning);
559 return true;
560 }
561
562 case PrepareResult::Fail: {
563 printError(q);
564 return false;
565 }
566
567 }
568
569 return false;
570
571}
572
573}
The Async class This is bundle of async templates and async wrappers.
Definition async.h:26
std::function< bool()> Job
Definition async.h:35
bool asyncLauncher(const Job &job, bool await=false, bool freaze=true) const
asyncLauncher This method invoke a job on the thread (using the asyncHandler method) of this object.
Definition async.cpp:80
The DBObject class- main class for work with data base.
Definition dbobject.h:94
virtual PrepareResult prepareSelectQuery(QSqlQuery &q) const
prepareSelectQuery This method should be prepare a query for selected data. Override this method for ...
Definition dbobject.cpp:30
virtual bool isBundle() const
isBundle This method definef determines whether the object will be abstract (composite objects) or si...
Definition dbobject.cpp:208
virtual DBObject * createDBObject() const =0
createDBObject This method should be create a object with the some type as the object called this met...
bool disableFK()
disableFK This method disable foreign key for the sqlite database.
bool deleteObject(const QSharedPointer< PKG::DBObject > &ptr, bool wait=false) override
deleteObject This method execute a delete method of obj and remove current object from database.
virtual bool updateQuery(const QSharedPointer< QH::PKG::DBObject > &ptr) const
updateQuery This method execute update query of object. For more Information see DBObject::prepareUpd...
QString databaseLocation() const
databaseLocation This method return location of database. If it is sqlite then return path to db file...
bool updateObject(const QSharedPointer< PKG::DBObject > &ptr, bool wait=false) override
updateObject This method execute a update method of the saveObject and save all changes into database...
bool doSql(const QString &sqlFile, bool wait) const override
doSql This method execute a query in this database.
QSqlDatabase * db()
db This method return db connection. If SqlDBWriter in not inited then return nullptr....
bool enableFK()
enableFK This method enable foreign key for the sqlite database.
virtual bool replaceQuery(const QSharedPointer< QH::PKG::DBObject > &insertObject) const
replaceQuery This method prepare the replce object query.
virtual QSqlDatabase initSqlDataBasse(const QString &driverName, const QString &name)
initSqlDataBasse This method create ad database connection. Without configuration....
SqlDBWriter(QThread *thread, QObject *ptr=nullptr)
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.
bool replaceObject(const QSharedPointer< PKG::DBObject > &ptr, bool wait=false) override
replaceObject This method execute a replace method of the saveObject and insert or save if not exists...
virtual bool selectQuery(const QH::PKG::DBObject &requestObject, QList< QSharedPointer< QH::PKG::DBObject > > &result)
selectQuery generate select query to database from parameters.
void setSQLSources(const QStringList &list) override
setSQLSources This method set sql sources for deployed database.
virtual bool isValid() const
isValid This method return true if database is successful inited and working correctly.
virtual bool deleteQuery(const QSharedPointer< QH::PKG::DBObject > &deleteObject) const
deleteQuery This method prepare the delete object query.
virtual bool initDb(const QString &initDbParams=DEFAULT_DB_PATH)
initDb This method is wraper of the initDb(const QVariantMap &params) method. This implementation rea...
virtual QVariantMap getInitParams(const QString &initFile) const
getInitPararm This method read parameters of database.
virtual ~SqlDBWriter() override
bool getAllObjects(const PKG::DBObject &templateObject, QList< QSharedPointer< PKG::DBObject > > &result) override
getAllObjects This method execute a select method of the templateObject and return list of all select...
virtual bool insertQuery(const QSharedPointer< QH::PKG::DBObject > &insertObject, const QWeakPointer< unsigned int > &autoIncrementID={}) const
insertQuery This method prepare the insert object query.
virtual QVariantMap defaultInitPararm() const
defaultInitPararm This method return default parameters of the database.
bool insertObject(const QSharedPointer< PKG::DBObject > &ptr, bool wait=false, const QWeakPointer< unsigned int > &autoincrementIdResult={}) override
insertObject This method execute a insert method of the saveObject and insert it into database.
#define DEFAULT_DB_PATH
Definition config.h:27
PrepareResult
The PrepareResult enum is result of work prepare sql query of dbobjects.
Definition dbobject.h:24
The QH namespace - QuasarApp Heart namespace. This namespace contains all classes of the Heart librar...
Definition heart.cpp:13