budget/src/database.cpp

179 lines
6.2 KiB
C++
Raw Normal View History

//
// Created by quentin on 1/18/23.
//
#include "database.h"
#include <sqlite3.h>
#include <stdexcept>
Budget::Models::Account Database::getAccount(const std::string &accountName, sqlite3 *db) {
sqlite3_stmt *stmt;
int rc = sqlite3_prepare_v2(db, "SELECT * FROM account WHERE name = ?", -1, &stmt, nullptr);
if (rc != SQLITE_OK)
throw std::runtime_error("Failed to prepare accountName exist query.");
sqlite3_bind_text(stmt, 1, accountName.c_str(), -1, SQLITE_TRANSIENT);
rc = sqlite3_step(stmt);
if (rc == SQLITE_ROW) {
Budget::Models::Account account(
sqlite3_column_int64(stmt, 0),
(char*)(sqlite3_column_text(stmt, 1)),
(sqlite3_column_type(stmt,2) == SQLITE_NULL) ? "" : (char*)(sqlite3_column_text(stmt, 2)),
(sqlite3_column_type(stmt, 3) == SQLITE_NULL) ? nullptr : new long double(sqlite3_column_double(stmt, 4))
);
sqlite3_finalize(stmt);
return account;
} else if (rc == SQLITE_DONE) {
sqlite3_finalize(stmt);
throw std::runtime_error("Account " + accountName + " does not exist");
} else {
sqlite3_finalize(stmt);
throw std::runtime_error("Failed to step accountName existing statement.");
}
}
void Database::deleteAccount(Budget::Models::Account *account, sqlite3 *db) {
sqlite3_stmt *stmt;
int rc = sqlite3_prepare_v2(db, "DELETE FROM account WHERE name = ?", -1, &stmt, nullptr);
if (rc != SQLITE_OK)
throw std::runtime_error("Failed to delete accountName " + account->name);
sqlite3_bind_text(stmt, 1, account->name.c_str(), -1, SQLITE_TRANSIENT);
rc = sqlite3_step(stmt);
sqlite3_finalize(stmt);
2023-01-27 19:06:19 -06:00
if (rc != SQLITE_DONE)
throw std::runtime_error("Failed to delete accountName " + account->name);
}
2023-01-22 17:05:29 -06:00
void Database::cacheAccountValue(Budget::Models::Account *account, sqlite3 *db) {
2023-01-22 17:05:29 -06:00
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 " + account->name);
2023-01-22 17:05:29 -06:00
sqlite3_bind_int64(stmt, 1, account->id);
sqlite3_bind_int64(stmt, 2, account->id);
2023-01-22 17:05:29 -06:00
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 " + account->name);
2023-01-22 17:05:29 -06:00
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 " + account->name);
sqlite3_bind_double(stmt, 1, value);
sqlite3_bind_int64(stmt, 2, account->id);
rc = sqlite3_step(stmt);
if (rc == SQLITE_DONE) {
account->cachedValue = new long double(value);
return;
}
throw std::runtime_error("Failed to set cashedValue for " + std::to_string(account->id));
}
void Database::accountDescription(Budget::Models::Account *account, sqlite3 *db) {
2023-01-26 18:54:38 -06:00
sqlite3_stmt *stmt;
int rc = sqlite3_prepare_v2(db, "UPDATE account SET description = ? WHERE name = ?", -1, &stmt, nullptr);
if (rc != SQLITE_OK)
throw std::runtime_error("Failed preparing accountDescription statement");
sqlite3_bind_text(stmt, 1, account->description.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 2, account->name.c_str(), -1, SQLITE_TRANSIENT);
2023-01-26 18:54:38 -06:00
rc = sqlite3_step(stmt);
sqlite3_finalize(stmt);
if (rc != SQLITE_DONE)
throw std::runtime_error("Failed to set description on " + account->name);
2023-01-26 18:54:38 -06:00
}
long long int Database::createAccount(Budget::OptHandlers::CreateOperation::Flags *flags, std::string &account, sqlite3 *db) {
sqlite3_stmt *stmt;
int rc = sqlite3_prepare_v2(db, "INSERT INTO account (name, description) VALUES (?, ?)", -1, &stmt, nullptr);
if (rc != SQLITE_OK)
throw std::runtime_error("Failed preparing createAccount statement");
sqlite3_bind_text(stmt, 1, account.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 2, (flags->description.empty() ? nullptr : flags->description.c_str()), -1, SQLITE_TRANSIENT);
rc = sqlite3_step(stmt);
if (rc != SQLITE_DONE) {
throw std::runtime_error("Failed to create accountName " + account);
}
sqlite3_finalize(stmt);
return sqlite3_last_insert_rowid(db);
}
2023-01-27 19:47:50 -06:00
long long int Database::earn(Budget::Models::Account *account, Budget::OptHandlers::EarnOperation::Flags *flags, sqlite3 *db) {
2023-01-27 19:47:50 -06:00
sqlite3_stmt *stmt;
int rc = sqlite3_prepare_v2(db, "INSERT INTO earning (value, description, receipt, accountId, date) VALUES "
"(?, ?, ?, ?, ?);",
-1, &stmt, nullptr);
2023-01-27 19:47:50 -06:00
if (rc != SQLITE_OK)
throw std::runtime_error("Failed preparing earn statement");
sqlite3_bind_double(stmt, 1, flags->value);
sqlite3_bind_text(stmt, 2, (flags->description.empty() ? nullptr : flags->description.c_str()), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 3, (flags->receipt.empty() ? nullptr : flags->receipt.c_str()), -1, SQLITE_TRANSIENT);
sqlite3_bind_int64(stmt, 4, account->id);
sqlite3_bind_int64(stmt, 5, flags->date);
2023-01-27 19:47:50 -06:00
rc = sqlite3_step(stmt);
sqlite3_finalize(stmt);
if (rc != SQLITE_DONE)
throw std::runtime_error("Failed to create earning");
cacheAccountValue(account, db);
return sqlite3_last_insert_rowid(db);
2023-01-27 19:47:50 -06:00
}
2023-01-27 20:47:33 -06:00
long long int Database::pay(Budget::Models::Account *account, Budget::OptHandlers::PaymentOperation::Flags *flags, sqlite3 *db) {
2023-01-27 20:47:33 -06:00
sqlite3_stmt *stmt;
int rc = sqlite3_prepare_v2(db, "INSERT INTO payment (value, description, receipt, accountId, date) VALUES "
"(?, ?, ?, ?, ?);",
-1, &stmt, nullptr);
2023-01-27 20:47:33 -06:00
if (rc != SQLITE_OK)
throw std::runtime_error("Failed preparing pay statement");
sqlite3_bind_double(stmt, 1, flags->value);
sqlite3_bind_text(stmt, 2, (flags->description.empty() ? nullptr : flags->description.c_str()), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 3, (flags->receipt.empty() ? nullptr : flags->receipt.c_str()), -1, SQLITE_TRANSIENT);
sqlite3_bind_int64(stmt, 4, account->id);
sqlite3_bind_int64(stmt, 5, flags->date);
2023-01-27 20:47:33 -06:00
rc = sqlite3_step(stmt);
sqlite3_finalize(stmt);
if (rc != SQLITE_DONE)
throw std::runtime_error("Failed to create payment");
cacheAccountValue(account, db);
return sqlite3_last_insert_rowid(db);
2023-01-27 20:47:33 -06:00
}