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-url>jdbc:sqlite:$USER_HOME$/.local/share/budget/budget.sqlite</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
<driver-properties>
<property name="foreign_keys" value="true" />
</driver-properties>
</data-source>
</component>
</project>

View File

@ -24,7 +24,7 @@ set(HEADERS
src/database.h
src/exceptions/helpRequested.h
src/exceptions/badValue.h
src/utilities.h)
src/utilities.h src/sqliteDb.h)
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;
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);
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) {
@ -106,3 +107,20 @@ double Database::cacheAccountValue(long long accountId, sqlite3 *db) {
return value;
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
*/
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
@ -58,6 +58,17 @@ public:
* @throws std::runtime_error If the database query fails
*/
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 "exceptions/helpRequested.h"
#include "exceptions/badValue.h"
#include "sqliteDb.h"
#include <pwd.h>
#include <unistd.h>
@ -30,12 +31,17 @@ void createRequiredFolders() {
int main(int argc, char *argv[]) {
sqlite3 *db;
SqliteDb dbRAII(db);
int rc;
rc = sqlite3_open(databaseFile.c_str(), &db);
if (rc != SQLITE_OK) {
if (rc != SQLITE_OK)
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);
try {
@ -54,6 +60,5 @@ int main(int argc, char *argv[]) {
return 1;
}
sqlite3_close_v2(db);
return 0;
}

View File

@ -26,6 +26,10 @@ void AccountOperation::commit() {
if (flags.value) {
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)) {

View File

@ -64,13 +64,13 @@ void MainOptHandler::accountOptHandler(std::string account) {
{"delete", no_argument, nullptr, 'd'},
{"force-delete", no_argument, nullptr, 'F'},
{"value", no_argument, nullptr, 'v'},
{"description", no_argument, nullptr, 'D'},
{"description", required_argument, nullptr, 'D'},
};
auto acctOperation = std::make_unique<AccountOperation>(db, account);
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)
break;
@ -238,7 +238,7 @@ void MainOptHandler::paymentOptHandler(std::string account) {
auto payOperation = std::make_unique<PaymentOperation>(db, account);
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)
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