Browse Source

Update of database tableName and tableColumn Logic

Before this commit, when we call ADatabase::connect() we write the table layout, that is tableNames and tableColumns into the member variables of the ADatabase class. This is normally ok since the database layout can be considered 'static' (as in does not change) during normal usage. It does provide a bit of a challenge however, for the database setup. The reason is this:

We call disconnect() before moving the backup, this is neccessary because we can't move/rename an open database. The backup gets made, and we call connect() again, to re-establish the connection. At this point, however, no database exists, so the tableNames and columnNames variables are written as empty. When then, later on verification of whether the data put into the database is sane takes place, it fails because the member variables holding the table layout are empty.

This problem is adressed here.
Felix 4 years ago
parent
commit
159c391d9b

+ 0 - 1
main.cpp

@@ -51,7 +51,6 @@ int main(int argc, char *argv[])
     ASettings::setup();
     ASettings::setup();
 
 
     AStyle::setup();
     AStyle::setup();
-
     aDB()->connect();
     aDB()->connect();
     if (!ASettings::read(ASettings::Setup::SetupComplete).toBool()) {
     if (!ASettings::read(ASettings::Setup::SetupComplete).toBool()) {
         if(FirstRunDialog().exec() == QDialog::Rejected){
         if(FirstRunDialog().exec() == QDialog::Rejected){

+ 24 - 18
src/database/adatabase.cpp

@@ -33,14 +33,33 @@ QString ADatabaseError::text() const
 
 
 ADatabase* ADatabase::instance = nullptr;
 ADatabase* ADatabase::instance = nullptr;
 
 
+//[F]: This is what I mentioned the other day, instead of writing the table names
+// to a member variable once at connect(), we are accessing the layout at the moment we query it.
+// While being a little more expensive, this makes the app much more robust because
+// it always returns an accurate description of the database, regardless of whether
+// it is already created or not. Also it encapsulates this functionality here instead
+// of being included in connect()
+/*!
+ * \brief Return the names of the tables in the database.
+ */
 TableNames ADatabase::getTableNames() const
 TableNames ADatabase::getTableNames() const
 {
 {
-    return tableNames;
+    auto db = ADatabase::database();
+    return db.tables();
 }
 }
 
 
-TableColumns ADatabase::getTableColumns() const
+/*!
+ * \brief Return the names of the columns for a table in the database
+ */
+TableColumns ADatabase::getTableColumns(TableName table_name) const
 {
 {
-    return tableColumns;
+    auto db = ADatabase::database();
+    TableColumns table_columns;
+    QSqlRecord fields = db.record(table_name);
+    for (int i = 0; i < fields.count(); i++) {
+        table_columns.append(fields.field(i).name());
+    }
+   return table_columns;
 }
 }
 
 
 ADatabase* ADatabase::getInstance()
 ADatabase* ADatabase::getInstance()
@@ -82,19 +101,6 @@ bool ADatabase::connect()
     DEB << "Database connection established." << db.lastError().text();
     DEB << "Database connection established." << db.lastError().text();
     // Enable foreign key restrictions
     // Enable foreign key restrictions
     QSqlQuery query(QStringLiteral("PRAGMA foreign_keys = ON;"));
     QSqlQuery query(QStringLiteral("PRAGMA foreign_keys = ON;"));
-    tableNames = db.tables();
-
-    QStringList column_names;
-    for (const auto &table : tableNames) {
-        column_names.clear();
-        QSqlRecord fields = db.record(table);
-        for (int i = 0; i < fields.count(); i++) {
-            column_names.append(fields.field(i).name());
-            tableColumns.insert(table, column_names);
-        }
-    }
-    DEB << "Database Tables: " << tableNames;
-    DEB << "Tables and Columns: " << tableColumns;
     return true;
     return true;
 }
 }
 
 
@@ -337,7 +343,7 @@ bool ADatabase::insert(AEntry new_entry)
 RowData ADatabase::getEntryData(DataPosition data_position)
 RowData ADatabase::getEntryData(DataPosition data_position)
 {
 {
     // check table exists
     // check table exists
-    if (!tableNames.contains(data_position.tableName)) {
+    if (!getTableNames().contains(data_position.tableName)) {
         DEB << data_position.tableName << " not a table in the database. Unable to retreive Entry data.";
         DEB << data_position.tableName << " not a table in the database. Unable to retreive Entry data.";
         return RowData();
         return RowData();
     }
     }
@@ -385,7 +391,7 @@ RowData ADatabase::getEntryData(DataPosition data_position)
     select_query.next();
     select_query.next();
     RowData entry_data;
     RowData entry_data;
 
 
-    for (const auto &column : tableColumns.value(data_position.tableName)) {
+    for (const auto &column : getTableColumns(data_position.tableName)) {
         entry_data.insert(column, select_query.value(column));
         entry_data.insert(column, select_query.value(column));
     }
     }
     return entry_data;
     return entry_data;

+ 1 - 3
src/database/adatabase.h

@@ -77,8 +77,6 @@ public:
 class ADatabase : public QObject {
 class ADatabase : public QObject {
     Q_OBJECT
     Q_OBJECT
 private:
 private:
-    TableNames tableNames;
-    TableColumns tableColumns;
     static ADatabase* instance;
     static ADatabase* instance;
     ADatabase();
     ADatabase();
 public:
 public:
@@ -87,7 +85,7 @@ public:
     void operator=(const ADatabase&) = delete;
     void operator=(const ADatabase&) = delete;
     static ADatabase* getInstance();
     static ADatabase* getInstance();
     TableNames getTableNames() const;
     TableNames getTableNames() const;
-    TableColumns getTableColumns() const;
+    TableColumns getTableColumns(TableName table_name) const;
     const QString sqliteVersion();
     const QString sqliteVersion();
 
 
     ADatabaseError lastError;
     ADatabaseError lastError;

+ 13 - 16
src/database/adatabasesetup.cpp

@@ -266,9 +266,6 @@ bool ADataBaseSetup::createDatabase()
         return false;
         return false;
     }
     }
 
 
-    // call connect again to (re-)populate tableNames and columnNames
-    aDB()->connect();
-
     DEB << "Populating tables...";
     DEB << "Populating tables...";
     if (!importDefaultData()) {
     if (!importDefaultData()) {
         DEB << "Populating tables failed.";
         DEB << "Populating tables failed.";
@@ -415,25 +412,25 @@ bool ADataBaseSetup::createSchemata(const QStringList &statements)
  * \param tableName as in the database
  * \param tableName as in the database
  * \return
  * \return
  */
  */
-bool ADataBaseSetup::commitData(QVector<QStringList> fromCSV, const QString &tableName)
+bool ADataBaseSetup::commitData(QVector<QStringList> from_csv, const QString &table_name)
 {
 {
     DEB << "Table names: " << aDB()->getTableNames();
     DEB << "Table names: " << aDB()->getTableNames();
-    DEB << "Importing Data to" << tableName;
-    if (!aDB()->getTableNames().contains(tableName)){
-        DEB << tableName << "is not a table in the database. Aborting.";
+    DEB << "Importing Data to" << table_name;
+    if (!aDB()->getTableNames().contains(table_name)){
+        DEB << table_name << "is not a table in the database. Aborting.";
         DEB << "Please check input data.";
         DEB << "Please check input data.";
         return false;
         return false;
     }
     }
     // create insert statement
     // create insert statement
-    QString statement = "INSERT INTO " + tableName + " (";
+    QString statement = "INSERT INTO " + table_name + " (";
     QString placeholder = ") VALUES (";
     QString placeholder = ") VALUES (";
-    for (auto& csvColumn : fromCSV) {
-        if(aDB()->getTableColumns().value(tableName).contains(csvColumn.first())) {
+    for (auto& csvColumn : from_csv) {
+        if(aDB()->getTableColumns(table_name).contains(csvColumn.first())) {
             statement += csvColumn.first() + ',';
             statement += csvColumn.first() + ',';
             csvColumn.removeFirst();
             csvColumn.removeFirst();
             placeholder.append("?,");
             placeholder.append("?,");
         } else {
         } else {
-            DEB << csvColumn.first() << "is not a column of " << tableName << "Aborting.";
+            DEB << csvColumn.first() << "is not a column of " << table_name << "Aborting.";
             DEB << "Please check input data.";
             DEB << "Please check input data.";
             return false;
             return false;
         }
         }
@@ -449,12 +446,12 @@ bool ADataBaseSetup::commitData(QVector<QStringList> fromCSV, const QString &tab
      */
      */
     QSqlQuery query;
     QSqlQuery query;
     query.exec("BEGIN EXCLUSIVE TRANSACTION;");
     query.exec("BEGIN EXCLUSIVE TRANSACTION;");
-    for (int i = 0; i < fromCSV.first().length(); i++){
+    for (int i = 0; i < from_csv.first().length(); i++){
         query.prepare(statement);
         query.prepare(statement);
-        for(int j = 0; j < fromCSV.length(); j++) {
-             fromCSV[j][i] == QString("") ? // make sure NULL is committed for empty values
+        for(int j = 0; j < from_csv.length(); j++) {
+             from_csv[j][i] == QString("") ? // make sure NULL is committed for empty values
                          query.addBindValue(QVariant(QVariant::String))
                          query.addBindValue(QVariant(QVariant::String))
-                       : query.addBindValue(fromCSV[j][i]);
+                       : query.addBindValue(from_csv[j][i]);
              //query.addBindValue(fromCSV[j][i]);
              //query.addBindValue(fromCSV[j][i]);
          }
          }
         query.exec();
         query.exec();
@@ -465,7 +462,7 @@ bool ADataBaseSetup::commitData(QVector<QStringList> fromCSV, const QString &tab
         DEB << "Error:" << query.lastError().text();
         DEB << "Error:" << query.lastError().text();
         return false;
         return false;
     } else {
     } else {
-        qDebug() << tableName << "Database successfully updated!";
+        qDebug() << table_name << "Database successfully updated!";
         return true;
         return true;
     }
     }
 }
 }

+ 1 - 1
src/database/adatabasesetup.h

@@ -47,7 +47,7 @@ public:
 
 
     static bool resetToDefault();
     static bool resetToDefault();
 
 
-    static bool commitData(QVector<QStringList> fromCSV, const QString &tableName);
+    static bool commitData(QVector<QStringList> from_csv, const QString &table_name);
 
 
 private:
 private:
 
 

+ 1 - 1
src/database/declarations.h

@@ -23,7 +23,7 @@ using TableNames = QStringList;
 using RowData = QMap<ColName, ColData>;
 using RowData = QMap<ColName, ColData>;
 using ColumnData = QPair<ColName, ColData>;
 using ColumnData = QPair<ColName, ColData>;
 using ColumnNames = QStringList;
 using ColumnNames = QStringList;
-using TableColumns = QMap<TableName, ColumnNames>;
+using TableColumns = QStringList;
 
 
 // [G]: Needs some work. Inheriting from QPair may be helpful but
 // [G]: Needs some work. Inheriting from QPair may be helpful but
 // may also be overkill. Lets determine the specific uses of DataPosition
 // may also be overkill. Lets determine the specific uses of DataPosition

+ 4 - 1
src/gui/dialogues/firstrundialog.ui

@@ -30,6 +30,9 @@
    </item>
    </item>
    <item row="0" column="0" colspan="2">
    <item row="0" column="0" colspan="2">
     <widget class="QStackedWidget" name="stackedWidget">
     <widget class="QStackedWidget" name="stackedWidget">
+     <property name="currentIndex">
+      <number>2</number>
+     </property>
      <widget class="QWidget" name="stackedWidgetPage1">
      <widget class="QWidget" name="stackedWidgetPage1">
       <layout class="QGridLayout" name="gridLayout_2">
       <layout class="QGridLayout" name="gridLayout_2">
        <item row="0" column="1">
        <item row="0" column="1">
@@ -397,7 +400,7 @@
        <item row="0" column="0" colspan="2">
        <item row="0" column="0" colspan="2">
         <widget class="QLabel" name="label_4">
         <widget class="QLabel" name="label_4">
          <property name="text">
          <property name="text">
-          <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-size:16pt;&quot;&gt;Finish&lt;/span&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;&lt;br/&gt;Almost done! Here you can select the theme to be used for the application.&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;This change will take effect the next time the application is launched.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+          <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;center&quot;&gt;&lt;span style=&quot; font-size:16pt;&quot;&gt;Finish&lt;/span&gt;&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;&lt;br/&gt;Almost done! We are now going to create the database for the application.&lt;/p&gt;&lt;p align=&quot;center&quot;&gt;If you want to use the most up-to-date version of the database, an internet connection is required, otherwise you can use the version included in the download.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
          </property>
          </property>
          <property name="textFormat">
          <property name="textFormat">
           <enum>Qt::RichText</enum>
           <enum>Qt::RichText</enum>