adatabase.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. /*
  2. *openPilotLog - A FOSS Pilot Logbook Application
  3. *Copyright (C) 2020-2021 Felix Turowsky
  4. *
  5. *This program is free software: you can redistribute it and/or modify
  6. *it under the terms of the GNU General Public License as published by
  7. *the Free Software Foundation, either version 3 of the License, or
  8. *(at your option) any later version.
  9. *
  10. *This program is distributed in the hope that it will be useful,
  11. *but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. *GNU General Public License for more details.
  14. *
  15. *You should have received a copy of the GNU General Public License
  16. *along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. #ifndef ADATABASE_H
  19. #define ADATABASE_H
  20. #include <QPair>
  21. #include <QMap>
  22. #include <QString>
  23. #include <QDir>
  24. #include <QSqlDatabase>
  25. #include <QSqlDriver>
  26. #include <QSqlQuery>
  27. #include <QSqlError>
  28. #include <QSqlTableModel>
  29. #include <QSqlQuery>
  30. #include <QSqlRecord>
  31. #include <QSqlField>
  32. #include "src/database/adatabasetypes.h"
  33. #include "src/classes/aentry.h"
  34. #include "src/classes/apilotentry.h"
  35. #include "src/classes/atailentry.h"
  36. #include "src/classes/aaircraftentry.h"
  37. #include "src/classes/aflightentry.h"
  38. #include "src/classes/astandardpaths.h"
  39. #include "src/classes/acurrencyentry.h"
  40. #define SQLITE_DRIVER QStringLiteral("QSQLITE")
  41. /*!
  42. * \brief Convenience macro that returns instance of DataBase.
  43. * Instead of this:
  44. * DataBase::getInstance().commit(...)
  45. * Write this:
  46. * aDB->commit(...)
  47. */
  48. #define aDB ADatabase::instance()
  49. /*!
  50. * \brief The DBTarget enum lists database items that are
  51. * used by completers, for content matching or need to be accessed programatically.
  52. */
  53. enum class ADatabaseTarget
  54. {
  55. airport_identifier_icao,
  56. airport_identifier_iata,
  57. airport_identifier_all,
  58. airport_names,
  59. registrations,
  60. companies,
  61. tails,
  62. pilots,
  63. aircraft
  64. };
  65. enum class ADatabaseTable
  66. {
  67. tails,
  68. flights,
  69. currencies,
  70. aircraft,
  71. pilots,
  72. };
  73. /*!
  74. * \brief Enumerates the QMap keys used when summarising a database
  75. */
  76. enum class ADatabaseSummaryKey {
  77. total_flights,
  78. total_tails,
  79. total_pilots,
  80. last_flight,
  81. total_time,
  82. };
  83. /*!
  84. * \brief Custom Database Error derived from QSqlError.
  85. * Extends text() adding "Database Error: " before the text.
  86. * Errors that are related to SQL are assigned their respective error codes.
  87. * Errors that occur with data in the database are handled with the error code "opl"
  88. * and QSqlError::UnknownError
  89. */
  90. class ADatabaseError : public QSqlError {
  91. public:
  92. ADatabaseError() = default;
  93. ADatabaseError(QString msg);
  94. QString text() const;
  95. ADatabaseError(QSqlError);
  96. };
  97. /*!
  98. * \brief The DB class encapsulates the SQL database by providing fast access
  99. * to hot database data.
  100. */
  101. class ADatabase : public QObject {
  102. Q_OBJECT
  103. private:
  104. static ADatabase* self;
  105. TableNames_T tableNames;
  106. TableColumns_T tableColumns;
  107. int databaseRevision;
  108. ADatabase();
  109. int checkDbVersion() const;
  110. const static QStringList userTableNames;
  111. const static QStringList templateTableNames;
  112. public:
  113. /*!
  114. * \brief lastError extends QSqlError. Holds information about the last error that ocurred during
  115. * a SQL operation. If the error type is QSqlError::UnknownError, the error is related to data
  116. * from the database (entry not found,...), otherwise the error is related to SQL execution. In this
  117. * case error.type() provides further information.
  118. *
  119. * If the error type is QSqlError::NoError, the last executed database query was successful.
  120. */
  121. QSqlError lastError;
  122. const QFileInfo databaseFile;
  123. // Ensure DB is not copiable or assignable
  124. ADatabase(const ADatabase&) = delete;
  125. void operator=(const ADatabase&) = delete;
  126. static ADatabase* instance();
  127. /*!
  128. * \brief dbRevision returns the database Revision Number. The Revision refers to what iteration
  129. * of the database layout is used. For the sqlite version of the database refer to sqliteVersion()
  130. * \return
  131. */
  132. int dbRevision() const;
  133. /*!
  134. * \brief Return the names of all tables in the database
  135. */
  136. const TableNames_T getTableNames() const;
  137. /*!
  138. * \brief Return the names of a given table in the database.
  139. */
  140. const ColumnNames_T getTableColumns(TableName_T table_name) const;
  141. /*!
  142. * \brief Updates the member variables tableNames and tableColumns with up-to-date layout information
  143. * if the database has been altered. This function is normally only required during database setup or maintenance.
  144. */
  145. void updateLayout();
  146. /*!
  147. * \brief ADatabase::sqliteVersion returns the database sqlite version. See also dbRevision()
  148. * \return sqlite version string
  149. */
  150. const QString sqliteVersion() const;
  151. /*!
  152. * \brief Connect to the database and populate database information.
  153. */
  154. bool connect();
  155. /*!
  156. * \brief closes the database connection.
  157. */
  158. void disconnect();
  159. /*!
  160. * \brief Can be used to access the database connection.
  161. * \return The QSqlDatabase object pertaining to the connection.
  162. */
  163. static QSqlDatabase database();
  164. /*!
  165. * \brief Can be used to send a complex query to the database.
  166. * \param query - the full sql query statement
  167. * \param returnValues - the number of return values
  168. */
  169. QVector<QVariant> customQuery(QString statement, int return_values);
  170. /*!
  171. * \brief Checks if an entry exists in the database, based on position data
  172. */
  173. bool exists(AEntry entry);
  174. bool exists(DataPosition data_position);
  175. /*!
  176. * \brief clear resets the database, i.e. deletes all content in the tables containing
  177. * userdata (pilots, flights, tails)
  178. */
  179. bool clear();
  180. /*!
  181. * \brief commits an entry to the database, calls either insert or update,
  182. * based on position data
  183. */
  184. bool commit(AEntry entry);
  185. /*!
  186. * \brief Create new entry in the databse based on UserInput
  187. */
  188. bool insert(AEntry new_entry);
  189. /*!
  190. * \brief Updates entry in database from existing entry tweaked by the user.
  191. */
  192. bool update(AEntry updated_entry);
  193. /*!
  194. * \brief deletes an entry from the database.
  195. */
  196. bool remove(AEntry entry);
  197. /*!
  198. * \brief deletes a list of entries from the database. Optimised for speed when
  199. * deleting many entries.
  200. */
  201. bool removeMany(QList<DataPosition>);
  202. /*!
  203. * \brief retreive entry data from the database to create an entry object
  204. */
  205. RowData_T getEntryData(DataPosition data_position);
  206. /*!
  207. * \brief retreive an Entry from the database.
  208. */
  209. AEntry getEntry(DataPosition data_position);
  210. /*!
  211. * \brief retreives a PilotEntry from the database.
  212. *
  213. * This function is a wrapper for DataBase::getEntry(DataPosition),
  214. * where the table is already set and which returns a PilotEntry
  215. * instead of an Entry. It allows for easy access to a pilot entry
  216. * with only the RowId required as input.
  217. */
  218. APilotEntry getPilotEntry(RowId_T row_id);
  219. /*!
  220. * \brief retreives a TailEntry from the database.
  221. *
  222. * This function is a wrapper for DataBase::getEntry(DataPosition),
  223. * where the table is already set and which returns a TailEntry
  224. * instead of an Entry. It allows for easy access to a tail entry
  225. * with only the RowId required as input.
  226. */
  227. ATailEntry getTailEntry(RowId_T row_id);
  228. /*!
  229. * \brief retreives a TailEntry from the database.
  230. *
  231. * This function is a wrapper for DataBase::getEntry(DataPosition),
  232. * where the table is already set and which returns an AAircraftEntry
  233. * instead of an AEntry. It allows for easy access to an aircraft entry
  234. * with only the RowId required as input.
  235. */
  236. AAircraftEntry getAircraftEntry(RowId_T row_id);
  237. /*!
  238. * \brief retreives a flight entry from the database.
  239. *
  240. * This function is a wrapper for DataBase::getEntry(DataPosition),
  241. * where the table is already set and which returns an AFlightEntry
  242. * instead of an AEntry. It allows for easy access to a flight entry
  243. * with only the RowId required as input.
  244. */
  245. AFlightEntry getFlightEntry(RowId_T row_id);
  246. /*!
  247. * \brief Retreives a currency entry from the database.
  248. */
  249. ACurrencyEntry getCurrencyEntry(ACurrencyEntry::CurrencyName currency_name);
  250. /*!
  251. * \brief getCompletionList returns a QStringList of values for a
  252. * QCompleter based on database values
  253. */
  254. const QStringList getCompletionList(ADatabaseTarget target);
  255. /*!
  256. * \brief returns a QMap<QString, RowId_t> of a human-readable database value and
  257. * its row id. Used in the Dialogs to map user input to unique database entries.
  258. * \todo What is this QString semantically? As i understand its a "QueryResult" QVariant cast to QString
  259. */
  260. const QMap<QString, RowId_T> getIdMap(ADatabaseTarget target);
  261. /*!
  262. * \brief returns the ROWID for the newest entry in the respective database.
  263. */
  264. int getLastEntry(ADatabaseTable table);
  265. /*!
  266. * \brief returns a list of ROWID's in the flights table for which foreign key constraints
  267. * exist.
  268. */
  269. QList<RowId_T> getForeignKeyConstraints(RowId_T foreign_row_id, ADatabaseTable target);
  270. /*!
  271. * \brief Resolves the foreign key in a flight entry
  272. * \return The Pilot Entry referencted by the foreign key.
  273. */
  274. APilotEntry resolveForeignPilot(RowId_T foreign_key);
  275. /*!
  276. * \brief Resolves the foreign key in a flight entry
  277. * \return The Tail Entry referencted by the foreign key.
  278. */
  279. ATailEntry resolveForeignTail(RowId_T foreign_key);
  280. /*!
  281. * \brief Return a summary of a database
  282. * \details Creates a summary of the database giving a quick overview of the relevant contents. The
  283. * function runs several specialised SQL queries to create a QMap<ADatabaseSummaryKey, QString> containing
  284. * Total Flight Time, Number of unique aircraft and pilots, as well as the date of last flight. Uses a temporary
  285. * database connection separate from the default connection in order to not tamper with the currently active
  286. * database connection.
  287. */
  288. QMap<ADatabaseSummaryKey, QString> databaseSummary(const QString& db_path);
  289. /*!
  290. * \brief returns a short summary string of the database, containing total time and date of last flight.
  291. */
  292. const QString databaseSummaryString(const QString& db_path);
  293. bool restoreBackup(const QString& backup_file);
  294. bool createBackup(const QString& dest_file);
  295. /*!
  296. * \brief getTable returns all contents of a given table from the database
  297. * \return
  298. */
  299. QVector<RowData_T> getTable(ADatabaseTable table_name);
  300. /*!
  301. * \brief getUserTableNames returns a list of the table names of tables that contain user-created data
  302. * (flights, pilots,..)
  303. * \return
  304. */
  305. QStringList getUserTableNames();
  306. /*!
  307. * \brief getTemplateTableNames returns a list of the table names of tables that contain template data
  308. * (aiports, aircraft,..)
  309. * \return
  310. */
  311. QStringList getTemplateTableNames();
  312. signals:
  313. /*!
  314. * \brief updated is emitted whenever the database contents have been updated.
  315. * This can be either a commit, update or remove. This signal should be used to
  316. * trigger an update to the models of the views displaying database contents in
  317. * the user interface so that a user is always presented with up-to-date information.
  318. */
  319. void dataBaseUpdated();
  320. /*!
  321. * \brief connectionReset is emitted whenever the database connection is reset, for
  322. * example when creating or restoring a backup.
  323. */
  324. void connectionReset();
  325. };
  326. #endif // ADATABASE_H