database.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  1. /*
  2. *openPilotLog - A FOSS Pilot Logbook Application
  3. *Copyright (C) 2020-2023 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. #include "database.h"
  19. #include "src/opl.h"
  20. #include "src/classes/jsonhelper.h"
  21. namespace OPL {
  22. bool Database::connect()
  23. {
  24. if (!QSqlDatabase::isDriverAvailable(SQLITE_DRIVER)) {
  25. LOG << "Error: No SQLITE Driver availabe.";
  26. return false;
  27. }
  28. QSqlDatabase db = QSqlDatabase::addDatabase(SQLITE_DRIVER);
  29. db.setDatabaseName(databaseFile.absoluteFilePath());
  30. if (!db.open()) {
  31. LOG << QString("Unable to establish database connection.<br>The following error has ocurred:<br><br>%1")
  32. .arg(db.lastError().databaseText());
  33. lastError = db.lastError();
  34. return false;
  35. }
  36. LOG << "Database connection established: " + databaseFile.absoluteFilePath();
  37. // Enable foreign key restrictions
  38. QSqlQuery query;
  39. query.prepare(QStringLiteral("PRAGMA foreign_keys = ON;"));
  40. query.exec();
  41. updateLayout();
  42. return true;
  43. }
  44. void Database::disconnect()
  45. {
  46. QString connection_name;
  47. {
  48. auto db = Database::database();
  49. connection_name = db.connectionName();
  50. db.close();
  51. }
  52. QSqlDatabase::removeDatabase(connection_name);
  53. LOG << "Database connection closed.";
  54. }
  55. const QList<OPL::DbTable> &Database::getTemplateTables() const
  56. {
  57. return TEMPLATE_TABLES;
  58. }
  59. const QList<OPL::DbTable> &Database::getUserTables() const
  60. {
  61. return USER_TABLES;
  62. }
  63. const QStringList Database::getTableColumns(OPL::DbTable table_name) const
  64. {
  65. return tableColumns.value(OPL::GLOBALS->getDbTableName(table_name));
  66. }
  67. const QStringList Database::getTableNames() const
  68. {
  69. return tableNames;
  70. }
  71. void Database::updateLayout()
  72. {
  73. auto db = Database::database();
  74. tableNames = db.tables();
  75. tableColumns.clear();
  76. for (const auto &table_name : std::as_const(tableNames)) {
  77. QStringList table_columns;
  78. QSqlRecord fields = db.record(table_name);
  79. for (int i = 0; i < fields.count(); i++) {
  80. table_columns.append(fields.field(i).name());
  81. }
  82. tableColumns.insert(table_name, table_columns);
  83. }
  84. emit dataBaseUpdated(DbTable::Any);
  85. }
  86. const QString Database::sqliteVersion() const
  87. {
  88. QSqlQuery query;
  89. query.prepare(QStringLiteral("SELECT sqlite_version()"));
  90. query.exec();
  91. query.next();
  92. return query.value(0).toString();
  93. }
  94. QSqlDatabase Database::database()
  95. {
  96. return QSqlDatabase::database(QStringLiteral("qt_sql_default_connection"));
  97. }
  98. bool Database::commit(const OPL::Row &row)
  99. {
  100. if (!row.isValid())
  101. return false;
  102. if (exists(row))
  103. return update(row);
  104. else
  105. return insert(row);
  106. }
  107. bool Database::commit(const QJsonArray &json_arr, const OPL::DbTable table)
  108. {
  109. // create statement
  110. const QString table_name = OPL::GLOBALS->getDbTableName(table);
  111. QString statement = QLatin1String("INSERT INTO ") + table_name + QLatin1String(" (");
  112. QString placeholder = QStringLiteral(") VALUES (");
  113. for (const auto &column_name : DB->getTableColumns(table)) {
  114. statement += column_name + ',';
  115. placeholder.append(QLatin1Char(':') + column_name + QLatin1Char(','));
  116. }
  117. statement.chop(1);
  118. placeholder.chop(1);
  119. placeholder.append(')');
  120. statement.append(placeholder);
  121. // Create query and commit
  122. QSqlQuery q;
  123. q.prepare(QStringLiteral("BEGIN EXCLUSIVE TRANSACTION"));
  124. q.exec();
  125. for (const auto &entry : json_arr) {
  126. q.prepare(statement);
  127. auto object = entry.toObject();
  128. const auto keys = object.keys();
  129. for (const auto &key : keys){
  130. //use QMetaType for binding null value in QT >= 6
  131. #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
  132. object.value(key).isNull() ? q.bindValue(key, QVariant(QMetaType(QMetaType::Int))) :
  133. #else
  134. object.value(key).isNull() ? q.bindValue(key, QVariant(QVariant::String)) :
  135. #endif
  136. q.bindValue(QLatin1Char(':') + key, object.value(key).toVariant());
  137. }
  138. q.exec();
  139. }
  140. q.prepare(QStringLiteral("COMMIT"));
  141. if (q.exec())
  142. return true;
  143. else
  144. return false;
  145. }
  146. bool Database::remove(const OPL::Row &row)
  147. {
  148. if (!exists(row)) {
  149. LOG << "Error: Database entry not found.";
  150. return false;
  151. }
  152. const QString table_name = OPL::GLOBALS->getDbTableName(row.getTable());
  153. QString statement = QLatin1String("DELETE FROM ") + table_name
  154. + QLatin1String(" WHERE ROWID=?");
  155. QSqlQuery query;
  156. query.prepare(statement);
  157. query.addBindValue(row.getRowId());
  158. if (query.exec())
  159. {
  160. LOG << "Entry removed:";
  161. LOG << row;
  162. emit dataBaseUpdated(row.getTable());
  163. return true;
  164. } else {
  165. DEB << "Unable to delete.";
  166. DEB << "Query: " << statement;
  167. DEB << "Query Error: " << query.lastError().text();
  168. lastError = query.lastError();
  169. return false;
  170. }
  171. }
  172. bool Database::removeMany(OPL::DbTable table, const QList<int> &row_id_list)
  173. {
  174. const QString table_name = OPL::GLOBALS->getDbTableName(table);
  175. int errorCount = 0;
  176. QSqlQuery query;
  177. query.prepare(QStringLiteral("BEGIN EXCLUSIVE TRANSACTION"));
  178. query.exec();
  179. for (const auto row_id : row_id_list) {
  180. const QString statement = QLatin1String("DELETE FROM ") + table_name +
  181. QLatin1String(" WHERE ROWID=?");
  182. query.prepare(statement);
  183. query.addBindValue(row_id);
  184. if (!query.exec())
  185. errorCount++;
  186. }
  187. if (errorCount == 0) {
  188. query.prepare(QStringLiteral("COMMIT"));
  189. if(query.exec()) {
  190. emit dataBaseUpdated(table);
  191. LOG << "Transaction successfull.";
  192. return true;
  193. } else {
  194. LOG << "Transaction unsuccessful (Interrupted). Error count: "
  195. + QString::number(errorCount);
  196. DEB << query.lastError().text();
  197. lastError = query.lastError();
  198. return false;
  199. }
  200. } else {
  201. query.prepare(QStringLiteral("ROLLBACK"));
  202. query.exec();
  203. LOG << "Transaction unsuccessful (no changes have been made). Error count: "
  204. + QString::number(errorCount);
  205. return false;
  206. }
  207. }
  208. bool Database::exists(const OPL::Row &row)
  209. {
  210. if (row.getRowId() == 0)
  211. return false;
  212. //Check database for row id
  213. QString statement = QLatin1String("SELECT COUNT(*) FROM ") + OPL::GLOBALS->getDbTableName(row.getTable())
  214. + QLatin1String(" WHERE ROWID=?");
  215. QSqlQuery query;
  216. query.prepare(statement);
  217. query.addBindValue(row.getRowId());
  218. query.setForwardOnly(true);
  219. query.exec();
  220. //this returns either 1 or 0 since row ids are unique
  221. if (!query.isActive()) {
  222. lastError = query.lastError();
  223. DEB << "Query Error: " << query.lastError().text() << statement;
  224. return false;
  225. }
  226. query.next();
  227. int rowId = query.value(0).toInt();
  228. if (rowId) {
  229. return true;
  230. } else {
  231. LOG << "Database entry not found.";
  232. return false;
  233. }
  234. }
  235. bool Database::clear()
  236. {
  237. QSqlQuery q;
  238. for (const auto &table : USER_TABLES) {
  239. q.prepare(QLatin1String("DELETE FROM ") + OPL::GLOBALS->getDbTableName(table));
  240. if (!q.exec()) {
  241. DEB << "Error: " << q.lastError().text();
  242. lastError = q.lastError();
  243. return false;
  244. }
  245. }
  246. return true;
  247. }
  248. bool Database::update(const OPL::Row &updated_row)
  249. {
  250. QString statement = QLatin1String("UPDATE ") + OPL::GLOBALS->getDbTableName(updated_row.getTable()) + QLatin1String(" SET ");
  251. const auto& data = updated_row.getData();
  252. for (auto i = data.constBegin(); i != data.constEnd(); ++i) {
  253. statement.append(i.key() + "=?,");
  254. }
  255. statement.chop(1);
  256. statement.append(QLatin1String(" WHERE ROWID=?"));
  257. QSqlQuery query;
  258. query.prepare(statement);
  259. DEB << "Statement: " << statement;
  260. for (auto i = data.constBegin(); i != data.constEnd(); ++i) {
  261. //use QMetaType for binding null value in QT >= 6
  262. #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
  263. if (i.value() == QVariant(QString())) {
  264. query.addBindValue(QVariant(QMetaType(QMetaType::Int)));
  265. #else
  266. if (i.value() == QVariant(QString())) {
  267. query.addBindValue(QVariant(QVariant::String));
  268. #endif
  269. } else {
  270. query.addBindValue(i.value());
  271. }
  272. }
  273. query.addBindValue(updated_row.getRowId());
  274. DEB << "Bound values: " << query.boundValues();
  275. if (query.exec())
  276. {
  277. LOG << QString("Entry successfully committed. %1").arg(updated_row.getPosition());
  278. emit dataBaseUpdated(updated_row.getTable());
  279. return true;
  280. } else {
  281. DEB << "Unable to commit.";
  282. DEB << "Query: " << statement;
  283. DEB << "Query Error: " << query.lastError().text();
  284. lastError = query.lastError();
  285. return false;
  286. }
  287. }
  288. bool Database::insert(const OPL::Row &new_row)
  289. {
  290. QString statement = QLatin1String("INSERT INTO ") + OPL::GLOBALS->getDbTableName(new_row.getTable()) + QLatin1String(" (");
  291. const auto& data = new_row.getData();
  292. QHash<QString, QVariant>::const_iterator i;
  293. for (i = data.constBegin(); i != data.constEnd(); ++i) {
  294. statement.append(i.key() + QLatin1Char(','));
  295. }
  296. statement.chop(1);
  297. statement += QLatin1String(") VALUES (");
  298. for (int i=0; i < new_row.getData().size(); ++i) {
  299. statement += QLatin1String("?,");
  300. }
  301. statement.chop(1);
  302. statement += QLatin1Char(')');
  303. QSqlQuery query;
  304. query.prepare(statement);
  305. for (i = data.constBegin(); i != data.constEnd(); ++i) {
  306. //use QMetaType for binding null value in QT >= 6
  307. #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
  308. if (i.value() == QVariant(QString())) {
  309. query.addBindValue(QVariant(QMetaType(QMetaType::Int)));
  310. #else
  311. if (i.value() == QVariant(QString())) {
  312. query.addBindValue(QVariant(QVariant::String));
  313. #endif
  314. } else {
  315. query.addBindValue(i.value());
  316. }
  317. }
  318. //check result.
  319. if (query.exec())
  320. {
  321. LOG << QString("Entry successfully committed. %1").arg(new_row.getPosition());
  322. emit dataBaseUpdated(new_row.getTable());
  323. return true;
  324. } else {
  325. DEB << "Unable to commit.";
  326. DEB << "Query: " << statement;
  327. DEB << "Bound Values: " << query.boundValues();
  328. DEB << "Query Error: " << query.lastError().text();
  329. lastError = query.lastError();
  330. return false;
  331. }
  332. }
  333. OPL::Row Database::getRow(const OPL::DbTable table, const int row_id)
  334. {
  335. QString statement = QLatin1String("SELECT * FROM ") + OPL::GLOBALS->getDbTableName(table)
  336. + QLatin1String(" WHERE ROWID=?");
  337. QSqlQuery q;
  338. q.prepare(statement);
  339. q.addBindValue(row_id);
  340. q.setForwardOnly(true);
  341. if (!q.exec()) {
  342. DEB << "SQL error: " << q.lastError().text();
  343. DEB << "Statement: " << q.lastQuery();
  344. lastError = q.lastError();
  345. return {}; // return invalid Row
  346. }
  347. RowData_T entry_data;
  348. if(q.next()) {
  349. auto r = q.record(); // retreive record
  350. if (r.count() == 0) // row is empty
  351. return {};
  352. for (int i = 0; i < r.count(); i++){ // iterate through fields to get key:value map
  353. if(!r.value(i).isNull()) {
  354. entry_data.insert(r.fieldName(i), r.value(i));
  355. }
  356. }
  357. }
  358. return OPL::Row(table, row_id, entry_data);
  359. }
  360. RowData_T Database::getRowData(const OPL::DbTable table, const int row_id)
  361. {
  362. QString statement = QLatin1String("SELECT * FROM ") + OPL::GLOBALS->getDbTableName(table)
  363. + QLatin1String(" WHERE ROWID=?");
  364. QSqlQuery q;
  365. q.prepare(statement);
  366. q.addBindValue(row_id);
  367. q.setForwardOnly(true);
  368. if (!q.exec()) {
  369. DEB << "SQL error: " << q.lastError().text();
  370. DEB << "Statement: " << q.lastQuery();
  371. lastError = q.lastError();
  372. return {}; // return invalid Row
  373. }
  374. RowData_T entry_data;
  375. if(q.next()) {
  376. auto r = q.record(); // retreive record
  377. if (r.count() == 0) // row is empty
  378. return {};
  379. for (int i = 0; i < r.count(); i++){ // iterate through fields to get key:value map
  380. if(!r.value(i).isNull()) {
  381. entry_data.insert(r.fieldName(i), r.value(i));
  382. }
  383. }
  384. }
  385. return entry_data;
  386. }
  387. int Database::getLastEntry(OPL::DbTable table)
  388. {
  389. QString statement = QLatin1String("SELECT MAX(ROWID) FROM ") + OPL::GLOBALS->getDbTableName(table);
  390. auto query = QSqlQuery(statement);
  391. if (query.first()) {
  392. return query.value(0).toInt();
  393. } else {
  394. LOG << "No entry found. (Database empty?)" << query.lastError().text();
  395. return 0;
  396. }
  397. }
  398. const RowData_T Database::getTotals(bool includePreviousExperience)
  399. {
  400. QString statement = "SELECT"
  401. " SUM(tblk) AS tblk,"
  402. " SUM(tSPSE) AS tSPSE,"
  403. " SUM(tSPME) AS tSPME,"
  404. " SUM(tMP) AS tMP,"
  405. " SUM(tPIC) AS tPIC,"
  406. " SUM(tSIC) AS tSIC,"
  407. " SUM(tDUAL) AS tDUAL,"
  408. " SUM(tFI) AS tFI,"
  409. " SUM(tPICUS) AS tPICUS,"
  410. " SUM(tNIGHT) AS tNIGHT,"
  411. " SUM(tIFR) AS tIFR,"
  412. " SUM(tSIM) AS tSIM,"
  413. " SUM(toDay) AS toDay,"
  414. " SUM(toNight) AS toNight,"
  415. " SUM(ldgDay) AS ldgDay,"
  416. " SUM(ldgNight) AS ldgNight"
  417. " FROM flights";
  418. QSqlQuery query;
  419. query.prepare(statement);
  420. if (!query.exec()) {
  421. DEB << "SQL error: " << query.lastError().text();
  422. DEB << "Statement: " << query.lastQuery();
  423. lastError = query.lastError();
  424. return {}; // return invalid Row
  425. }
  426. RowData_T entry_data;
  427. if(query.next()) {
  428. auto r = query.record(); // retreive record
  429. if (r.count() == 0) // row is empty
  430. return {};
  431. for (int i = 0; i < r.count(); i++){ // iterate through fields to get key:value map
  432. if(!r.value(i).isNull()) {
  433. entry_data.insert(r.fieldName(i), r.value(i));
  434. }
  435. }
  436. }
  437. if(!includePreviousExperience) {
  438. return entry_data;
  439. }
  440. // name the return types for easy mapping to QLineEdit names
  441. statement = "SELECT"
  442. " SUM(tblk) AS tblk,"
  443. " SUM(tSPSE) AS tSPSE,"
  444. " SUM(tSPME) AS tSPME,"
  445. " SUM(tMP) AS tMP,"
  446. " SUM(tPIC) AS tPIC,"
  447. " SUM(tSIC) AS tSIC,"
  448. " SUM(tDUAL) AS tDUAL,"
  449. " SUM(tFI) AS tFI,"
  450. " SUM(tPICUS) AS tPICUS,"
  451. " SUM(tNIGHT) AS tNIGHT,"
  452. " SUM(tIFR) AS tIFR,"
  453. " SUM(tSIM) AS tSIM,"
  454. " SUM(toDay) AS toDay,"
  455. " SUM(toNight) AS toNight,"
  456. " SUM(ldgDay) AS ldgDay,"
  457. " SUM(ldgNight) AS ldgNight"
  458. " FROM previousExperience";
  459. query.prepare(statement);
  460. if (!query.exec()) {
  461. DEB << "SQL error: " << query.lastError().text();
  462. DEB << "Statement: " << query.lastQuery();
  463. lastError = query.lastError();
  464. return {}; // return invalid Row
  465. }
  466. RowData_T prev_exp_data;
  467. if(query.next()) {
  468. auto r = query.record(); // retreive record
  469. if (r.count() == 0) // row is empty
  470. return {};
  471. for (int i = 0; i < r.count(); i++){ // iterate through fields to get key:value map
  472. if(!r.value(i).isNull()) {
  473. prev_exp_data.insert(r.fieldName(i), r.value(i));
  474. }
  475. }
  476. }
  477. // add up the two query results
  478. for(auto it = prev_exp_data.begin(); it != prev_exp_data.end(); it++) {
  479. int prevXpValue = it.value().toInt();
  480. int entryValue = entry_data.value(it.key()).toInt();
  481. const QVariant sum = prevXpValue + entryValue;
  482. entry_data.insert(it.key(), sum);
  483. }
  484. return entry_data;
  485. }
  486. QList<int> Database::getForeignKeyConstraints(int foreign_row_id, OPL::DbTable table)
  487. {
  488. QString statement = QLatin1String("SELECT ROWID FROM flights WHERE ");
  489. switch (table) {
  490. case OPL::DbTable::Pilots:
  491. statement.append(QLatin1String("pic=?"));
  492. break;
  493. case OPL::DbTable::Tails:
  494. statement.append(QLatin1String("acft=?"));
  495. break;
  496. default:
  497. DEB << "Not a valid target for this function.";
  498. return QList<int>();
  499. break;
  500. }
  501. QSqlQuery query;
  502. query.prepare(statement);
  503. query.addBindValue(foreign_row_id);
  504. query.exec();
  505. if (!query.isActive()) {
  506. lastError = query.lastError();
  507. DEB << "Error";
  508. DEB << statement;
  509. DEB << query.lastError().text();
  510. return QList<int>();
  511. }
  512. QList<int> row_ids;
  513. while (query.next()) {
  514. row_ids.append(query.value(0).toInt());
  515. }
  516. return row_ids;
  517. }
  518. QVector<QVariant> Database::customQuery(QString statement, int return_values)
  519. {
  520. QSqlQuery query(statement);
  521. if(!query.exec()) {
  522. lastError = query.lastError();
  523. DEB << "Query Error: " << lastError.text();
  524. return {};
  525. }
  526. if (!query.first()) {
  527. LOG << "No result found. Check Query and Error.";
  528. DEB << "Error: " << query.lastError().text();
  529. DEB << "Statement: " << statement;
  530. return QVector<QVariant>();
  531. } else {
  532. query.first();
  533. query.previous();
  534. QVector<QVariant> result;
  535. while (query.next()) {
  536. for (int i = 0; i < return_values ; i++) {
  537. result.append(query.value(i));
  538. }
  539. }
  540. lastError = QString();
  541. return result;
  542. }
  543. }
  544. QVector<RowData_T> Database::getTable(OPL::DbTable table)
  545. {
  546. const QString query_str = QStringLiteral("SELECT * FROM ") + GLOBALS->getDbTableName(table);
  547. QSqlQuery q;
  548. q.prepare(query_str);
  549. q.setForwardOnly(true);
  550. if (!q.exec()) {
  551. LOG << "SQL error: " << q.lastError().text();
  552. LOG << "Statement: " << query_str;
  553. lastError = q.lastError();
  554. return {};
  555. }
  556. QVector<RowData_T> entry_data;
  557. while(q.next()) { // iterate through records
  558. auto r = q.record();
  559. //DEB << r;
  560. RowData_T row;
  561. for (int i = 0; i < r.count(); i++){
  562. if(!r.value(i).isNull()) {
  563. row.insert(r.fieldName(i), r.value(i));
  564. }
  565. }
  566. entry_data.append(row);
  567. }
  568. return entry_data;
  569. }
  570. bool Database::createBackup(const QString& dest_file)
  571. {
  572. LOG << "Backing up current database to: " << dest_file;
  573. Database::disconnect();
  574. QFile db_file(QDir::toNativeSeparators(databaseFile.absoluteFilePath()));
  575. if (!db_file.copy(QDir::toNativeSeparators(dest_file))) {
  576. LOG << "Unable to backup old database:" << db_file.errorString();
  577. return false;
  578. }
  579. LOG << "Backed up old database as:" << dest_file;
  580. Database::connect();
  581. emit connectionReset();
  582. return true;
  583. }
  584. bool Database::restoreBackup(const QString& backup_file)
  585. {
  586. Database::disconnect();
  587. LOG << "Restoring backup from file:" << backup_file;
  588. QString databaseFilePath = QDir::toNativeSeparators(databaseFile.absoluteFilePath());
  589. DEB << "DB File Path: " << databaseFilePath;
  590. QString backupFilePath = QDir::toNativeSeparators(backup_file);
  591. QFile dbFile(databaseFilePath);
  592. if(dbFile.exists())
  593. if(!dbFile.remove()) {
  594. LOG << dbFile.errorString() << "Unable to remove current db file";
  595. return false;
  596. }
  597. QFile backupFile(backupFilePath);
  598. if(!backupFile.copy(databaseFilePath)) {
  599. LOG << backupFile.errorString() << "Could not copy" << backupFile.fileName() << " to " << databaseFilePath;
  600. return false;
  601. }
  602. LOG << "Backup successfully restored!";
  603. Database::connect();
  604. emit connectionReset();
  605. return true;
  606. }
  607. bool Database::createSchema()
  608. {
  609. // Read Database layout from sql file
  610. QFile f(OPL::Assets::DATABASE_SCHEMA);
  611. f.open(QIODevice::ReadOnly);
  612. QByteArray filedata = f.readAll();
  613. // create individual queries for each table/view
  614. auto list = filedata.split(';');
  615. // make sure last empty line in sql file has not been parsed
  616. if(list.last() == QByteArray("\n") || list.last() == QByteArray("\r\n"))
  617. list.removeLast();
  618. // Create Tables
  619. QSqlQuery q;
  620. QVector<QSqlError> errors;
  621. for (const auto &query_string : list) {
  622. q.prepare(query_string);
  623. if (!q.exec()) {
  624. errors.append(q.lastError());
  625. LOG << "Unable to execute query: ";
  626. LOG << q.lastQuery();
  627. LOG << q.lastError();
  628. }
  629. }
  630. DB->updateLayout();
  631. if (errors.isEmpty()) {
  632. LOG << "Database succesfully created.";
  633. return true;
  634. } else {
  635. LOG << "Database creation has failed. The following error(s) have ocurred: ";
  636. for (const auto &error : std::as_const(errors)) {
  637. LOG << error.type() << error.text();
  638. }
  639. return false;
  640. }
  641. }
  642. bool Database::importTemplateData(bool use_local_ressources)
  643. {
  644. for (const auto& table : DB->getTemplateTables()) {
  645. const QString table_name = OPL::GLOBALS->getDbTableName(table);
  646. //clear table
  647. QSqlQuery q;
  648. q.prepare(QLatin1String("DELETE FROM ") + table_name);
  649. if (!q.exec()) {
  650. LOG << "Error clearing tables: " << q.lastError().text();
  651. return false;
  652. }
  653. //Prepare data
  654. QJsonArray data_to_commit;
  655. QString error_message("Error importing data ");
  656. if (use_local_ressources) {
  657. data_to_commit = JsonHelper::readFileToDoc(QLatin1String(":database/templates/")
  658. + table_name + QLatin1String(".json")).array();
  659. error_message.append(QLatin1String(" (ressource) "));
  660. } else {
  661. const QString file_path = OPL::Paths::filePath(OPL::Paths::Templates,
  662. table_name + QLatin1String(".json"));
  663. data_to_commit = JsonHelper::readFileToDoc(file_path).array();
  664. //data_to_commit = AJson::readFileToDoc(AStandardPaths::directory(
  665. // AStandardPaths::Templates).absoluteFilePath(
  666. // table_name + QLatin1String(".json"))).array();
  667. error_message.append(QLatin1String(" (downloaded) "));
  668. }
  669. // commit Data from Array
  670. if (!DB->commit(data_to_commit, table)) {
  671. LOG << error_message;
  672. return false;
  673. }
  674. } // for table_name
  675. return true;
  676. }
  677. bool Database::resetUserData()
  678. {
  679. QSqlQuery query;
  680. for (const auto& table : DB->getUserTables()) {
  681. query.prepare(QLatin1String("DELETE FROM ") + OPL::GLOBALS->getDbTableName(table));
  682. if (!query.exec()) {
  683. lastError = query.lastError();
  684. return false;
  685. }
  686. }
  687. return true;
  688. }
  689. } // namespace OPL