summaryrefslogtreecommitdiff
path: root/schist_queries/src/utils
diff options
context:
space:
mode:
authorJoe Carstairs <me@joeac.net>2024-12-12 08:28:04 +0000
committerJoe Carstairs <me@joeac.net>2024-12-12 08:28:04 +0000
commit54894f9de9bad4fecb2a116d59a03cdd003f84c0 (patch)
tree6ce5517cecf23d4e93d7a381a374e1fa6c810cee /schist_queries/src/utils
parent8a30bcbdf9264d235bf93da3df8e170cfde53d02 (diff)
Moves rust workspace to root
Diffstat (limited to 'schist_queries/src/utils')
-rw-r--r--schist_queries/src/utils/calculate_budgets_accrual.rs72
-rw-r--r--schist_queries/src/utils/calculate_category_balance.rs130
-rw-r--r--schist_queries/src/utils/find_by_id_or.rs41
-rw-r--r--schist_queries/src/utils/mod.rs8
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;