/*
*openPilotLog - A FOSS Pilot Logbook Application
*Copyright (C) 2020-2021 Felix Turowsky
*
*This program is free software: you can redistribute it and/or modify
*it under the terms of the GNU General Public License as published by
*the Free Software Foundation, either version 3 of the License, or
*(at your option) any later version.
*
*This program is distributed in the hope that it will be useful,
*but WITHOUT ANY WARRANTY; without even the implied warranty of
*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*GNU General Public License for more details.
*
*You should have received a copy of the GNU General Public License
*along with this program. If not, see .
*/
#ifndef ADATABASE_H
#define ADATABASE_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "src/database/adatabasetypes.h"
#include "src/classes/aentry.h"
#include "src/classes/apilotentry.h"
#include "src/classes/atailentry.h"
#include "src/classes/aaircraftentry.h"
#include "src/classes/aflightentry.h"
#include "src/classes/astandardpaths.h"
#include "src/classes/acurrencyentry.h"
#define SQLITE_DRIVER QStringLiteral("QSQLITE")
/*!
* \brief Convenience macro that returns instance of DataBase.
* Instead of this:
* DataBase::getInstance().commit(...)
* Write this:
* aDB->commit(...)
*/
#define aDB ADatabase::instance()
/*!
* \brief The DBTarget enum lists database items that are
* used by completers, for content matching or need to be accessed programatically.
*/
enum class ADatabaseTarget
{
airport_identifier_icao,
airport_identifier_iata,
airport_identifier_all,
airport_names,
registrations,
companies,
tails,
pilots,
aircraft
};
enum class ADatabaseTable
{
tails,
flights,
currencies,
aircraft,
pilots,
};
/*!
* \brief Enumerates the QMap keys used when summarising a database
*/
enum class ADatabaseSummaryKey {
total_flights,
total_tails,
total_pilots,
last_flight,
total_time,
};
/*!
* \brief Custom Database Error derived from QSqlError.
* Extends text() adding "Database Error: " before the text.
* Errors that are related to SQL are assigned their respective error codes.
* Errors that occur with data in the database are handled with the error code "opl"
* and QSqlError::UnknownError
*/
class ADatabaseError : public QSqlError {
public:
ADatabaseError() = default;
ADatabaseError(QString msg);
QString text() const;
ADatabaseError(QSqlError);
};
/*!
* \brief The DB class encapsulates the SQL database by providing fast access
* to hot database data.
*/
class ADatabase : public QObject {
Q_OBJECT
private:
static ADatabase* self;
TableNames_T tableNames;
TableColumns_T tableColumns;
int databaseRevision;
ADatabase();
int checkDbVersion() const;
const static QStringList userTableNames;
const static QStringList templateTableNames;
public:
/*!
* \brief lastError extends QSqlError. Holds information about the last error that ocurred during
* a SQL operation. If the error type is QSqlError::UnknownError, the error is related to data
* from the database (entry not found,...), otherwise the error is related to SQL execution. In this
* case error.type() provides further information.
*
* If the error type is QSqlError::NoError, the last executed database query was successful.
*/
QSqlError lastError;
const QFileInfo databaseFile;
// Ensure DB is not copiable or assignable
ADatabase(const ADatabase&) = delete;
void operator=(const ADatabase&) = delete;
static ADatabase* instance();
/*!
* \brief dbRevision returns the database Revision Number. The Revision refers to what iteration
* of the database layout is used. For the sqlite version of the database refer to sqliteVersion()
* \return
*/
int dbRevision() const;
/*!
* \brief Return the names of all tables in the database
*/
const TableNames_T getTableNames() const;
/*!
* \brief Return the names of a given table in the database.
*/
const ColumnNames_T getTableColumns(TableName_T table_name) const;
/*!
* \brief Updates the member variables tableNames and tableColumns with up-to-date layout information
* if the database has been altered. This function is normally only required during database setup or maintenance.
*/
void updateLayout();
/*!
* \brief ADatabase::sqliteVersion returns the database sqlite version. See also dbRevision()
* \return sqlite version string
*/
const QString sqliteVersion() const;
/*!
* \brief Connect to the database and populate database information.
*/
bool connect();
/*!
* \brief closes the database connection.
*/
void disconnect();
/*!
* \brief Can be used to access the database connection.
* \return The QSqlDatabase object pertaining to the connection.
*/
static QSqlDatabase database();
/*!
* \brief Can be used to send a complex query to the database.
* \param query - the full sql query statement
* \param returnValues - the number of return values
*/
QVector customQuery(QString statement, int return_values);
/*!
* \brief Checks if an entry exists in the database, based on position data
*/
bool exists(AEntry entry);
bool exists(DataPosition data_position);
/*!
* \brief clear resets the database, i.e. deletes all content in the tables containing
* userdata (pilots, flights, tails)
*/
bool clear();
/*!
* \brief commits an entry to the database, calls either insert or update,
* based on position data
*/
bool commit(AEntry entry);
/*!
* \brief Create new entry in the databse based on UserInput
*/
bool insert(AEntry new_entry);
/*!
* \brief Updates entry in database from existing entry tweaked by the user.
*/
bool update(AEntry updated_entry);
/*!
* \brief deletes an entry from the database.
*/
bool remove(AEntry entry);
/*!
* \brief deletes a list of entries from the database. Optimised for speed when
* deleting many entries.
*/
bool removeMany(QList);
/*!
* \brief retreive entry data from the database to create an entry object
*/
RowData_T getEntryData(DataPosition data_position);
/*!
* \brief retreive an Entry from the database.
*/
AEntry getEntry(DataPosition data_position);
/*!
* \brief retreives a PilotEntry from the database.
*
* This function is a wrapper for DataBase::getEntry(DataPosition),
* where the table is already set and which returns a PilotEntry
* instead of an Entry. It allows for easy access to a pilot entry
* with only the RowId required as input.
*/
APilotEntry getPilotEntry(RowId_T row_id);
/*!
* \brief retreives a TailEntry from the database.
*
* This function is a wrapper for DataBase::getEntry(DataPosition),
* where the table is already set and which returns a TailEntry
* instead of an Entry. It allows for easy access to a tail entry
* with only the RowId required as input.
*/
ATailEntry getTailEntry(RowId_T row_id);
/*!
* \brief retreives a TailEntry from the database.
*
* This function is a wrapper for DataBase::getEntry(DataPosition),
* where the table is already set and which returns an AAircraftEntry
* instead of an AEntry. It allows for easy access to an aircraft entry
* with only the RowId required as input.
*/
AAircraftEntry getAircraftEntry(RowId_T row_id);
/*!
* \brief retreives a flight entry from the database.
*
* This function is a wrapper for DataBase::getEntry(DataPosition),
* where the table is already set and which returns an AFlightEntry
* instead of an AEntry. It allows for easy access to a flight entry
* with only the RowId required as input.
*/
AFlightEntry getFlightEntry(RowId_T row_id);
/*!
* \brief Retreives a currency entry from the database.
*/
ACurrencyEntry getCurrencyEntry(ACurrencyEntry::CurrencyName currency_name);
/*!
* \brief getCompletionList returns a QStringList of values for a
* QCompleter based on database values
*/
const QStringList getCompletionList(ADatabaseTarget target);
/*!
* \brief returns a QMap of a human-readable database value and
* its row id. Used in the Dialogs to map user input to unique database entries.
* \todo What is this QString semantically? As i understand its a "QueryResult" QVariant cast to QString
*/
const QMap getIdMap(ADatabaseTarget target);
/*!
* \brief returns the ROWID for the newest entry in the respective database.
*/
int getLastEntry(ADatabaseTable table);
/*!
* \brief returns a list of ROWID's in the flights table for which foreign key constraints
* exist.
*/
QList getForeignKeyConstraints(RowId_T foreign_row_id, ADatabaseTable target);
/*!
* \brief Resolves the foreign key in a flight entry
* \return The Pilot Entry referencted by the foreign key.
*/
APilotEntry resolveForeignPilot(RowId_T foreign_key);
/*!
* \brief Resolves the foreign key in a flight entry
* \return The Tail Entry referencted by the foreign key.
*/
ATailEntry resolveForeignTail(RowId_T foreign_key);
/*!
* \brief Return a summary of a database
* \details Creates a summary of the database giving a quick overview of the relevant contents. The
* function runs several specialised SQL queries to create a QMap containing
* Total Flight Time, Number of unique aircraft and pilots, as well as the date of last flight. Uses a temporary
* database connection separate from the default connection in order to not tamper with the currently active
* database connection.
*/
QMap databaseSummary(const QString& db_path);
/*!
* \brief returns a short summary string of the database, containing total time and date of last flight.
*/
const QString databaseSummaryString(const QString& db_path);
bool restoreBackup(const QString& backup_file);
bool createBackup(const QString& dest_file);
/*!
* \brief getTable returns all contents of a given table from the database
* \return
*/
QVector getTable(ADatabaseTable table_name);
/*!
* \brief getUserTableNames returns a list of the table names of tables that contain user-created data
* (flights, pilots,..)
* \return
*/
QStringList getUserTableNames();
/*!
* \brief getTemplateTableNames returns a list of the table names of tables that contain template data
* (aiports, aircraft,..)
* \return
*/
QStringList getTemplateTableNames();
signals:
/*!
* \brief updated is emitted whenever the database contents have been updated.
* This can be either a commit, update or remove. This signal should be used to
* trigger an update to the models of the views displaying database contents in
* the user interface so that a user is always presented with up-to-date information.
*/
void dataBaseUpdated();
/*!
* \brief connectionReset is emitted whenever the database connection is reset, for
* example when creating or restoring a backup.
*/
void connectionReset();
};
#endif // ADATABASE_H