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();
 
     AStyle::setup();
-
     aDB()->connect();
     if (!ASettings::read(ASettings::Setup::SetupComplete).toBool()) {
         if(FirstRunDialog().exec() == QDialog::Rejected){

+ 24 - 18
src/database/adatabase.cpp

@@ -33,14 +33,33 @@ QString ADatabaseError::text() const
 
 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
 {
-    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()
@@ -82,19 +101,6 @@ bool ADatabase::connect()
     DEB << "Database connection established." << db.lastError().text();
     // Enable foreign key restrictions
     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;
 }
 
@@ -337,7 +343,7 @@ bool ADatabase::insert(AEntry new_entry)
 RowData ADatabase::getEntryData(DataPosition data_position)
 {
     // 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.";
         return RowData();
     }
@@ -385,7 +391,7 @@ RowData ADatabase::getEntryData(DataPosition data_position)
     select_query.next();
     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));
     }
     return entry_data;

+ 1 - 3
src/database/adatabase.h

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

+ 13 - 16
src/database/adatabasesetup.cpp

@@ -266,9 +266,6 @@ bool ADataBaseSetup::createDatabase()
         return false;
     }
 
-    // call connect again to (re-)populate tableNames and columnNames
-    aDB()->connect();
-
     DEB << "Populating tables...";
     if (!importDefaultData()) {
         DEB << "Populating tables failed.";
@@ -415,25 +412,25 @@ bool ADataBaseSetup::createSchemata(const QStringList &statements)
  * \param tableName as in the database
  * \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 << "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.";
         return false;
     }
     // create insert statement
-    QString statement = "INSERT INTO " + tableName + " (";
+    QString statement = "INSERT INTO " + table_name + " (";
     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() + ',';
             csvColumn.removeFirst();
             placeholder.append("?,");
         } 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.";
             return false;
         }
@@ -449,12 +446,12 @@ bool ADataBaseSetup::commitData(QVector<QStringList> fromCSV, const QString &tab
      */
     QSqlQuery query;
     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);
-        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(fromCSV[j][i]);
+                       : query.addBindValue(from_csv[j][i]);
              //query.addBindValue(fromCSV[j][i]);
          }
         query.exec();
@@ -465,7 +462,7 @@ bool ADataBaseSetup::commitData(QVector<QStringList> fromCSV, const QString &tab
         DEB << "Error:" << query.lastError().text();
         return false;
     } else {
-        qDebug() << tableName << "Database successfully updated!";
+        qDebug() << table_name << "Database successfully updated!";
         return true;
     }
 }

+ 1 - 1
src/database/adatabasesetup.h

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

+ 1 - 1
src/database/declarations.h

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

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

@@ -30,6 +30,9 @@
    </item>
    <item row="0" column="0" colspan="2">
     <widget class="QStackedWidget" name="stackedWidget">
+     <property name="currentIndex">
+      <number>2</number>
+     </property>
      <widget class="QWidget" name="stackedWidgetPage1">
       <layout class="QGridLayout" name="gridLayout_2">
        <item row="0" column="1">
@@ -397,7 +400,7 @@
        <item row="0" column="0" colspan="2">
         <widget class="QLabel" name="label_4">
          <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 name="textFormat">
           <enum>Qt::RichText</enum>