summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Carstairs <me@joeac.net>2026-01-15 22:35:39 +0000
committerJoe Carstairs <me@joeac.net>2026-01-17 11:49:54 +0000
commit2809e6a2ef3ea636f3de5873f6c874923b410400 (patch)
treec018f557a34efcec5bdb3780be6fba898d37d074
parent1056421dd45b7e9af6f63a95026cb069cfa34e29 (diff)
renames categories -> buckets, refactors category_transfers -> bucket_transactions
-rw-r--r--schist_core/schist_fakes/src/bucket_transaction.rs15
-rw-r--r--schist_core/schist_fakes/src/bucket_transfer.rs16
-rw-r--r--schist_core/schist_fakes/src/lib.rs2
-rw-r--r--schist_core/schist_models/migrations/2024-08-31-084439_initial_setup/down.sql2
-rw-r--r--schist_core/schist_models/migrations/2024-08-31-084439_initial_setup/up.sql11
-rw-r--r--schist_core/schist_models/src/bucket.rs2
-rw-r--r--schist_core/schist_models/src/bucket_transaction.rs (renamed from schist_core/schist_models/src/bucket_transfer.rs)7
-rw-r--r--schist_core/schist_models/src/lib.rs4
-rw-r--r--schist_core/schist_models/src/schema.rs8
-rw-r--r--schist_core/schist_models/user_data.sqlitebin45056 -> 49152 bytes
-rw-r--r--schist_core/schist_queries/src/bucket_transactions.rs65
-rw-r--r--schist_core/schist_queries/src/bucket_transfers.rs82
-rw-r--r--schist_core/schist_queries/src/clear.rs6
-rw-r--r--schist_core/schist_queries/src/lib.rs2
-rw-r--r--schist_core/schist_queries/tests/bucket_transactions.rs160
-rw-r--r--schist_core/schist_queries/tests/buckets.rs83
-rw-r--r--schist_core/schist_queries/tests/category_transfers.rs201
-rw-r--r--transformers/actualbudget_transformer/actualbudget_queries/src/actualbudget_accounts.rs21
-rw-r--r--transformers/actualbudget_transformer/actualbudget_queries/tests/actualbudget_accounts.rs15
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/actualbudget_state.rs16
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/schist_state.rs8
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state.rs10
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/is_category_transfer.rs (renamed from transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/is_bucket_transfer.rs)14
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_accounts.rs4
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_bucket_transactions.rs406
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_state.rs12
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_transactions.rs4
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_transactions_to_bucket_transfers.rs383
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/bucket_transaction_matchers.rs51
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/bucket_transfer_matchers.rs8
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/mod.rs4
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/run.rs22
32 files changed, 860 insertions, 784 deletions
diff --git a/schist_core/schist_fakes/src/bucket_transaction.rs b/schist_core/schist_fakes/src/bucket_transaction.rs
new file mode 100644
index 0000000..3dd0a6f
--- /dev/null
+++ b/schist_core/schist_fakes/src/bucket_transaction.rs
@@ -0,0 +1,15 @@
+use schist_models::{BucketTransaction, BucketTransactionBuilder};
+
+pub fn make_fake_bucket_transaction(id: i32) -> BucketTransaction {
+ make_fake_bucket_transaction_builder(id).build().unwrap()
+}
+
+pub fn make_fake_bucket_transaction_builder(id: i32) -> BucketTransactionBuilder {
+ let mut builder = BucketTransactionBuilder::default();
+ builder
+ .id(id)
+ .description(String::from("Fake bucket transaction"))
+ .amount(0)
+ .bucket_id(1);
+ builder
+}
diff --git a/schist_core/schist_fakes/src/bucket_transfer.rs b/schist_core/schist_fakes/src/bucket_transfer.rs
deleted file mode 100644
index 1342ca2..0000000
--- a/schist_core/schist_fakes/src/bucket_transfer.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-use schist_models::{BucketTransfer, BucketTransferBuilder};
-
-pub fn make_fake_bucket_transfer(id: i32) -> BucketTransfer {
- make_fake_bucket_transfer_builder(id).build().unwrap()
-}
-
-pub fn make_fake_bucket_transfer_builder(id: i32) -> BucketTransferBuilder {
- let mut builder = BucketTransferBuilder::default();
- builder
- .id(id)
- .description(String::from("Fake bucket transfer"))
- .amount(0)
- .from_bucket_id(0)
- .to_bucket_id(1);
- builder
-}
diff --git a/schist_core/schist_fakes/src/lib.rs b/schist_core/schist_fakes/src/lib.rs
index 0e4cbb4..7ac98fa 100644
--- a/schist_core/schist_fakes/src/lib.rs
+++ b/schist_core/schist_fakes/src/lib.rs
@@ -1,7 +1,7 @@
pub mod account;
pub mod account_transfer;
pub mod bucket;
-pub mod bucket_transfer;
+pub mod bucket_transaction;
pub mod drip;
pub mod pipe;
pub mod transaction;
diff --git a/schist_core/schist_models/migrations/2024-08-31-084439_initial_setup/down.sql b/schist_core/schist_models/migrations/2024-08-31-084439_initial_setup/down.sql
index 3b2c73e..f6ead07 100644
--- a/schist_core/schist_models/migrations/2024-08-31-084439_initial_setup/down.sql
+++ b/schist_core/schist_models/migrations/2024-08-31-084439_initial_setup/down.sql
@@ -1,7 +1,7 @@
DROP TABLE accounts;
DROP TABLE account_transfers;
DROP TABLE buckets;
-DROP TABLE bucket_transfers;
+DROP TABLE bucket_transactions;
DROP TABLE drips;
DROP TABLE pipes;
DROP TABLE transactions;
diff --git a/schist_core/schist_models/migrations/2024-08-31-084439_initial_setup/up.sql b/schist_core/schist_models/migrations/2024-08-31-084439_initial_setup/up.sql
index b37c626..e645d43 100644
--- a/schist_core/schist_models/migrations/2024-08-31-084439_initial_setup/up.sql
+++ b/schist_core/schist_models/migrations/2024-08-31-084439_initial_setup/up.sql
@@ -32,17 +32,12 @@ CREATE TABLE buckets(
name TEXT NOT NULL
);
-CREATE TABLE bucket_transfers(
+CREATE TABLE bucket_transactions(
id INTEGER NOT NULL PRIMARY KEY,
amount INTEGER NOT NULL,
+ bucket_id INTEGER NOT NULL,
description TEXT NOT NULL,
- from_bucket_id INTEGER NOT NULL,
- to_bucket_id INTEGER NOT NULL,
- FOREIGN KEY (from_bucket_id)
- REFERENCES buckets (id)
- ON UPDATE CASCADE
- ON DELETE RESTRICT,
- FOREIGN KEY (to_bucket_id)
+ FOREIGN KEY (bucket_id)
REFERENCES buckets (id)
ON UPDATE CASCADE
ON DELETE RESTRICT
diff --git a/schist_core/schist_models/src/bucket.rs b/schist_core/schist_models/src/bucket.rs
index 67ed31e..debbab7 100644
--- a/schist_core/schist_models/src/bucket.rs
+++ b/schist_core/schist_models/src/bucket.rs
@@ -35,9 +35,7 @@ impl Bucket {
.iter()
.all(|t| t.bucket_id.is_none_or(|id| id != self.id))
}
-}
-impl Bucket {
pub fn pretty_balance_per_100(&self) -> String {
let abs_balance_per_100 = self.balance.unwrap_or(0).div(100).abs();
if self.balance.is_none_or(|balance| balance >= 0) {
diff --git a/schist_core/schist_models/src/bucket_transfer.rs b/schist_core/schist_models/src/bucket_transaction.rs
index 7c3a9d2..2aeae8a 100644
--- a/schist_core/schist_models/src/bucket_transfer.rs
+++ b/schist_core/schist_models/src/bucket_transaction.rs
@@ -2,11 +2,10 @@ use derive_builder::Builder;
use diesel::prelude::*;
#[derive(Builder, Queryable, Identifiable, Selectable, Debug, PartialEq, Insertable)]
-#[diesel(table_name = crate::schema::bucket_transfers)]
-pub struct BucketTransfer {
+#[diesel(table_name = crate::schema::bucket_transactions)]
+pub struct BucketTransaction {
pub id: i32,
pub amount: i32,
+ pub bucket_id: i32,
pub description: String,
- pub from_bucket_id: i32,
- pub to_bucket_id: i32,
}
diff --git a/schist_core/schist_models/src/lib.rs b/schist_core/schist_models/src/lib.rs
index 3aa4733..2a119cb 100644
--- a/schist_core/schist_models/src/lib.rs
+++ b/schist_core/schist_models/src/lib.rs
@@ -1,7 +1,7 @@
mod account;
mod account_transfer;
mod bucket;
-mod bucket_transfer;
+mod bucket_transaction;
mod budget_period_unit;
mod date_utc;
mod datetime_utc;
@@ -15,7 +15,7 @@ pub mod schema;
pub use account::Account;
pub use account_transfer::{AccountTransfer, AccountTransferBuilder};
pub use bucket::{Bucket, BucketBuilder};
-pub use bucket_transfer::{BucketTransfer, BucketTransferBuilder};
+pub use bucket_transaction::{BucketTransaction, BucketTransactionBuilder};
pub use budget_period_unit::BudgetPeriodUnit;
pub use date_utc::DateUtc;
pub use datetime_utc::DatetimeUtc;
diff --git a/schist_core/schist_models/src/schema.rs b/schist_core/schist_models/src/schema.rs
index d16e636..8744696 100644
--- a/schist_core/schist_models/src/schema.rs
+++ b/schist_core/schist_models/src/schema.rs
@@ -21,12 +21,11 @@ diesel::table! {
}
diesel::table! {
- bucket_transfers (id) {
+ bucket_transactions (id) {
id -> Integer,
amount -> Integer,
+ bucket_id -> Integer,
description -> Text,
- from_bucket_id -> Integer,
- to_bucket_id -> Integer,
}
}
@@ -74,6 +73,7 @@ diesel::table! {
}
}
+diesel::joinable!(bucket_transactions -> buckets (bucket_id));
diesel::joinable!(drips -> buckets (bucket_id));
diesel::joinable!(pipes -> buckets (bucket_id));
diesel::joinable!(transactions -> accounts (account_id));
@@ -81,7 +81,7 @@ diesel::joinable!(transactions -> accounts (account_id));
diesel::allow_tables_to_appear_in_same_query!(
account_transfers,
accounts,
- bucket_transfers,
+ bucket_transactions,
buckets,
drips,
pipes,
diff --git a/schist_core/schist_models/user_data.sqlite b/schist_core/schist_models/user_data.sqlite
index 175ce60..81fd25c 100644
--- a/schist_core/schist_models/user_data.sqlite
+++ b/schist_core/schist_models/user_data.sqlite
Binary files differ
diff --git a/schist_core/schist_queries/src/bucket_transactions.rs b/schist_core/schist_queries/src/bucket_transactions.rs
new file mode 100644
index 0000000..da06341
--- /dev/null
+++ b/schist_core/schist_queries/src/bucket_transactions.rs
@@ -0,0 +1,65 @@
+use anyhow::{Context, Result};
+use diesel::{dsl::sum, QueryDsl, RunQueryDsl, SelectableHelper, SqliteConnection};
+use schist_models::BucketTransaction;
+use schist_schema::schema::bucket_transactions::{
+ self as bucket_transactions_schema, dsl::bucket_transactions as bucket_transactions_table,
+};
+
+pub fn delete_all_bucket_transactions(connection: &mut SqliteConnection) -> Result<usize> {
+ let num_rows_deleted = diesel::delete(bucket_transactions_table)
+ .execute(connection)
+ .with_context(|| "failed to delete all bucket transactions")?;
+ Ok(num_rows_deleted)
+}
+
+pub fn get_all_bucket_transactions(
+ connection: &mut SqliteConnection,
+) -> Result<Vec<BucketTransaction>> {
+ let all_bucket_transactions = bucket_transactions_table
+ .select(BucketTransaction::as_select())
+ .load(connection)
+ .with_context(|| "failed to get all bucket transactions")?;
+ Ok(all_bucket_transactions)
+}
+
+pub fn insert_bucket_transactions(
+ bucket_transactions: &[BucketTransaction],
+ connection: &mut SqliteConnection,
+) -> Result<usize> {
+ let num_rows_inserted = diesel::insert_into(bucket_transactions_table)
+ .values(bucket_transactions)
+ .execute(connection)
+ .with_context(|| insert_err_msg(&bucket_transactions))?;
+ Ok(num_rows_inserted)
+}
+
+fn insert_err_msg(bucket_transactions: &[BucketTransaction]) -> String {
+ format!(
+ "failed to insert bucket transactions: [{}]",
+ bucket_transactions
+ .iter()
+ .map(|ct| ct.id.to_string())
+ .collect::<Vec<String>>()
+ .join(", ")
+ )
+}
+
+pub fn sum_bucket_transaction_amount_per_bucket_id(
+ connection: &mut SqliteConnection,
+) -> Result<Vec<(i32, i64)>> {
+ let sum = bucket_transactions_table
+ .group_by(bucket_transactions_schema::bucket_id)
+ .select((
+ bucket_transactions_schema::bucket_id,
+ sum(bucket_transactions_schema::amount),
+ ))
+ .load::<(i32, Option<i64>)>(connection)
+ .map(|result| {
+ result
+ .iter()
+ .map(|sum| (sum.0, sum.1.unwrap_or(0)))
+ .collect()
+ })
+ .with_context(|| "failed to sum bucket transaction amount per bucket ID")?;
+ Ok(sum)
+}
diff --git a/schist_core/schist_queries/src/bucket_transfers.rs b/schist_core/schist_queries/src/bucket_transfers.rs
deleted file mode 100644
index 652c8e0..0000000
--- a/schist_core/schist_queries/src/bucket_transfers.rs
+++ /dev/null
@@ -1,82 +0,0 @@
-use anyhow::{Context, Result};
-use diesel::{dsl::sum, QueryDsl, RunQueryDsl, SelectableHelper, SqliteConnection};
-use schist_models::BucketTransfer;
-use schist_schema::schema::bucket_transfers::{
- self as bucket_transfers_schema, dsl::bucket_transfers as bucket_transfers_table,
-};
-
-pub fn delete_all_bucket_transfers(connection: &mut SqliteConnection) -> Result<usize> {
- let num_rows_deleted = diesel::delete(bucket_transfers_table)
- .execute(connection)
- .with_context(|| "failed to delete all bucket transfers")?;
- Ok(num_rows_deleted)
-}
-
-pub fn get_all_bucket_transfers(connection: &mut SqliteConnection) -> Result<Vec<BucketTransfer>> {
- let all_bucket_transfers = bucket_transfers_table
- .select(BucketTransfer::as_select())
- .load(connection)
- .with_context(|| "failed to get all bucket transfers")?;
- Ok(all_bucket_transfers)
-}
-
-pub fn insert_bucket_transfers(
- bucket_transfers: &[BucketTransfer],
- connection: &mut SqliteConnection,
-) -> Result<usize> {
- let num_rows_inserted = diesel::insert_into(bucket_transfers_table)
- .values(bucket_transfers)
- .execute(connection)
- .with_context(|| insert_err_msg(&bucket_transfers))?;
- Ok(num_rows_inserted)
-}
-
-fn insert_err_msg(bucket_transfers: &[BucketTransfer]) -> String {
- format!(
- "failed to insert bucket transfers: [{}]",
- bucket_transfers
- .iter()
- .map(|ct| ct.id.to_string())
- .collect::<Vec<String>>()
- .join(", ")
- )
-}
-
-pub fn sum_bucket_transfer_quantity_per_from_bucket_id(
- connection: &mut SqliteConnection,
-) -> Result<Vec<(i32, i64)>> {
- let sum = bucket_transfers_table
- .group_by(bucket_transfers_schema::from_bucket_id)
- .select((
- bucket_transfers_schema::from_bucket_id,
- sum(bucket_transfers_schema::amount),
- ))
- .load::<(i32, Option<i64>)>(connection)
- .map(|result| {
- result
- .iter()
- .map(|sum| (sum.0, sum.1.unwrap_or(0)))
- .collect()
- })
- .with_context(|| "failed to sum bucket transfer quantity per from bucket ID")?;
- Ok(sum)
-}
-
-pub fn sum_bucket_transfer_quantity_per_to_bucket_id(
- connection: &mut SqliteConnection,
-) -> Result<Vec<(i32, i64)>> {
- let sum = bucket_transfers_table
- .group_by(bucket_transfers_schema::to_bucket_id)
- .select((
- bucket_transfers_schema::to_bucket_id,
- sum(bucket_transfers_schema::amount),
- ))
- .load::<(i32, Option<i64>)>(connection)
- .map(|vec| {
- vec.iter()
- .map(|(id, sum)| (*id, sum.unwrap_or(0)))
- .collect()
- })
- .with_context(|| "failed to sum bucket transfer quantity per to bucket ID")?;
- Ok(sum)
-}
diff --git a/schist_core/schist_queries/src/clear.rs b/schist_core/schist_queries/src/clear.rs
index a5a82f3..845e109 100644
--- a/schist_core/schist_queries/src/clear.rs
+++ b/schist_core/schist_queries/src/clear.rs
@@ -2,7 +2,9 @@ use anyhow::Result;
use diesel::SqliteConnection;
use crate::{
- account_transfers::delete_all_account_transfers, accounts::delete_all_accounts, bucket_transfers::delete_all_bucket_transfers, buckets::delete_all_buckets, drips::delete_all_drips, pipes::delete_all_pipes, transactions::delete_all_transactions
+ account_transfers::delete_all_account_transfers, accounts::delete_all_accounts,
+ bucket_transactions::delete_all_bucket_transactions, buckets::delete_all_buckets,
+ drips::delete_all_drips, pipes::delete_all_pipes, transactions::delete_all_transactions,
};
pub fn clear(connection: &mut SqliteConnection) -> Result<()> {
@@ -11,7 +13,7 @@ pub fn clear(connection: &mut SqliteConnection) -> Result<()> {
delete_all_pipes(connection)?;
delete_all_transactions(connection)?;
delete_all_accounts(connection)?;
- delete_all_bucket_transfers(connection)?;
+ delete_all_bucket_transactions(connection)?;
delete_all_buckets(connection)?;
Ok(())
}
diff --git a/schist_core/schist_queries/src/lib.rs b/schist_core/schist_queries/src/lib.rs
index ccd558d..ee74d6b 100644
--- a/schist_core/schist_queries/src/lib.rs
+++ b/schist_core/schist_queries/src/lib.rs
@@ -1,6 +1,6 @@
pub mod account_transfers;
pub mod accounts;
-pub mod bucket_transfers;
+pub mod bucket_transactions;
pub mod buckets;
pub mod clear;
pub mod drips;
diff --git a/schist_core/schist_queries/tests/bucket_transactions.rs b/schist_core/schist_queries/tests/bucket_transactions.rs
new file mode 100644
index 0000000..9c877af
--- /dev/null
+++ b/schist_core/schist_queries/tests/bucket_transactions.rs
@@ -0,0 +1,160 @@
+mod common;
+
+use common::test_context::TestContext;
+use diesel::{Connection, SqliteConnection};
+use schist_fakes::{
+ bucket::make_fake_bucket, bucket_transaction::make_fake_bucket_transaction_builder,
+};
+use schist_queries as queries;
+
+#[test]
+fn when_insert_bucket_transactions_then_returns_num_bucket_transactions() {
+ let context = TestContext::new();
+ let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
+ let buckets = [make_fake_bucket(0), make_fake_bucket(1)];
+ let bucket_transactions = [
+ make_fake_bucket_transaction_builder(0)
+ .bucket_id(0)
+ .build()
+ .unwrap(),
+ make_fake_bucket_transaction_builder(1)
+ .bucket_id(1)
+ .build()
+ .unwrap(),
+ ];
+ let _ = queries::buckets::insert_buckets(&buckets, connection);
+
+ let num_bucket_transactions_inserted =
+ queries::bucket_transactions::insert_bucket_transactions(&bucket_transactions, connection)
+ .unwrap();
+
+ assert_eq!(num_bucket_transactions_inserted, 2);
+}
+
+#[test]
+fn given_bucket_transactions_when_get_all_bucket_transactions_then_return_bucket_transactions() {
+ let context = TestContext::new();
+ let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
+ let buckets = [make_fake_bucket(0), make_fake_bucket(1)];
+ let bucket_transactions = [
+ make_fake_bucket_transaction_builder(0)
+ .bucket_id(0)
+ .build()
+ .unwrap(),
+ make_fake_bucket_transaction_builder(1)
+ .bucket_id(1)
+ .build()
+ .unwrap(),
+ ];
+ let _ = queries::buckets::insert_buckets(&buckets, connection);
+ let _ =
+ queries::bucket_transactions::insert_bucket_transactions(&bucket_transactions, connection)
+ .unwrap();
+
+ let bucket_transactions_in_db =
+ queries::bucket_transactions::get_all_bucket_transactions(connection).unwrap();
+
+ assert_eq!(bucket_transactions_in_db.len(), bucket_transactions.len());
+ for bucket_transaction in &bucket_transactions {
+ assert!(bucket_transactions_in_db
+ .iter()
+ .any(|bucket_transaction_in_db| bucket_transaction_in_db.eq(&bucket_transaction)));
+ }
+ for bucket_transaction_in_db in bucket_transactions_in_db {
+ assert!(bucket_transactions
+ .iter()
+ .any(|bucket_transaction| bucket_transaction.eq(&bucket_transaction_in_db)));
+ }
+}
+
+#[test]
+fn given_bucket_transactions_when_delete_all_bucket_transactions_then_return_num_of_bucket_transactions(
+) {
+ let context = TestContext::new();
+ let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
+ let buckets = [make_fake_bucket(0), make_fake_bucket(1)];
+ let bucket_transactions = [
+ make_fake_bucket_transaction_builder(0)
+ .bucket_id(0)
+ .build()
+ .unwrap(),
+ make_fake_bucket_transaction_builder(1)
+ .bucket_id(1)
+ .build()
+ .unwrap(),
+ ];
+ let _ = queries::buckets::insert_buckets(&buckets, connection);
+ let _ =
+ queries::bucket_transactions::insert_bucket_transactions(&bucket_transactions, connection)
+ .unwrap();
+
+ let num_bucket_transactions_deleted =
+ queries::bucket_transactions::delete_all_bucket_transactions(connection).unwrap();
+
+ assert_eq!(num_bucket_transactions_deleted, bucket_transactions.len());
+}
+
+#[test]
+fn given_deleted_bucket_transactions_when_get_all_bucket_transactions_then_return_empty() {
+ let context = TestContext::new();
+ let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
+ let buckets = [make_fake_bucket(0), make_fake_bucket(1)];
+ let bucket_transactions = [
+ make_fake_bucket_transaction_builder(0)
+ .bucket_id(0)
+ .build()
+ .unwrap(),
+ make_fake_bucket_transaction_builder(1)
+ .bucket_id(1)
+ .build()
+ .unwrap(),
+ ];
+ let _ = queries::buckets::insert_buckets(&buckets, connection);
+ let _ =
+ queries::bucket_transactions::insert_bucket_transactions(&bucket_transactions, connection)
+ .unwrap();
+ let _ = queries::bucket_transactions::delete_all_bucket_transactions(connection).unwrap();
+
+ let bucket_transactions_returned =
+ queries::bucket_transactions::get_all_bucket_transactions(connection).unwrap();
+
+ assert_eq!(bucket_transactions_returned.len(), 0);
+}
+
+#[test]
+fn given_bucket_transactions_when_sum_quantity_per_bucket_id_then_returns_sum_per_bucket_id() {
+ let context = TestContext::new();
+ let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
+ let buckets = [make_fake_bucket(0), make_fake_bucket(1)];
+ let bucket_transactions = [
+ make_fake_bucket_transaction_builder(0)
+ .bucket_id(0)
+ .amount(1)
+ .build()
+ .unwrap(),
+ make_fake_bucket_transaction_builder(1)
+ .bucket_id(0)
+ .amount(2)
+ .build()
+ .unwrap(),
+ make_fake_bucket_transaction_builder(2)
+ .bucket_id(1)
+ .amount(4)
+ .build()
+ .unwrap(),
+ ];
+ let _ = queries::buckets::insert_buckets(&buckets, connection);
+ let _ =
+ queries::bucket_transactions::insert_bucket_transactions(&bucket_transactions, connection)
+ .unwrap();
+
+ let sums =
+ queries::bucket_transactions::sum_bucket_transaction_amount_per_bucket_id(connection);
+
+ assert!(sums.is_ok());
+ let mut sums = sums.unwrap();
+ sums.sort_by_key(|sum| sum.0);
+ assert_eq!(buckets.len(), sums.len());
+ assert_eq!(3, sums[0].1);
+ assert_eq!(4, sums[1].1);
+}
diff --git a/schist_core/schist_queries/tests/buckets.rs b/schist_core/schist_queries/tests/buckets.rs
new file mode 100644
index 0000000..72dd4c7
--- /dev/null
+++ b/schist_core/schist_queries/tests/buckets.rs
@@ -0,0 +1,83 @@
+mod common;
+
+use common::test_context::TestContext;
+use diesel::{Connection, SqliteConnection};
+use schist_fakes::bucket::make_fake_bucket;
+use schist_models::Bucket;
+use schist_queries as queries;
+
+fn given_buckets(connection: &mut SqliteConnection) -> Vec<Bucket> {
+ let buckets = vec![make_fake_bucket(0), make_fake_bucket(1)];
+ let _ = queries::buckets::insert_buckets(&buckets, connection).unwrap();
+ buckets
+}
+
+#[test]
+fn when_insert_buckets_then_returns_num_buckets() {
+ let context = TestContext::new();
+ let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
+ let buckets = [make_fake_bucket(0), make_fake_bucket(1)];
+
+ let num_buckets_inserted = queries::buckets::insert_buckets(&buckets, connection).unwrap();
+
+ assert_eq!(num_buckets_inserted, 2);
+}
+
+#[test]
+fn given_buckets_when_get_all_buckets_then_return_buckets() {
+ let context = TestContext::new();
+ let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
+ let buckets = given_buckets(connection);
+
+ let buckets_in_db = queries::buckets::get_all_buckets(connection).unwrap();
+
+ assert_eq!(buckets_in_db.len(), buckets.len());
+ for bucket in &buckets {
+ assert!(buckets_in_db
+ .iter()
+ .any(|bucket_in_db| bucket_in_db.eq(&bucket)));
+ }
+ for bucket_in_db in buckets_in_db {
+ assert!(buckets.iter().any(|bucket| bucket.eq(&bucket_in_db)));
+ }
+}
+
+#[test]
+fn given_buckets_when_delete_all_buckets_then_return_num_of_buckets() {
+ let context = TestContext::new();
+ let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
+ let buckets = given_buckets(connection);
+
+ let num_buckets_deleted = queries::buckets::delete_all_buckets(connection).unwrap();
+
+ assert_eq!(num_buckets_deleted, buckets.len());
+}
+
+#[test]
+fn given_deleted_buckets_when_get_all_buckets_then_return_empty() {
+ let context = TestContext::new();
+ let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
+ given_buckets(connection);
+ let _ = queries::buckets::delete_all_buckets(connection).unwrap();
+
+ let buckets_returned = queries::buckets::get_all_buckets(connection).unwrap();
+
+ assert_eq!(buckets_returned.len(), 0);
+}
+
+#[test]
+fn given_buckets_when_get_all_ids_then_return_all_ids() {
+ let context = TestContext::new();
+ let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
+ let buckets = given_buckets(connection);
+
+ let ids = queries::buckets::get_all_bucket_ids(connection).unwrap();
+
+ assert_eq!(buckets.len(), ids.len());
+ for bucket in &buckets {
+ assert!(ids.iter().any(|id| bucket.id == *id));
+ }
+ for id in ids {
+ assert!(buckets.iter().any(|bucket| bucket.id == id));
+ }
+}
diff --git a/schist_core/schist_queries/tests/category_transfers.rs b/schist_core/schist_queries/tests/category_transfers.rs
deleted file mode 100644
index f7c75a7..0000000
--- a/schist_core/schist_queries/tests/category_transfers.rs
+++ /dev/null
@@ -1,201 +0,0 @@
-mod common;
-
-use common::test_context::TestContext;
-use diesel::{Connection, SqliteConnection};
-use schist_fakes::{bucket::make_fake_bucket, bucket_transfer::make_fake_bucket_transfer_builder};
-use schist_queries as queries;
-
-#[test]
-fn when_insert_bucket_transfers_then_returns_num_bucket_transfers() {
- let context = TestContext::new();
- let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
- let buckets = [make_fake_bucket(0), make_fake_bucket(1)];
- let bucket_transfers = [
- make_fake_bucket_transfer_builder(0)
- .from_bucket_id(0)
- .to_bucket_id(1)
- .build()
- .unwrap(),
- make_fake_bucket_transfer_builder(1)
- .from_bucket_id(0)
- .to_bucket_id(1)
- .build()
- .unwrap(),
- ];
- let _ = queries::buckets::insert_buckets(&buckets, connection);
-
- let num_bucket_transfers_inserted =
- queries::bucket_transfers::insert_bucket_transfers(&bucket_transfers, connection).unwrap();
-
- assert_eq!(num_bucket_transfers_inserted, 2);
-}
-
-#[test]
-fn given_bucket_transfers_when_get_all_bucket_transfers_then_return_bucket_transfers() {
- let context = TestContext::new();
- let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
- let buckets = [make_fake_bucket(0), make_fake_bucket(1)];
- let bucket_transfers = [
- make_fake_bucket_transfer_builder(0)
- .from_bucket_id(0)
- .to_bucket_id(1)
- .build()
- .unwrap(),
- make_fake_bucket_transfer_builder(1)
- .from_bucket_id(0)
- .to_bucket_id(1)
- .build()
- .unwrap(),
- ];
- let _ = queries::buckets::insert_buckets(&buckets, connection);
- let _ =
- queries::bucket_transfers::insert_bucket_transfers(&bucket_transfers, connection).unwrap();
-
- let bucket_transfers_in_db =
- queries::bucket_transfers::get_all_bucket_transfers(connection).unwrap();
-
- assert_eq!(bucket_transfers_in_db.len(), bucket_transfers.len());
- for bucket_transfer in &bucket_transfers {
- assert!(bucket_transfers_in_db
- .iter()
- .any(|bucket_transfer_in_db| bucket_transfer_in_db.eq(&bucket_transfer)));
- }
- for bucket_transfer_in_db in bucket_transfers_in_db {
- assert!(bucket_transfers
- .iter()
- .any(|bucket_transfer| bucket_transfer.eq(&bucket_transfer_in_db)));
- }
-}
-
-#[test]
-fn given_bucket_transfers_when_delete_all_bucket_transfers_then_return_num_of_bucket_transfers() {
- let context = TestContext::new();
- let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
- let buckets = [make_fake_bucket(0), make_fake_bucket(1)];
- let bucket_transfers = [
- make_fake_bucket_transfer_builder(0)
- .from_bucket_id(0)
- .to_bucket_id(1)
- .build()
- .unwrap(),
- make_fake_bucket_transfer_builder(1)
- .from_bucket_id(0)
- .to_bucket_id(1)
- .build()
- .unwrap(),
- ];
- let _ = queries::buckets::insert_buckets(&buckets, connection);
- let _ =
- queries::bucket_transfers::insert_bucket_transfers(&bucket_transfers, connection).unwrap();
-
- let num_bucket_transfers_deleted =
- queries::bucket_transfers::delete_all_bucket_transfers(connection).unwrap();
-
- assert_eq!(num_bucket_transfers_deleted, bucket_transfers.len());
-}
-
-#[test]
-fn given_deleted_bucket_transfers_when_get_all_bucket_transfers_then_return_empty() {
- let context = TestContext::new();
- let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
- let buckets = [make_fake_bucket(0), make_fake_bucket(1)];
- let bucket_transfers = [
- make_fake_bucket_transfer_builder(0)
- .from_bucket_id(0)
- .to_bucket_id(1)
- .build()
- .unwrap(),
- make_fake_bucket_transfer_builder(1)
- .from_bucket_id(0)
- .to_bucket_id(1)
- .build()
- .unwrap(),
- ];
- let _ = queries::buckets::insert_buckets(&buckets, connection);
- let _ =
- queries::bucket_transfers::insert_bucket_transfers(&bucket_transfers, connection).unwrap();
- let _ = queries::bucket_transfers::delete_all_bucket_transfers(connection).unwrap();
-
- let bucket_transfers_returned =
- queries::bucket_transfers::get_all_bucket_transfers(connection).unwrap();
-
- assert_eq!(bucket_transfers_returned.len(), 0);
-}
-
-#[test]
-fn given_bucket_transfers_when_sum_quantity_per_from_bucket_id_then_returns_sum_per_from_bucket_id()
-{
- let context = TestContext::new();
- let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
- let buckets = [make_fake_bucket(0), make_fake_bucket(1)];
- let bucket_transfers = [
- make_fake_bucket_transfer_builder(0)
- .from_bucket_id(0)
- .to_bucket_id(1)
- .amount(1)
- .build()
- .unwrap(),
- make_fake_bucket_transfer_builder(1)
- .from_bucket_id(0)
- .to_bucket_id(1)
- .amount(2)
- .build()
- .unwrap(),
- make_fake_bucket_transfer_builder(2)
- .from_bucket_id(1)
- .to_bucket_id(0)
- .amount(4)
- .build()
- .unwrap(),
- ];
- let _ = queries::buckets::insert_buckets(&buckets, connection);
- let _ =
- queries::bucket_transfers::insert_bucket_transfers(&bucket_transfers, connection).unwrap();
-
- let sums =
- queries::bucket_transfers::sum_bucket_transfer_quantity_per_from_bucket_id(connection);
-
- assert!(sums.is_ok());
- let mut sums = sums.unwrap();
- sums.sort_by_key(|sum| sum.0);
- assert_eq!(buckets.len(), sums.len());
- assert_eq!(3, sums[0].1);
- assert_eq!(4, sums[1].1);
-}
-
-#[test]
-fn given_bucket_transfers_when_sum_quantity_per_to_bucket_id_then_returns_sum_per_to_bucket_id() {
- let context = TestContext::new();
- let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
- let buckets = [make_fake_bucket(0), make_fake_bucket(1)];
- let bucket_transfers = [
- make_fake_bucket_transfer_builder(0)
- .from_bucket_id(0)
- .to_bucket_id(1)
- .amount(1)
- .build()
- .unwrap(),
- make_fake_bucket_transfer_builder(1)
- .from_bucket_id(0)
- .to_bucket_id(1)
- .amount(2)
- .build()
- .unwrap(),
- make_fake_bucket_transfer_builder(2)
- .from_bucket_id(1)
- .to_bucket_id(0)
- .amount(4)
- .build()
- .unwrap(),
- ];
- let _ = queries::buckets::insert_buckets(&buckets, connection);
- let _ =
- queries::bucket_transfers::insert_bucket_transfers(&bucket_transfers, connection).unwrap();
-
- let sums = queries::bucket_transfers::sum_bucket_transfer_quantity_per_to_bucket_id(connection);
-
- assert!(sums.is_ok());
- let mut sums = sums.unwrap();
- sums.sort_by_key(|sum| sum.0);
- assert_eq!([(0, 4), (1, 3)], sums.as_slice());
-}
diff --git a/transformers/actualbudget_transformer/actualbudget_queries/src/actualbudget_accounts.rs b/transformers/actualbudget_transformer/actualbudget_queries/src/actualbudget_accounts.rs
index d499208..8a590a1 100644
--- a/transformers/actualbudget_transformer/actualbudget_queries/src/actualbudget_accounts.rs
+++ b/transformers/actualbudget_transformer/actualbudget_queries/src/actualbudget_accounts.rs
@@ -1,25 +1,14 @@
use actualbudget_models::ActualbudgetAccount;
-use actualbudget_schema::actualbudget_schema::accounts::{
- self as accounts_schema,
- dsl::accounts as accounts_table,
-};
+use actualbudget_schema::actualbudget_schema::accounts::dsl::accounts as accounts_table;
use anyhow::{Context, Result};
-use diesel::{ExpressionMethods, OptionalExtension, QueryDsl, RunQueryDsl, SelectableHelper, SqliteConnection};
+use diesel::{QueryDsl, RunQueryDsl, SelectableHelper, SqliteConnection};
-pub fn get_all_actualbudget_accounts(connection: &mut SqliteConnection) -> Result<Vec<ActualbudgetAccount>> {
+pub fn get_all_actualbudget_accounts(
+ connection: &mut SqliteConnection,
+) -> Result<Vec<ActualbudgetAccount>> {
let actualbudget_accounts = accounts_table
.select(ActualbudgetAccount::as_select())
.load(connection)
.with_context(|| "failed to get all Actualbudget accounts")?;
Ok(actualbudget_accounts)
}
-
-pub fn get_category_transfers_account(connection: &mut SqliteConnection) -> Result<Option<ActualbudgetAccount>> {
- let category_transfers_account = accounts_table
- .filter(accounts_schema::name.eq("Category transfers"))
- .select(ActualbudgetAccount::as_select())
- .first(connection)
- .optional()
- .with_context(|| "failed to get Category Transfers account")?;
- Ok(category_transfers_account)
-}
diff --git a/transformers/actualbudget_transformer/actualbudget_queries/tests/actualbudget_accounts.rs b/transformers/actualbudget_transformer/actualbudget_queries/tests/actualbudget_accounts.rs
index 954cac1..78953f2 100644
--- a/transformers/actualbudget_transformer/actualbudget_queries/tests/actualbudget_accounts.rs
+++ b/transformers/actualbudget_transformer/actualbudget_queries/tests/actualbudget_accounts.rs
@@ -1,6 +1,6 @@
pub mod common;
-use actualbudget_queries::actualbudget_accounts::{get_all_actualbudget_accounts, get_category_transfers_account};
+use actualbudget_queries::actualbudget_accounts::get_all_actualbudget_accounts;
use common::{account_names::ACCOUNT_NAMES, db_url::DB_URL};
use diesel::{Connection, SqliteConnection};
@@ -17,16 +17,3 @@ fn given_test_database_when_get_all_accounts_then_return_accounts() {
assert!(accounts.iter().any(|a| a.name.as_str() == *account_name));
}
}
-
-#[test]
-fn given_test_database_when_get_category_transfer_account_then_return_category_transfer_account() {
- let connection = &mut SqliteConnection::establish(DB_URL).unwrap();
-
- let account = get_category_transfers_account(connection);
-
- assert!(account.is_ok());
- let account = account.unwrap();
- assert!(account.is_some());
- let account = account.unwrap();
- assert!(account.name == "Category transfers");
-}
diff --git a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/actualbudget_state.rs b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/actualbudget_state.rs
index cda63b1..22c1eef 100644
--- a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/actualbudget_state.rs
+++ b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/actualbudget_state.rs
@@ -1,12 +1,18 @@
use std::cmp::min;
use actualbudget_models::{
- ActualbudgetAccount, ActualbudgetCategory, ActualbudgetCategoryGroup, ActualbudgetDate, ActualbudgetPayee, ActualbudgetTransaction, ActualbudgetZeroBudget
+ ActualbudgetAccount, ActualbudgetCategory, ActualbudgetCategoryGroup, ActualbudgetDate,
+ ActualbudgetPayee, ActualbudgetTransaction, ActualbudgetZeroBudget,
};
use actualbudget_queries::{
- actualbudget_accounts::get_all_actualbudget_accounts, actualbudget_categories::get_all_actualbudget_categories, actualbudget_category_groups::get_all_actualbudget_category_groups, actualbudget_payees::get_all_actualbudget_payees, actualbudget_transactions::{
+ actualbudget_accounts::get_all_actualbudget_accounts,
+ actualbudget_categories::get_all_actualbudget_categories,
+ actualbudget_category_groups::get_all_actualbudget_category_groups,
+ actualbudget_payees::get_all_actualbudget_payees,
+ actualbudget_transactions::{
get_all_actualbudget_transactions, get_first_actualbudget_transaction_date,
- }, actualbudget_zero_budgets::{get_all_actualbudget_zero_budgets, get_first_zero_budget_date}
+ },
+ actualbudget_zero_budgets::{get_all_actualbudget_zero_budgets, get_first_zero_budget_date},
};
use anyhow::Result;
use diesel::SqliteConnection;
@@ -31,7 +37,9 @@ pub fn read_actualbudget_state(
),
actualbudget_accounts: get_all_actualbudget_accounts(actualbudget_connection)?,
actualbudget_categories: get_all_actualbudget_categories(actualbudget_connection)?,
- actualbudget_category_groups: get_all_actualbudget_category_groups(actualbudget_connection)?,
+ actualbudget_category_groups: get_all_actualbudget_category_groups(
+ actualbudget_connection,
+ )?,
actualbudget_payees: get_all_actualbudget_payees(actualbudget_connection)?,
actualbudget_zero_budgets: get_all_actualbudget_zero_budgets(actualbudget_connection)?,
actualbudget_transactions: get_all_actualbudget_transactions(actualbudget_connection)?,
diff --git a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/schist_state.rs b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/schist_state.rs
index ca5a15c..f42fd16 100644
--- a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/schist_state.rs
+++ b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/schist_state.rs
@@ -1,7 +1,7 @@
use anyhow::Result;
use diesel::SqliteConnection;
use schist_models::{
- Account, AccountTransfer, Bucket, BucketTransfer, DateUtc, Drip, Pipe, Transaction,
+ Account, AccountTransfer, Bucket, BucketTransaction, DateUtc, Drip, Pipe, Transaction,
};
pub struct SchistState {
@@ -12,7 +12,7 @@ pub struct SchistState {
pub budget_drips: Vec<Drip>,
pub transactions: Vec<Transaction>,
pub pipes: Vec<Pipe>,
- pub bucket_transfers: Vec<BucketTransfer>,
+ pub bucket_transactions: Vec<BucketTransaction>,
}
pub fn export_schist_state(
@@ -32,8 +32,8 @@ pub fn export_schist_state(
schist_connection,
)?;
schist_queries::pipes::insert_pipes(&schist_state.pipes, schist_connection)?;
- schist_queries::bucket_transfers::insert_bucket_transfers(
- &schist_state.bucket_transfers,
+ schist_queries::bucket_transactions::insert_bucket_transactions(
+ &schist_state.bucket_transactions,
schist_connection,
)?;
Ok(())
diff --git a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state.rs b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state.rs
index a116649..1f5ead3 100644
--- a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state.rs
+++ b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state.rs
@@ -1,27 +1,27 @@
mod is_account_transfer;
-mod is_bucket_transfer;
+mod is_category_transfer;
mod transform_account_transfers;
mod transform_accounts;
+mod transform_bucket_transactions;
mod transform_categories_to_buckets;
mod transform_date;
mod transform_id;
mod transform_state;
mod transform_transactions;
-mod transform_transactions_to_bucket_transfers;
mod transform_zero_budgets_to_drips;
mod transform_zero_budgets_to_pipes;
use is_account_transfer::is_account_transfer;
use is_account_transfer::is_not_account_transfer;
-use is_bucket_transfer::is_bucket_transfer;
-use is_bucket_transfer::is_not_bucket_transfer;
+use is_category_transfer::is_category_transfer;
+use is_category_transfer::is_not_category_transfer;
use transform_account_transfers::transform_account_transfers;
use transform_accounts::transform_accounts;
+use transform_bucket_transactions::transform_bucket_transactions;
use transform_categories_to_buckets::transform_categories_to_buckets;
use transform_date::transform_date;
use transform_id::transform_id;
use transform_transactions::transform_transactions;
-use transform_transactions_to_bucket_transfers::transform_transactions_to_bucket_transfers;
use transform_zero_budgets_to_pipes::transform_zero_budgets_to_pipes;
pub use transform_state::transform_state;
diff --git a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/is_bucket_transfer.rs b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/is_category_transfer.rs
index 188697e..75d48b7 100644
--- a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/is_bucket_transfer.rs
+++ b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/is_category_transfer.rs
@@ -1,14 +1,14 @@
use actualbudget_models::ActualbudgetTransaction;
-pub fn is_bucket_transfer(
+pub fn is_category_transfer(
transaction: &ActualbudgetTransaction,
transactions: &[ActualbudgetTransaction],
) -> bool {
- is_parent_bucket_transfer(transaction, transactions)
- || is_child_bucket_transfer(transaction, transactions)
+ is_parent_category_transfer(transaction, transactions)
+ || is_child_category_transfer(transaction, transactions)
}
-fn is_parent_bucket_transfer(
+fn is_parent_category_transfer(
transaction: &ActualbudgetTransaction,
transactions: &[ActualbudgetTransaction],
) -> bool {
@@ -24,7 +24,7 @@ fn is_parent_bucket_transfer(
sum_of_children_amounts == 0
}
-fn is_child_bucket_transfer(
+fn is_child_category_transfer(
transaction: &ActualbudgetTransaction,
transactions: &[ActualbudgetTransaction],
) -> bool {
@@ -38,9 +38,9 @@ fn is_parent_and_child(parent: &ActualbudgetTransaction, child: &ActualbudgetTra
parent.is_parent && child.is_child && child.parent_id.clone().is_some_and(|id| id == parent.id)
}
-pub fn is_not_bucket_transfer(
+pub fn is_not_category_transfer(
transaction: &ActualbudgetTransaction,
transactions: &[ActualbudgetTransaction],
) -> bool {
- !is_bucket_transfer(transaction, transactions)
+ !is_category_transfer(transaction, transactions)
}
diff --git a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_accounts.rs b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_accounts.rs
index 76eaf0c..13f63c0 100644
--- a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_accounts.rs
+++ b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_accounts.rs
@@ -1,7 +1,7 @@
use actualbudget_models::{ActualbudgetAccount, ActualbudgetTransaction};
use schist_models::{Account, DateUtc};
-use super::{is_bucket_transfer, transform_id};
+use super::{is_category_transfer, transform_id};
pub fn transform_accounts(
actualbudget_accounts: &[ActualbudgetAccount],
@@ -22,7 +22,7 @@ fn is_empty_account(
actualbudget_transactions.iter().all(|t| {
t.is_starting_balance() && t.amount == 0
|| t.account_id != actualbudget_account.id
- || is_bucket_transfer(t, actualbudget_transactions)
+ || is_category_transfer(t, actualbudget_transactions)
})
}
diff --git a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_bucket_transactions.rs b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_bucket_transactions.rs
new file mode 100644
index 0000000..22ee95e
--- /dev/null
+++ b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_bucket_transactions.rs
@@ -0,0 +1,406 @@
+use actualbudget_models::ActualbudgetTransaction;
+use anyhow::{bail, Context, Result};
+use schist_models::BucketTransaction;
+
+use super::{is_category_transfer, transform_id};
+
+pub fn transform_bucket_transactions(
+ actualbudget_transactions: &[ActualbudgetTransaction],
+) -> Result<Vec<BucketTransaction>> {
+ let actualbudget_category_transfers = actualbudget_transactions
+ .iter()
+ .filter(|transaction| is_category_transfer(transaction, actualbudget_transactions));
+ let actualbudget_parent_category_transfers: Vec<ActualbudgetTransaction> =
+ actualbudget_category_transfers
+ .clone()
+ .filter(|t| t.is_parent)
+ .map(ActualbudgetTransaction::clone)
+ .collect();
+ let actualbudget_child_category_transfers: Vec<ActualbudgetTransaction> =
+ actualbudget_category_transfers
+ .filter(|t| t.is_child)
+ .map(ActualbudgetTransaction::clone)
+ .collect();
+
+ let mut result = Vec::new();
+ for pct in actualbudget_parent_category_transfers {
+ result.extend(
+ transform_category_transfer(&pct, &actualbudget_child_category_transfers)
+ .with_context(|| "failed to transform bucket transactions")?,
+ )
+ }
+ Ok(result)
+}
+
+fn transform_category_transfer(
+ actualbudget_parent_category_transfer: &ActualbudgetTransaction,
+ actualbudget_child_category_transfers: &[ActualbudgetTransaction],
+) -> Result<Vec<BucketTransaction>> {
+ transform_category_transfer_without_context(
+ actualbudget_parent_category_transfer,
+ actualbudget_child_category_transfers,
+ )
+ .with_context(|| "failed to transform category transfer")
+}
+
+fn transform_category_transfer_without_context(
+ actualbudget_parent_category_transfer: &ActualbudgetTransaction,
+ actualbudget_child_category_transfers: &[ActualbudgetTransaction],
+) -> Result<Vec<BucketTransaction>> {
+ let actualbudget_child_category_transfers = actualbudget_child_category_transfers
+ .iter()
+ .filter(|t| {
+ t.parent_id
+ .clone()
+ .is_some_and(|parent_id| parent_id == actualbudget_parent_category_transfer.id)
+ })
+ .map(ActualbudgetTransaction::clone);
+
+ let withdrawals: Vec<ActualbudgetTransaction> = actualbudget_child_category_transfers
+ .clone()
+ .filter(|t| t.amount < 0)
+ .collect();
+ if withdrawals.len() != 1 {
+ bail!(
+ "actualbudget parent category transfer {} had {} withdrawals",
+ actualbudget_parent_category_transfer.id,
+ withdrawals.len(),
+ );
+ }
+ let withdrawal = withdrawals.get(0).unwrap();
+ println!("withdrawal: {:?}", withdrawal);
+
+ if withdrawal.category_id.is_none() {
+ bail!(
+ "actualbudget child withdrawal {} had no category ID",
+ withdrawal.id
+ );
+ }
+ let withdrawal_bucket_id: i32 = transform_id(&withdrawal.category_id.clone().unwrap());
+
+ let deposits: Vec<ActualbudgetTransaction> = actualbudget_child_category_transfers
+ .clone()
+ .filter(|t| t.amount > 0)
+ .collect();
+ if deposits.len() != 1 {
+ bail!(
+ "actualbudget parent category transfer {} had {} deposits",
+ actualbudget_parent_category_transfer.id,
+ deposits.len(),
+ );
+ }
+ let deposit = deposits.get(0).unwrap();
+ println!("deposit: {:?}", deposit);
+
+ if deposit.category_id.is_none() {
+ bail!(
+ "actualbudget child deposit {} had no category ID",
+ deposit.id
+ );
+ }
+ let deposit_id: i32 = transform_id(&deposit.category_id.clone().unwrap());
+
+ if withdrawal.amount != -deposit.amount {
+ bail!("actualbudget category transfer amounts did not sum to zero");
+ }
+
+ let quantity: i32 = deposit.amount.try_into().unwrap();
+
+ Ok(vec![
+ BucketTransaction {
+ id: transform_id(&deposit.id),
+ description: actualbudget_parent_category_transfer
+ .notes
+ .clone()
+ .unwrap_or_else(String::new),
+ amount: -quantity,
+ bucket_id: withdrawal_bucket_id,
+ },
+ BucketTransaction {
+ id: transform_id(&withdrawal.id),
+ description: actualbudget_parent_category_transfer
+ .notes
+ .clone()
+ .unwrap_or_else(String::new),
+ amount: quantity,
+ bucket_id: deposit_id,
+ },
+ ])
+}
+
+#[cfg(test)]
+mod test {
+ use actualbudget_fakes::actualbudget_transaction::make_fake_actualbudget_transaction_builder;
+ use actualbudget_models::{ActualbudgetTransaction, ActualbudgetTransactionBuilder};
+ use schist_models::BucketTransaction;
+
+ use crate::transform_state::transform_id::transform_id;
+
+ use super::transform_bucket_transactions;
+
+ #[test]
+ fn when_one_category_transfer_then_transforms() {
+ let actualbudget_transactions = [
+ make_fake_parent_transaction("0"),
+ make_fake_child_withdrawal("1", "0"),
+ make_fake_child_deposit("2", "0"),
+ ];
+
+ let result = transform_bucket_transactions(&actualbudget_transactions);
+
+ assert!(result.is_ok());
+ let bucket_transactions = result.unwrap();
+ assert_eq!(2, bucket_transactions.len());
+
+ let bucket_withdrawal = bucket_transactions.iter().find(|bt| bt.amount < 0).unwrap();
+ assert_eq!(-100, bucket_withdrawal.amount);
+ assert_eq!("I was a parent transaction", bucket_withdrawal.description);
+ assert_eq!(transform_id("0"), bucket_withdrawal.bucket_id);
+
+ let bucket_deposit = bucket_transactions.iter().find(|bt| bt.amount > 0).unwrap();
+ assert_eq!(100, bucket_deposit.amount);
+ assert_eq!("I was a parent transaction", bucket_deposit.description);
+ assert_eq!(transform_id("1"), bucket_deposit.bucket_id);
+ }
+
+ #[test]
+ fn when_many_transactions_then_transforms() {
+ let actualbudget_transactions = [
+ make_fake_parent_transaction("0"),
+ make_fake_child_withdrawal_builder("1", 100, "0")
+ .category_id(Some(String::from("0")))
+ .build()
+ .unwrap(),
+ make_fake_child_deposit_builder("2", 100, "0")
+ .category_id(Some(String::from("1")))
+ .build()
+ .unwrap(),
+ make_fake_parent_transaction("3"),
+ make_fake_child_withdrawal_builder("4", 200, "3")
+ .category_id(Some(String::from("1")))
+ .build()
+ .unwrap(),
+ make_fake_child_deposit_builder("5", 200, "3")
+ .category_id(Some(String::from("0")))
+ .build()
+ .unwrap(),
+ make_fake_actualbudget_transaction_builder("6")
+ .amount(300)
+ .build()
+ .unwrap(),
+ make_fake_actualbudget_transaction_builder("7")
+ .amount(-400)
+ .build()
+ .unwrap(),
+ ];
+
+ let result = transform_bucket_transactions(&actualbudget_transactions);
+
+ assert!(result.is_ok());
+ let bucket_transactions = result.unwrap();
+ assert_eq!(4, bucket_transactions.len());
+
+ let bucket_withdrawal_0: Vec<&BucketTransaction> = bucket_transactions
+ .iter()
+ .filter(|ct| ct.amount == -100)
+ .collect();
+ assert_eq!(1, bucket_withdrawal_0.len());
+ let bucket_withdrawal_0 = bucket_withdrawal_0.get(0).unwrap();
+ assert_eq!(transform_id("0"), bucket_withdrawal_0.bucket_id);
+
+ let bucket_deposit_0: Vec<&BucketTransaction> = bucket_transactions
+ .iter()
+ .filter(|ct| ct.amount == 100)
+ .collect();
+ assert_eq!(1, bucket_deposit_0.len());
+ let bucket_deposit_0 = bucket_deposit_0.get(0).unwrap();
+ assert_eq!(transform_id("1"), bucket_deposit_0.bucket_id);
+
+ let bucket_withdrawal_1: Vec<&BucketTransaction> = bucket_transactions
+ .iter()
+ .filter(|ct| ct.amount == -200)
+ .collect();
+ assert_eq!(1, bucket_withdrawal_1.len());
+ let bucket_withdrawal_1 = bucket_withdrawal_1.get(0).unwrap();
+ assert_eq!(transform_id("1"), bucket_withdrawal_1.bucket_id);
+
+ let bucket_deposit_1: Vec<&BucketTransaction> = bucket_transactions
+ .iter()
+ .filter(|ct| ct.amount == 200)
+ .collect();
+ assert_eq!(1, bucket_deposit_1.len());
+ let bucket_deposit_1 = bucket_deposit_1.get(0).unwrap();
+ assert_eq!(transform_id("0"), bucket_deposit_1.bucket_id);
+ }
+
+ #[test]
+ fn when_multiple_child_withdrawals_then_err() {
+ let actualbudget_transactions = [
+ make_fake_parent_transaction("0"),
+ make_fake_child_withdrawal_builder("1", 50, "0")
+ .build()
+ .unwrap(),
+ make_fake_child_withdrawal_builder("2", 50, "0")
+ .build()
+ .unwrap(),
+ make_fake_child_deposit_builder("3", 100, "0")
+ .build()
+ .unwrap(),
+ ];
+
+ let result = transform_bucket_transactions(&actualbudget_transactions);
+
+ assert!(result.is_err());
+ }
+
+ #[test]
+ fn when_multiple_child_deposits_then_err() {
+ let actualbudget_transactions = [
+ make_fake_parent_transaction("0"),
+ make_fake_child_withdrawal_builder("1", 100, "0")
+ .build()
+ .unwrap(),
+ make_fake_child_deposit_builder("2", 50, "0")
+ .build()
+ .unwrap(),
+ make_fake_child_deposit_builder("3", 50, "0")
+ .build()
+ .unwrap(),
+ ];
+
+ let result = transform_bucket_transactions(&actualbudget_transactions);
+
+ assert!(result.is_err());
+ }
+
+ #[test]
+ fn when_no_child_withdrawals_then_return_empty() {
+ let actualbudget_transactions = [
+ make_fake_parent_transaction("0"),
+ make_fake_child_deposit("1", "0"),
+ ];
+
+ let result = transform_bucket_transactions(&actualbudget_transactions);
+
+ assert!(result.is_ok());
+ assert_eq!(0, result.unwrap().len());
+ }
+
+ #[test]
+ fn when_no_child_deposits_then_return_empty() {
+ let actualbudget_transactions = [
+ make_fake_parent_transaction("0"),
+ make_fake_child_withdrawal("1", "0"),
+ ];
+
+ let result = transform_bucket_transactions(&actualbudget_transactions);
+
+ assert!(result.is_ok());
+ assert_eq!(0, result.unwrap().len());
+ }
+
+ #[test]
+ fn when_child_amounts_dont_add_up_to_zero_then_return_empty() {
+ let actualbudget_transactions = [
+ make_fake_parent_transaction("0"),
+ make_fake_child_withdrawal_builder("1", 50, "0")
+ .build()
+ .unwrap(),
+ make_fake_child_deposit_builder("2", 100, "0")
+ .build()
+ .unwrap(),
+ ];
+
+ let result = transform_bucket_transactions(&actualbudget_transactions);
+
+ assert!(result.is_ok());
+ assert_eq!(0, result.unwrap().len());
+ }
+
+ #[test]
+ fn when_child_category_transfer_has_no_category_then_err() {
+ let actualbudget_transactions_0 = [
+ make_fake_parent_transaction("0"),
+ make_fake_child_withdrawal_builder("1", 100, "0")
+ .category_id(None)
+ .build()
+ .unwrap(),
+ make_fake_child_deposit_builder("2", 100, "0")
+ .build()
+ .unwrap(),
+ ];
+ let actualbudget_transactions_1 = [
+ make_fake_parent_transaction("0"),
+ make_fake_child_withdrawal_builder("1", 100, "0")
+ .build()
+ .unwrap(),
+ make_fake_child_deposit_builder("2", 100, "0")
+ .category_id(None)
+ .build()
+ .unwrap(),
+ ];
+
+ let result_0 = transform_bucket_transactions(&actualbudget_transactions_0);
+ let result_1 = transform_bucket_transactions(&actualbudget_transactions_1);
+
+ assert!(result_0.is_err());
+ assert!(result_1.is_err());
+ }
+
+ fn make_fake_parent_transaction(id: &str) -> ActualbudgetTransaction {
+ make_fake_parent_transaction_builder(id).build().unwrap()
+ }
+
+ fn make_fake_parent_transaction_builder(id: &str) -> ActualbudgetTransactionBuilder {
+ let mut builder = make_fake_actualbudget_transaction_builder(id);
+ builder
+ .account_id(String::from("0"))
+ .notes(Some(String::from("I was a parent transaction")))
+ .is_parent(true);
+ builder
+ }
+
+ fn make_fake_child_withdrawal(id: &str, parent_id: &str) -> ActualbudgetTransaction {
+ make_fake_child_withdrawal_builder(id, 100, parent_id)
+ .build()
+ .unwrap()
+ }
+
+ fn make_fake_child_withdrawal_builder(
+ id: &str,
+ amount: i32,
+ parent_id: &str,
+ ) -> ActualbudgetTransactionBuilder {
+ let mut builder = make_fake_actualbudget_transaction_builder(id);
+ builder
+ .account_id(String::from("0"))
+ .category_id(Some(String::from("0")))
+ .amount(-amount)
+ .is_child(true)
+ .notes(Some(String::from("I was a child withdrawal")))
+ .parent_id(Some(String::from(parent_id)));
+ builder
+ }
+
+ fn make_fake_child_deposit(id: &str, parent_id: &str) -> ActualbudgetTransaction {
+ make_fake_child_deposit_builder(id, 100, parent_id)
+ .build()
+ .unwrap()
+ }
+
+ fn make_fake_child_deposit_builder(
+ id: &str,
+ amount: i32,
+ parent_id: &str,
+ ) -> ActualbudgetTransactionBuilder {
+ let mut builder = make_fake_actualbudget_transaction_builder(id);
+ builder
+ .account_id(String::from("0"))
+ .category_id(Some(String::from("1")))
+ .amount(amount)
+ .is_child(true)
+ .notes(Some(String::from("I was a child deposit")))
+ .parent_id(Some(String::from(parent_id)));
+ builder
+ }
+}
diff --git a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_state.rs b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_state.rs
index 835ceff..8e71a47 100644
--- a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_state.rs
+++ b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_state.rs
@@ -1,11 +1,11 @@
use anyhow::{Context, Result};
-use schist_models::{Account, Bucket, BucketTransfer, Pipe, Transaction};
+use schist_models::{Account, Bucket, Pipe, Transaction};
use crate::{actualbudget_state::ActualbudgetState, schist_state::SchistState};
use super::{
- transform_account_transfers, transform_accounts, transform_categories_to_buckets,
- transform_date, transform_transactions, transform_transactions_to_bucket_transfers,
+ transform_account_transfers, transform_accounts, transform_bucket_transactions,
+ transform_categories_to_buckets, transform_date, transform_transactions,
transform_zero_budgets_to_drips::transform_budget_drips, transform_zero_budgets_to_pipes,
};
@@ -36,8 +36,8 @@ fn transform_state_without_context(actualbudget_state: ActualbudgetState) -> Res
);
let pipes: Vec<Pipe> =
transform_zero_budgets_to_pipes(&actualbudget_state.actualbudget_zero_budgets)?;
- let bucket_transfers: Vec<BucketTransfer> =
- transform_transactions_to_bucket_transfers(&remaining_transactions)?;
+ let bucket_transactions =
+ transform_bucket_transactions(&actualbudget_state.actualbudget_transactions)?;
Ok(SchistState {
first_transaction_date: first_activity_date,
@@ -47,6 +47,6 @@ fn transform_state_without_context(actualbudget_state: ActualbudgetState) -> Res
budget_drips,
pipes: pipes,
transactions,
- bucket_transfers,
+ bucket_transactions,
})
}
diff --git a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_transactions.rs b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_transactions.rs
index 11765be..dce07af 100644
--- a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_transactions.rs
+++ b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_transactions.rs
@@ -2,7 +2,7 @@ use actualbudget_models::{ActualbudgetPayee, ActualbudgetTransaction};
use anyhow::{Context, Result};
use schist_models::Transaction;
-use super::{is_not_bucket_transfer, transform_date, transform_id};
+use super::{is_not_category_transfer, transform_date, transform_id};
pub fn transform_transactions(
actualbudget_transactions: &[ActualbudgetTransaction],
@@ -21,7 +21,7 @@ fn transform_transactions_without_context(
let actualbudget_transactions = actualbudget_transactions
.iter()
.filter(|t| !t.is_starting_balance())
- .filter(|t| is_not_bucket_transfer(t, actualbudget_transactions));
+ .filter(|t| is_not_category_transfer(t, actualbudget_transactions));
let parent_actualbudget_transactions: Vec<&ActualbudgetTransaction> = actualbudget_transactions
.clone()
.filter(|t| t.is_parent)
diff --git a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_transactions_to_bucket_transfers.rs b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_transactions_to_bucket_transfers.rs
deleted file mode 100644
index 51545c3..0000000
--- a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_transactions_to_bucket_transfers.rs
+++ /dev/null
@@ -1,383 +0,0 @@
-use actualbudget_models::ActualbudgetTransaction;
-use anyhow::{bail, Context, Result};
-use itertools::Itertools;
-use schist_models::BucketTransfer;
-
-use super::transform_id;
-
-pub fn transform_transactions_to_bucket_transfers(
- actualbudget_transactions: &[ActualbudgetTransaction],
-) -> Result<Vec<BucketTransfer>> {
- let children: Vec<&ActualbudgetTransaction> = actualbudget_transactions
- .into_iter()
- .filter(|&t| t.is_child)
- .collect();
- let parent_children_pairs: Vec<(&ActualbudgetTransaction, Vec<&ActualbudgetTransaction>)> =
- actualbudget_transactions
- .iter()
- .filter(|t| t.is_parent)
- .map(|parent| {
- (
- parent,
- children
- .clone()
- .into_iter()
- .filter(|&c| c.parent_id.clone().is_some_and(|id| id == parent.id))
- .collect::<Vec<&ActualbudgetTransaction>>(),
- )
- })
- .map(|(parent, children)| {
- let children_total_amount: i32 = children.iter().map(|child| child.amount).sum();
- if parent.amount != children_total_amount {
- bail!("parent transaction {} has amount: {}, but its {} children add up to a total amount of: {}",
- parent.id,
- parent.amount,
- children.len(),
- children_total_amount);
- }
- Ok((parent, children))
- })
- .filter(|result|
- match result {
- Ok((parent, _children)) => parent.amount == 0,
- Err(_) => true,
- })
- .try_collect()?;
-
- Ok(parent_children_pairs
- .iter()
- .map(|(parent, children)| transform_category_transfer(parent, children))
- .filter_ok(Option::is_some)
- .map_ok(Option::unwrap)
- .collect::<Result<Vec<BucketTransfer>>>()
- .with_context(|| "failed to transform category transfers")?)
-}
-
-fn transform_category_transfer(
- actualbudget_parent_category_transfer: &ActualbudgetTransaction,
- actualbudget_child_category_transfers: &[&ActualbudgetTransaction],
-) -> Result<Option<BucketTransfer>> {
- transform_category_transfer_without_context(
- actualbudget_parent_category_transfer,
- actualbudget_child_category_transfers,
- )
- .with_context(|| "failed to transform category transfer")
-}
-
-fn transform_category_transfer_without_context(
- actualbudget_parent_category_transfer: &ActualbudgetTransaction,
- actualbudget_child_category_transfers: &[&ActualbudgetTransaction],
-) -> Result<Option<BucketTransfer>> {
- let from_transfers: Vec<&ActualbudgetTransaction> = actualbudget_child_category_transfers
- .into_iter()
- .cloned()
- .filter(|&t| t.amount < 0)
- .collect();
- if from_transfers.len() != 1 {
- bail!(
- "actualbudget parent category transfer {} had {} from child transfers",
- actualbudget_parent_category_transfer.id,
- from_transfers.len(),
- );
- }
- let from_transfer = from_transfers.get(0).unwrap();
-
- if from_transfer.category_id.is_none() {
- bail!(
- "actualbudget child from transfer {} had no category ID",
- from_transfer.id
- );
- }
- let from_category_id: i32 = transform_id(&from_transfer.category_id.clone().unwrap());
-
- let to_transfers: Vec<&ActualbudgetTransaction> = actualbudget_child_category_transfers
- .iter()
- .filter(|&t| t.amount > 0)
- .cloned()
- .collect();
- if to_transfers.len() != 1 {
- bail!(
- "actualbudget parent category transfer {} had {} to child transfers",
- actualbudget_parent_category_transfer.id,
- to_transfers.len(),
- );
- }
- let to_transfer = to_transfers.get(0).unwrap();
-
- if to_transfer.category_id.is_none() {
- bail!(
- "actualbudget child to transfer {} had no category ID",
- to_transfer.id
- );
- }
- let to_category_id: i32 = transform_id(&to_transfer.category_id.clone().unwrap());
-
- if from_transfer.amount != -to_transfer.amount {
- bail!("actualbudget category transfer amounts did not sum to zero");
- }
-
- Ok(Some(BucketTransfer {
- id: transform_id(&actualbudget_parent_category_transfer.id),
- description: actualbudget_parent_category_transfer
- .notes
- .clone()
- .unwrap_or_else(String::new),
- amount: to_transfer.amount.try_into().unwrap(),
- from_bucket_id: from_category_id,
- to_bucket_id: to_category_id,
- }))
-}
-
-#[cfg(test)]
-mod test {
- use actualbudget_fakes::actualbudget_transaction::make_fake_actualbudget_transaction_builder;
- use actualbudget_models::{ActualbudgetTransaction, ActualbudgetTransactionBuilder};
- use schist_models::BucketTransfer;
-
- use crate::transform_state::transform_id::transform_id;
-
- use super::transform_transactions_to_bucket_transfers;
-
- #[test]
- fn when_one_category_transfer_then_transforms() {
- let actualbudget_transactions = [
- make_fake_parent_transaction("0"),
- make_fake_from_child_transaction("1", "0"),
- make_fake_to_child_transaction("2", "0"),
- ];
-
- let result = transform_transactions_to_bucket_transfers(&actualbudget_transactions);
-
- assert!(result.is_ok());
- let bucket_transfers = result.unwrap();
- assert_eq!(1, bucket_transfers.len());
- let bucket_transfer = bucket_transfers.get(0).unwrap();
- assert_eq!(100, bucket_transfer.amount);
- assert_eq!("I was a parent transaction", bucket_transfer.description);
- assert_eq!(transform_id("0"), bucket_transfer.from_bucket_id);
- assert_eq!(transform_id("1"), bucket_transfer.to_bucket_id);
- }
-
- #[test]
- fn when_many_transactions_then_transforms() {
- let actualbudget_transactions = [
- make_fake_parent_transaction("0"),
- make_fake_from_child_transaction_builder("1", 100, "0")
- .category_id(Some(String::from("0")))
- .build()
- .unwrap(),
- make_fake_to_child_transaction_builder("2", 100, "0")
- .category_id(Some(String::from("1")))
- .build()
- .unwrap(),
- make_fake_parent_transaction("3"),
- make_fake_from_child_transaction_builder("4", 200, "3")
- .category_id(Some(String::from("1")))
- .build()
- .unwrap(),
- make_fake_to_child_transaction_builder("5", 200, "3")
- .category_id(Some(String::from("0")))
- .build()
- .unwrap(),
- make_fake_actualbudget_transaction_builder("6")
- .amount(300)
- .build()
- .unwrap(),
- make_fake_actualbudget_transaction_builder("7")
- .amount(-400)
- .build()
- .unwrap(),
- ];
-
- let result = transform_transactions_to_bucket_transfers(&actualbudget_transactions);
-
- assert!(result.is_ok());
- let bucket_transfers = result.unwrap();
- assert_eq!(2, bucket_transfers.len());
-
- let bucket_transfer_0: Vec<&BucketTransfer> = bucket_transfers
- .iter()
- .filter(|ct| ct.amount == 100)
- .collect();
- assert_eq!(1, bucket_transfer_0.len());
- let bucket_transfer_0 = bucket_transfer_0.get(0).unwrap();
- assert_eq!(transform_id("0"), bucket_transfer_0.from_bucket_id);
- assert_eq!(transform_id("1"), bucket_transfer_0.to_bucket_id);
-
- let bucket_transfer_1: Vec<&BucketTransfer> = bucket_transfers
- .iter()
- .filter(|ct| ct.amount == 200)
- .collect();
- assert_eq!(1, bucket_transfer_1.len());
- let bucket_transfer_1 = bucket_transfer_1.get(0).unwrap();
- assert_eq!(transform_id("1"), bucket_transfer_1.from_bucket_id);
- assert_eq!(transform_id("0"), bucket_transfer_1.to_bucket_id);
- }
-
- #[test]
- fn when_multiple_child_from_transactions_then_err() {
- let actualbudget_transactions = [
- make_fake_parent_transaction("0"),
- make_fake_from_child_transaction_builder("1", 50, "0")
- .build()
- .unwrap(),
- make_fake_from_child_transaction_builder("2", 50, "0")
- .build()
- .unwrap(),
- make_fake_to_child_transaction_builder("3", 100, "0")
- .build()
- .unwrap(),
- ];
-
- let result = transform_transactions_to_bucket_transfers(&actualbudget_transactions);
-
- assert!(result.is_err());
- }
-
- #[test]
- fn when_multiple_child_to_transactions_then_err() {
- let actualbudget_transactions = [
- make_fake_parent_transaction("0"),
- make_fake_from_child_transaction_builder("1", 100, "0")
- .build()
- .unwrap(),
- make_fake_to_child_transaction_builder("2", 50, "0")
- .build()
- .unwrap(),
- make_fake_to_child_transaction_builder("3", 50, "0")
- .build()
- .unwrap(),
- ];
-
- let result = transform_transactions_to_bucket_transfers(&actualbudget_transactions);
-
- assert!(result.is_err());
- }
-
- #[test]
- fn when_no_child_from_transactions_then_err() {
- let actualbudget_transactions = [
- make_fake_parent_transaction("0"),
- make_fake_to_child_transaction("1", "0"),
- ];
-
- let result = transform_transactions_to_bucket_transfers(&actualbudget_transactions);
-
- assert!(result.is_err());
- }
-
- #[test]
- fn when_no_child_to_transactions_then_err() {
- let actualbudget_transactions = [
- make_fake_parent_transaction("0"),
- make_fake_from_child_transaction("1", "0"),
- ];
-
- let result = transform_transactions_to_bucket_transfers(&actualbudget_transactions);
-
- assert!(result.is_err());
- }
-
- #[test]
- fn when_child_amounts_dont_add_up_to_zero_then_err() {
- let actualbudget_transactions = [
- make_fake_parent_transaction("0"),
- make_fake_from_child_transaction_builder("1", 50, "0")
- .build()
- .unwrap(),
- make_fake_to_child_transaction_builder("2", 100, "0")
- .build()
- .unwrap(),
- ];
-
- let result = transform_transactions_to_bucket_transfers(&actualbudget_transactions);
-
- assert!(result.is_err());
- }
-
- #[test]
- fn when_child_category_transfer_has_no_category_then_err() {
- let actualbudget_transactions_0 = [
- make_fake_parent_transaction("0"),
- make_fake_from_child_transaction_builder("1", 100, "0")
- .category_id(None)
- .build()
- .unwrap(),
- make_fake_to_child_transaction_builder("2", 100, "0")
- .build()
- .unwrap(),
- ];
- let actualbudget_transactions_1 = [
- make_fake_parent_transaction("0"),
- make_fake_from_child_transaction_builder("1", 100, "0")
- .build()
- .unwrap(),
- make_fake_to_child_transaction_builder("2", 100, "0")
- .category_id(None)
- .build()
- .unwrap(),
- ];
-
- let result_0 = transform_transactions_to_bucket_transfers(&actualbudget_transactions_0);
- let result_1 = transform_transactions_to_bucket_transfers(&actualbudget_transactions_1);
-
- assert!(result_0.is_err());
- assert!(result_1.is_err());
- }
-
- fn make_fake_parent_transaction(id: &str) -> ActualbudgetTransaction {
- make_fake_parent_transaction_builder(id).build().unwrap()
- }
-
- fn make_fake_parent_transaction_builder(id: &str) -> ActualbudgetTransactionBuilder {
- let mut builder = make_fake_actualbudget_transaction_builder(id);
- builder
- .account_id(String::from("0"))
- .notes(Some(String::from("I was a parent transaction")))
- .is_parent(true);
- builder
- }
-
- fn make_fake_from_child_transaction(id: &str, parent_id: &str) -> ActualbudgetTransaction {
- make_fake_from_child_transaction_builder(id, 100, parent_id)
- .build()
- .unwrap()
- }
- fn make_fake_from_child_transaction_builder(
- id: &str,
- amount: i32,
- parent_id: &str,
- ) -> ActualbudgetTransactionBuilder {
- let mut builder = make_fake_actualbudget_transaction_builder(id);
- builder
- .account_id(String::from("0"))
- .category_id(Some(String::from("0")))
- .amount(-amount)
- .is_child(true)
- .notes(Some(String::from("I was a from child transaction")))
- .parent_id(Some(String::from(parent_id)));
- builder
- }
-
- fn make_fake_to_child_transaction(id: &str, parent_id: &str) -> ActualbudgetTransaction {
- make_fake_to_child_transaction_builder(id, 100, parent_id)
- .build()
- .unwrap()
- }
-
- fn make_fake_to_child_transaction_builder(
- id: &str,
- amount: i32,
- parent_id: &str,
- ) -> ActualbudgetTransactionBuilder {
- let mut builder = make_fake_actualbudget_transaction_builder(id);
- builder
- .account_id(String::from("0"))
- .category_id(Some(String::from("1")))
- .amount(amount)
- .is_child(true)
- .notes(Some(String::from("I was a to child transaction")))
- .parent_id(Some(String::from(parent_id)));
- builder
- }
-}
diff --git a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/bucket_transaction_matchers.rs b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/bucket_transaction_matchers.rs
new file mode 100644
index 0000000..decc189
--- /dev/null
+++ b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/bucket_transaction_matchers.rs
@@ -0,0 +1,51 @@
+use schist_models::{Bucket, BucketTransaction};
+
+use super::bucket_names::{BUCKET_NAME_GENERAL, BUCKET_NAME_SAVINGS};
+
+pub fn get_bucket_transaction_matchers() -> Vec<Box<dyn Fn(&BucketTransaction, &[Bucket]) -> bool>>
+{
+ vec![
+ Box::new(|ct, c| matches_withdrawal_120_savings_23_oct_2024(ct, c)),
+ Box::new(|ct, c| matches_deposit_120_general_23_oct_2024(ct, c)),
+ ]
+}
+
+fn matches_withdrawal_120_savings_23_oct_2024(
+ bucket_transactions: &BucketTransaction,
+ buckets: &[Bucket],
+) -> bool {
+ let savings_bucket = buckets
+ .iter()
+ .find(|c| c.name == BUCKET_NAME_SAVINGS)
+ .expect("failed to find savings bucket");
+
+ match bucket_transactions {
+ BucketTransaction {
+ id: _id,
+ description,
+ amount: -120_00,
+ bucket_id,
+ } => *bucket_id == savings_bucket.id && description.as_str() == "",
+ _ => false,
+ }
+}
+
+fn matches_deposit_120_general_23_oct_2024(
+ bucket_transaction: &BucketTransaction,
+ buckets: &[Bucket],
+) -> bool {
+ let general_bucket = buckets
+ .iter()
+ .find(|c| c.name == BUCKET_NAME_GENERAL)
+ .expect("failed to find general bucket");
+
+ match bucket_transaction {
+ BucketTransaction {
+ id: _id,
+ description,
+ amount: 120_00,
+ bucket_id,
+ } => *bucket_id == general_bucket.id && description.as_str() == "",
+ _ => false,
+ }
+}
diff --git a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/bucket_transfer_matchers.rs b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/bucket_transfer_matchers.rs
index c31b9bc..a093cce 100644
--- a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/bucket_transfer_matchers.rs
+++ b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/bucket_transfer_matchers.rs
@@ -1,15 +1,15 @@
-use schist_models::{Bucket, BucketTransfer};
+use schist_models::{Bucket, BucketTransaction};
use super::bucket_names::{BUCKET_NAME_GENERAL, BUCKET_NAME_SAVINGS};
-pub fn get_bucket_transfer_matchers() -> Vec<Box<dyn Fn(&BucketTransfer, &[Bucket]) -> bool>> {
+pub fn get_bucket_transfer_matchers() -> Vec<Box<dyn Fn(&BucketTransaction, &[Bucket]) -> bool>> {
vec![Box::new(|ct, c| {
matches_120_savings_to_general_23_oct_2024(ct, c)
})]
}
fn matches_120_savings_to_general_23_oct_2024(
- bucket_transfer: &BucketTransfer,
+ bucket_transfer: &BucketTransaction,
buckets: &[Bucket],
) -> bool {
let savings_bucket = buckets
@@ -23,7 +23,7 @@ fn matches_120_savings_to_general_23_oct_2024(
.expect("failed to find general bucket");
match bucket_transfer {
- BucketTransfer {
+ BucketTransaction {
id: _id,
description,
amount: 120_00,
diff --git a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/mod.rs b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/mod.rs
index 82d7870..1dd718c 100644
--- a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/mod.rs
+++ b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/mod.rs
@@ -3,7 +3,7 @@ mod account_names;
mod account_transfer_matchers;
mod bucket_matchers;
mod bucket_names;
-mod bucket_transfer_matchers;
+mod bucket_transaction_matchers;
mod db_url;
mod drip_matchers;
mod pipe_matchers;
@@ -15,7 +15,7 @@ pub use account_names::ACCOUNT_NAMES_DICT;
pub use account_transfer_matchers::get_account_transfer_matchers;
pub use bucket_matchers::get_bucket_matchers;
pub use bucket_names::BUCKET_NAMES_DICT;
-pub use bucket_transfer_matchers::get_bucket_transfer_matchers;
+pub use bucket_transaction_matchers::get_bucket_transaction_matchers;
pub use db_url::TEST_IN_DB_URL;
pub use db_url::TEST_OUT_DB_URL;
pub use drip_matchers::assert_drip_matches;
diff --git a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/run.rs b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/run.rs
index 04c21ca..1232016 100644
--- a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/run.rs
+++ b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/run.rs
@@ -3,15 +3,15 @@ pub mod common;
use actualbudget_to_schist_transformer::run::run;
use common::{
assert_drip_matches, get_account_matchers, get_account_transfer_matchers, get_bucket_matchers,
- get_bucket_transfer_matchers, get_num_expected_drips, get_transaction_matchers, TestContext,
+ get_bucket_transaction_matchers, get_num_expected_drips, get_transaction_matchers, TestContext,
TEST_IN_DB_URL, TEST_OUT_DB_URL,
};
use diesel::{Connection, SqliteConnection};
use schist_queries::{
account_transfers::get_all_account_transfers, accounts::get_all_accounts,
- bucket_transfers::get_all_bucket_transfers, buckets::get_all_buckets, drips::get_all_drips,
- pipes::get_all_pipes, transactions::get_all_transactions,
+ bucket_transactions::get_all_bucket_transactions, buckets::get_all_buckets,
+ drips::get_all_drips, pipes::get_all_pipes, transactions::get_all_transactions,
};
use crate::common::get_pipe_matchers;
@@ -25,7 +25,7 @@ fn given_test_database_when_run_then_exports_expected_schist_state() {
let account_transfers = get_all_account_transfers(connection).unwrap();
let drips = get_all_drips(connection).unwrap();
let buckets = get_all_buckets(connection).unwrap();
- let bucket_transfers = get_all_bucket_transfers(connection).unwrap();
+ let bucket_transactions = get_all_bucket_transactions(connection).unwrap();
let pipes = get_all_pipes(connection).unwrap();
let transactions = get_all_transactions(connection).unwrap();
@@ -66,15 +66,15 @@ fn given_test_database_when_run_then_exports_expected_schist_state() {
);
}
- let bucket_transfer_matchers = get_bucket_transfer_matchers();
- assert_eq!(bucket_transfer_matchers.len(), bucket_transfers.len());
- for bucket_transfer in bucket_transfers {
+ let bucket_transaction_matchers = get_bucket_transaction_matchers();
+ assert_eq!(bucket_transaction_matchers.len(), bucket_transactions.len());
+ for bucket_transaction in bucket_transactions {
assert!(
- bucket_transfer_matchers
+ bucket_transaction_matchers
.iter()
- .any(|m| m(&bucket_transfer, &buckets)),
- "no match found for bucket_transfer {:?}",
- bucket_transfer,
+ .any(|m| m(&bucket_transaction, &buckets)),
+ "no match found for bucket_transaction {:?}",
+ bucket_transaction,
);
}