sqldatabasestorage.h 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /*
  2. Copyright 2017 Herik Lima de Castro and Marcelo Medeiros Eler
  3. Distributed under MIT license, or public domain if desired and
  4. recognized in your jurisdiction.
  5. See file LICENSE for detail.
  6. */
  7. #ifndef SQLDATABASESTORAGE_H
  8. #define SQLDATABASESTORAGE_H
  9. #include <QDebug>
  10. #include <QSqlDatabase>
  11. #include <QSqlError>
  12. #include <QThreadStorage>
  13. #include <QUuid>
  14. #include "cppwebframework_global.h"
  15. #include <iostream>
  16. #if __cplusplus >= 201703L
  17. #include <optional>
  18. #endif
  19. #if __cplusplus == 201402L
  20. #include <experimental/optional>
  21. #endif
  22. CWF_BEGIN_NAMESPACE
  23. /**
  24. * @brief The SqlDatabaseStorage class allows you to reuse connections made to the database through the QSqlDatabase class within QThreadPool.
  25. */
  26. class CPPWEBFRAMEWORKSHARED_EXPORT SqlDatabaseStorage
  27. {
  28. class Database
  29. {
  30. friend class SqlDatabaseStorage;
  31. // Map database connection names the library user uses to database connection names
  32. // which are valid for this thread
  33. std::map<QString, QSqlDatabase *>
  34. DatabaseConnections; //Unique Name to Heap allocated Connection
  35. std::map<QString, QString> trivialNameToUniqueID; //Names given by User to Unique Name
  36. //#if __cplusplus == 201402L
  37. // std::experimental::optional<QSqlDatabase> DBConnection; //C++ 14 Compatablity
  38. //#endif
  39. //#if __cplusplus >= 201703L
  40. // std::optional<QSqlDatabase> DBConnection;
  41. //#endif
  42. public:
  43. Database() = default;
  44. Database(Database &other)
  45. {
  46. DatabaseConnections = other.DatabaseConnections;
  47. trivialNameToUniqueID = other.trivialNameToUniqueID;
  48. //qDebug() << "Database Constructed";
  49. }
  50. ~Database()
  51. {
  52. // qDebug() << "Database Destructed";
  53. if (!DatabaseConnections.empty()) {
  54. // const QString conName(DBConnection->connectionName());
  55. // Remove all Database connnections this thread has and which will become invalid
  56. for (auto const &ConnectionNamePair : DatabaseConnections) {
  57. auto DBConnection = ConnectionNamePair.second;
  58. DBConnection->close();
  59. delete DBConnection;
  60. qDebug() << "" << ConnectionNamePair.first << "" << ConnectionNamePair.second;
  61. QSqlDatabase::removeDatabase(ConnectionNamePair.first);
  62. }
  63. }
  64. }
  65. };
  66. QString type;
  67. QString hostName;
  68. QString databaseName;
  69. QString userName;
  70. QString password;
  71. int port;
  72. QThreadStorage<Database> pool;
  73. public:
  74. /**
  75. * @brief This constructor receives informations to create a connection to the database.
  76. * @param const QString &type : Driver type.
  77. * @param const QString &hostName : Sets the connection's host name to host.
  78. * @param const QString &databaseName : Sets the connection's database name to name.
  79. * @param const QString &userName : Sets the connection's user name to name.
  80. * @param const QString &password : Sets the connection's password to password.
  81. * @param int port : Sets the connection's port number to port.
  82. */
  83. SqlDatabaseStorage(const QString &type = "",
  84. const QString &hostName = "",
  85. const QString &databaseName = "",
  86. const QString &userName = "",
  87. const QString &password = "",
  88. int port = 0)
  89. : type(type)
  90. , hostName(hostName)
  91. , databaseName(databaseName)
  92. , userName(userName)
  93. , password(password)
  94. , port(port)
  95. {}
  96. /**
  97. * @brief Returns the type.
  98. */
  99. inline QString getType() const { return type; }
  100. /**
  101. * @brief Returns the password.
  102. */
  103. inline QString getPassword() const { return password; }
  104. /**
  105. * @brief Returns the host name.
  106. */
  107. inline QString getHostName() const { return hostName; }
  108. /**
  109. * @brief Returns the database's name.
  110. */
  111. inline QString getDatabaseName() const { return databaseName; }
  112. /**
  113. * @brief Returns the user's name.
  114. */
  115. inline QString getUserName() const { return userName; }
  116. /**
  117. * @brief Returns the port.
  118. */
  119. inline int getPort() const { return port; }
  120. /**
  121. * @brief Returns the existing connection to the current thread's database. If there is no open connection to the current thread, a new connection will be created and returned.
  122. */
  123. QSqlDatabase &getDatabase()
  124. {
  125. if (!pool.hasLocalData()) //Pool has no Local Data -> create DataBaseConnection
  126. {
  127. Database database;
  128. QString UniqueID = QUuid::createUuid().toString();
  129. auto DBConnection = new QSqlDatabase(QSqlDatabase::addDatabase(type, UniqueID));
  130. DBConnection->setHostName(hostName);
  131. DBConnection->setDatabaseName(databaseName);
  132. DBConnection->setPort(port);
  133. DBConnection->setUserName(userName);
  134. DBConnection->setPassword(password);
  135. if (!DBConnection->open()) {
  136. qDebug() << DBConnection->lastError().text();
  137. std::cout << "Database not openable \t" << databaseName.toStdString() << "\n";
  138. }
  139. pool.setLocalData(database);
  140. pool.localData().DatabaseConnections.insert({UniqueID, DBConnection});
  141. pool.localData().trivialNameToUniqueID.insert({databaseName, UniqueID});
  142. } else { //Pool has Local Data
  143. auto IteratorToUserDatabaseName = pool.localData().trivialNameToUniqueID.find(
  144. databaseName);
  145. QString NameOfDBConnectionToThread;
  146. QString UniqueConnectionName;
  147. if (IteratorToUserDatabaseName != pool.localData().trivialNameToUniqueID.end()) {
  148. // this thread has a Connection to the Database
  149. // if (PublicDBName->second == pool.localData().DBConnection->connectionName()) {
  150. // //already right connection
  151. // } else {
  152. // //set the right connection
  153. // NameOfDBConnectionToThread = IteratorToUserDatabaseName->first;
  154. // UniqueConnectionName = IteratorToUserDatabaseName->second;
  155. // //pool.localData().DBConnection->close();
  156. // pool.localData().DBConnection = QSqlDatabase::database(UniqueConnectionName, false);
  157. // pool.localData().DBConnection->setHostName(hostName);
  158. // pool.localData().DBConnection->setDatabaseName(databaseName);
  159. // pool.localData().DBConnection->setPort(port);
  160. // pool.localData().DBConnection->setUserName(userName);
  161. // pool.localData().DBConnection->setPassword(password);
  162. // if(!pool.localData().DBConnection->open()) {
  163. // qDebug() << pool.localData().DBConnection->lastError().text();
  164. // }
  165. // }
  166. } else {
  167. //make new Database connection for this thread
  168. QString UniqueID = QUuid::createUuid().toString();
  169. auto DBConnection = new QSqlDatabase(QSqlDatabase::addDatabase(type, UniqueID));
  170. DBConnection->setHostName(hostName);
  171. DBConnection->setDatabaseName(databaseName);
  172. DBConnection->setPort(port);
  173. DBConnection->setUserName(userName);
  174. DBConnection->setPassword(password);
  175. if (!DBConnection->open()) {
  176. qDebug() << DBConnection->lastError().text();
  177. std::cout << "Database not openable \t" << databaseName.toStdString() << "\n";
  178. }
  179. pool.localData().DatabaseConnections.insert({UniqueID, DBConnection});
  180. pool.localData().trivialNameToUniqueID.insert({databaseName, UniqueID});
  181. }
  182. }
  183. // std::cerr << "Name To ID Mapping";
  184. // for ( auto const & foo : pool.localData().trivialNameToUniqueID) {
  185. // std::cerr << "Name " << foo.first.toStdString()
  186. // << "\tID " << foo.second.toStdString()
  187. // << "\n";
  188. // }
  189. auto UniqueName = pool.localData().trivialNameToUniqueID.at(databaseName);
  190. return *pool.localData().DatabaseConnections.at(UniqueName);
  191. //
  192. }
  193. };
  194. CWF_END_NAMESPACE
  195. #endif // SQLDATABASESTORAGE_H