diff --git a/src/database.cpp b/src/database.cpp index aa98bb2..7f0cca4 100644 --- a/src/database.cpp +++ b/src/database.cpp @@ -11,7 +11,7 @@ bool Database::doesAccountExist(const std::string &account, sqlite3 *db) { int rc = sqlite3_prepare_v2(db, "SELECT * FROM account WHERE name = ?", -1, &stmt, nullptr); if (rc != SQLITE_OK) - throw std::runtime_error("Failed to create account existing query"); + throw std::runtime_error("Failed to prepare account exist query."); sqlite3_bind_text(stmt, 1, account.c_str(), -1, SQLITE_TRANSIENT); @@ -42,3 +42,67 @@ bool Database::deleteAccount(const std::string &account, sqlite3 *db) { return (rc == SQLITE_DONE); } + +double Database::getValue(const std::string &account, sqlite3 *db) { + sqlite3_stmt *stmt; + int rc = sqlite3_prepare_v2(db, "SELECT id, cachedValue FROM account WHERE name = ?", -1, &stmt, nullptr); + + if (rc != SQLITE_OK) + throw std::runtime_error("Failed preparing cashedValue " + account); + + sqlite3_bind_text(stmt, 1, account.c_str(), -1, SQLITE_TRANSIENT); + + rc = sqlite3_step(stmt); + + if (rc == SQLITE_ROW) { + double value; + if (sqlite3_column_type(stmt, 1) == SQLITE_NULL) { + value = cacheAccountValue(sqlite3_column_int64(stmt, 0), db); + sqlite3_finalize(stmt); + return value; + } + value = sqlite3_column_double(stmt, 1); + sqlite3_finalize(stmt); + return value; + } else if (rc == SQLITE_DONE) + throw std::runtime_error("Account doesnt exist? Shouldn't be possible in this call."); + else + throw std::runtime_error("Failed to step getValue statement."); +} + +double Database::cacheAccountValue(long long accountId, sqlite3 *db) { + sqlite3_stmt *stmt; + int rc = sqlite3_prepare_v2(db, "SELECT SUM(value) FROM (" + "SELECT value * -1 as value FROM payment WHERE accountId = ? " + "UNION ALL " + "SELECT value FROM earning WHERE accountId = ?);", -1, &stmt, nullptr); + + if (rc != SQLITE_OK) + throw std::runtime_error("Failed preparing get cashedValue " + std::to_string(accountId)); + + sqlite3_bind_int64(stmt, 1, accountId); + sqlite3_bind_int64(stmt, 2, accountId); + + rc = sqlite3_step(stmt); + + double value; + if (rc == SQLITE_ROW) + value = sqlite3_column_double(stmt, 0); + else if (rc == SQLITE_DONE) + value = 0; + else + throw std::runtime_error("Failed get cashedValue " + std::to_string(accountId)); + + sqlite3_reset(stmt); + rc = sqlite3_prepare_v2(db, "UPDATE account SET cachedValue = ? WHERE id = ?", -1, &stmt, nullptr); + if (rc != SQLITE_OK) + throw std::runtime_error("Failed preparing set cashedValue " + std::to_string(accountId)); + + sqlite3_bind_double(stmt, 1, value); + sqlite3_bind_int64(stmt, 2, accountId); + + rc = sqlite3_step(stmt); + if (rc == SQLITE_DONE) + return value; + throw std::runtime_error("Failed to set cashedValue for " + std::to_string(accountId)); +} diff --git a/src/database.h b/src/database.h index aeb0de5..218b26b 100644 --- a/src/database.h +++ b/src/database.h @@ -14,6 +14,10 @@ public: static bool doesAccountExist(const std::string &account, sqlite3 *db); static bool deleteAccount(const std::string &account, sqlite3 *db); + + static double getValue(const std::string &account, sqlite3 *db); + + static double cacheAccountValue(long long accountId, sqlite3 *db); }; diff --git a/src/optHandlers/accountOperation.cpp b/src/optHandlers/accountOperation.cpp index c4efa4c..3b4f248 100644 --- a/src/optHandlers/accountOperation.cpp +++ b/src/optHandlers/accountOperation.cpp @@ -8,6 +8,7 @@ #include "../utilities.h" #include +#include using namespace Budget::OptHandlers; @@ -21,6 +22,10 @@ void AccountOperation::commit() { return; } } + + if (flags.value) { + std::cout << Database::getValue(account, db) << std::endl; + } } AccountOperation::AccountOperation(sqlite3 *db, std::string account) : Operation(db), account(std::move(account)) {