diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml
index 74c6532..786e53d 100644
--- a/.idea/dataSources.xml
+++ b/.idea/dataSources.xml
@@ -11,5 +11,15 @@
+
+ sqlite.xerial
+ true
+ org.sqlite.JDBC
+ jdbc:sqlite:$USER_HOME$/.local/share/budget/budgetDebug.sqlite
+ $ProjectFileDir$
+
+
+
+
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9310807..d99a3a0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,7 +10,7 @@ set(SOURCES
src/optHandlers/accountOperation.cpp
src/optHandlers/createOperation.cpp
src/optHandlers/earnOperation.cpp
- src/optHandlers/PaymentOperation.cpp
+ src/optHandlers/paymentOperation.cpp
src/database.cpp
src/utilities.cpp)
@@ -20,13 +20,17 @@ set(HEADERS
src/optHandlers/accountOperation.h
src/optHandlers/createOperation.h
src/optHandlers/earnOperation.h
- src/optHandlers/PaymentOperation.h
+ src/optHandlers/paymentOperation.h
src/database.h
src/exceptions/helpRequested.h
src/exceptions/badValue.h
src/utilities.h
src/sqliteDb.h
- src/main.h)
+ src/main.h
+ src/models/account.h
+ src/models/transaction.h
+ src/models/earning.h
+ src/models/payment.h)
add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS})
diff --git a/README.md b/README.md
index ce123a8..a6735f4 100644
--- a/README.md
+++ b/README.md
@@ -43,6 +43,6 @@ budget -cAcct -eAcct -v10.00 -r"./receipt.pdf" -pAcct -v5.50 -r"./payment.pdf"
````
Does the following in order:
-Creates an account named Acct with no description.
+Creates an accountName named Acct with no description.
Earns 10.00 to it with a receipt.
Pays 5.50 to it with a receipt.
diff --git a/src/database.cpp b/src/database.cpp
index 8619adf..cb7695a 100644
--- a/src/database.cpp
+++ b/src/database.cpp
@@ -6,72 +6,52 @@
#include
#include
-bool Database::doesAccountExist(const std::string &account, sqlite3 *db) {
+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 account exist query.");
+ throw std::runtime_error("Failed to prepare accountName exist query.");
- sqlite3_bind_text(stmt, 1, account.c_str(), -1, SQLITE_TRANSIENT);
+ sqlite3_bind_text(stmt, 1, accountName.c_str(), -1, SQLITE_TRANSIENT);
rc = sqlite3_step(stmt);
- sqlite3_finalize(stmt);
if (rc == SQLITE_ROW) {
- return true;
+ 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) {
- return false;
+ sqlite3_finalize(stmt);
+ throw std::runtime_error("Account " + accountName + " does not exist");
} else {
- throw std::runtime_error("Failed to step account existing statement.");
+ sqlite3_finalize(stmt);
+ throw std::runtime_error("Failed to step accountName existing statement.");
}
-
}
-void Database::deleteAccount(const std::string &account, sqlite3 *db) {
+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 account " + account);
+ throw std::runtime_error("Failed to delete accountName " + account->name);
- sqlite3_bind_text(stmt, 1, account.c_str(), -1, SQLITE_TRANSIENT);
+ sqlite3_bind_text(stmt, 1, account->name.c_str(), -1, SQLITE_TRANSIENT);
rc = sqlite3_step(stmt);
sqlite3_finalize(stmt);
if (rc != SQLITE_DONE)
- throw std::runtime_error("Failed to delete account " + account);
+ throw std::runtime_error("Failed to delete accountName " + account->name);
}
-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) {
+void Database::cacheAccountValue(Budget::Models::Account *account, sqlite3 *db) {
sqlite3_stmt *stmt;
int rc = sqlite3_prepare_v2(db, "SELECT SUM(value) FROM ("
"SELECT value * -1 as value FROM payment WHERE accountId = ? "
@@ -79,10 +59,10 @@ double Database::cacheAccountValue(long long accountId, sqlite3 *db) {
"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));
+ throw std::runtime_error("Failed preparing get cashedValue " + account->name);
- sqlite3_bind_int64(stmt, 1, accountId);
- sqlite3_bind_int64(stmt, 2, accountId);
+ sqlite3_bind_int64(stmt, 1, account->id);
+ sqlite3_bind_int64(stmt, 2, account->id);
rc = sqlite3_step(stmt);
@@ -92,79 +72,42 @@ double Database::cacheAccountValue(long long accountId, sqlite3 *db) {
else if (rc == SQLITE_DONE)
value = 0;
else
- throw std::runtime_error("Failed get cashedValue " + std::to_string(accountId));
+ throw std::runtime_error("Failed get cashedValue " + account->name);
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));
+ throw std::runtime_error("Failed preparing set cashedValue " + account->name);
sqlite3_bind_double(stmt, 1, value);
- sqlite3_bind_int64(stmt, 2, accountId);
+ sqlite3_bind_int64(stmt, 2, account->id);
rc = sqlite3_step(stmt);
- if (rc == SQLITE_DONE)
- return value;
- throw std::runtime_error("Failed to set cashedValue for " + std::to_string(accountId));
+ 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));
}
-double Database::cacheAccountValue(const std::string &account, sqlite3 *db) {
- sqlite3_stmt *stmt;
- int rc = sqlite3_prepare_v2(db, "SELECT SUM(value) FROM ("
- "SELECT value * -1 as value FROM payment WHERE accountId = "
- "(SELECT id FROM account where name = ?) "
- "UNION ALL "
- "SELECT value FROM earning WHERE accountId = "
- "(SELECT id FROM account where name = ?));", -1, &stmt, nullptr);
-
- if (rc != SQLITE_OK)
- throw std::runtime_error("Failed preparing get cashedValue " + account);
-
- sqlite3_bind_text(stmt, 1, account.c_str(), -1, SQLITE_TRANSIENT);
- sqlite3_bind_text(stmt, 2, account.c_str(), -1, SQLITE_TRANSIENT);
-
- 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);
-
- sqlite3_reset(stmt);
- rc = sqlite3_prepare_v2(db, "UPDATE account SET cachedValue = ? WHERE name = ?", -1, &stmt, nullptr);
- if (rc != SQLITE_OK)
- throw std::runtime_error("Failed preparing set cashedValue " + account);
-
- sqlite3_bind_double(stmt, 1, value);
- sqlite3_bind_text(stmt, 2, account.c_str(), -1, SQLITE_TRANSIENT);
-
- rc = sqlite3_step(stmt);
- if (rc == SQLITE_DONE)
- return value;
- throw std::runtime_error("Failed to set cashedValue for " + account);
-}
-
-void Database::accountDescription(const std::string &account, const std::string &description, sqlite3 *db) {
+void Database::accountDescription(Budget::Models::Account *account, 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);
+ sqlite3_bind_text(stmt, 1, account->description.c_str(), -1, SQLITE_TRANSIENT);
+ sqlite3_bind_text(stmt, 2, account->name.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);
+ throw std::runtime_error("Failed to set description on " + account->name);
}
-void Database::createAccount(const std::string &account, const std::string &description, sqlite3 *db) {
+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);
@@ -172,46 +115,33 @@ void Database::createAccount(const std::string &account, const std::string &desc
throw std::runtime_error("Failed preparing createAccount statement");
sqlite3_bind_text(stmt, 1, account.c_str(), -1, SQLITE_TRANSIENT);
- sqlite3_bind_text(stmt, 2, description.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);
- if (rc != SQLITE_DONE)
- throw std::runtime_error("Failed to create account " + account);
+ return sqlite3_last_insert_rowid(db);
}
-void Database::createAccount(const std::string &account, sqlite3 *db) {
- sqlite3_stmt *stmt;
- int rc = sqlite3_prepare_v2(db, "INSERT INTO account (name) 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);
-
- rc = sqlite3_step(stmt);
- sqlite3_finalize(stmt);
-
- if (rc != SQLITE_DONE)
- throw std::runtime_error("Failed to create account " + account);
-}
-
-long long int Database::earn(const std::string &account, long double &value, std::string &description, std::string &receipt,
- long long date, sqlite3 *db) {
+long long int Database::earn(Budget::Models::Account *account, Budget::OptHandlers::EarnOperation::Flags *flags, sqlite3 *db) {
sqlite3_stmt *stmt;
int rc = sqlite3_prepare_v2(db, "INSERT INTO earning (value, description, receipt, accountId, date) VALUES "
- "(?, ?, ?, (SELECT id FROM account WHERE name = ?), ?);",
+ "(?, ?, ?, ?, ?);",
-1, &stmt, nullptr);
if (rc != SQLITE_OK)
throw std::runtime_error("Failed preparing earn statement");
- sqlite3_bind_double(stmt, 1, value);
- sqlite3_bind_text(stmt, 2, (description.empty() ? nullptr : description.c_str()), -1, SQLITE_TRANSIENT);
- sqlite3_bind_text(stmt, 3, (receipt.empty() ? nullptr : receipt.c_str()), -1, SQLITE_TRANSIENT);
- sqlite3_bind_text(stmt, 4, (account.empty() ? nullptr : account.c_str()), -1, SQLITE_TRANSIENT);
- sqlite3_bind_int64(stmt, 5, date);
+ 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);
rc = sqlite3_step(stmt);
sqlite3_finalize(stmt);
@@ -223,21 +153,20 @@ long long int Database::earn(const std::string &account, long double &value, std
return sqlite3_last_insert_rowid(db);
}
-long long int Database::pay(const std::string &account, long double &value, std::string &description, std::string &receipt,
- long long date, sqlite3 *db) {
+long long int Database::pay(Budget::Models::Account *account, Budget::OptHandlers::PaymentOperation::Flags *flags, sqlite3 *db) {
sqlite3_stmt *stmt;
int rc = sqlite3_prepare_v2(db, "INSERT INTO payment (value, description, receipt, accountId, date) VALUES "
- "(?, ?, ?, (SELECT id FROM account WHERE name = ?), ?);",
+ "(?, ?, ?, ?, ?);",
-1, &stmt, nullptr);
if (rc != SQLITE_OK)
throw std::runtime_error("Failed preparing pay statement");
- sqlite3_bind_double(stmt, 1, value);
- sqlite3_bind_text(stmt, 2, (description.empty() ? nullptr : description.c_str()), -1, SQLITE_TRANSIENT);
- sqlite3_bind_text(stmt, 3, (receipt.empty() ? nullptr : receipt.c_str()), -1, SQLITE_TRANSIENT);
- sqlite3_bind_text(stmt, 4, (account.empty() ? nullptr : account.c_str()), -1, SQLITE_TRANSIENT);
- sqlite3_bind_int64(stmt, 5, date);
+ 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);
rc = sqlite3_step(stmt);
sqlite3_finalize(stmt);
diff --git a/src/database.h b/src/database.h
index 51ad163..55cdd6c 100644
--- a/src/database.h
+++ b/src/database.h
@@ -5,6 +5,10 @@
#ifndef BUDGET_DATABASE_H
#define BUDGET_DATABASE_H
+#include "models/account.h"
+#include "optHandlers/createOperation.h"
+#include "optHandlers/earnOperation.h"
+#include "optHandlers/paymentOperation.h"
#include
#include
@@ -12,101 +16,67 @@
class Database {
public:
/**
- * @brief Checks if an account exists in the database
+ * @brief Checks if an accountName exists in the database
*
- * @param account The name of the account to check for
+ * @param accountName The name of the accountName to check for
* @param db The database connection to use
*
- * @return True if the account exists, false otherwise
+ * @return True if the accountName exists, false otherwise
*
* @throws std::runtime_error If the database query fails
*/
- static bool doesAccountExist(const std::string &account, sqlite3 *db);
+ static Budget::Models::Account getAccount(const std::string &accountName, sqlite3 *db);
/**
- * @brief Deletes an account from the database
+ * @brief Deletes an accountName from the database
*
- * @param account The name of the account to delete
+ * @param account The name of the accountName to delete
* @param db The database connection to use
*
- * @return True if the account was successfully deleted, false otherwise
+ * @return True if the accountName was successfully deleted, false otherwise
*
* @throws std::runtime_error If the database query fails
*/
- static void deleteAccount(const std::string &account, sqlite3 *db);
+ static void deleteAccount(Budget::Models::Account *account, sqlite3 *db);
/**
- * @brief Retrieves the cached value of an account from the database
+ * @brief Caches the value of an accountName by calculating the sum of all payments and earnings
*
- * @param account The name of the account to retrieve the value of
+ * @param accountId The ID of the accountName to cache the value of
* @param db The database connection to use
*
- * @return The cached value of the account
- *
- * @throws std::runtime_error If the database query fails or the account doesn't exist
- */
- static double getValue(const std::string &account, sqlite3 *db);
-
- /**
- * @brief Caches the value of an account by calculating the sum of all payments and earnings
- *
- * @param accountId The ID of the account to cache the value of
- * @param db The database connection to use
- *
- * @return The cached value of the account
+ * @return The cached value of the accountName
*
* @throws std::runtime_error If the database query fails
*/
- static double cacheAccountValue(long long accountId, sqlite3 *db);
+ static void cacheAccountValue(Budget::Models::Account *account, sqlite3 *db);
/**
- * @brief Caches the value of an account by calculating the sum of all payments and earnings
+ * @brief Sets a new description for an accountName
*
- * @param account The name of the account to cache the value of
- * @param db The database connection to use
- *
- * @return The cached value of the account
- *
- * @throws std::runtime_error If the database query fails
- */
- static double cacheAccountValue(const std::string &account, sqlite3 *db);
-
- /**
- * @brief Sets a new description for an account
- *
- * @param account The account name
+ * @param account The accountName 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);
+ static void accountDescription(Budget::Models::Account *account, sqlite3 *db);
/**
- * @brief Creates a new account in the database with the given name and description
+ * @brief Creates a new accountName in the database with the given name and description
*
- * @param account The name of the account to create
- * @param description The description of the account to create
+ * @param account The name of the accountName to create
+ * @param description The description of the accountName to create
* @param db The sqlite3 database connection to use
*
- * @throws std::runtime_error If the account could not be created in the database
+ * @throws std::runtime_error If the accountName could not be created in the database
*/
- static void createAccount(const std::string &account, const std::string &description, sqlite3 *db);
-
- /**
- * @brief Creates a new account in the database with the given name
- *
- * @param account The name of the account to create
- * @param db The sqlite3 database connection to use
- *
- * @throws std::runtime_error If the account could not be created in the database
- */
- static void createAccount(const std::string &account, sqlite3 *db);
+ static long long int createAccount(Budget::OptHandlers::CreateOperation::Flags *flags, std::string &account, sqlite3 *db);
/**
* @brief The function records an earning in the database
*
- * @param account The name of the account to record the earning in
+ * @param account The name of the accountName to record the earning in
* @param value The value of the earning
* @param description A description of the earning, can be an empty string
* @param receipt A receipt of the earning, can be an empty string
@@ -116,18 +86,17 @@ public:
* @throws std::runtime_error If the earning could not be created in the database
*
* This function records an earning in the database by inserting a new row in the 'earning' table with the provided information.
- * The accountId is retrieved from the 'account' table using the provided account name.
+ * The accountId is retrieved from the 'accountName' table using the provided accountName name.
* If the query fails to prepare or execute, the function throws a runtime_error.
*/
static long long int
- earn(const std::string &account, long double &value, std::string &description, std::string &receipt,
- long long int date,
+ earn(Budget::Models::Account *account, Budget::OptHandlers::EarnOperation::Flags *flags,
sqlite3 *db);
/**
* @brief The function records an payment in the database
*
- * @param account The name of the account to record the payment in
+ * @param account The name of the accountName to record the payment in
* @param value The value of the payment
* @param description A description of the payment, can be an empty string
* @param receipt A receipt of the payment, can be an empty string
@@ -137,13 +106,11 @@ public:
* @throws std::runtime_error If the payment could not be created in the database
*
* This function records an payment in the database by inserting a new row in the 'payment' table with the provided information.
- * The accountId is retrieved from the 'account' table using the provided account name.
+ * The accountId is retrieved from the 'accountName' table using the provided accountName name.
* If the query fails to prepare or execute, the function throws a runtime_error.
*/
static long long int
- pay(const std::string &account, long double &value, std::string &description, std::string &receipt,
- long long int date,
- sqlite3 *db);
+ pay(Budget::Models::Account *account, Budget::OptHandlers::PaymentOperation::Flags *flags, sqlite3 *db);
};
diff --git a/src/main.cpp b/src/main.cpp
index 0ddf811..be4321e 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -16,11 +16,11 @@
using namespace Budget;
-const char* createTables = "CREATE TABLE IF NOT EXISTS account (id INTEGER CONSTRAINT account_pk PRIMARY KEY AUTOINCREMENT, name TEXT, description TEXT, cachedValue DOUBLE);"
- "CREATE UNIQUE INDEX IF NOT EXISTS account_name_uindex ON account (name);"
- "CREATE TABLE IF NOT EXISTS earning (id INTEGER CONSTRAINT earning_pk PRIMARY KEY AUTOINCREMENT, value DOUBLE NOT NULL, description TEXT, receipt TEXT, accountId INT NOT NULL REFERENCES account ON UPDATE CASCADE ON DELETE CASCADE, date INTEGER NOT NULL);"
+const char* createTables = "CREATE TABLE IF NOT EXISTS accountName (id INTEGER CONSTRAINT account_pk PRIMARY KEY AUTOINCREMENT, name TEXT, description TEXT, cachedValue DOUBLE);"
+ "CREATE UNIQUE INDEX IF NOT EXISTS account_name_uindex ON accountName (name);"
+ "CREATE TABLE IF NOT EXISTS earning (id INTEGER CONSTRAINT earning_pk PRIMARY KEY AUTOINCREMENT, value DOUBLE NOT NULL, description TEXT, receipt TEXT, accountId INT NOT NULL REFERENCES accountName ON UPDATE CASCADE ON DELETE CASCADE, date INTEGER NOT NULL);"
"CREATE INDEX IF NOT EXISTS earning_date_index ON earning (date DESC);"
- "CREATE TABLE IF NOT EXISTS payment (id INTEGER CONSTRAINT payment_pk PRIMARY KEY AUTOINCREMENT, value DOUBLE NOT NULL, description TEXT, receipt TEXT, accountId INT NOT NULL REFERENCES account ON UPDATE CASCADE ON DELETE CASCADE, date INTEGER NOT NULL);"
+ "CREATE TABLE IF NOT EXISTS payment (id INTEGER CONSTRAINT payment_pk PRIMARY KEY AUTOINCREMENT, value DOUBLE NOT NULL, description TEXT, receipt TEXT, accountId INT NOT NULL REFERENCES accountName ON UPDATE CASCADE ON DELETE CASCADE, date INTEGER NOT NULL);"
"CREATE INDEX IF NOT EXISTS payment_date_index ON payment (date DESC);";
void createRequiredFolders() {
diff --git a/src/models/account.h b/src/models/account.h
new file mode 100644
index 0000000..295fecc
--- /dev/null
+++ b/src/models/account.h
@@ -0,0 +1,27 @@
+//
+// Created by quentin on 2/2/23.
+//
+
+#ifndef BUDGET_ACCOUNT_H
+#define BUDGET_ACCOUNT_H
+
+#include
+#include
+namespace Budget::Models {
+ class Account {
+ public:
+ Account(long long int id, std::string name, std::string description, long double* cachedValue)
+ : id(id), name(std::move(name)), description(std::move(description)), cachedValue(new long double(3.3)) {}
+
+// ~Account() {
+// delete cachedValue;
+// }
+ public:
+ long long id;
+ std::string name;
+ std::string description;
+ long double* cachedValue;
+ };
+}
+
+#endif //BUDGET_ACCOUNT_H
diff --git a/src/models/earning.h b/src/models/earning.h
new file mode 100644
index 0000000..90ed231
--- /dev/null
+++ b/src/models/earning.h
@@ -0,0 +1,14 @@
+//
+// Created by quentin on 2/2/23.
+//
+
+#ifndef BUDGET_EARNING_H
+#define BUDGET_EARNING_H
+
+#include "transaction.h"
+
+namespace Budget::Models {
+ class Earning : Transaction {};
+}
+
+#endif //BUDGET_EARNING_H
diff --git a/src/models/payment.h b/src/models/payment.h
new file mode 100644
index 0000000..ce4914d
--- /dev/null
+++ b/src/models/payment.h
@@ -0,0 +1,14 @@
+//
+// Created by quentin on 2/2/23.
+//
+
+#ifndef BUDGET_EARNING_H
+#define BUDGET_EARNING_H
+
+#include "transaction.h"
+
+namespace Budget::Models {
+ class Payment : Transaction {};
+}
+
+#endif //BUDGET_EARNING_H
diff --git a/src/models/transaction.h b/src/models/transaction.h
new file mode 100644
index 0000000..23bad71
--- /dev/null
+++ b/src/models/transaction.h
@@ -0,0 +1,22 @@
+//
+// Created by quentin on 2/2/23.
+//
+
+#ifndef BUDGET_TRANSACTION_H
+#define BUDGET_TRANSACTION_H
+
+#include
+
+namespace Budget::Models {
+ class Transaction {
+ public:
+ long long int id;
+ long double value;
+ std::string description;
+ std::string receipt;
+ long long int accountId;
+ long long int date;
+ };
+}
+
+#endif //BUDGET_TRANSACTION_H
diff --git a/src/optHandlers/PaymentOperation.cpp b/src/optHandlers/PaymentOperation.cpp
deleted file mode 100644
index 9bd9213..0000000
--- a/src/optHandlers/PaymentOperation.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-//
-// Created by quentin on 1/17/23.
-//
-
-#include
-#include "PaymentOperation.h"
-#include "../database.h"
-#include "../exceptions/badValue.h"
-#include "../main.h"
-
-using namespace Budget::OptHandlers;
-
-void PaymentOperation::commit() {
- if (!Database::doesAccountExist(account, db))
- throw Budget::Exceptions::BadValue("Account " + account + " doesn't exist");
-
- long long id = Database::pay(account, flags.value, flags.description, flags.receipt, flags.date, db);
-
- if (!flags.receipt.empty()) {
- std::string extension;
- size_t pos = flags.receipt.find_last_of('.');
- if (pos != std::string::npos) {
- extension = flags.receipt.substr(pos);
- }
-
- std::ifstream source(flags.receipt, std::ios::binary);
- std::ofstream dest(storageD + "receipts/payment/" + std::to_string(id) + extension, std::ios::binary);
- dest << source.rdbuf();
- source.close();
- dest.close();
- }
-}
-
-PaymentOperation::PaymentOperation(sqlite3 *db, std::string account) : Operation(db), account(std::move(account)) {}
\ No newline at end of file
diff --git a/src/optHandlers/accountOperation.cpp b/src/optHandlers/accountOperation.cpp
index 1855db3..57aeed2 100644
--- a/src/optHandlers/accountOperation.cpp
+++ b/src/optHandlers/accountOperation.cpp
@@ -13,23 +13,24 @@
using namespace Budget::OptHandlers;
void AccountOperation::commit() {
- if (!Database::doesAccountExist(account, db))
- throw Budget::Exceptions::BadValue("Account " + account + " doesn't exist");
+ Budget::Models::Account account = Database::getAccount(accountName, db);
if (flags.del) {
- if (flags.forceDel || Utilities::confirm("Are you sure you'd like to delete " + account)) {
- Database::deleteAccount(account, db);
+ if (flags.forceDel || Utilities::confirm("Are you sure you'd like to delete " + accountName)) {
+ Database::deleteAccount(&account, db);
return;
}
}
if (flags.value) {
- std::cout << Database::getValue(account, db) << std::endl;
+ if (account.cachedValue == nullptr)
+ Database::cacheAccountValue(&account, db);
+ std::cout << *account.cachedValue << std::endl;
}
if (!flags.description.empty()) {
- Database::accountDescription(account, flags.description, db);
+ Database::accountDescription(&account, db);
}
}
-AccountOperation::AccountOperation(sqlite3 *db, std::string account) : Operation(db), account(std::move(account)) {}
+AccountOperation::AccountOperation(sqlite3 *db, std::string account) : Operation(db), accountName(std::move(account)) {}
diff --git a/src/optHandlers/accountOperation.h b/src/optHandlers/accountOperation.h
index 2399347..333fb36 100644
--- a/src/optHandlers/accountOperation.h
+++ b/src/optHandlers/accountOperation.h
@@ -25,7 +25,7 @@ namespace Budget::OptHandlers {
Flags flags;
private:
- std::string account;
+ std::string accountName;
};
}
diff --git a/src/optHandlers/createOperation.cpp b/src/optHandlers/createOperation.cpp
index 8055f73..1151145 100644
--- a/src/optHandlers/createOperation.cpp
+++ b/src/optHandlers/createOperation.cpp
@@ -9,14 +9,7 @@
using namespace Budget::OptHandlers;
void CreateOperation::commit() {
- if (Database::doesAccountExist(account, db)) {
- throw Budget::Exceptions::BadValue("Account already exists, cant create " + account);
- }
- if (flags.description.empty()) {
- Database::createAccount(account, db);
- return;
- }
- Database::createAccount(account, flags.description, db);
+ long long int id = Database::createAccount(&flags, accountName, db);
}
-CreateOperation::CreateOperation(sqlite3 *db, std::string account) : Operation(db), account(std::move(account)) {}
+CreateOperation::CreateOperation(sqlite3 *db, std::string account) : Operation(db), accountName(std::move(account)) {}
diff --git a/src/optHandlers/createOperation.h b/src/optHandlers/createOperation.h
index cee218e..c1d183c 100644
--- a/src/optHandlers/createOperation.h
+++ b/src/optHandlers/createOperation.h
@@ -21,7 +21,7 @@ namespace Budget::OptHandlers {
Flags flags;
private:
- std::string account;
+ std::string accountName;
};
}
diff --git a/src/optHandlers/earnOperation.cpp b/src/optHandlers/earnOperation.cpp
index ef62e51..4ba0ea6 100644
--- a/src/optHandlers/earnOperation.cpp
+++ b/src/optHandlers/earnOperation.cpp
@@ -11,24 +11,28 @@
using namespace Budget::OptHandlers;
void EarnOperation::commit() {
- if (!Database::doesAccountExist(account, db))
- throw Budget::Exceptions::BadValue("Account " + account + " doesn't exist");
-
- long long id = Database::earn(account, flags.value, flags.description, flags.receipt, flags.date, db);
+ Models::Account account = Database::getAccount(accountName, db);
if (!flags.receipt.empty()) {
- std::string extension;
- size_t pos = flags.receipt.find_last_of('.');
- if (pos != std::string::npos) {
- extension = flags.receipt.substr(pos);
- }
-
std::ifstream source(flags.receipt, std::ios::binary);
- std::ofstream dest(storageD + "receipts/receipt/" + std::to_string(id) + extension, std::ios::binary);
- dest << source.rdbuf();
- source.close();
- dest.close();
+ if (source.good()) {
+ std::string extension;
+ size_t pos = flags.receipt.find_last_of('.');
+ if (pos != std::string::npos) {
+ extension = flags.receipt.substr(pos);
+ }
+
+ std::ofstream dest(storageD + "receipts/receipt/" + std::to_string(account.id) + extension, std::ios::binary);
+ dest << source.rdbuf();
+ source.close();
+ dest.close();
+ }
+ else {
+ throw Exceptions::BadValue("File " + flags.receipt + " does not exist");
+ }
}
+
+ Database::earn(&account, &flags, db);
}
-EarnOperation::EarnOperation(sqlite3 *db, std::string account) : Operation(db), account(std::move(account)) {}
\ No newline at end of file
+EarnOperation::EarnOperation(sqlite3 *db, std::string account) : Operation(db), accountName(std::move(account)) {}
\ No newline at end of file
diff --git a/src/optHandlers/earnOperation.h b/src/optHandlers/earnOperation.h
index c44640b..052566d 100644
--- a/src/optHandlers/earnOperation.h
+++ b/src/optHandlers/earnOperation.h
@@ -26,7 +26,7 @@ namespace Budget::OptHandlers {
Flags flags;
private:
- std::string account;
+ std::string accountName;
};
}
diff --git a/src/optHandlers/mainOptHandler.cpp b/src/optHandlers/mainOptHandler.cpp
index 3aa14f5..65b6693 100644
--- a/src/optHandlers/mainOptHandler.cpp
+++ b/src/optHandlers/mainOptHandler.cpp
@@ -5,7 +5,7 @@
#include "accountOperation.h"
#include "createOperation.h"
#include "earnOperation.h"
-#include "PaymentOperation.h"
+#include "paymentOperation.h"
#include "../exceptions/helpRequested.h"
#include "../exceptions/badValue.h"
#include
@@ -17,7 +17,7 @@ using namespace Budget::OptHandlers;
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'},
+ {"accountName", required_argument, nullptr, 'a'},
{"create", required_argument, nullptr, 'c'},
{"earn", required_argument, nullptr, 'e'},
{"payment", required_argument, nullptr, 'p'}
@@ -56,7 +56,7 @@ MainOptHandler::MainOptHandler(const std::vector &_argv, sqlite3 *db) :
void MainOptHandler::accountOptHandler(std::string account) {
struct option accountLongOpts[] = {
{"help", no_argument, nullptr, 'h'},
- {"account", required_argument, nullptr, 'a'},
+ {"accountName", required_argument, nullptr, 'a'},
{"create", required_argument, nullptr, 'c'},
{"earn", required_argument, nullptr, 'e'},
{"payment", required_argument, nullptr, 'p'},
@@ -77,7 +77,7 @@ void MainOptHandler::accountOptHandler(std::string account) {
switch (opt) {
case 'h':
help();
- throw Budget::Exceptions::HelpRequested("Help requested at account");
+ throw Budget::Exceptions::HelpRequested("Help requested at accountName");
case 'a':
case 'c':
case 'e':
@@ -100,7 +100,7 @@ void MainOptHandler::accountOptHandler(std::string account) {
break;
case '?':
help();
- throw Budget::Exceptions::HelpRequested("Help requested at account, unknown argument.");
+ throw Budget::Exceptions::HelpRequested("Help requested at accountName, unknown argument.");
default:
break;
}
@@ -111,7 +111,7 @@ void MainOptHandler::accountOptHandler(std::string account) {
void MainOptHandler::createOptHandler(std::string account) {
struct option createLongOpts[] = {
{"help", no_argument, nullptr, 'h'},
- {"account", required_argument, nullptr, 'a'},
+ {"accountName", required_argument, nullptr, 'a'},
{"create", required_argument, nullptr, 'c'},
{"earn", required_argument, nullptr, 'e'},
{"payment", required_argument, nullptr, 'p'},
@@ -153,7 +153,7 @@ void MainOptHandler::createOptHandler(std::string account) {
void MainOptHandler::earnOptHandler(std::string account) {
struct option earnLongOpts[] = {
{"help", no_argument, nullptr, 'h'},
- {"account", required_argument, nullptr, 'a'},
+ {"accountName", required_argument, nullptr, 'a'},
{"create", required_argument, nullptr, 'c'},
{"earn", required_argument, nullptr, 'e'},
{"payment", required_argument, nullptr, 'p'},
@@ -224,7 +224,7 @@ void MainOptHandler::earnOptHandler(std::string account) {
void MainOptHandler::paymentOptHandler(std::string account) {
struct option paymentLongOpts[] = {
{"help", no_argument, nullptr, 'h'},
- {"account", required_argument, nullptr, 'a'},
+ {"accountName", required_argument, nullptr, 'a'},
{"create", required_argument, nullptr, 'c'},
{"earn", required_argument, nullptr, 'e'},
{"payment", required_argument, nullptr, 'p'},
@@ -298,17 +298,17 @@ void MainOptHandler::help() {
" budget [options] ...\n"
"Actions:\n"
" -h --help Prints this.\n"
- " -a --account<=STRING> Management tools for an account.\n"
- " -c --create<=STRING> Creates a new account with NAME.\n"
- " -e --earn<=STRING> Add an earning to an account.\n"
- " -p --payment<=STRING> Add a payment to an account.\n"
+ " -a --accountName<=STRING> Management tools for an accountName.\n"
+ " -c --create<=STRING> Creates a new accountName with NAME.\n"
+ " -e --earn<=STRING> Add an earning to an accountName.\n"
+ " -p --payment<=STRING> Add a payment to an accountName.\n"
"Account Options: [-dvD]\n"
- " -d --delete Deletes specified account.\n"
- " --force-delete Deletes the specified account without confirmation.\n"
- " -v --value Gets the current value of the account.\n"
- " -D --description<=STRING> Changes the description of the account.\n"
+ " -d --delete Deletes specified accountName.\n"
+ " --force-delete Deletes the specified accountName without confirmation.\n"
+ " -v --value Gets the current value of the accountName.\n"
+ " -D --description<=STRING> Changes the description of the accountName.\n"
"Create Options: [-d]\n"
- " -d --description<=STRING> Sets a description for an account.\n"
+ " -d --description<=STRING> Sets a description for an accountName.\n"
"Earn Options: -v [-drD]\n"
" -v --value= Value for earning.\n"
" -d --description= Description for earning.\n"
@@ -325,7 +325,7 @@ void MainOptHandler::help() {
"budget -cAcct -eAcct -v10.00 -r\"./receipt.pdf\" -pAcct -v5.50 -r\"./payment.pdf\"\n"
"\n"
"Does the following in order:\n"
- "Creates an account named Acct with no description.\n"
+ "Creates an accountName named Acct with no description.\n"
"Earns 10.00 to it with a receipt.\n"
"Pays 5.50 to it with a receipt." << std::endl;
}
diff --git a/src/optHandlers/paymentOperation.cpp b/src/optHandlers/paymentOperation.cpp
new file mode 100644
index 0000000..9289166
--- /dev/null
+++ b/src/optHandlers/paymentOperation.cpp
@@ -0,0 +1,38 @@
+//
+// Created by quentin on 1/17/23.
+//
+
+#include
+#include "paymentOperation.h"
+#include "../database.h"
+#include "../exceptions/badValue.h"
+#include "../main.h"
+
+using namespace Budget::OptHandlers;
+
+void PaymentOperation::commit() {
+ Models::Account account = Database::getAccount(accountName, db);
+
+ if (!flags.receipt.empty()) {
+ std::ifstream source(flags.receipt, std::ios::binary);
+ if (source.good()) {
+ std::string extension;
+ size_t pos = flags.receipt.find_last_of('.');
+ if (pos != std::string::npos) {
+ extension = flags.receipt.substr(pos);
+ }
+
+ std::ofstream dest(storageD + "receipts/receipt/" + std::to_string(account.id) + extension, std::ios::binary);
+ dest << source.rdbuf();
+ source.close();
+ dest.close();
+ }
+ else {
+ throw Exceptions::BadValue("File " + flags.receipt + " does not exist");
+ }
+ }
+
+ Database::pay(&account, &flags, db);
+}
+
+PaymentOperation::PaymentOperation(sqlite3 *db, std::string account) : Operation(db), accountName(std::move(account)) {}
\ No newline at end of file
diff --git a/src/optHandlers/PaymentOperation.h b/src/optHandlers/paymentOperation.h
similarity index 95%
rename from src/optHandlers/PaymentOperation.h
rename to src/optHandlers/paymentOperation.h
index 38802ab..7630c33 100644
--- a/src/optHandlers/PaymentOperation.h
+++ b/src/optHandlers/paymentOperation.h
@@ -27,7 +27,7 @@ namespace Budget::OptHandlers {
Flags flags;
private:
- std::string account;
+ std::string accountName;
};
}