diff options
Diffstat (limited to 'schist_queries/src/utils')
| -rw-r--r-- | schist_queries/src/utils/calculate_budgets_accrual.rs | 72 | ||||
| -rw-r--r-- | schist_queries/src/utils/calculate_category_balance.rs | 130 | ||||
| -rw-r--r-- | schist_queries/src/utils/find_by_id_or.rs | 41 | ||||
| -rw-r--r-- | schist_queries/src/utils/mod.rs | 8 |
4 files changed, 251 insertions, 0 deletions
diff --git a/schist_queries/src/utils/calculate_budgets_accrual.rs b/schist_queries/src/utils/calculate_budgets_accrual.rs new file mode 100644 index 0000000..ca82953 --- /dev/null +++ b/schist_queries/src/utils/calculate_budgets_accrual.rs @@ -0,0 +1,72 @@ +use anyhow::Result; +use schist_models::{ + budget_drip::BudgetDrip, + category::Category, +}; + +pub fn calculate_budgets_accrual(category: &Category, budget_drips: &[BudgetDrip]) -> Result<i64> { + Ok(budget_drips + .iter() + .filter(|bd| bd.category_id == category.id) + .map(|bd| Into::<i64>::into(bd.quantity)) + .sum() + ) +} + +#[cfg(test)] +mod test { + use schist_fakes::{budget_drip::make_fake_budget_drip_builder, category::make_fake_category}; + + use super::calculate_budgets_accrual; + + #[test] + fn when_no_budget_drips_then_return_zero() { + let category = make_fake_category(0); + let budget_drips = []; + + let result = calculate_budgets_accrual(&category, &budget_drips); + + assert!(result.is_ok()); + assert_eq!(result.unwrap(), 0_i64); + } + + #[test] + fn when_one_budget_drip_for_another_category_then_return_zero() { + let category = make_fake_category(0); + let budget_drips = [ + make_fake_budget_drip_builder(0).quantity(100).category_id(1).build().unwrap(), + ]; + + let result = calculate_budgets_accrual(&category, &budget_drips); + + assert!(result.is_ok()); + assert_eq!(result.unwrap(), 0_i64); + } + + #[test] + fn when_one_budget_drip_then_return_quantity() { + let category = make_fake_category(0); + let budget_drips = [ + make_fake_budget_drip_builder(0).quantity(100).category_id(0).build().unwrap(), + ]; + + let result = calculate_budgets_accrual(&category, &budget_drips); + + assert!(result.is_ok()); + assert_eq!(result.unwrap(), 100); + } + + #[test] + fn when_two_budget_drips_then_return_sum() { + let category = make_fake_category(0); + let budget_drips = [ + make_fake_budget_drip_builder(0).quantity(100).category_id(0).build().unwrap(), + make_fake_budget_drip_builder(1).quantity(120).category_id(0).build().unwrap(), + ]; + + let result = calculate_budgets_accrual(&category, &budget_drips); + + assert!(result.is_ok()); + assert_eq!(result.unwrap(), 220); + } +} diff --git a/schist_queries/src/utils/calculate_category_balance.rs b/schist_queries/src/utils/calculate_category_balance.rs new file mode 100644 index 0000000..73e80cd --- /dev/null +++ b/schist_queries/src/utils/calculate_category_balance.rs @@ -0,0 +1,130 @@ +use anyhow::Result; +use schist_models::{budget_drip::BudgetDrip, category::Category}; + +use super::{calculate_budgets_accrual, find_by_id_or}; + +pub fn calculate_category_balance( + category: &Category, + transaction_sums: &[(i32, i64)], + category_transfer_from_sums: &[(i32, i64)], + category_transfer_to_sums: &[(i32, i64)], + budget_drips: &[BudgetDrip], +) -> Result<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_drips)?; + + Ok( + transaction_sum + + budget_accruals_sum + + category_transfer_to_sum + - category_transfer_from_sum + ) +} + +#[cfg(test)] +mod test { + use schist_fakes::{budget_drip::make_fake_budget_drip_builder, category::make_fake_category}; + + use super::calculate_category_balance; + + #[test] + fn when_no_data_then_returns_zero() { + let category = make_fake_category(0); + + let result = calculate_category_balance(&category, &[], &[], &[], &[]); + + assert!(result.is_ok()); + assert_eq!(result.unwrap(), 0_i64); + } + + #[test] + fn when_data_only_for_another_category_then_returns_zero() { + let category = make_fake_category(0); + let transaction_sums = [(1, 100)]; + let category_transfer_from_sums = [(1, 91)]; + let category_transfer_to_sums = [(2, 79)]; + let budget_drips = [ + make_fake_budget_drip_builder(0).quantity(100).category_id(1).build().unwrap(), + ]; + + let result = calculate_category_balance( + &category, + &transaction_sums, + &category_transfer_from_sums, + &category_transfer_to_sums, + &budget_drips, + ); + + assert!(result.is_ok()); + assert_eq!(result.unwrap(), 0_i64); + } + + #[test] + fn when_transaction_sum_is_zero_then_returns_zero() { + let category = make_fake_category(0); + let transaction_sums = [(0, 0)]; + let category_transfer_from_sums = []; + let category_transfer_to_sums = []; + let budget_drips = []; + + let result = calculate_category_balance( + &category, + &transaction_sums, + &category_transfer_from_sums, + &category_transfer_to_sums, + &budget_drips, + ); + + assert!(result.is_ok()); + assert_eq!(result.unwrap(), 0_i64); + } + + #[test] + fn when_category_transfers_are_zero_then_returns_zero() { + let category = make_fake_category(0); + let transaction_sums = []; + let category_transfer_from_sums = [(0, 0)]; + let category_transfer_to_sums = [(0, 0)]; + let budget_drips = []; + + let result = calculate_category_balance( + &category, + &transaction_sums, + &category_transfer_from_sums, + &category_transfer_to_sums, + &budget_drips, + ); + + assert!(result.is_ok()); + assert_eq!(result.unwrap(), 0_i64); + } + + #[test] + fn when_some_data_then_calculates_as_expected() { + let category = make_fake_category(0); + let transaction_sums = [(0, 100)]; + let category_transfer_from_sums = [(0, 91)]; + let category_transfer_to_sums = [(0, 79)]; + let budget_drips = [ + make_fake_budget_drip_builder(0).quantity(77).category_id(0).build().unwrap(), + make_fake_budget_drip_builder(0).quantity(77).category_id(0).build().unwrap(), + make_fake_budget_drip_builder(0).quantity(77).category_id(0).build().unwrap(), + make_fake_budget_drip_builder(0).quantity(77).category_id(0).build().unwrap(), + make_fake_budget_drip_builder(0).quantity(77).category_id(0).build().unwrap(), + ]; + + let result = calculate_category_balance( + &category, + &transaction_sums, + &category_transfer_from_sums, + &category_transfer_to_sums, + &budget_drips, + ); + + let expected_result = 100 + (-91) + 79 + 77 * 5; + assert!(result.is_ok()); + assert_eq!(result.unwrap(), expected_result); + } +} diff --git a/schist_queries/src/utils/find_by_id_or.rs b/schist_queries/src/utils/find_by_id_or.rs new file mode 100644 index 0000000..8335e5c --- /dev/null +++ b/schist_queries/src/utils/find_by_id_or.rs @@ -0,0 +1,41 @@ +pub fn find_by_id_or<Id: PartialEq, Val: Copy>( + arr: &[(Id, Val)], + id: Id, + default: Val, +) -> Val { + arr.iter() + .find(|(elem_id, _)| *elem_id == id) + .map_or(default, |row| row.1) +} + +#[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, 100), (2, 200)]; + + let result = find_by_id_or(&arr, 1, 42); + + assert_eq!(result, 42); + } + + #[test] + fn when_id_in_elements_then_return_value() { + let arr = [(1, 67)]; + + let result = find_by_id_or(&arr, 1, 42); + + assert_eq!(result, 67); + } +} diff --git a/schist_queries/src/utils/mod.rs b/schist_queries/src/utils/mod.rs new file mode 100644 index 0000000..f2653d8 --- /dev/null +++ b/schist_queries/src/utils/mod.rs @@ -0,0 +1,8 @@ +mod calculate_budgets_accrual; +mod calculate_category_balance; +mod find_by_id_or; + +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; |
