diff options
| author | Joe Carstairs <me@joeac.net> | 2024-10-16 12:51:21 +0100 |
|---|---|---|
| committer | Joe Carstairs <me@joeac.net> | 2024-10-16 12:51:21 +0100 |
| commit | 27b95c9186bd45edd4c982a7cc89cf69cf2c5d46 (patch) | |
| tree | bf104ff9d64e601bfec5516eb51ef298f3095e9b /backend/src | |
| parent | 76974785294089965efc3f55b2a08d4089029c52 (diff) | |
All backend stuff lives in backend folder
Diffstat (limited to 'backend/src')
45 files changed, 0 insertions, 1173 deletions
diff --git a/backend/src/databases.rs b/backend/src/databases.rs deleted file mode 100644 index 7202e78..0000000 --- a/backend/src/databases.rs +++ /dev/null @@ -1,11 +0,0 @@ -use rocket_sync_db_pools::{database, diesel}; - -cfg_if::cfg_if! { - if #[cfg(test)] { - #[database("user_data.test")] - pub struct UserDataDb(diesel::SqliteConnection); - } else { - #[database("user_data")] - pub struct UserDataDb(diesel::SqliteConnection); - } -} diff --git a/backend/src/main.rs b/backend/src/main.rs deleted file mode 100644 index c3e02e5..0000000 --- a/backend/src/main.rs +++ /dev/null @@ -1,57 +0,0 @@ -use diesel::SqliteConnection; -use diesel_migrations::MigrationHarness; -use diesel_migrations::{embed_migrations, EmbeddedMigrations}; -use rocket::fairing::AdHoc; -use rocket::http::ContentType; -use rocket::{launch, routes, Build, Rocket}; - -use crate::databases::UserDataDb; - -pub mod databases; -pub mod models; -pub mod queries; -pub mod routes; -pub mod schema; -pub mod utils; - -pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations"); - -fn run_database_migrations(connection: &mut SqliteConnection) { - connection - .run_pending_migrations(MIGRATIONS) - .expect("Error running database migrations"); -} - -#[launch] -async fn rocket() -> Rocket<Build> { - rocket::build() - .attach(UserDataDb::fairing()) - .attach(AdHoc::on_liftoff("Database Migration", |rocket| { - Box::pin(async move { - let user_data_db = UserDataDb::get_one(rocket).await.expect( - "Failed to get connection to user data database in order to run migrations", - ); - user_data_db.run(run_database_migrations).await; - }) - })) - .attach(AdHoc::on_response("Add CORS headers", |_req, res| { - Box::pin(async move { - res.set_header(ContentType::JSON); - res.set_header(rocket::http::Header::new( - "Access-Control-Allow-Origin", - "http://localhost:5173", - )); - }) - })) - .mount( - "/", - routes![ - routes::account::get_all_accounts, - routes::account::create_account, - routes::balance::get_all_category_balances, - routes::budget::get_current_category_budget_per_category, - routes::budget_update::get_all_budget_updates, - routes::category::get_all_categories, - ], - ) -} diff --git a/backend/src/models/account.rs b/backend/src/models/account.rs deleted file mode 100644 index c10bd5f..0000000 --- a/backend/src/models/account.rs +++ /dev/null @@ -1,15 +0,0 @@ -use diesel::prelude::*; -use serde::{Deserialize, Serialize}; - -use super::date_time_utc::DateTimeUtc; - -#[derive( - Insertable, Queryable, Identifiable, Selectable, Debug, PartialEq, Clone, Serialize, Deserialize, -)] -#[diesel(table_name = crate::schema::accounts)] -pub struct Account { - pub id: i32, - pub name: String, - pub opening_balance: i32, - pub opening_date: DateTimeUtc, -} diff --git a/backend/src/models/budget.rs b/backend/src/models/budget.rs deleted file mode 100644 index cc18f2e..0000000 --- a/backend/src/models/budget.rs +++ /dev/null @@ -1,44 +0,0 @@ -use serde::Serialize; - -use super::budget_update::BudgetUpdate; - -#[derive(Debug, Eq, PartialEq, Serialize)] -pub struct Budget { - pub quantity: i32, - pub period: i32, -} - -impl From<&BudgetUpdate> for Budget { - fn from(budget_update: &BudgetUpdate) -> Self { - Self { - quantity: budget_update.new_budget, - period: budget_update.new_period, - } - } -} - -#[cfg(test)] -mod test { - use chrono::Utc; - - use crate::models::date_time_utc::DateTimeUtc; - - use super::*; - - #[test] - fn when_from_budget_update_then_returns_budget() { - let quantity = 2; - let period = 3; - let budget_update = BudgetUpdate { - id: 0, - category_id: 1, - date: DateTimeUtc::new(Utc::now()), - new_budget: quantity, - new_period: period, - }; - - let budget = Budget::from(&budget_update); - - assert_eq!(budget, Budget { quantity, period }); - } -} diff --git a/backend/src/models/budget_update.rs b/backend/src/models/budget_update.rs deleted file mode 100644 index c63e957..0000000 --- a/backend/src/models/budget_update.rs +++ /dev/null @@ -1,17 +0,0 @@ -use diesel::prelude::*; -use serde::Serialize; - -use crate::models::category::Category; - -use super::date_time_utc::DateTimeUtc; - -#[derive(Clone, Serialize, Queryable, Identifiable, Selectable, Associations, Debug, PartialEq)] -#[diesel(table_name = crate::schema::budget_updates)] -#[diesel(belongs_to(Category))] -pub struct BudgetUpdate { - pub id: i32, - pub category_id: i32, - pub date: DateTimeUtc, - pub new_budget: i32, - pub new_period: i32, -} diff --git a/backend/src/models/category.rs b/backend/src/models/category.rs deleted file mode 100644 index 5cb2609..0000000 --- a/backend/src/models/category.rs +++ /dev/null @@ -1,9 +0,0 @@ -use diesel::prelude::*; -use serde::{Deserialize, Serialize}; - -#[derive(Queryable, Identifiable, Selectable, Debug, PartialEq, Serialize, Deserialize)] -#[diesel(table_name = crate::schema::categories)] -pub struct Category { - pub id: i32, - pub name: String, -} diff --git a/backend/src/models/category_balance.rs b/backend/src/models/category_balance.rs deleted file mode 100644 index 796b40b..0000000 --- a/backend/src/models/category_balance.rs +++ /dev/null @@ -1,7 +0,0 @@ -use serde::Serialize; - -#[derive(Serialize)] -pub struct CategoryBalance { - pub category_id: i32, - pub balance: i32, -} diff --git a/backend/src/models/category_budget.rs b/backend/src/models/category_budget.rs deleted file mode 100644 index 9796261..0000000 --- a/backend/src/models/category_budget.rs +++ /dev/null @@ -1,9 +0,0 @@ -use serde::Serialize; - -use super::budget::Budget; - -#[derive(Serialize)] -pub struct CategoryBudget { - pub category_id: i32, - pub budget: Option<Budget>, -} diff --git a/backend/src/models/category_transfer.rs b/backend/src/models/category_transfer.rs deleted file mode 100644 index 6cbda0e..0000000 --- a/backend/src/models/category_transfer.rs +++ /dev/null @@ -1,11 +0,0 @@ -use diesel::prelude::*; - -#[derive(Queryable, Identifiable, Selectable, Debug, PartialEq)] -#[diesel(table_name = crate::schema::category_transfers)] -pub struct CategoryTransfer { - pub id: i32, - pub description: String, - pub quantity: i32, - pub from_category_id: i32, - pub to_category_id: i32, -} diff --git a/backend/src/models/date_time_utc.rs b/backend/src/models/date_time_utc.rs deleted file mode 100644 index 03d5802..0000000 --- a/backend/src/models/date_time_utc.rs +++ /dev/null @@ -1,131 +0,0 @@ -use chrono::{DateTime, Datelike, Utc}; -use diesel::{ - backend::Backend, - deserialize::{self, FromSql, FromSqlRow}, - expression::AsExpression, - serialize::{self, ToSql}, - sql_types::Text, - sqlite::Sqlite, -}; -use serde::{Deserialize, Serialize}; - -#[derive( - Eq, - PartialEq, - Ord, - PartialOrd, - Serialize, - Deserialize, - Copy, - Clone, - Debug, - AsExpression, - FromSqlRow, -)] -#[diesel(sql_type=Text)] -pub struct DateTimeUtc(DateTime<Utc>); - -impl DateTimeUtc { - pub fn day_diff(&self, other: &DateTimeUtc) -> u32 { - self.0 - .num_days_from_ce() - .abs_diff(other.0.num_days_from_ce()) - } - - pub fn to_day_str(&self) -> String { - self.0 - .to_rfc3339() - .split_at_checked(10) - .map(|(day_str, _)| String::from(day_str)) - .unwrap_or_else(|| String::from("")) - } - - pub fn new(date_time_utc: DateTime<Utc>) -> Self { - Self(date_time_utc) - } - - pub fn now() -> Self { - Self(Utc::now()) - } -} - -impl ToSql<Text, Sqlite> for DateTimeUtc { - fn to_sql<'b>( - &'b self, - out: &mut diesel::serialize::Output<'b, '_, Sqlite>, - ) -> serialize::Result { - out.set_value(self.to_day_str()); - Ok(diesel::serialize::IsNull::No) - } -} - -impl FromSql<Text, Sqlite> for DateTimeUtc { - fn from_sql(bytes: <Sqlite as Backend>::RawValue<'_>) -> deserialize::Result<DateTimeUtc> { - let str: String = FromSql::<Text, Sqlite>::from_sql(bytes)?; - let date_time = str.as_str().parse::<DateTime<Utc>>()?; - Ok(DateTimeUtc(date_time)) - } -} - -#[cfg(test)] -mod test { - use chrono::TimeZone; - - use super::*; - - #[test] - fn given_midnight_when_day_diff_next_midnight_less_1s_then_return_0() { - let start = DateTimeUtc::new(Utc.with_ymd_and_hms(2000, 1, 1, 0, 0, 0).unwrap().to_utc()); - let end = DateTimeUtc::new( - Utc.with_ymd_and_hms(2000, 1, 1, 23, 59, 59) - .unwrap() - .to_utc(), - ); - - let day_diff = start.day_diff(&end); - let neg_day_diff = end.day_diff(&start); - - assert_eq!(day_diff, 0); - assert_eq!(day_diff, neg_day_diff); - } - - #[test] - fn given_midnight_when_day_diff_next_midnight_then_return_1() { - let start = DateTimeUtc::new(Utc.with_ymd_and_hms(2000, 1, 1, 0, 0, 0).unwrap().to_utc()); - let end = DateTimeUtc::new(Utc.with_ymd_and_hms(2000, 1, 2, 0, 0, 0).unwrap().to_utc()); - - let day_diff = start.day_diff(&end); - let neg_day_diff = end.day_diff(&start); - - assert_eq!(day_diff, 1); - assert_eq!(day_diff, neg_day_diff); - } - - #[test] - fn given_midnight_less_1s_when_day_diff_midnight_then_return_1() { - let start = DateTimeUtc::new( - Utc.with_ymd_and_hms(2000, 1, 1, 23, 59, 59) - .unwrap() - .to_utc(), - ); - let end = DateTimeUtc::new(Utc.with_ymd_and_hms(2000, 1, 2, 0, 0, 0).unwrap().to_utc()); - - let day_diff = start.day_diff(&end); - let neg_day_diff = end.day_diff(&start); - - assert_eq!(day_diff, 1); - assert_eq!(day_diff, neg_day_diff); - } - - #[test] - fn given_23_nov_1970_when_to_day_str_then_return_iso_day_str() { - let date_time_utc = DateTimeUtc::new( - Utc.with_ymd_and_hms(1970, 11, 23, 0, 0, 0) - .unwrap() - .to_utc(), - ); - let day_str = date_time_utc.to_day_str(); - - assert_eq!(day_str, "1970-11-23"); - } -} diff --git a/backend/src/models/mod.rs b/backend/src/models/mod.rs deleted file mode 100644 index b790fcb..0000000 --- a/backend/src/models/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -pub mod account; -pub mod budget; -pub mod budget_update; -pub mod category; -pub mod category_balance; -pub mod category_budget; -pub mod category_transfer; -pub mod date_time_utc; -pub mod transaction; -pub mod transaction_categorisation; diff --git a/backend/src/models/transaction.rs b/backend/src/models/transaction.rs deleted file mode 100644 index 36f33f8..0000000 --- a/backend/src/models/transaction.rs +++ /dev/null @@ -1,17 +0,0 @@ -use diesel::prelude::*; - -use crate::models::account::Account; - -use super::date_time_utc::DateTimeUtc; - -#[derive(Queryable, Identifiable, Selectable, Associations, Debug, PartialEq)] -#[diesel(table_name = crate::schema::transactions)] -#[diesel(belongs_to(Account))] -pub struct Transaction { - pub id: i32, - pub description: String, - pub payee: String, - pub quantity: i32, - pub date: DateTimeUtc, - pub account_id: i32, -} diff --git a/backend/src/models/transaction_categorisation.rs b/backend/src/models/transaction_categorisation.rs deleted file mode 100644 index d2867f1..0000000 --- a/backend/src/models/transaction_categorisation.rs +++ /dev/null @@ -1,11 +0,0 @@ -use diesel::prelude::*; - -#[derive(Queryable, Identifiable, Selectable, Debug, PartialEq)] -#[diesel(table_name = crate::schema::transaction_categorisations)] -pub struct TransactionCategorisations { - pub id: i32, - pub description: String, - pub quantity: i32, - pub transaction_id: i32, - pub category_id: i32, -} diff --git a/backend/src/queries/accounts/get_all.rs b/backend/src/queries/accounts/get_all.rs deleted file mode 100644 index 12941ac..0000000 --- a/backend/src/queries/accounts/get_all.rs +++ /dev/null @@ -1,7 +0,0 @@ -use diesel::{result::Error, QueryDsl, RunQueryDsl, SelectableHelper, SqliteConnection}; - -use crate::{models::account::Account, schema::accounts::dsl::accounts}; - -pub fn get_all_accounts(connection: &mut SqliteConnection) -> Result<Vec<Account>, Error> { - accounts.select(Account::as_select()).load(connection) -} diff --git a/backend/src/queries/accounts/insert.rs b/backend/src/queries/accounts/insert.rs deleted file mode 100644 index c20cf60..0000000 --- a/backend/src/queries/accounts/insert.rs +++ /dev/null @@ -1,14 +0,0 @@ -use diesel::prelude::*; -use diesel::result::Error; - -use crate::models::account::Account; -use crate::schema::accounts::dsl::accounts as accounts_table; - -pub fn insert_account( - accounts: &[Account], - connection: &mut SqliteConnection, -) -> Result<usize, Error> { - diesel::insert_into(accounts_table) - .values(accounts) - .execute(connection) -} diff --git a/backend/src/queries/accounts/mod.rs b/backend/src/queries/accounts/mod.rs deleted file mode 100644 index 94fa360..0000000 --- a/backend/src/queries/accounts/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod get_all; -mod insert; - -pub use get_all::get_all_accounts; -pub use insert::insert_account; diff --git a/backend/src/queries/budget_updates/get_all.rs b/backend/src/queries/budget_updates/get_all.rs deleted file mode 100644 index 97f2f2f..0000000 --- a/backend/src/queries/budget_updates/get_all.rs +++ /dev/null @@ -1,13 +0,0 @@ -use crate::{ - models::budget_update::BudgetUpdate, - schema::budget_updates::dsl::budget_updates as budget_updates_table, -}; -use diesel::{result::Error, QueryDsl, RunQueryDsl, SelectableHelper, SqliteConnection}; - -pub fn get_all_budget_updates( - connection: &mut SqliteConnection, -) -> Result<Vec<BudgetUpdate>, Error> { - budget_updates_table - .select(BudgetUpdate::as_select()) - .load::<BudgetUpdate>(connection) -} diff --git a/backend/src/queries/budget_updates/get_first_with_date.rs b/backend/src/queries/budget_updates/get_first_with_date.rs deleted file mode 100644 index a2824be..0000000 --- a/backend/src/queries/budget_updates/get_first_with_date.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::{ - models::budget_update::BudgetUpdate, - schema::budget_updates::{ - self as budget_updates_schema, dsl::budget_updates as budget_updates_table, - }, -}; -use diesel::{ - result::Error, ExpressionMethods, QueryDsl, RunQueryDsl, SelectableHelper, SqliteConnection, -}; - -pub fn get_first_budget_update_with_date( - date: &str, - connection: &mut SqliteConnection, -) -> Result<BudgetUpdate, Error> { - budget_updates_table - .select(BudgetUpdate::as_select()) - .filter(budget_updates_schema::date.eq(date)) - .first(connection) -} diff --git a/backend/src/queries/budget_updates/get_most_recent_with_category_id.rs b/backend/src/queries/budget_updates/get_most_recent_with_category_id.rs deleted file mode 100644 index 4753092..0000000 --- a/backend/src/queries/budget_updates/get_most_recent_with_category_id.rs +++ /dev/null @@ -1,18 +0,0 @@ -use crate::{ - models::date_time_utc::DateTimeUtc, - schema::budget_updates::{ - self as budget_updates_schema, dsl::budget_updates as budget_updates_table, - }, -}; -use diesel::{dsl::max, result::Error, ExpressionMethods, QueryDsl, RunQueryDsl, SqliteConnection}; - -pub fn get_most_recent_budget_update_date_with_category_id( - category_id: i32, - connection: &mut SqliteConnection, -) -> Result<Option<String>, Error> { - budget_updates_table - .select(max(budget_updates_schema::date)) - .filter(budget_updates_schema::category_id.eq(category_id)) - .filter(budget_updates_schema::date.le(DateTimeUtc::now().to_day_str())) - .first(connection) -} diff --git a/backend/src/queries/budget_updates/mod.rs b/backend/src/queries/budget_updates/mod.rs deleted file mode 100644 index 3b514dd..0000000 --- a/backend/src/queries/budget_updates/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -mod get_all; -mod get_first_with_date; -mod get_most_recent_with_category_id; - -pub use get_all::get_all_budget_updates; -pub use get_first_with_date::get_first_budget_update_with_date; -pub use get_most_recent_with_category_id::get_most_recent_budget_update_date_with_category_id; diff --git a/backend/src/queries/categories/get_all.rs b/backend/src/queries/categories/get_all.rs deleted file mode 100644 index db5a073..0000000 --- a/backend/src/queries/categories/get_all.rs +++ /dev/null @@ -1,8 +0,0 @@ -use crate::{models::category::Category, schema::categories::dsl::categories as categories_table}; -use diesel::{result::Error, QueryDsl, RunQueryDsl, SelectableHelper, SqliteConnection}; - -pub fn get_all_categories(connection: &mut SqliteConnection) -> Result<Vec<Category>, Error> { - categories_table - .select(Category::as_select()) - .load(connection) -} diff --git a/backend/src/queries/categories/get_all_ids.rs b/backend/src/queries/categories/get_all_ids.rs deleted file mode 100644 index 7c7c912..0000000 --- a/backend/src/queries/categories/get_all_ids.rs +++ /dev/null @@ -1,8 +0,0 @@ -use crate::schema::categories::{self as categories_schema, dsl::categories as categories_table}; -use diesel::{result::Error, QueryDsl, RunQueryDsl, SqliteConnection}; - -pub fn get_all_category_ids(connection: &mut SqliteConnection) -> Result<Vec<i32>, Error> { - categories_table - .select(categories_schema::id) - .load(connection) -} diff --git a/backend/src/queries/categories/mod.rs b/backend/src/queries/categories/mod.rs deleted file mode 100644 index 80356b3..0000000 --- a/backend/src/queries/categories/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod get_all; -mod get_all_ids; - -pub use self::get_all::get_all_categories; -pub use self::get_all_ids::get_all_category_ids; diff --git a/backend/src/queries/category_balances/get_all.rs b/backend/src/queries/category_balances/get_all.rs deleted file mode 100644 index 713fbeb..0000000 --- a/backend/src/queries/category_balances/get_all.rs +++ /dev/null @@ -1,43 +0,0 @@ -use crate::{ - models::category_balance::CategoryBalance, - queries::{ - budget_updates::get_all_budget_updates, - categories::get_all_categories, - category_transfers::{ - sum_category_transfer_quantity_per_from_category_id, - sum_category_transfer_quantity_per_to_category_id, - }, - transaction_categorisations::sum_transaction_categorisation_quantity_per_category_id, - }, - utils::calculate_category_balance, -}; -use diesel::{result::Error, SqliteConnection}; - -pub fn get_all_category_balances( - connection: &mut SqliteConnection, -) -> Result<Vec<CategoryBalance>, Error> { - let categories = get_all_categories(connection)?; - let transaction_sums = sum_transaction_categorisation_quantity_per_category_id(connection)?; - let category_transfer_from_sums = - sum_category_transfer_quantity_per_from_category_id(connection)?; - let category_transfer_to_sums = sum_category_transfer_quantity_per_to_category_id(connection)?; - let budget_updates = get_all_budget_updates(connection)?; - - let mut balances = Vec::<CategoryBalance>::new(); - for category in categories { - let balance = calculate_category_balance( - &category, - &transaction_sums, - &category_transfer_from_sums, - &category_transfer_to_sums, - &budget_updates, - ); - - balances.push(CategoryBalance { - category_id: category.id, - balance: balance.try_into().unwrap(), - }) - } - - Ok(balances) -} diff --git a/backend/src/queries/category_balances/mod.rs b/backend/src/queries/category_balances/mod.rs deleted file mode 100644 index 3fc1be2..0000000 --- a/backend/src/queries/category_balances/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod get_all; - -pub use get_all::get_all_category_balances; diff --git a/backend/src/queries/category_budgets/get_most_recent_per_category_id.rs b/backend/src/queries/category_budgets/get_most_recent_per_category_id.rs deleted file mode 100644 index 6b76efd..0000000 --- a/backend/src/queries/category_budgets/get_most_recent_per_category_id.rs +++ /dev/null @@ -1,42 +0,0 @@ -use crate::{ - models::{budget::Budget, category_budget::CategoryBudget}, - queries::{ - budget_updates::{ - get_first_budget_update_with_date, get_most_recent_budget_update_date_with_category_id, - }, - categories::get_all_category_ids, - }, -}; -use diesel::{result::Error, SqliteConnection}; - -pub fn get_most_recent_category_budget_per_category_id( - connection: &mut SqliteConnection, -) -> Result<Vec<CategoryBudget>, Error> { - let category_ids: Vec<i32> = get_all_category_ids(connection)?; - - let mut budgets = Vec::<CategoryBudget>::new(); - for category_id in category_ids { - let most_recent_budget_update_date = - get_most_recent_budget_update_date_with_category_id(category_id, connection)?; - - if most_recent_budget_update_date.is_none() { - budgets.push(CategoryBudget { - category_id, - budget: Option::None, - }); - continue; - } - - let most_recent_budget_update = get_first_budget_update_with_date( - most_recent_budget_update_date.unwrap().as_str(), - connection, - )?; - - budgets.push(CategoryBudget { - category_id, - budget: Some(Budget::from(&most_recent_budget_update)), - }); - } - - Ok(budgets) -} diff --git a/backend/src/queries/category_budgets/mod.rs b/backend/src/queries/category_budgets/mod.rs deleted file mode 100644 index 29fc246..0000000 --- a/backend/src/queries/category_budgets/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod get_most_recent_per_category_id; - -pub use self::get_most_recent_per_category_id::get_most_recent_category_budget_per_category_id; diff --git a/backend/src/queries/category_transfers/mod.rs b/backend/src/queries/category_transfers/mod.rs deleted file mode 100644 index 85eb1c8..0000000 --- a/backend/src/queries/category_transfers/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod sum_quantity_per_from_category_id; -mod sum_quantity_per_to_category_id; - -pub use sum_quantity_per_from_category_id::sum_category_transfer_quantity_per_from_category_id; -pub use sum_quantity_per_to_category_id::sum_category_transfer_quantity_per_to_category_id; diff --git a/backend/src/queries/category_transfers/sum_quantity_per_from_category_id.rs b/backend/src/queries/category_transfers/sum_quantity_per_from_category_id.rs deleted file mode 100644 index ae3a51a..0000000 --- a/backend/src/queries/category_transfers/sum_quantity_per_from_category_id.rs +++ /dev/null @@ -1,17 +0,0 @@ -use diesel::{dsl::sum, result::Error, QueryDsl, RunQueryDsl, SqliteConnection}; - -use crate::schema::category_transfers::{ - self as category_transfers_schema, dsl::category_transfers as category_transfers_table, -}; - -pub fn sum_category_transfer_quantity_per_from_category_id( - connection: &mut SqliteConnection, -) -> Result<Vec<(i32, Option<i64>)>, Error> { - category_transfers_table - .group_by(category_transfers_schema::from_category_id) - .select(( - category_transfers_schema::from_category_id, - sum(category_transfers_schema::quantity), - )) - .load::<(i32, Option<i64>)>(connection) -} diff --git a/backend/src/queries/category_transfers/sum_quantity_per_to_category_id.rs b/backend/src/queries/category_transfers/sum_quantity_per_to_category_id.rs deleted file mode 100644 index fe6f3a7..0000000 --- a/backend/src/queries/category_transfers/sum_quantity_per_to_category_id.rs +++ /dev/null @@ -1,17 +0,0 @@ -use diesel::{dsl::sum, result::Error, QueryDsl, RunQueryDsl, SqliteConnection}; - -use crate::schema::category_transfers::{ - self as category_transfers_schema, dsl::category_transfers as category_transfers_table, -}; - -pub fn sum_category_transfer_quantity_per_to_category_id( - connection: &mut SqliteConnection, -) -> Result<Vec<(i32, Option<i64>)>, Error> { - category_transfers_table - .group_by(category_transfers_schema::to_category_id) - .select(( - category_transfers_schema::to_category_id, - sum(category_transfers_schema::quantity), - )) - .load::<(i32, Option<i64>)>(connection) -} diff --git a/backend/src/queries/mod.rs b/backend/src/queries/mod.rs deleted file mode 100644 index 43328e2..0000000 --- a/backend/src/queries/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub mod accounts; -pub mod budget_updates; -pub mod categories; -pub mod category_balances; -pub mod category_budgets; -pub mod category_transfers; -pub mod transaction_categorisations; diff --git a/backend/src/queries/transaction_categorisations/mod.rs b/backend/src/queries/transaction_categorisations/mod.rs deleted file mode 100644 index d4217cc..0000000 --- a/backend/src/queries/transaction_categorisations/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod sum_quantity_per_category_id; - -pub use sum_quantity_per_category_id::sum_transaction_categorisation_quantity_per_category_id; diff --git a/backend/src/queries/transaction_categorisations/sum_quantity_per_category_id.rs b/backend/src/queries/transaction_categorisations/sum_quantity_per_category_id.rs deleted file mode 100644 index 7f93e0c..0000000 --- a/backend/src/queries/transaction_categorisations/sum_quantity_per_category_id.rs +++ /dev/null @@ -1,17 +0,0 @@ -use crate::schema::transaction_categorisations::{ - self as transaction_categorisations_schema, - dsl::transaction_categorisations as transaction_categorisations_table, -}; -use diesel::{dsl::sum, result::Error, QueryDsl, RunQueryDsl, SqliteConnection}; - -pub fn sum_transaction_categorisation_quantity_per_category_id( - connection: &mut SqliteConnection, -) -> Result<Vec<(i32, Option<i64>)>, Error> { - transaction_categorisations_table - .group_by(transaction_categorisations_schema::category_id) - .select(( - transaction_categorisations_schema::category_id, - sum(transaction_categorisations_schema::quantity), - )) - .load::<(i32, Option<i64>)>(connection) -} diff --git a/backend/src/queries/transaction_categorisations/sum_quantity_per_to_category_id.rs b/backend/src/queries/transaction_categorisations/sum_quantity_per_to_category_id.rs deleted file mode 100644 index e69de29..0000000 --- a/backend/src/queries/transaction_categorisations/sum_quantity_per_to_category_id.rs +++ /dev/null diff --git a/backend/src/routes/account.rs b/backend/src/routes/account.rs deleted file mode 100644 index 7bbdb4f..0000000 --- a/backend/src/routes/account.rs +++ /dev/null @@ -1,57 +0,0 @@ -use diesel::result::DatabaseErrorKind; -use rocket::http::Status; -use rocket::serde::json::Json; -use rocket::{get, post, Responder}; - -use crate::databases::UserDataDb; -use crate::models::account::Account; -use crate::queries::accounts::{get_all_accounts as get_all_accounts_query, insert_account}; - -#[get("/account")] -pub async fn get_all_accounts(user_data_db: UserDataDb) -> Result<Json<Vec<Account>>, Status> { - user_data_db - .run(get_all_accounts_query) - .await - .map(Json) - .map_err(|_| Status { code: 500 }) -} - -#[derive(Responder)] -pub enum CreateAccountResponder { - #[response(status = 500, content_type = "text")] - InternalServerError(String), - - #[response(status = 202, content_type = "json")] - Created(Json<Account>), - - #[response(status = 400, content_type = "text")] - BadRequest(String), -} - -#[post("/account", data = "<account>", format = "json")] -pub async fn create_account( - account: Json<Account>, - user_data_db: UserDataDb, -) -> CreateAccountResponder { - let account = account.into_inner(); - let accounts_vec = vec![account.clone()]; - - let num_rows_inserted = user_data_db - .run(move |connection| insert_account(&accounts_vec, connection)) - .await; - - match num_rows_inserted { - Ok(_) => CreateAccountResponder::Created(Json(account)), - Err(err) => match err { - diesel::result::Error::DatabaseError(DatabaseErrorKind::UniqueViolation, info) => { - let column = info.column_name().unwrap_or("account"); - CreateAccountResponder::BadRequest(format!( - "Error creating account: {column} was not unique." - )) - } - _ => CreateAccountResponder::InternalServerError(format!( - "Error creating account: {err}" - )), - }, - } -} diff --git a/backend/src/routes/balance.rs b/backend/src/routes/balance.rs deleted file mode 100644 index f423c90..0000000 --- a/backend/src/routes/balance.rs +++ /dev/null @@ -1,17 +0,0 @@ -use rocket::{get, http::Status, serde::json::Json}; - -use crate::{ - databases::UserDataDb, models::category_balance::CategoryBalance, - queries::category_balances::get_all_category_balances as get_all_category_balances_query, -}; - -#[get("/balance/category")] -pub async fn get_all_category_balances( - user_data_db: UserDataDb, -) -> Result<Json<Vec<CategoryBalance>>, Status> { - user_data_db - .run(get_all_category_balances_query) - .await - .map(Json) - .map_err(|_| Status { code: 500 }) -} diff --git a/backend/src/routes/budget.rs b/backend/src/routes/budget.rs deleted file mode 100644 index 67aae8e..0000000 --- a/backend/src/routes/budget.rs +++ /dev/null @@ -1,18 +0,0 @@ -use rocket::get; -use rocket::http::Status; -use rocket::serde::json::Json; - -use crate::databases::UserDataDb; -use crate::models::category_budget::CategoryBudget; -use crate::queries; - -#[get("/budget/category?current")] -pub async fn get_current_category_budget_per_category( - user_data_db: UserDataDb, -) -> Result<Json<Vec<CategoryBudget>>, Status> { - user_data_db - .run(queries::category_budgets::get_most_recent_category_budget_per_category_id) - .await - .map(Json) - .map_err(|_| Status { code: 500 }) -} diff --git a/backend/src/routes/budget_update.rs b/backend/src/routes/budget_update.rs deleted file mode 100644 index 7732c7b..0000000 --- a/backend/src/routes/budget_update.rs +++ /dev/null @@ -1,18 +0,0 @@ -use rocket::get; -use rocket::http::Status; -use rocket::serde::json::Json; - -use crate::databases::UserDataDb; -use crate::models::budget_update::BudgetUpdate; -use crate::queries; - -#[get("/budget-update")] -pub async fn get_all_budget_updates( - user_data_db: UserDataDb, -) -> Result<Json<Vec<BudgetUpdate>>, Status> { - user_data_db - .run(queries::budget_updates::get_all_budget_updates) - .await - .map(Json) - .map_err(|_| Status { code: 500 }) -} diff --git a/backend/src/routes/category.rs b/backend/src/routes/category.rs deleted file mode 100644 index 01fd8d1..0000000 --- a/backend/src/routes/category.rs +++ /dev/null @@ -1,16 +0,0 @@ -use rocket::get; -use rocket::http::Status; -use rocket::serde::json::Json; - -use crate::databases::UserDataDb; -use crate::models::category::Category; -use crate::queries::categories::get_all_categories as get_all_categories_query; - -#[get("/category")] -pub async fn get_all_categories(user_data_db: UserDataDb) -> Result<Json<Vec<Category>>, Status> { - user_data_db - .run(get_all_categories_query) - .await - .map(Json) - .map_err(|_| Status { code: 500 }) -} diff --git a/backend/src/routes/mod.rs b/backend/src/routes/mod.rs deleted file mode 100644 index bf0ab4a..0000000 --- a/backend/src/routes/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod account; -pub mod balance; -pub mod budget; -pub mod budget_update; -pub mod category; diff --git a/backend/src/schema.rs b/backend/src/schema.rs deleted file mode 100644 index 372f8f3..0000000 --- a/backend/src/schema.rs +++ /dev/null @@ -1,72 +0,0 @@ -// @generated automatically by Diesel CLI. - -diesel::table! { - accounts (id) { - id -> Integer, - name -> Text, - opening_balance -> Integer, - opening_date -> Text, - } -} - -diesel::table! { - budget_updates (id) { - id -> Integer, - category_id -> Integer, - date -> Text, - new_budget -> Integer, - new_period -> Integer, - } -} - -diesel::table! { - categories (id) { - id -> Integer, - name -> Text, - } -} - -diesel::table! { - category_transfers (id) { - id -> Integer, - description -> Text, - quantity -> Integer, - from_category_id -> Integer, - to_category_id -> Integer, - } -} - -diesel::table! { - transaction_categorisations (id) { - id -> Integer, - description -> Text, - quantity -> Integer, - transaction_id -> Integer, - category_id -> Integer, - } -} - -diesel::table! { - transactions (id) { - id -> Integer, - description -> Text, - payee -> Text, - quantity -> Integer, - date -> Text, - account_id -> Integer, - } -} - -diesel::joinable!(budget_updates -> categories (category_id)); -diesel::joinable!(transaction_categorisations -> categories (category_id)); -diesel::joinable!(transaction_categorisations -> transactions (transaction_id)); -diesel::joinable!(transactions -> accounts (account_id)); - -diesel::allow_tables_to_appear_in_same_query!( - accounts, - budget_updates, - categories, - category_transfers, - transaction_categorisations, - transactions, -); diff --git a/backend/src/utils/calculate_budgets_accrual.rs b/backend/src/utils/calculate_budgets_accrual.rs deleted file mode 100644 index f14260d..0000000 --- a/backend/src/utils/calculate_budgets_accrual.rs +++ /dev/null @@ -1,159 +0,0 @@ -use crate::models::{budget_update::BudgetUpdate, category::Category, date_time_utc::DateTimeUtc}; - -pub fn calculate_budgets_accrual(category: &Category, budget_updates: &[BudgetUpdate]) -> i64 { - let mut budget_updates = budget_updates - .iter() - .filter(|bu| bu.category_id == category.id) - .collect::<Vec<&BudgetUpdate>>(); - budget_updates.sort_by_key(|bu| bu.date); - budget_updates.reverse(); - - let mut budgets_accrual = 0.0_f64; - let mut calculated_back_to_date = DateTimeUtc::now(); - - for budget_update in budget_updates { - let days_on_this_budget = calculated_back_to_date.day_diff(&budget_update.date); - if days_on_this_budget == 0_u32 { - continue; - } - let budget_per_day = budget_update.new_budget as f64 / budget_update.new_period as f64; - budgets_accrual += days_on_this_budget as f64 * budget_per_day; - calculated_back_to_date = budget_update.date; - } - - budgets_accrual.floor() as i64 -} - -#[cfg(test)] -mod test { - use chrono::{Days, Timelike, Utc}; - - use crate::models::{ - budget_update::BudgetUpdate, category::Category, date_time_utc::DateTimeUtc, - }; - - use super::calculate_budgets_accrual; - - #[test] - fn when_no_budget_updates_then_return_zero() { - let category = Category { - id: 0, - name: String::from("Groceries"), - }; - let budget_updates = []; - - let result = calculate_budgets_accrual(&category, &budget_updates); - - assert_eq!(result, 0_i64); - } - - #[test] - fn when_one_budget_update_for_another_category_then_return_zero() { - let category = Category { - id: 0, - name: String::from("Groceries"), - }; - let budget_updates = [BudgetUpdate { - id: 0, - category_id: 1, - date: DateTimeUtc::now(), - new_budget: 100, - new_period: 1, - }]; - - let result = calculate_budgets_accrual(&category, &budget_updates); - - assert_eq!(result, 0_i64); - } - - #[test] - fn when_one_budget_update_then_return_quantity_times_days_in_past() { - let category = Category { - id: 0, - name: String::from("Groceries"), - }; - let budget_updates = [BudgetUpdate { - id: 0, - category_id: 0, - date: DateTimeUtc::new(Utc::now().checked_sub_days(Days::new(120)).unwrap()), - new_budget: 100, - new_period: 1, - }]; - - let result = calculate_budgets_accrual(&category, &budget_updates); - - assert_eq!(result, 12_000); - } - - #[test] - fn when_two_budget_updates_then_calculates_as_expected() { - let category = Category { - id: 0, - name: String::from("Groceries"), - }; - let budget_updates = [ - BudgetUpdate { - id: 0, - category_id: 0, - date: DateTimeUtc::new(Utc::now().checked_sub_days(Days::new(60)).unwrap()), - new_budget: 200, - new_period: 1, - }, - BudgetUpdate { - id: 0, - category_id: 0, - date: DateTimeUtc::new(Utc::now().checked_sub_days(Days::new(120)).unwrap()), - new_budget: 100, - new_period: 1, - }, - ]; - - let result = calculate_budgets_accrual(&category, &budget_updates); - - assert_eq!(result, 18_000); - } - - #[test] - fn when_two_budget_updates_on_same_day_then_uses_latest_only() { - let category = Category { - id: 0, - name: String::from("Groceries"), - }; - let budget_updates = [ - BudgetUpdate { - id: 0, - category_id: 0, - date: DateTimeUtc::new( - Utc::now() - .checked_sub_days(Days::new(120)) - .unwrap() - .with_hour(13) - .unwrap(), - ), - new_budget: 200, - new_period: 1, - }, - BudgetUpdate { - id: 0, - category_id: 0, - date: DateTimeUtc::new( - Utc::now() - .checked_sub_days(Days::new(120)) - .unwrap() - .with_hour(12) - .unwrap(), - ), - new_budget: 100, - new_period: 1, - }, - ]; - let mut budget_updates_reversed = budget_updates.clone(); - budget_updates_reversed.reverse(); - - let result_leftways = calculate_budgets_accrual(&category, &budget_updates); - let result_rightways = calculate_budgets_accrual(&category, &budget_updates_reversed); - - assert_eq!(result_leftways, 24_000); - assert_eq!(result_rightways, 24_000); - } -} diff --git a/backend/src/utils/calculate_category_balance.rs b/backend/src/utils/calculate_category_balance.rs deleted file mode 100644 index 3c1c62f..0000000 --- a/backend/src/utils/calculate_category_balance.rs +++ /dev/null @@ -1,141 +0,0 @@ -use crate::models::{budget_update::BudgetUpdate, category::Category}; - -use super::{calculate_budgets_accrual, find_by_id_or}; - -pub fn calculate_category_balance( - category: &Category, - transaction_sums: &[(i32, Option<i64>)], - category_transfer_from_sums: &[(i32, Option<i64>)], - category_transfer_to_sums: &[(i32, Option<i64>)], - budget_updates: &[BudgetUpdate], -) -> i64 { - let transaction_sum = find_by_id_or(transaction_sums, category.id, 0); - let category_transfer_from_sum = find_by_id_or(category_transfer_from_sums, category.id, 0); - let category_transfer_to_sum = find_by_id_or(category_transfer_to_sums, category.id, 0); - let budget_accruals_sum = calculate_budgets_accrual(category, budget_updates); - - transaction_sum + budget_accruals_sum + category_transfer_to_sum - category_transfer_from_sum -} - -#[cfg(test)] -mod test { - use chrono::{Days, Utc}; - - use crate::{ - models::{budget_update::BudgetUpdate, category::Category, date_time_utc::DateTimeUtc}, - utils::calculate_category_balance, - }; - - #[test] - fn when_no_data_then_returns_zero() { - let category = Category { - id: 0, - name: String::new(), - }; - - let result = calculate_category_balance(&category, &[], &[], &[], &[]); - - assert_eq!(result, 0_i64); - } - - #[test] - fn when_data_only_for_another_category_then_returns_zero() { - let category = Category { - id: 0, - name: String::new(), - }; - let transaction_sums = [(1, Some(100))]; - let category_transfer_from_sums = [(1, Some(91))]; - let category_transfer_to_sums = [(2, Some(79))]; - let budget_updates = [BudgetUpdate { - id: 0, - category_id: 1, - date: DateTimeUtc::new(Utc::now().checked_sub_days(Days::new(120)).unwrap()), - new_budget: 77, - new_period: 1, - }]; - - let result = calculate_category_balance( - &category, - &transaction_sums, - &category_transfer_from_sums, - &category_transfer_to_sums, - &budget_updates, - ); - - assert_eq!(result, 0_i64); - } - - #[test] - fn when_transaction_sum_is_none_then_returns_zero() { - let category = Category { - id: 0, - name: String::new(), - }; - let transaction_sums = [(0, None)]; - let category_transfer_from_sums = []; - let category_transfer_to_sums = []; - let budget_updates = []; - - let result = calculate_category_balance( - &category, - &transaction_sums, - &category_transfer_from_sums, - &category_transfer_to_sums, - &budget_updates, - ); - - assert_eq!(result, 0_i64); - } - - #[test] - fn when_category_transfers_are_none_then_returns_zero() { - let category = Category { - id: 0, - name: String::new(), - }; - let transaction_sums = []; - let category_transfer_from_sums = [(0, None)]; - let category_transfer_to_sums = [(0, None)]; - let budget_updates = []; - - let result = calculate_category_balance( - &category, - &transaction_sums, - &category_transfer_from_sums, - &category_transfer_to_sums, - &budget_updates, - ); - - assert_eq!(result, 0_i64); - } - - #[test] - fn when_some_data_then_calculates_as_expected() { - let category = Category { - id: 0, - name: String::new(), - }; - let transaction_sums = [(0, Some(100))]; - let category_transfer_from_sums = [(0, Some(91))]; - let category_transfer_to_sums = [(0, Some(79))]; - let budget_updates = [BudgetUpdate { - id: 0, - category_id: 0, - date: DateTimeUtc::new(Utc::now().checked_sub_days(Days::new(120)).unwrap()), - new_budget: 77, - new_period: 1, - }]; - - let result = calculate_category_balance( - &category, - &transaction_sums, - &category_transfer_from_sums, - &category_transfer_to_sums, - &budget_updates, - ); - - let expected_result = 100 + (-91) + 79 + 77 * 120; - assert_eq!(result, expected_result); - } -} diff --git a/backend/src/utils/find_by_id_or.rs b/backend/src/utils/find_by_id_or.rs deleted file mode 100644 index f5add30..0000000 --- a/backend/src/utils/find_by_id_or.rs +++ /dev/null @@ -1,53 +0,0 @@ -pub fn find_by_id_or<Id: PartialEq, Val: Copy>( - arr: &[(Id, Option<Val>)], - id: Id, - default: Val, -) -> Val { - arr.iter() - .find(|(elem_id, _)| *elem_id == id) - .map_or(default, |row| match row { - (_, Some(quantity)) => *quantity, - (_, _) => default, - }) -} - -#[cfg(test)] -mod test { - use super::find_by_id_or; - - #[test] - fn when_no_elements_then_return_default() { - let arr = []; - - let result = find_by_id_or(&arr, 1, 42); - - assert_eq!(result, 42); - } - - #[test] - fn when_id_not_in_elements_then_return_default() { - let arr = [(0, Some(100)), (2, Some(200))]; - - let result = find_by_id_or(&arr, 1, 42); - - assert_eq!(result, 42); - } - - #[test] - fn when_value_is_none_then_return_default() { - let arr = [(1, None)]; - - let result = find_by_id_or(&arr, 1, 42); - - assert_eq!(result, 42); - } - - #[test] - fn when_value_is_some_then_return_value() { - let arr = [(1, Some(67))]; - - let result = find_by_id_or(&arr, 1, 42); - - assert_eq!(result, 67); - } -} diff --git a/backend/src/utils/mod.rs b/backend/src/utils/mod.rs deleted file mode 100644 index 84a27af..0000000 --- a/backend/src/utils/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -mod calculate_budgets_accrual; -mod calculate_category_balance; -mod find_by_id_or; - -pub use calculate_budgets_accrual::calculate_budgets_accrual; -pub use calculate_category_balance::calculate_category_balance; -pub use find_by_id_or::find_by_id_or; |
