Compare commits

...

2 Commits

8 changed files with 76 additions and 11 deletions

3
.idea/dataSources.xml generated
View File

@ -7,6 +7,9 @@
<jdbc-driver>org.sqlite.JDBC</jdbc-driver> <jdbc-driver>org.sqlite.JDBC</jdbc-driver>
<jdbc-url>jdbc:sqlite:$USER_HOME$/.local/share/budget/budget.sqlite</jdbc-url> <jdbc-url>jdbc:sqlite:$USER_HOME$/.local/share/budget/budget.sqlite</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir> <working-dir>$ProjectFileDir$</working-dir>
<driver-properties>
<property name="foreign_keys" value="true" />
</driver-properties>
</data-source> </data-source>
</component> </component>
</project> </project>

View File

@ -24,7 +24,7 @@ set(HEADERS
src/database.h src/database.h
src/exceptions/helpRequested.h src/exceptions/helpRequested.h
src/exceptions/badValue.h src/exceptions/badValue.h
src/utilities.h) src/utilities.h src/sqliteDb.h)
add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS}) add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS})

View File

@ -28,7 +28,7 @@ bool Database::doesAccountExist(const std::string &account, sqlite3 *db) {
} }
bool Database::deleteAccount(const std::string &account, sqlite3 *db) { void Database::deleteAccount(const std::string &account, sqlite3 *db) {
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
int rc = sqlite3_prepare_v2(db, "DELETE FROM account WHERE name = ?", -1, &stmt, nullptr); int rc = sqlite3_prepare_v2(db, "DELETE FROM account WHERE name = ?", -1, &stmt, nullptr);
@ -39,8 +39,9 @@ bool Database::deleteAccount(const std::string &account, sqlite3 *db) {
rc = sqlite3_step(stmt); rc = sqlite3_step(stmt);
sqlite3_finalize(stmt); sqlite3_finalize(stmt);
return (rc == SQLITE_DONE); if (rc != SQLITE_DONE)
throw std::runtime_error("Failed to delete account " + account);
} }
double Database::getValue(const std::string &account, sqlite3 *db) { double Database::getValue(const std::string &account, sqlite3 *db) {
@ -106,3 +107,20 @@ double Database::cacheAccountValue(long long accountId, sqlite3 *db) {
return value; return value;
throw std::runtime_error("Failed to set cashedValue for " + std::to_string(accountId)); throw std::runtime_error("Failed to set cashedValue for " + std::to_string(accountId));
} }
void Database::accountDescription(const std::string& account, const std::string& description, sqlite3 *db) {
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, description.c_str(), -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 2, account.c_str(), -1, SQLITE_TRANSIENT);
rc = sqlite3_step(stmt);
sqlite3_finalize(stmt);
if (rc != SQLITE_DONE)
throw std::runtime_error("Failed to set description on " + account);
}

View File

@ -33,7 +33,7 @@ public:
* *
* @throws std::runtime_error If the database query fails * @throws std::runtime_error If the database query fails
*/ */
static bool deleteAccount(const std::string &account, sqlite3 *db); static void deleteAccount(const std::string &account, sqlite3 *db);
/** /**
* @brief Retrieves the cached value of an account from the database * @brief Retrieves the cached value of an account from the database
@ -58,6 +58,17 @@ public:
* @throws std::runtime_error If the database query fails * @throws std::runtime_error If the database query fails
*/ */
static double cacheAccountValue(long long accountId, sqlite3 *db); static double cacheAccountValue(long long accountId, sqlite3 *db);
/**
* @brief Sets a new description for an account
*
* @param account The account name
* @param description The new description
* @param db The database connection to use
*
* @throws std::runtime_error If the statement fails to prepare or the step fails to execute
*/
static void accountDescription(const std::string& account, const std::string& description, sqlite3 *db);
}; };

View File

