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