1 // For license of this file, see <project-root-folder>/LICENSE.md.
2
3 #include "database/databasefactory.h"
4
5 #include "3rd-party/boolinq/boolinq.h"
6 #include "database/mariadbdriver.h"
7 #include "database/sqlitedriver.h"
8 #include "exceptions/applicationexception.h"
9 #include "gui/messagebox.h"
10 #include "miscellaneous/application.h"
11 #include "miscellaneous/iofactory.h"
12 #include "miscellaneous/textfactory.h"
13
14 #include <QDir>
15 #include <QSqlDriver>
16 #include <QSqlError>
17 #include <QSqlField>
18 #include <QSqlQuery>
19 #include <QVariant>
20
DatabaseFactory(QObject * parent)21 DatabaseFactory::DatabaseFactory(QObject* parent)
22 : QObject(parent), m_dbDriver(nullptr) {
23 determineDriver();
24 }
25
removeConnection(const QString & connection_name)26 void DatabaseFactory::removeConnection(const QString& connection_name) {
27 qDebugNN << LOGSEC_DB << "Removing database connection '" << connection_name << "'.";
28 QSqlDatabase::removeDatabase(connection_name);
29 }
30
determineDriver()31 void DatabaseFactory::determineDriver() {
32 m_allDbDrivers = {
33 new SqliteDriver(qApp->settings()->value(GROUP(Database), SETTING(Database::UseInMemory)).toBool(), this)
34 };
35
36 if (QSqlDatabase::isDriverAvailable(QSL(APP_DB_MYSQL_DRIVER))) {
37 m_allDbDrivers.append(new MariaDbDriver(this));
38 }
39
40 const QString db_driver = qApp->settings()->value(GROUP(Database), SETTING(Database::ActiveDriver)).toString();
41
42 m_dbDriver = boolinq::from(m_allDbDrivers).firstOrDefault([db_driver](DatabaseDriver* driv) {
43 return QString::compare(driv->qtDriverCode(), db_driver, Qt::CaseSensitivity::CaseInsensitive) == 0;
44 });
45
46 if (m_dbDriver == nullptr) {
47 qFatal("DB driver for '%s' was not found.", qPrintable(db_driver));
48 }
49
50 if (m_dbDriver->driverType() != DatabaseDriver::DriverType::SQLite) {
51 // Try to setup connection and fallback to SQLite.
52 try {
53 m_dbDriver->connection(QSL("DatabaseFactory"));
54 }
55 catch (const ApplicationException& ex) {
56 qCriticalNN << LOGSEC_DB
57 << "Failed to reach connection to DB source, let's fallback to SQLite:"
58 << QUOTE_W_SPACE_DOT(ex.message());
59
60 MessageBox::show(nullptr,
61 QMessageBox::Icon::Critical,
62 tr("Cannot connect to database"),
63 tr("Connection to your database was not established with error: '%1'. "
64 "Falling back to SQLite.").arg(ex.message()));
65
66 m_dbDriver = boolinq::from(m_allDbDrivers).first([](DatabaseDriver* driv) {
67 return driv->driverType() == DatabaseDriver::DriverType::SQLite;
68 });
69 }
70 }
71 }
72
driver() const73 DatabaseDriver* DatabaseFactory::driver() const {
74 return m_dbDriver;
75 }
76
driverForType(DatabaseDriver::DriverType d) const77 DatabaseDriver* DatabaseFactory::driverForType(DatabaseDriver::DriverType d) const {
78 return boolinq::from(m_allDbDrivers).firstOrDefault([d](DatabaseDriver* driv) {
79 return driv->driverType() == d;
80 });
81 }
82
lastExecutedQuery(const QSqlQuery & query)83 QString DatabaseFactory::lastExecutedQuery(const QSqlQuery& query) {
84 QString str = query.lastQuery();
85 QMapIterator<QString, QVariant> it(query.boundValues());
86
87 while (it.hasNext()) {
88 it.next();
89
90 if (it.value().type() == QVariant::Type::Char ||
91 it.value().type() == QVariant::Type::String) {
92 str.replace(it.key(), QSL("'%1'").arg(it.value().toString()));
93 }
94 else {
95 str.replace(it.key(), it.value().toString());
96 }
97 }
98
99 return str;
100 }
101
escapeQuery(const QString & query)102 QString DatabaseFactory::escapeQuery(const QString& query) {
103 return QString(query)
104 .replace(QSL("'"), QSL("''"));
105
106 //.replace(QSL("\""), QSL("\\\""));
107 }
108
activeDatabaseDriver() const109 DatabaseDriver::DriverType DatabaseFactory::activeDatabaseDriver() const {
110 return m_dbDriver->driverType();
111 }
112