@ -5,6 +5,7 @@
#include "optHandlers/mainOptHandler.h" #include "optHandlers/mainOptHandler.h"
#include "exceptions/helpRequested.h" #include "exceptions/helpRequested.h"
#include "exceptions/badValue.h" #include "exceptions/badValue.h"
#include "sqliteDb.h"
#include <pwd.h> #include <pwd.h>
#include <unistd.h> #include <unistd.h>
@ -30,12 +31,17 @@ void createRequiredFolders() {
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
sqlite3 *db; sqlite3 *db;
SqliteDb dbRAII(db);
int rc; int rc;
rc = sqlite3_open(databaseFile.c_str(), &db); rc = sqlite3_open(databaseFile.c_str(), &db);
if (rc != SQLITE_OK) { if (rc != SQLITE_OK)
throw std::runtime_error("Error opening database connection."); throw std::runtime_error("Error opening database connection.");
}
rc = sqlite3_exec(db, "PRAGMA foreign_keys = 1;", nullptr, nullptr, nullptr);
if (rc != SQLITE_OK)
throw std::runtime_error("Error enabling foreign_keys. Database might be malformed.");
std::vector<char *> args(argv, argv + argc); std::vector<char *> args(argv, argv + argc);
try { try {
@ -54,6 +60,5 @@ int main(int argc, char *argv[]) {
return 1; return 1;
} }
sqlite3_close_v2(db);
return 0; return 0;
} }

View File

@ -26,6 +26,10 @@ void AccountOperation::commit() {
if (flags.value) { if (flags.value) {
std::cout << Database::getValue(account, db) << std::endl; std::cout << Database::getValue(account, db) << std::endl;
} }
if (!flags.description.empty()) {
Database::accountDescription(account, flags.description, db);
}
} }
AccountOperation::AccountOperation(sqlite3 *db, std::string account) : Operation(db), account(std::move(account)) { AccountOperation::AccountOperation(sqlite3 *db, std::string account) : Operation(db), account(std::move(account)) {

View File

@ -64,13 +64,13 @@ void MainOptHandler::accountOptHandler(std::string account) {
{"delete", no_argument, nullptr, 'd'}, {"delete", no_argument, nullptr, 'd'},
{"force-delete", no_argument, nullptr, 'F'}, {"force-delete", no_argument, nullptr, 'F'},
{"value", no_argument, nullptr, 'v'}, {"value", no_argument, nullptr, 'v'},
{"description", no_argument, nullptr, 'D'}, {"description", required_argument, nullptr, 'D'},
}; };
auto acctOperation = std::make_unique<AccountOperation>(db, account); auto acctOperation = std::make_unique<AccountOperation>(db, account);
while (true) { while (true) {
int opt = getopt_long(argv.size(), argv.data(), "ha:c:e:p:dFvD", accountLongOpts, nullptr); int opt = getopt_long(argv.size(), argv.data(), "ha:c:e:p:dFvD:", accountLongOpts, nullptr);
if (opt == -1) if (opt == -1)
break; break;
@ -238,7 +238,7 @@ void MainOptHandler::paymentOptHandler(std::string account) {
auto payOperation = std::make_unique<PaymentOperation>(db, account); auto payOperation = std::make_unique<PaymentOperation>(db, account);
while (true) { while (true) {
int opt = getopt_long(argv.size(), argv.data(), "ha:c:e:p:v:d:r:D", paymentLongOpts, nullptr); int opt = getopt_long(argv.size(), argv.data(), "ha:c:e:p:v:d:r:D:", paymentLongOpts, nullptr);
if (opt == -1) if (opt == -1)
break; break;

24
src/sqliteDb.h Normal file
View File

@ -0,0 +1,24 @@
//
// Created by quentin on 1/22/23.
//
#ifndef BUDGET_SQLITEDB_H
#define BUDGET_SQLITEDB_H
#include <sqlite3.h>
class SqliteDb {
public:
explicit SqliteDb(sqlite3* db) : m_db(db) {}
~SqliteDb() {
sqlite3_close(m_db);
}
explicit operator sqlite3*() {
return m_db;
}
private:
sqlite3* m_db;
};
#endif //BUDGET_SQLITEDB_H