diff --git a/CMakeLists.txt b/CMakeLists.txt index a666e9d..039712a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ set(SOURCES src/optHandlers/createOperation.cpp src/optHandlers/earnOperation.cpp src/optHandlers/PaymentOperation.cpp - ) + src/database.cpp) set(HEADERS src/optHandlers/mainOptHandler.h @@ -20,6 +20,11 @@ set(HEADERS src/optHandlers/createOperation.h src/optHandlers/earnOperation.h src/optHandlers/PaymentOperation.h - ) + src/database.h + src/exceptions/helpRequested.h + src/exceptions/badValue.h) -add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS}) \ No newline at end of file + +add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS}) + +target_link_libraries(${PROJECT_NAME} sqlite3) diff --git a/src/database.cpp b/src/database.cpp new file mode 100644 index 0000000..94037d5 --- /dev/null +++ b/src/database.cpp @@ -0,0 +1,30 @@ +// +// Created by quentin on 1/18/23. +// + +#include "database.h" +#include +#include + +bool Database::doesAccountExist(const std::string &account, 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 create account existing query"); + } + + sqlite3_bind_text(stmt, 1, account.c_str(), -1, SQLITE_TRANSIENT); + + rc = sqlite3_step(stmt); + sqlite3_finalize(stmt); + + if (rc == SQLITE_ROW) { + return true; + } else if (rc == SQLITE_DONE) { + return false; + } else { + throw std::runtime_error("Failed to step account existing statement."); + } + +} diff --git a/src/database.h b/src/database.h new file mode 100644 index 0000000..b264552 --- /dev/null +++ b/src/database.h @@ -0,0 +1,18 @@ +// +// Created by quentin on 1/18/23. +// + +#ifndef BUDGET_DATABASE_H +#define BUDGET_DATABASE_H + + +#include +#include + +class Database { +public: + static bool doesAccountExist(const std::string &account, sqlite3 *db); +}; + + +#endif //BUDGET_DATABASE_H diff --git a/src/exceptions/badValue.h b/src/exceptions/badValue.h new file mode 100644 index 0000000..5aef299 --- /dev/null +++ b/src/exceptions/badValue.h @@ -0,0 +1,17 @@ +// +// Created by quentin on 1/18/23. +// + +#ifndef BUDGET_BADVALUE_H +#define BUDGET_BADVALUE_H + +#include + +namespace Budget::Exceptions { + class BadValue : public std::runtime_error { + public: + explicit BadValue(const std::string &what_arg) : std::runtime_error(what_arg) {} + }; +} + +#endif //BUDGET_BADVALUE_H diff --git a/src/exceptions/helpRequested.h b/src/exceptions/helpRequested.h new file mode 100644 index 0000000..2466531 --- /dev/null +++ b/src/exceptions/helpRequested.h @@ -0,0 +1,18 @@ +// +// Created by quentin on 1/18/23. +// + +#ifndef BUDGET_HELPREQUESTED_H +#define BUDGET_HELPREQUESTED_H + +#include + +namespace Budget::Exceptions { + class HelpRequested : public std::runtime_error { + public: + explicit HelpRequested(const std::string &what_arg) : std::runtime_error(what_arg) {} + }; +} + + +#endif //BUDGET_HELPREQUESTED_H diff --git a/src/main.cpp b/src/main.cpp index f924e29..26a281d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,11 +3,15 @@ // #include "optHandlers/mainOptHandler.h" +#include "exceptions/helpRequested.h" +#include "exceptions/badValue.h" #include #include #include #include +#include +#include using namespace Budget; @@ -15,16 +19,41 @@ using namespace Budget; const std::string homeDirectory = getpwuid(getuid())->pw_dir; const std::string configD = homeDirectory + "/.config/budget/"; const std::string storageD = homeDirectory + "/.local/share/budget/"; +const std::string databaseFile = homeDirectory + "/.local/share/budget/budget.sqlite"; + void createRequiredFolders() { std::filesystem::create_directory(configD); std::filesystem::create_directories(storageD); - std::filesystem::create_directories(storageD + "accounts"); std::filesystem::create_directories(storageD + "receipts"); } int main(int argc, char *argv[]) { + sqlite3 *db; + int rc; + rc = sqlite3_open(databaseFile.c_str(), &db); + + if (rc != SQLITE_OK) { + throw std::runtime_error("Error opening database connection."); + } + std::vector args(argv, argv + argc); - OptHandlers::MainOptHandler moh(args); + try { + OptHandlers::MainOptHandler moh(args, db); + std::queue> *opts = &moh.operations; + + while (!opts->empty()) { + opts->front()->commit(); + opts->pop(); + } + + } catch (const Budget::Exceptions::HelpRequested &e) { + return 0; + } catch (const Budget::Exceptions::BadValue &e) { + std::cout << e.what() << std::endl; + return 1; + } + + return 0; } diff --git a/src/optHandlers/PaymentOperation.cpp b/src/optHandlers/PaymentOperation.cpp index c2eabc9..83fa4c8 100644 --- a/src/optHandlers/PaymentOperation.cpp +++ b/src/optHandlers/PaymentOperation.cpp @@ -10,6 +10,6 @@ void PaymentOperation::commit() { //TODO This function will be called when the action needs to be done } -PaymentOperation::PaymentOperation(std::string account) : account(std::move(account)) { +PaymentOperation::PaymentOperation(sqlite3 *db, std::string account) : Operation(db), account(std::move(account)) { } \ No newline at end of file diff --git a/src/optHandlers/PaymentOperation.h b/src/optHandlers/PaymentOperation.h index b2b1216..38802ab 100644 --- a/src/optHandlers/PaymentOperation.h +++ b/src/optHandlers/PaymentOperation.h @@ -15,7 +15,7 @@ namespace Budget::OptHandlers { public: void commit() override; - explicit PaymentOperation(std::string account); + explicit PaymentOperation(sqlite3 *db, std::string account); struct Flags : public Operation::Flags { long double value; diff --git a/src/optHandlers/accountOperation.cpp b/src/optHandlers/accountOperation.cpp index bd169fb..a2f7db1 100644 --- a/src/optHandlers/accountOperation.cpp +++ b/src/optHandlers/accountOperation.cpp @@ -3,15 +3,16 @@ // #include "accountOperation.h" +#include "../database.h" #include using namespace Budget::OptHandlers; void AccountOperation::commit() { - //TODO This function will be called when the action needs to be done + Database::doesAccountExist(account, db); } -AccountOperation::AccountOperation(std::string account) : account(std::move(account)) { +AccountOperation::AccountOperation(sqlite3 *db, std::string account) : Operation(db), account(std::move(account)) { } diff --git a/src/optHandlers/accountOperation.h b/src/optHandlers/accountOperation.h index 8c134e7..2399347 100644 --- a/src/optHandlers/accountOperation.h +++ b/src/optHandlers/accountOperation.h @@ -14,7 +14,7 @@ namespace Budget::OptHandlers { public: void commit() override; - explicit AccountOperation(std::string account); + explicit AccountOperation(sqlite3 *db, std::string account); struct Flags : public Operation::Flags { bool del = false; diff --git a/src/optHandlers/createOperation.cpp b/src/optHandlers/createOperation.cpp index 549f2de..2f194e0 100644 --- a/src/optHandlers/createOperation.cpp +++ b/src/optHandlers/createOperation.cpp @@ -10,6 +10,6 @@ void CreateOperation::commit() { //TODO This function will be called when the action needs to be done } -CreateOperation::CreateOperation(std::string account) : account(std::move(account)) { +CreateOperation::CreateOperation(sqlite3 *db, std::string account) : Operation(db), account(std::move(account)) { } diff --git a/src/optHandlers/createOperation.h b/src/optHandlers/createOperation.h index 6ac7aa5..cee218e 100644 --- a/src/optHandlers/createOperation.h +++ b/src/optHandlers/createOperation.h @@ -13,7 +13,7 @@ namespace Budget::OptHandlers { public: void commit() override; - explicit CreateOperation(std::string account); + explicit CreateOperation(sqlite3 *db, std::string account); struct Flags : public Operation::Flags { std::string description; diff --git a/src/optHandlers/earnOperation.cpp b/src/optHandlers/earnOperation.cpp index 2276f52..91ec28d 100644 --- a/src/optHandlers/earnOperation.cpp +++ b/src/optHandlers/earnOperation.cpp @@ -10,6 +10,6 @@ void EarnOperation::commit() { //TODO This function will be called when the action needs to be done } -EarnOperation::EarnOperation(std::string account) : account(std::move(account)) { +EarnOperation::EarnOperation(sqlite3 *db, std::string account) : Operation(db), account(std::move(account)) { } \ No newline at end of file diff --git a/src/optHandlers/earnOperation.h b/src/optHandlers/earnOperation.h index b5df130..c44640b 100644 --- a/src/optHandlers/earnOperation.h +++ b/src/optHandlers/earnOperation.h @@ -14,7 +14,7 @@ namespace Budget::OptHandlers { public: void commit() override; - explicit EarnOperation(std::string account); + explicit EarnOperation(sqlite3 *db, std::string account); struct Flags : public Operation::Flags { long double value; diff --git a/src/optHandlers/mainOptHandler.cpp b/src/optHandlers/mainOptHandler.cpp index f5cbc7b..fa25e47 100644 --- a/src/optHandlers/mainOptHandler.cpp +++ b/src/optHandlers/mainOptHandler.cpp @@ -6,13 +6,15 @@ #include "createOperation.h" #include "earnOperation.h" #include "PaymentOperation.h" +#include "../exceptions/helpRequested.h" +#include "../exceptions/badValue.h" #include #include #include using namespace Budget::OptHandlers; -MainOptHandler::MainOptHandler(const std::vector &_argv) : argv(_argv) { +MainOptHandler::MainOptHandler(const std::vector &_argv, sqlite3 *db) : argv(_argv), db(db) { struct option actionLongOpts[] = { {"help", no_argument, nullptr, 'h'}, {"account", required_argument, nullptr, 'a'}, @@ -29,7 +31,7 @@ MainOptHandler::MainOptHandler(const std::vector &_argv) : argv(_argv) { switch (opt) { case 'h': help(); - exit(0); + throw Budget::Exceptions::HelpRequested("Help requested at main"); case 'a': accountOptHandler(optarg); break; @@ -44,7 +46,7 @@ MainOptHandler::MainOptHandler(const std::vector &_argv) : argv(_argv) { break; case '?': help(); - exit(0); + throw Budget::Exceptions::HelpRequested("Help requested at main, unknown argument."); default: break; } @@ -65,7 +67,7 @@ void MainOptHandler::accountOptHandler(std::string account) { {"description", no_argument, nullptr, 'D'}, }; - auto acctOperation = std::make_unique(account); + auto acctOperation = std::make_unique(db, account); while (true) { int opt = getopt_long(argv.size(), argv.data(), "ha:c:e:p:dFvD", accountLongOpts, nullptr); @@ -75,7 +77,7 @@ void MainOptHandler::accountOptHandler(std::string account) { switch (opt) { case 'h': help(); - exit(0); + throw Budget::Exceptions::HelpRequested("Help requested at account"); case 'a': case 'c': case 'e': @@ -98,7 +100,7 @@ void MainOptHandler::accountOptHandler(std::string account) { break; case '?': help(); - exit(0); + throw Budget::Exceptions::HelpRequested("Help requested at account, unknown argument."); default: break; } @@ -117,7 +119,7 @@ void MainOptHandler::createOptHandler(std::string account) { {"description", required_argument, nullptr, 'd'}, }; - auto createOperation = std::make_unique(account); + auto createOperation = std::make_unique(db, account); while (true) { int opt = getopt_long(argv.size(), argv.data(), "ha:c:e:p:d:", createLongOpts, nullptr); @@ -127,7 +129,7 @@ void MainOptHandler::createOptHandler(std::string account) { switch (opt) { case 'h': help(); - exit(0); + throw Budget::Exceptions::HelpRequested("Help requested at create"); case 'a': case 'c': case 'e': @@ -140,7 +142,7 @@ void MainOptHandler::createOptHandler(std::string account) { break; case '?': help(); - exit(0); + throw Budget::Exceptions::HelpRequested("Help requested at create, unknown argument."); default: break; } @@ -162,7 +164,7 @@ void MainOptHandler::earnOptHandler(std::string account) { {"date", required_argument, nullptr, 'D'}, }; - auto earnOperation = std::make_unique(account); + auto earnOperation = std::make_unique(db, account); while (true) { int opt = getopt_long(argv.size(), argv.data(), "ha:c:e:p:v:d:r:D:", earnLongOpts, nullptr); @@ -172,7 +174,7 @@ void MainOptHandler::earnOptHandler(std::string account) { switch (opt) { case 'h': help(); - exit(0); + throw Budget::Exceptions::HelpRequested("Help requested at earn"); case 'a': case 'c': case 'e': @@ -186,7 +188,7 @@ void MainOptHandler::earnOptHandler(std::string account) { } catch (std::exception const &e) { help(); std::cout << "Bad value value" << std::endl; - exit(1); + throw Budget::Exceptions::BadValue("Bad value, cannot parse to decimal."); } break; } @@ -203,7 +205,7 @@ void MainOptHandler::earnOptHandler(std::string account) { if (strptime(optarg, "%m/%d/%YT%H:%M:%S", &t) == nullptr) { help(); std::cout << "Bad time value" << std::endl; - exit(1); + throw Budget::Exceptions::BadValue("Bad Value, cannot parse to int."); } ts = mktime(&t); earnOperation->flags.date = (long long) ts; @@ -211,7 +213,7 @@ void MainOptHandler::earnOptHandler(std::string account) { } case '?': help(); - exit(0); + throw Budget::Exceptions::HelpRequested("Help requested at earn, unknown argument."); default: break; } @@ -233,7 +235,7 @@ void MainOptHandler::paymentOptHandler(std::string account) { {"date", required_argument, nullptr, 'D'}, }; - auto payOperation = std::make_unique(account); + auto payOperation = std::make_unique(db, account); while (true) { int opt = getopt_long(argv.size(), argv.data(), "ha:c:e:p:v:d:r:D", paymentLongOpts, nullptr); @@ -243,7 +245,7 @@ void MainOptHandler::paymentOptHandler(std::string account) { switch (opt) { case 'h': help(); - exit(0); + throw Budget::Exceptions::HelpRequested("Help requested at payment"); case 'a': case 'c': case 'e': @@ -257,7 +259,7 @@ void MainOptHandler::paymentOptHandler(std::string account) { } catch (std::exception const &e) { help(); std::cout << "Bad value value" << std::endl; - exit(1); + throw Budget::Exceptions::BadValue("Bad value, cannot parse to decimal."); } break; } @@ -274,7 +276,7 @@ void MainOptHandler::paymentOptHandler(std::string account) { if (strptime(optarg, "%m/%d/%YT%H:%M:%S", &t) == nullptr) { help(); std::cout << "Bad time value" << std::endl; - exit(1); + throw Budget::Exceptions::BadValue("Bad value, time invalid."); } ts = mktime(&t); payOperation->flags.date = (long long) ts; @@ -282,7 +284,7 @@ void MainOptHandler::paymentOptHandler(std::string account) { } case '?': help(); - exit(0); + throw Budget::Exceptions::HelpRequested("Help requested at payment"); default: break; } diff --git a/src/optHandlers/mainOptHandler.h b/src/optHandlers/mainOptHandler.h index dcdcf11..0b7984b 100644 --- a/src/optHandlers/mainOptHandler.h +++ b/src/optHandlers/mainOptHandler.h @@ -14,7 +14,7 @@ namespace Budget::OptHandlers { class MainOptHandler { public: - explicit MainOptHandler(const std::vector &argv); + explicit MainOptHandler(const std::vector &argv, sqlite3 *pSqlite3); void help(); @@ -30,6 +30,8 @@ namespace Budget::OptHandlers { void paymentOptHandler(std::string account); const std::vector &argv; + + sqlite3 *db; }; } diff --git a/src/optHandlers/operation.cpp b/src/optHandlers/operation.cpp index 8f080c6..63f234b 100644 --- a/src/optHandlers/operation.cpp +++ b/src/optHandlers/operation.cpp @@ -3,3 +3,5 @@ // #include "operation.h" + +Budget::OptHandlers::Operation::Operation(sqlite3 *db) : db(db) {} diff --git a/src/optHandlers/operation.h b/src/optHandlers/operation.h index 7f9aa36..1d8158b 100644 --- a/src/optHandlers/operation.h +++ b/src/optHandlers/operation.h @@ -5,13 +5,20 @@ #ifndef BUDGET_OPERATION_H #define BUDGET_OPERATION_H +#include + namespace Budget::OptHandlers { class Operation { public: + explicit Operation(sqlite3 *db); + virtual void commit() = 0; struct Flags { }; + + protected: + sqlite3 *db{}; }; }