|  | @@ -15,62 +15,41 @@
 | 
	
		
			
				|  |  |   *You should have received a copy of the GNU General Public License
 | 
	
		
			
				|  |  |   *along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  | -#include "adatabase.h"
 | 
	
		
			
				|  |  | +#include "database.h"
 | 
	
		
			
				|  |  |  #include "src/functions/alog.h"
 | 
	
		
			
				|  |  |  #include "src/classes/astandardpaths.h"
 | 
	
		
			
				|  |  |  #include "src/opl.h"
 | 
	
		
			
				|  |  |  #include "src/functions/alog.h"
 | 
	
		
			
				|  |  |  #include "src/classes/ajson.h"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -const int ADatabase::minimumDatabaseRevision = 0;
 | 
	
		
			
				|  |  | +namespace OPL {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -const QStringList ADatabase::userTableNames = {
 | 
	
		
			
				|  |  | -    QStringLiteral("flights"),
 | 
	
		
			
				|  |  | -    QStringLiteral("pilots"),
 | 
	
		
			
				|  |  | -    QStringLiteral("tails")
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -const QStringList ADatabase::templateTableNames = {
 | 
	
		
			
				|  |  | -    QStringLiteral("aircraft"),
 | 
	
		
			
				|  |  | -    QStringLiteral("airports"),
 | 
	
		
			
				|  |  | -    QStringLiteral("currencies"),
 | 
	
		
			
				|  |  | -    QStringLiteral("changelog")
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -ADatabase* ADatabase::self = nullptr;
 | 
	
		
			
				|  |  | +Database* Database::self = nullptr;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -ADatabase::ADatabase()
 | 
	
		
			
				|  |  | +Database::Database()
 | 
	
		
			
				|  |  |      : databaseFile(QFileInfo(AStandardPaths::directory(AStandardPaths::Database).
 | 
	
		
			
				|  |  |                               absoluteFilePath(QStringLiteral("logbook.db"))))
 | 
	
		
			
				|  |  |  {}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -int ADatabase::dbRevision() const
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -    return databaseRevision;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -int ADatabase::checkDbVersion() const
 | 
	
		
			
				|  |  | +const QString Database::version() const
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      QSqlQuery query(QStringLiteral("SELECT COUNT(*) FROM changelog"));
 | 
	
		
			
				|  |  |      query.next();
 | 
	
		
			
				|  |  | -    return query.value(0).toInt();
 | 
	
		
			
				|  |  | +    return QStringLiteral("OPL Database Revision: ") + QString::number(query.value(0).toInt());
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -int ADatabase::getMinimumDatabaseRevision()
 | 
	
		
			
				|  |  | +const QList<OPL::DbTable> &Database::getTemplateTables() const
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -    return minimumDatabaseRevision;
 | 
	
		
			
				|  |  | +    return TEMPLATE_TABLES;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -const QStringList &ADatabase::getTemplateTableNames() const
 | 
	
		
			
				|  |  | +const QList<OPL::DbTable> &Database::getUserTables() const
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -    return templateTableNames;
 | 
	
		
			
				|  |  | +    return USER_TABLES;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -const QStringList& ADatabase::getUserTableNames() const
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -    return userTableNames;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -UserDataState ADatabase::getUserDataState()
 | 
	
		
			
				|  |  | +const UserDataState Database::getUserDataState() const
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      QSqlQuery q;
 | 
	
		
			
				|  |  |      q.prepare(QStringLiteral("SELECT COUNT (*) FROM tails"));
 | 
	
	
		
			
				|  | @@ -86,37 +65,24 @@ UserDataState ADatabase::getUserDataState()
 | 
	
		
			
				|  |  |      return UserDataState(tails, pilots);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -bool ADatabase::resetUserData()
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -    QSqlQuery query;
 | 
	
		
			
				|  |  | -    for (const auto& table : userTableNames) {
 | 
	
		
			
				|  |  | -        query.prepare(QLatin1String("DELETE FROM ") + table);
 | 
	
		
			
				|  |  | -        if (!query.exec()) {
 | 
	
		
			
				|  |  | -            DEB << "Error: " << query.lastError().text();
 | 
	
		
			
				|  |  | -            return false;
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    return true;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -const ColumnNames_T ADatabase::getTableColumns(TableName_T table_name) const
 | 
	
		
			
				|  |  | +const QStringList Database::getTableColumns(OPL::DbTable table_name) const
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -    return tableColumns.value(table_name);
 | 
	
		
			
				|  |  | +    return tableColumns.value(OPL::GLOBALS->getDbTableName(table_name));
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -const TableNames_T ADatabase::getTableNames() const
 | 
	
		
			
				|  |  | +const QStringList Database::getTableNames() const
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      return tableNames;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -void ADatabase::updateLayout()
 | 
	
		
			
				|  |  | +void Database::updateLayout()
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -    auto db = ADatabase::database();
 | 
	
		
			
				|  |  | +    auto db = Database::database();
 | 
	
		
			
				|  |  |      tableNames = db.tables();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      tableColumns.clear();
 | 
	
		
			
				|  |  |      for (const auto &table_name : qAsConst(tableNames)) {
 | 
	
		
			
				|  |  | -        ColumnNames_T table_columns;
 | 
	
		
			
				|  |  | +        QStringList table_columns;
 | 
	
		
			
				|  |  |          QSqlRecord fields = db.record(table_name);
 | 
	
		
			
				|  |  |          for (int i = 0; i < fields.count(); i++) {
 | 
	
		
			
				|  |  |              table_columns.append(fields.field(i).name());
 | 
	
	
		
			
				|  | @@ -126,86 +92,15 @@ void ADatabase::updateLayout()
 | 
	
		
			
				|  |  |      emit dataBaseUpdated();
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -ADatabase* ADatabase::instance()
 | 
	
		
			
				|  |  | +Database* Database::instance()
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      if(!self)
 | 
	
		
			
				|  |  | -        self = new ADatabase();
 | 
	
		
			
				|  |  | +        self = new Database();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      return self;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -bool ADatabase::createSchema()
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -    // Read Database layout from sql file
 | 
	
		
			
				|  |  | -    QFile f(OPL::Assets::DATABASE_SCHEMA);
 | 
	
		
			
				|  |  | -    f.open(QIODevice::ReadOnly);
 | 
	
		
			
				|  |  | -    QByteArray filedata = f.readAll();
 | 
	
		
			
				|  |  | -    // create individual queries for each table/view
 | 
	
		
			
				|  |  | -    auto list = filedata.split(';');
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    // Create Tables
 | 
	
		
			
				|  |  | -    QSqlQuery q;
 | 
	
		
			
				|  |  | -    QVector<QSqlError> errors;
 | 
	
		
			
				|  |  | -    for (const auto &query_string : list) {
 | 
	
		
			
				|  |  | -        q.prepare(query_string);
 | 
	
		
			
				|  |  | -        if (!q.exec()) {
 | 
	
		
			
				|  |  | -            errors.append(q.lastError());
 | 
	
		
			
				|  |  | -            LOG << "Unable to execute query: ";
 | 
	
		
			
				|  |  | -            LOG << q.lastQuery();
 | 
	
		
			
				|  |  | -            LOG << q.lastError();
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    updateLayout();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    if (errors.isEmpty()) {
 | 
	
		
			
				|  |  | -        LOG << "Database succesfully created.";
 | 
	
		
			
				|  |  | -        return true;
 | 
	
		
			
				|  |  | -    } else {
 | 
	
		
			
				|  |  | -        LOG << "Database creation has failed. The following error(s) have ocurred: ";
 | 
	
		
			
				|  |  | -        for (const auto &error : qAsConst(errors)) {
 | 
	
		
			
				|  |  | -            LOG << error.type() << error.text();
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        return false;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -bool ADatabase::importTemplateData(bool use_local_ressources)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -    for (const auto& table_name : templateTableNames) {
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        //clear table
 | 
	
		
			
				|  |  | -        QSqlQuery q;
 | 
	
		
			
				|  |  | -        q.prepare(QLatin1String("DELETE FROM ") + table_name);
 | 
	
		
			
				|  |  | -        if (!q.exec()) {
 | 
	
		
			
				|  |  | -            LOG << "Error clearing tables: " << q.lastError().text();
 | 
	
		
			
				|  |  | -            return false;
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        //Prepare data
 | 
	
		
			
				|  |  | -        QJsonArray data_to_commit;
 | 
	
		
			
				|  |  | -        QString error_message("Error importing data ");
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        if (use_local_ressources) {
 | 
	
		
			
				|  |  | -            data_to_commit = AJson::readFileToDoc(QLatin1String(":database/templates/")
 | 
	
		
			
				|  |  | -                                      + table_name + QLatin1String(".json")).array();
 | 
	
		
			
				|  |  | -            error_message.append(QLatin1String(" (ressource) "));
 | 
	
		
			
				|  |  | -        } else {
 | 
	
		
			
				|  |  | -            data_to_commit = AJson::readFileToDoc(AStandardPaths::directory(
 | 
	
		
			
				|  |  | -                                          AStandardPaths::Templates).absoluteFilePath(
 | 
	
		
			
				|  |  | -                                          table_name + QLatin1String(".json"))).array();
 | 
	
		
			
				|  |  | -            error_message.append(QLatin1String(" (downloaded) "));
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        // commit Data from Array
 | 
	
		
			
				|  |  | -        if (!commit(data_to_commit, table_name)) {
 | 
	
		
			
				|  |  | -            LOG << error_message;
 | 
	
		
			
				|  |  | -            return false;
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -    } // for table_name
 | 
	
		
			
				|  |  | -    return true;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -const QString ADatabase::sqliteVersion() const
 | 
	
		
			
				|  |  | +const QString Database::sqliteVersion() const
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      QSqlQuery query;
 | 
	
		
			
				|  |  |      query.prepare(QStringLiteral("SELECT sqlite_version()"));
 | 
	
	
		
			
				|  | @@ -214,7 +109,7 @@ const QString ADatabase::sqliteVersion() const
 | 
	
		
			
				|  |  |      return query.value(0).toString();
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -bool ADatabase::connect()
 | 
	
		
			
				|  |  | +bool Database::connect()
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      if (!QSqlDatabase::isDriverAvailable(SQLITE_DRIVER)) {
 | 
	
		
			
				|  |  |          LOG << "Error: No SQLITE Driver availabe.";
 | 
	
	
		
			
				|  | @@ -238,24 +133,23 @@ bool ADatabase::connect()
 | 
	
		
			
				|  |  |      query.prepare(QStringLiteral("PRAGMA foreign_keys = ON;"));
 | 
	
		
			
				|  |  |      query.exec();
 | 
	
		
			
				|  |  |      updateLayout();
 | 
	
		
			
				|  |  | -    databaseRevision = checkDbVersion();
 | 
	
		
			
				|  |  |      return true;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -void ADatabase::disconnect()
 | 
	
		
			
				|  |  | +void Database::disconnect()
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -    auto db = ADatabase::database();
 | 
	
		
			
				|  |  | +    auto db = Database::database();
 | 
	
		
			
				|  |  |      db.close();
 | 
	
		
			
				|  |  |      db.removeDatabase(db.connectionName());
 | 
	
		
			
				|  |  |      LOG << "Database connection closed.";
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -QSqlDatabase ADatabase::database()
 | 
	
		
			
				|  |  | +QSqlDatabase Database::database()
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      return QSqlDatabase::database(QStringLiteral("qt_sql_default_connection"));
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -//bool ADatabase::commit(const AEntry &entry)
 | 
	
		
			
				|  |  | +//bool Database::commit(const AEntry &entry)
 | 
	
		
			
				|  |  |  //{
 | 
	
		
			
				|  |  |  //    if (exists(entry)) {
 | 
	
		
			
				|  |  |  //        return update(entry);
 | 
	
	
		
			
				|  | @@ -264,7 +158,7 @@ QSqlDatabase ADatabase::database()
 | 
	
		
			
				|  |  |  //    }
 | 
	
		
			
				|  |  |  //}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -bool ADatabase::commit(const OPL::Row &row)
 | 
	
		
			
				|  |  | +bool Database::commit(const OPL::Row &row)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      if (!row.isValid())
 | 
	
		
			
				|  |  |          return false;
 | 
	
	
		
			
				|  | @@ -275,12 +169,13 @@ bool ADatabase::commit(const OPL::Row &row)
 | 
	
		
			
				|  |  |          return insert(row);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -bool ADatabase::commit(const QJsonArray &json_arr, const QString &table_name)
 | 
	
		
			
				|  |  | +bool Database::commit(const QJsonArray &json_arr, const OPL::DbTable table)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      // create statement
 | 
	
		
			
				|  |  | +    const QString table_name = OPL::GLOBALS->getDbTableName(table);
 | 
	
		
			
				|  |  |      QString statement = QLatin1String("INSERT INTO ") + table_name + QLatin1String(" (");
 | 
	
		
			
				|  |  |      QString placeholder = QStringLiteral(") VALUES (");
 | 
	
		
			
				|  |  | -    for (const auto &column_name : aDB->getTableColumns(table_name)) {
 | 
	
		
			
				|  |  | +    for (const auto &column_name : DB->getTableColumns(table)) {
 | 
	
		
			
				|  |  |          statement += column_name + ',';
 | 
	
		
			
				|  |  |          placeholder.append(QLatin1Char(':') + column_name + QLatin1Char(','));
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -312,7 +207,7 @@ bool ADatabase::commit(const QJsonArray &json_arr, const QString &table_name)
 | 
	
		
			
				|  |  |          return false;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -//bool ADatabase::remove(const AEntry &entry)
 | 
	
		
			
				|  |  | +//bool Database::remove(const AEntry &entry)
 | 
	
		
			
				|  |  |  //{
 | 
	
		
			
				|  |  |  //    if (!exists(entry)) {
 | 
	
		
			
				|  |  |  //        LOG << "Error: Database entry not found.";
 | 
	
	
		
			
				|  | @@ -340,7 +235,7 @@ bool ADatabase::commit(const QJsonArray &json_arr, const QString &table_name)
 | 
	
		
			
				|  |  |  //    }
 | 
	
		
			
				|  |  |  //}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -bool ADatabase::remove(const OPL::Row &row)
 | 
	
		
			
				|  |  | +bool Database::remove(const OPL::Row &row)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      if (!exists(row)) {
 | 
	
		
			
				|  |  |          LOG << "Error: Database entry not found.";
 | 
	
	
		
			
				|  | @@ -369,22 +264,21 @@ bool ADatabase::remove(const OPL::Row &row)
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -bool ADatabase::removeMany(const QList<DataPosition> &position_list)
 | 
	
		
			
				|  |  | +bool Database::removeMany(OPL::DbTable table, const QList<int> &row_id_list)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | +    const QString table_name = OPL::GLOBALS->getDbTableName(table);
 | 
	
		
			
				|  |  |      int errorCount = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |      QSqlQuery query;
 | 
	
		
			
				|  |  |      query.prepare(QStringLiteral("BEGIN EXCLUSIVE TRANSACTION"));
 | 
	
		
			
				|  |  |      query.exec();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    for (const auto& data_position : position_list) {
 | 
	
		
			
				|  |  | -        if (!exists(data_position)) {
 | 
	
		
			
				|  |  | -            errorCount++;
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        QString statement = QLatin1String("DELETE FROM ") + data_position.tableName +
 | 
	
		
			
				|  |  | +    for (const auto row_id : row_id_list) {
 | 
	
		
			
				|  |  | +        const QString statement = QLatin1String("DELETE FROM ") + table_name +
 | 
	
		
			
				|  |  |                  QLatin1String(" WHERE ROWID=?");
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          query.prepare(statement);
 | 
	
		
			
				|  |  | -        query.addBindValue(data_position.rowId);
 | 
	
		
			
				|  |  | +        query.addBindValue(row_id);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          if (!query.exec())
 | 
	
		
			
				|  |  |              errorCount++;
 | 
	
	
		
			
				|  | @@ -412,35 +306,7 @@ bool ADatabase::removeMany(const QList<DataPosition> &position_list)
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -bool ADatabase::exists(const DataPosition &data_position)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -    if(data_position.rowId == 0)
 | 
	
		
			
				|  |  | -        return false;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    //Check database for row id
 | 
	
		
			
				|  |  | -    QString statement = QLatin1String("SELECT COUNT(*) FROM ") + data_position.tableName
 | 
	
		
			
				|  |  | -            + QLatin1String(" WHERE ROWID=?");
 | 
	
		
			
				|  |  | -    QSqlQuery query;
 | 
	
		
			
				|  |  | -    query.prepare(statement);
 | 
	
		
			
				|  |  | -    query.addBindValue(data_position.rowId);
 | 
	
		
			
				|  |  | -    query.setForwardOnly(true);
 | 
	
		
			
				|  |  | -    query.exec();
 | 
	
		
			
				|  |  | -    //this returns either 1 or 0 since row ids are unique
 | 
	
		
			
				|  |  | -    if (!query.isActive()) {
 | 
	
		
			
				|  |  | -        lastError = query.lastError();
 | 
	
		
			
				|  |  | -        LOG << "Query Error: " << query.lastError().text() << statement;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    query.next();
 | 
	
		
			
				|  |  | -    int rowId = query.value(0).toInt();
 | 
	
		
			
				|  |  | -    if (rowId) {
 | 
	
		
			
				|  |  | -        return true;
 | 
	
		
			
				|  |  | -    } else {
 | 
	
		
			
				|  |  | -        LOG << "No entry exists at DataPosition: " << data_position.tableName << data_position.rowId;
 | 
	
		
			
				|  |  | -        return false;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -bool ADatabase::exists(const OPL::Row &row)
 | 
	
		
			
				|  |  | +bool Database::exists(const OPL::Row &row)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      if (row.getRowId() == 0)
 | 
	
		
			
				|  |  |          return false;
 | 
	
	
		
			
				|  | @@ -469,12 +335,12 @@ bool ADatabase::exists(const OPL::Row &row)
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -bool ADatabase::clear()
 | 
	
		
			
				|  |  | +bool Database::clear()
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      QSqlQuery q;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    for (const auto &table_name : userTableNames) {
 | 
	
		
			
				|  |  | -        q.prepare(QLatin1String("DELETE FROM ") + table_name);
 | 
	
		
			
				|  |  | +    for (const auto &table : USER_TABLES) {
 | 
	
		
			
				|  |  | +        q.prepare(QLatin1String("DELETE FROM ") + OPL::GLOBALS->getDbTableName(table));
 | 
	
		
			
				|  |  |          if (!q.exec()) {
 | 
	
		
			
				|  |  |              DEB << "Error: " << q.lastError().text();
 | 
	
		
			
				|  |  |              lastError = q.lastError();
 | 
	
	
		
			
				|  | @@ -484,10 +350,11 @@ bool ADatabase::clear()
 | 
	
		
			
				|  |  |      return true;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -bool ADatabase::update(const OPL::Row &updated_row)
 | 
	
		
			
				|  |  | +bool Database::update(const OPL::Row &updated_row)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      QString statement = QLatin1String("UPDATE ") + OPL::GLOBALS->getDbTableName(updated_row.getTableName()) + QLatin1String(" SET ");
 | 
	
		
			
				|  |  | -    for (auto i = updated_row.getData().constBegin(); i != updated_row.getData().constEnd(); ++i) {
 | 
	
		
			
				|  |  | +    const auto& data = updated_row.getData();
 | 
	
		
			
				|  |  | +    for (auto i = data.constBegin(); i != data.constEnd(); ++i) {
 | 
	
		
			
				|  |  |          statement.append(i.key() + "=?,");
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      statement.chop(1);
 | 
	
	
		
			
				|  | @@ -495,7 +362,7 @@ bool ADatabase::update(const OPL::Row &updated_row)
 | 
	
		
			
				|  |  |      QSqlQuery query;
 | 
	
		
			
				|  |  |      query.prepare(statement);
 | 
	
		
			
				|  |  |      DEB << "Statement: " << statement;
 | 
	
		
			
				|  |  | -    for (auto i = updated_row.getData().constBegin(); i != updated_row.getData().constEnd(); ++i) {
 | 
	
		
			
				|  |  | +    for (auto i = data.constBegin(); i != data.constEnd(); ++i) {
 | 
	
		
			
				|  |  |          if (i.value() == QVariant(QString()) || i.value() == 0) {
 | 
	
		
			
				|  |  |              query.addBindValue(QVariant(QVariant::String));
 | 
	
		
			
				|  |  |          } else {
 | 
	
	
		
			
				|  | @@ -519,11 +386,12 @@ bool ADatabase::update(const OPL::Row &updated_row)
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -bool ADatabase::insert(const OPL::Row &new_row)
 | 
	
		
			
				|  |  | +bool Database::insert(const OPL::Row &new_row)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      QString statement = QLatin1String("INSERT INTO ") + OPL::GLOBALS->getDbTableName(new_row.getTableName()) + QLatin1String(" (");
 | 
	
		
			
				|  |  | +    const auto& data = new_row.getData();
 | 
	
		
			
				|  |  |      QHash<QString, QVariant>::const_iterator i;
 | 
	
		
			
				|  |  | -    for (i = new_row.getData().constBegin(); i != new_row.getData().constEnd(); ++i) {
 | 
	
		
			
				|  |  | +    for (i = data.constBegin(); i != data.constEnd(); ++i) {
 | 
	
		
			
				|  |  |          statement.append(i.key() + QLatin1Char(','));
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      statement.chop(1);
 | 
	
	
		
			
				|  | @@ -538,7 +406,7 @@ bool ADatabase::insert(const OPL::Row &new_row)
 | 
	
		
			
				|  |  |      QSqlQuery query;
 | 
	
		
			
				|  |  |      query.prepare(statement);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    for (i = new_row.getData().constBegin(); i != new_row.getData().constEnd(); ++i) {
 | 
	
		
			
				|  |  | +    for (i = data.constBegin(); i != data.constEnd(); ++i) {
 | 
	
		
			
				|  |  |          if (i.value() == QVariant(QString()) || i.value() == 0) {
 | 
	
		
			
				|  |  |              query.addBindValue(QVariant(QVariant::String));
 | 
	
		
			
				|  |  |          } else {
 | 
	
	
		
			
				|  | @@ -561,64 +429,7 @@ bool ADatabase::insert(const OPL::Row &new_row)
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -RowData_T ADatabase::getEntryData(const DataPosition &data_position)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -    // check table exists
 | 
	
		
			
				|  |  | -    if (!getTableNames().contains(data_position.tableName)) {
 | 
	
		
			
				|  |  | -        DEB << data_position.tableName << " not a table in the database. Unable to retreive Entry data.";
 | 
	
		
			
				|  |  | -        return RowData_T();
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    //Check Database for rowId
 | 
	
		
			
				|  |  | -    QString statement = QLatin1String("SELECT COUNT(*) FROM ") + data_position.tableName
 | 
	
		
			
				|  |  | -                      + QLatin1String(" WHERE ROWID=?");
 | 
	
		
			
				|  |  | -    QSqlQuery check_query;
 | 
	
		
			
				|  |  | -    check_query.prepare(statement);
 | 
	
		
			
				|  |  | -    check_query.addBindValue(data_position.rowId);
 | 
	
		
			
				|  |  | -    check_query.setForwardOnly(true);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    if (!check_query.exec()) {
 | 
	
		
			
				|  |  | -        DEB << "SQL error: " << check_query.lastError().text();
 | 
	
		
			
				|  |  | -        DEB << "Statement: " << statement;
 | 
	
		
			
				|  |  | -        lastError = check_query.lastError();
 | 
	
		
			
				|  |  | -        return RowData_T();
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    check_query.next();
 | 
	
		
			
				|  |  | -    if (check_query.value(0).toInt() == 0) {
 | 
	
		
			
				|  |  | -        LOG << "No Entry found for row id: " << data_position.rowId;
 | 
	
		
			
				|  |  | -        return RowData_T();
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    // Retreive TableData
 | 
	
		
			
				|  |  | -    statement = QLatin1String("SELECT * FROM ") + data_position.tableName
 | 
	
		
			
				|  |  | -              + QLatin1String(" WHERE ROWID=?");
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    QSqlQuery select_query;
 | 
	
		
			
				|  |  | -    select_query.prepare(statement);
 | 
	
		
			
				|  |  | -    select_query.addBindValue(data_position.rowId);
 | 
	
		
			
				|  |  | -    select_query.setForwardOnly(true);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    if (!select_query.exec()) {
 | 
	
		
			
				|  |  | -        DEB << "SQL error: " << select_query.lastError().text();
 | 
	
		
			
				|  |  | -        DEB << "Statement: " << select_query.lastQuery();
 | 
	
		
			
				|  |  | -        lastError = select_query.lastError();
 | 
	
		
			
				|  |  | -        return {};
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    RowData_T entry_data;
 | 
	
		
			
				|  |  | -    if(select_query.next()) { // retreive records
 | 
	
		
			
				|  |  | -        auto r = select_query.record();
 | 
	
		
			
				|  |  | -        for (int i = 0; i < r.count(); i++){
 | 
	
		
			
				|  |  | -            if(!r.value(i).isNull()) {
 | 
	
		
			
				|  |  | -                entry_data.insert(r.fieldName(i), r.value(i));
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    return entry_data;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -OPL::Row ADatabase::getRow(const OPL::DbTable table, const int row_id)
 | 
	
		
			
				|  |  | +OPL::Row Database::getRow(const OPL::DbTable table, const int row_id)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      QString statement = QLatin1String("SELECT * FROM ") + OPL::GLOBALS->getDbTableName(table)
 | 
	
		
			
				|  |  |              + QLatin1String(" WHERE ROWID=?");
 | 
	
	
		
			
				|  | @@ -650,7 +461,7 @@ OPL::Row ADatabase::getRow(const OPL::DbTable table, const int row_id)
 | 
	
		
			
				|  |  |      return OPL::Row(table, row_id, entry_data);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -RowData_T ADatabase::getRowData(const OPL::DbTable table, const int row_id)
 | 
	
		
			
				|  |  | +RowData_T Database::getRowData(const OPL::DbTable table, const int row_id)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      QString statement = QLatin1String("SELECT * FROM ") + OPL::GLOBALS->getDbTableName(table)
 | 
	
		
			
				|  |  |              + QLatin1String(" WHERE ROWID=?");
 | 
	
	
		
			
				|  | @@ -682,120 +493,10 @@ RowData_T ADatabase::getRowData(const OPL::DbTable table, const int row_id)
 | 
	
		
			
				|  |  |      return entry_data;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -const QStringList ADatabase::getCompletionList(ADatabaseTarget target)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -    QString statement;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    switch (target) {
 | 
	
		
			
				|  |  | -    case ADatabaseTarget::pilots:
 | 
	
		
			
				|  |  | -        statement.append(QStringLiteral("SELECT lastname||', '||firstname FROM pilots"));
 | 
	
		
			
				|  |  | -        break;
 | 
	
		
			
				|  |  | -    case ADatabaseTarget::aircraft:
 | 
	
		
			
				|  |  | -        statement.append(QStringLiteral("SELECT make||' '||model FROM aircraft WHERE model IS NOT NULL AND variant IS NULL "
 | 
	
		
			
				|  |  | -                         "UNION "
 | 
	
		
			
				|  |  | -                         "SELECT make||' '||model||'-'||variant FROM aircraft WHERE variant IS NOT NULL"));
 | 
	
		
			
				|  |  | -        break;
 | 
	
		
			
				|  |  | -    case ADatabaseTarget::airport_identifier_all:
 | 
	
		
			
				|  |  | -        statement.append(QStringLiteral("SELECT icao FROM airports UNION SELECT iata FROM airports"));
 | 
	
		
			
				|  |  | -        break;
 | 
	
		
			
				|  |  | -    case ADatabaseTarget::registrations:
 | 
	
		
			
				|  |  | -        statement.append(QStringLiteral("SELECT registration FROM tails"));
 | 
	
		
			
				|  |  | -        break;
 | 
	
		
			
				|  |  | -    case ADatabaseTarget::companies:
 | 
	
		
			
				|  |  | -        statement.append(QStringLiteral("SELECT company FROM pilots"));
 | 
	
		
			
				|  |  | -        break;
 | 
	
		
			
				|  |  | -    default:
 | 
	
		
			
				|  |  | -        DEB << "Not a valid completer target for this function.";
 | 
	
		
			
				|  |  | -        return QStringList();
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    QSqlQuery query;
 | 
	
		
			
				|  |  | -    query.prepare(statement);
 | 
	
		
			
				|  |  | -    query.setForwardOnly(true);
 | 
	
		
			
				|  |  | -    query.exec();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    if(!query.isActive()) {
 | 
	
		
			
				|  |  | -        lastError = query.lastError();
 | 
	
		
			
				|  |  | -        return QStringList();
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    QStringList completer_list;
 | 
	
		
			
				|  |  | -    while (query.next())
 | 
	
		
			
				|  |  | -        completer_list.append(query.value(0).toString());
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    completer_list.sort();
 | 
	
		
			
				|  |  | -    completer_list.removeAll(QString());
 | 
	
		
			
				|  |  | -    completer_list.removeDuplicates();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    return completer_list;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -const QHash<RowId_T, QString> ADatabase::getIdMap(ADatabaseTarget target)
 | 
	
		
			
				|  |  | +int Database::getLastEntry(OPL::DbTable table)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | -    QString statement;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    switch (target) {
 | 
	
		
			
				|  |  | -    case ADatabaseTarget::pilots:
 | 
	
		
			
				|  |  | -        statement.append(QStringLiteral("SELECT ROWID, lastname||', '||firstname FROM pilots"));
 | 
	
		
			
				|  |  | -        break;
 | 
	
		
			
				|  |  | -    case ADatabaseTarget::aircraft:
 | 
	
		
			
				|  |  | -        statement.append(QStringLiteral("SELECT ROWID, make||' '||model FROM aircraft WHERE model IS NOT NULL AND variant IS NULL "
 | 
	
		
			
				|  |  | -                         "UNION "
 | 
	
		
			
				|  |  | -                         "SELECT ROWID, make||' '||model||'-'||variant FROM aircraft WHERE variant IS NOT NULL"));
 | 
	
		
			
				|  |  | -        break;
 | 
	
		
			
				|  |  | -    case ADatabaseTarget::airport_identifier_icao:
 | 
	
		
			
				|  |  | -        statement.append(QStringLiteral("SELECT ROWID, icao FROM airports"));
 | 
	
		
			
				|  |  | -        break;
 | 
	
		
			
				|  |  | -    case ADatabaseTarget::airport_identifier_iata:
 | 
	
		
			
				|  |  | -        statement.append(QStringLiteral("SELECT ROWID, iata FROM airports WHERE iata NOT NULL"));
 | 
	
		
			
				|  |  | -        break;
 | 
	
		
			
				|  |  | -    case ADatabaseTarget::airport_names:
 | 
	
		
			
				|  |  | -        statement.append(QStringLiteral("SELECT ROWID, name FROM airports"));
 | 
	
		
			
				|  |  | -        break;
 | 
	
		
			
				|  |  | -    case ADatabaseTarget::tails:
 | 
	
		
			
				|  |  | -        statement.append(QStringLiteral("SELECT ROWID, registration FROM tails"));
 | 
	
		
			
				|  |  | -        break;
 | 
	
		
			
				|  |  | -    default:
 | 
	
		
			
				|  |  | -        DEB << "Not a valid completer target for this function.";
 | 
	
		
			
				|  |  | -        return {};
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    QSqlQuery query;
 | 
	
		
			
				|  |  | -    query.setForwardOnly(true);
 | 
	
		
			
				|  |  | -    query.prepare(statement);
 | 
	
		
			
				|  |  | -    query.exec();
 | 
	
		
			
				|  |  | -    //auto query = QSqlQuery(statement);
 | 
	
		
			
				|  |  | -    if (!query.isActive()) {
 | 
	
		
			
				|  |  | -        DEB << "No result found. Check Query and Error.";
 | 
	
		
			
				|  |  | -        DEB << "Query: " << statement;
 | 
	
		
			
				|  |  | -        DEB << "Error: " << query.lastError().text();
 | 
	
		
			
				|  |  | -        lastError = query.lastError();
 | 
	
		
			
				|  |  | -        return {};
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    auto id_map = QHash<RowId_T, QString>();
 | 
	
		
			
				|  |  | -    while (query.next())
 | 
	
		
			
				|  |  | -        id_map.insert(query.value(0).toInt(), query.value(1).toString());
 | 
	
		
			
				|  |  | -    return id_map;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | +    QString statement = QLatin1String("SELECT MAX(ROWID) FROM ") + OPL::GLOBALS->getDbTableName(table);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -RowId_T ADatabase::getLastEntry(ADatabaseTable table)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -    QString statement = QLatin1String("SELECT MAX(ROWID) FROM ");
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    switch (table) {
 | 
	
		
			
				|  |  | -    case ADatabaseTable::pilots:
 | 
	
		
			
				|  |  | -        statement.append(OPL::Db::TABLE_PILOTS);
 | 
	
		
			
				|  |  | -        break;
 | 
	
		
			
				|  |  | -    case ADatabaseTable::aircraft:
 | 
	
		
			
				|  |  | -        statement.append(OPL::Db::TABLE_AIRCRAFT);
 | 
	
		
			
				|  |  | -        break;
 | 
	
		
			
				|  |  | -    case ADatabaseTable::tails:
 | 
	
		
			
				|  |  | -        statement.append(OPL::Db::TABLE_TAILS);
 | 
	
		
			
				|  |  | -        break;
 | 
	
		
			
				|  |  | -    default:
 | 
	
		
			
				|  |  | -        DEB << "Not a valid completer target for this function.";
 | 
	
		
			
				|  |  | -        return 0;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  |      auto query = QSqlQuery(statement);
 | 
	
		
			
				|  |  |      if (query.first()) {
 | 
	
		
			
				|  |  |          return query.value(0).toInt();
 | 
	
	
		
			
				|  | @@ -805,15 +506,15 @@ RowId_T ADatabase::getLastEntry(ADatabaseTable table)
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -QList<RowId_T> ADatabase::getForeignKeyConstraints(RowId_T foreign_row_id, ADatabaseTable target)
 | 
	
		
			
				|  |  | +QList<int> Database::getForeignKeyConstraints(int foreign_row_id, OPL::DbTable table)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      QString statement = QLatin1String("SELECT ROWID FROM flights WHERE ");
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    switch (target) {
 | 
	
		
			
				|  |  | -    case ADatabaseTable::pilots:
 | 
	
		
			
				|  |  | +    switch (table) {
 | 
	
		
			
				|  |  | +    case OPL::DbTable::Pilots:
 | 
	
		
			
				|  |  |          statement.append(QLatin1String("pic=?"));
 | 
	
		
			
				|  |  |          break;
 | 
	
		
			
				|  |  | -    case ADatabaseTable::tails:
 | 
	
		
			
				|  |  | +    case OPL::DbTable::Tails:
 | 
	
		
			
				|  |  |          statement.append(QLatin1String("acft=?"));
 | 
	
		
			
				|  |  |          break;
 | 
	
		
			
				|  |  |      default:
 | 
	
	
		
			
				|  | @@ -842,7 +543,7 @@ QList<RowId_T> ADatabase::getForeignKeyConstraints(RowId_T foreign_row_id, AData
 | 
	
		
			
				|  |  |      return row_ids;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -QVector<QVariant> ADatabase::customQuery(QString statement, int return_values)
 | 
	
		
			
				|  |  | +QVector<QVariant> Database::customQuery(QString statement, int return_values)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      QSqlQuery query(statement);
 | 
	
		
			
				|  |  |      if(!query.exec()) {
 | 
	
	
		
			
				|  | @@ -870,89 +571,14 @@ QVector<QVariant> ADatabase::customQuery(QString statement, int return_values)
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -QMap<ADatabaseSummaryKey, QString> ADatabase::databaseSummary(const QString &db_path)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -    const QString connection_name = QStringLiteral("summary_connection");
 | 
	
		
			
				|  |  | -    QMap<ADatabaseSummaryKey, QString> return_values;
 | 
	
		
			
				|  |  | -    { // scope for a temporary database connection, ensures proper cleanup when removeDatabase() is called.
 | 
	
		
			
				|  |  | -        //DEB << "Adding temporary connection to database:" << db_path;
 | 
	
		
			
				|  |  | -        QSqlDatabase temp_database = QSqlDatabase::addDatabase(SQLITE_DRIVER, connection_name); // Don't use default connection
 | 
	
		
			
				|  |  | -        temp_database.setDatabaseName(db_path);
 | 
	
		
			
				|  |  | -        if (!temp_database.open())
 | 
	
		
			
				|  |  | -            return {};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        QSqlQuery query(temp_database); // Query object using the temporary connection
 | 
	
		
			
				|  |  | -        ADatabaseSummaryKey key;  // Used among the queries for verbosity... and sanity
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        const QVector<QPair<ADatabaseSummaryKey, QString>> key_table_pairs = {
 | 
	
		
			
				|  |  | -            {ADatabaseSummaryKey::total_flights, QStringLiteral("flights")},
 | 
	
		
			
				|  |  | -            {ADatabaseSummaryKey::total_tails, QStringLiteral("tails")},
 | 
	
		
			
				|  |  | -            {ADatabaseSummaryKey::total_pilots, QStringLiteral("pilots")}
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -        // retreive amount of flights, tails and pilots
 | 
	
		
			
				|  |  | -        for (const auto & pair : key_table_pairs) {
 | 
	
		
			
				|  |  | -            query.prepare(QLatin1String("SELECT COUNT (*) FROM ") + pair.second);
 | 
	
		
			
				|  |  | -            query.exec();
 | 
	
		
			
				|  |  | -            key = pair.first;
 | 
	
		
			
				|  |  | -            if (query.first()){
 | 
	
		
			
				|  |  | -                return_values[key] = query.value(0).toString();
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -            else{
 | 
	
		
			
				|  |  | -                return_values[key] = QString();
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        // retreive date of last flight
 | 
	
		
			
				|  |  | -        query.prepare(QStringLiteral("SELECT MAX(doft) FROM flights"));
 | 
	
		
			
				|  |  | -        query.exec();
 | 
	
		
			
				|  |  | -        key = ADatabaseSummaryKey::last_flight;
 | 
	
		
			
				|  |  | -        if (query.first()){
 | 
	
		
			
				|  |  | -            return_values[key] = query.value(0).toString();
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        else {
 | 
	
		
			
				|  |  | -            return_values[key] = QString();
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        // retreive total flight time as a string "hh:mm"
 | 
	
		
			
				|  |  | -        query.prepare(QStringLiteral("SELECT "
 | 
	
		
			
				|  |  | -                                     "printf(\"%02d\",CAST(SUM(tblk) AS INT)/60)"
 | 
	
		
			
				|  |  | -                                     "||':'||"
 | 
	
		
			
				|  |  | -                                     "printf(\"%02d\",CAST(SUM(tblk) AS INT)%60) FROM flights"));
 | 
	
		
			
				|  |  | -        key = ADatabaseSummaryKey::total_time;
 | 
	
		
			
				|  |  | -        query.exec();
 | 
	
		
			
				|  |  | -        if (query.first()){
 | 
	
		
			
				|  |  | -            return_values[key] = query.value(0).toString();
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        else {
 | 
	
		
			
				|  |  | -            return_values[key] = QString();
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    QSqlDatabase::removeDatabase(connection_name); // cleanly removes temp connection without leaks since query+db are out of scope
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    return return_values;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -const QString ADatabase::databaseSummaryString(const QString &db_path)
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -    auto summary_map = databaseSummary(db_path);
 | 
	
		
			
				|  |  | -    QString out = QLatin1String("<table>");
 | 
	
		
			
				|  |  | -    out.append(tr("<tr><td>Total Time: </td><td>%1</td>").arg(summary_map[ADatabaseSummaryKey::total_time]));
 | 
	
		
			
				|  |  | -    out.append(tr("<tr><td>Last Flight: </td><td>%1</td>").arg(summary_map[ADatabaseSummaryKey::last_flight]));
 | 
	
		
			
				|  |  | -    out.append(tr("<tr><td>Number of flights: </td><td>%1</td>").arg(summary_map[ADatabaseSummaryKey::total_flights]));
 | 
	
		
			
				|  |  | -    out.append(tr("<tr><td>Number of aircraft: </td><td>%1</td>").arg(summary_map[ADatabaseSummaryKey::total_tails]));
 | 
	
		
			
				|  |  | -    out.append(tr("<tr><td>Number of Pilots: </td><td>%1</td>").arg(summary_map[ADatabaseSummaryKey::total_pilots]));
 | 
	
		
			
				|  |  | -    out.append("</table>");
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    return out;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  /*!
 | 
	
		
			
				|  |  | - * \brief ADatabase::createBackup copies the currently used database to an external backup location provided by the user
 | 
	
		
			
				|  |  | + * \brief Database::createBackup copies the currently used database to an external backup location provided by the user
 | 
	
		
			
				|  |  |   * \param dest_file This is the full path and filename of where the backup will be created, e.g. 'home/Sully/myBackups/backupFromOpl.db'
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  | -bool ADatabase::createBackup(const QString& dest_file)
 | 
	
		
			
				|  |  | +bool Database::createBackup(const QString& dest_file)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      LOG << "Backing up current database to: " << dest_file;
 | 
	
		
			
				|  |  | -    ADatabase::disconnect();
 | 
	
		
			
				|  |  | +    Database::disconnect();
 | 
	
		
			
				|  |  |      QFile db_file(databaseFile.absoluteFilePath());
 | 
	
		
			
				|  |  |      //DEB << "File to Overwrite:" << db_file;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -962,25 +588,25 @@ bool ADatabase::createBackup(const QString& dest_file)
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      LOG << "Backed up old database as:" << dest_file;
 | 
	
		
			
				|  |  | -    ADatabase::connect();
 | 
	
		
			
				|  |  | +    Database::connect();
 | 
	
		
			
				|  |  |      emit connectionReset();
 | 
	
		
			
				|  |  |      return true;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -QVector<RowData_T> ADatabase::getTable(ADatabaseTable table_name)
 | 
	
		
			
				|  |  | +QVector<RowData_T> Database::getTable(OPL::DbTable table)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      auto query_str = QStringLiteral("SELECT * FROM ");
 | 
	
		
			
				|  |  | -    switch (table_name) {
 | 
	
		
			
				|  |  | -    case ADatabaseTable::pilots:
 | 
	
		
			
				|  |  | +    switch (table) {
 | 
	
		
			
				|  |  | +    case OPL::DbTable::Pilots:
 | 
	
		
			
				|  |  |          query_str.append(OPL::Db::TABLE_PILOTS);
 | 
	
		
			
				|  |  |          break;
 | 
	
		
			
				|  |  | -    case ADatabaseTable::tails:
 | 
	
		
			
				|  |  | +    case OPL::DbTable::Tails:
 | 
	
		
			
				|  |  |          query_str.append(OPL::Db::TABLE_TAILS);
 | 
	
		
			
				|  |  |          break;
 | 
	
		
			
				|  |  | -    case ADatabaseTable::flights:
 | 
	
		
			
				|  |  | +    case OPL::DbTable::Flights:
 | 
	
		
			
				|  |  |          query_str.append(OPL::Db::TABLE_FLIGHTS);
 | 
	
		
			
				|  |  |          break;
 | 
	
		
			
				|  |  | -    case ADatabaseTable::currencies:
 | 
	
		
			
				|  |  | +    case OPL::DbTable::Currencies:
 | 
	
		
			
				|  |  |          query_str.append(OPL::Db::TABLE_CURRENCIES);
 | 
	
		
			
				|  |  |      default:
 | 
	
		
			
				|  |  |          break;
 | 
	
	
		
			
				|  | @@ -1013,16 +639,16 @@ QVector<RowData_T> ADatabase::getTable(ADatabaseTable table_name)
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /*!
 | 
	
		
			
				|  |  | - * \brief ADatabase::restoreBackup restores the database from a given backup file and replaces the currently active database.
 | 
	
		
			
				|  |  | + * \brief Database::restoreBackup restores the database from a given backup file and replaces the currently active database.
 | 
	
		
			
				|  |  |   * \param backup_file This is the full path and filename of the backup, e.g. 'home/Sully/myBackups/backupFromOpl.db'
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  | -bool ADatabase::restoreBackup(const QString& backup_file)
 | 
	
		
			
				|  |  | +bool Database::restoreBackup(const QString& backup_file)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |      LOG << "Restoring backup from file:" << backup_file;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      QString default_loc = databaseFile.absoluteFilePath();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    ADatabase::disconnect();
 | 
	
		
			
				|  |  | +    Database::disconnect();
 | 
	
		
			
				|  |  |      QFile backup(backup_file);
 | 
	
		
			
				|  |  |      QFile current_db(default_loc);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1042,8 +668,94 @@ bool ADatabase::restoreBackup(const QString& backup_file)
 | 
	
		
			
				|  |  |      // backup has been restored, clean up the previously moved file
 | 
	
		
			
				|  |  |      current_db.remove();
 | 
	
		
			
				|  |  |      LOG << "Backup successfully restored!";
 | 
	
		
			
				|  |  | -    ADatabase::connect();
 | 
	
		
			
				|  |  | +    Database::connect();
 | 
	
		
			
				|  |  |      emit connectionReset();
 | 
	
		
			
				|  |  |      return true;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +bool Database::createSchema()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    // Read Database layout from sql file
 | 
	
		
			
				|  |  | +    QFile f(OPL::Assets::DATABASE_SCHEMA);
 | 
	
		
			
				|  |  | +    f.open(QIODevice::ReadOnly);
 | 
	
		
			
				|  |  | +    QByteArray filedata = f.readAll();
 | 
	
		
			
				|  |  | +    // create individual queries for each table/view
 | 
	
		
			
				|  |  | +    auto list = filedata.split(';');
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Create Tables
 | 
	
		
			
				|  |  | +    QSqlQuery q;
 | 
	
		
			
				|  |  | +    QVector<QSqlError> errors;
 | 
	
		
			
				|  |  | +    for (const auto &query_string : list) {
 | 
	
		
			
				|  |  | +        q.prepare(query_string);
 | 
	
		
			
				|  |  | +        if (!q.exec()) {
 | 
	
		
			
				|  |  | +            errors.append(q.lastError());
 | 
	
		
			
				|  |  | +            LOG << "Unable to execute query: ";
 | 
	
		
			
				|  |  | +            LOG << q.lastQuery();
 | 
	
		
			
				|  |  | +            LOG << q.lastError();
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    DB->updateLayout();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (errors.isEmpty()) {
 | 
	
		
			
				|  |  | +        LOG << "Database succesfully created.";
 | 
	
		
			
				|  |  | +        return true;
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +        LOG << "Database creation has failed. The following error(s) have ocurred: ";
 | 
	
		
			
				|  |  | +        for (const auto &error : qAsConst(errors)) {
 | 
	
		
			
				|  |  | +            LOG << error.type() << error.text();
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        return false;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +bool Database::importTemplateData(bool use_local_ressources)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    for (const auto& table : DB->getTemplateTables()) {
 | 
	
		
			
				|  |  | +        const QString table_name = OPL::GLOBALS->getDbTableName(table);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        //clear table
 | 
	
		
			
				|  |  | +        QSqlQuery q;
 | 
	
		
			
				|  |  | +        q.prepare(QLatin1String("DELETE FROM ") + table_name);
 | 
	
		
			
				|  |  | +        if (!q.exec()) {
 | 
	
		
			
				|  |  | +            LOG << "Error clearing tables: " << q.lastError().text();
 | 
	
		
			
				|  |  | +            return false;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        //Prepare data
 | 
	
		
			
				|  |  | +        QJsonArray data_to_commit;
 | 
	
		
			
				|  |  | +        QString error_message("Error importing data ");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if (use_local_ressources) {
 | 
	
		
			
				|  |  | +            data_to_commit = AJson::readFileToDoc(QLatin1String(":database/templates/")
 | 
	
		
			
				|  |  | +                                      + table_name + QLatin1String(".json")).array();
 | 
	
		
			
				|  |  | +            error_message.append(QLatin1String(" (ressource) "));
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +            data_to_commit = AJson::readFileToDoc(AStandardPaths::directory(
 | 
	
		
			
				|  |  | +                                          AStandardPaths::Templates).absoluteFilePath(
 | 
	
		
			
				|  |  | +                                          table_name + QLatin1String(".json"))).array();
 | 
	
		
			
				|  |  | +            error_message.append(QLatin1String(" (downloaded) "));
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // commit Data from Array
 | 
	
		
			
				|  |  | +        if (!DB->commit(data_to_commit, table)) {
 | 
	
		
			
				|  |  | +            LOG << error_message;
 | 
	
		
			
				|  |  | +            return false;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    } // for table_name
 | 
	
		
			
				|  |  | +    return true;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +bool Database::resetUserData()
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    QSqlQuery query;
 | 
	
		
			
				|  |  | +    for (const auto& table : DB->getUserTables()) {
 | 
	
		
			
				|  |  | +        query.prepare(QLatin1String("DELETE FROM ") + OPL::GLOBALS->getDbTableName(table));
 | 
	
		
			
				|  |  | +        if (!query.exec()) {
 | 
	
		
			
				|  |  | +            DEB << "Error: " << query.lastError().text();
 | 
	
		
			
				|  |  | +            return false;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    return true;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +} // namespace OPL
 |