summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Carstairs <me@joeac.net>2025-08-15 16:02:40 +0000
committerjoeac <me@joeac.net>2025-08-15 16:02:40 +0000
commit703496a49315f7b67442abf0e0df3c41d3605d3b (patch)
tree8e92f3842710162f3b26e910eb931950c1049f07
parent8d714f760bd0349560d464583a151a04a19de1c9 (diff)
task-012 (#2)
Co-authored-by: Joe Carstairs <jcarstairs@scottlogic.com> Reviewed-on: https://git.joeac.net/joeac/schist/pulls/2 Co-authored-by: Joe Carstairs <me@joeac.net> Co-committed-by: Joe Carstairs <me@joeac.net>
-rw-r--r--.gitignore1
-rw-r--r--Cargo.lock112
-rw-r--r--Cargo.toml1
-rw-r--r--diesel.toml (renamed from schist_core/schist_models/diesel.toml)4
-rw-r--r--requirements/kanban.md1
-rw-r--r--requirements/tasks/epic-000.md4
-rw-r--r--requirements/tasks/task-012.md2
-rw-r--r--schist_core/schist_fakes/src/account_transfer.rs9
-rw-r--r--schist_core/schist_fakes/src/bucket.rs14
-rw-r--r--schist_core/schist_fakes/src/bucket_transfer.rs2
-rw-r--r--schist_core/schist_fakes/src/budget_drip.rs16
-rw-r--r--schist_core/schist_fakes/src/drip.rs15
-rw-r--r--schist_core/schist_fakes/src/lib.rs4
-rw-r--r--schist_core/schist_fakes/src/pipe.rs21
-rw-r--r--schist_core/schist_fakes/src/transaction.rs15
-rw-r--r--schist_core/schist_fakes/src/transaction_categorisation.rs16
-rw-r--r--schist_core/schist_models/migrations/2024-08-31-084439_initial_setup/down.sql8
-rw-r--r--schist_core/schist_models/migrations/2024-08-31-084439_initial_setup/up.sql88
-rw-r--r--schist_core/schist_models/migrations/2025-08-15-090859_dummy_data/down.sql39
-rw-r--r--schist_core/schist_models/migrations/2025-08-15-090859_dummy_data/up.sql14
-rw-r--r--schist_core/schist_models/src/account_transfer.rs2
-rw-r--r--schist_core/schist_models/src/bucket.rs12
-rw-r--r--schist_core/schist_models/src/bucket_transfer.rs2
-rw-r--r--schist_core/schist_models/src/budget_drip.rs14
-rw-r--r--schist_core/schist_models/src/drip.rs28
-rw-r--r--schist_core/schist_models/src/lib.rs4
-rw-r--r--schist_core/schist_models/src/pipe.rs27
-rw-r--r--schist_core/schist_models/src/schema.rs59
-rw-r--r--schist_core/schist_models/src/transaction.rs13
-rw-r--r--schist_core/schist_models/src/transaction_categorisation.rs12
-rw-r--r--schist_core/schist_models/user_data.sqlitebin45056 -> 45056 bytes
-rw-r--r--schist_core/schist_queries/src/accounts.rs8
-rw-r--r--schist_core/schist_queries/src/bucket_transfers.rs22
-rw-r--r--schist_core/schist_queries/src/buckets.rs5
-rw-r--r--schist_core/schist_queries/src/budget_drips.rs40
-rw-r--r--schist_core/schist_queries/src/clear.rs8
-rw-r--r--schist_core/schist_queries/src/drips.rs38
-rw-r--r--schist_core/schist_queries/src/lib.rs8
-rw-r--r--schist_core/schist_queries/src/pipes.rs55
-rw-r--r--schist_core/schist_queries/src/transaction_categorisations.rs59
-rw-r--r--schist_core/schist_queries/src/transactions.rs2
-rw-r--r--schist_core/schist_queries/src/utils/calculate_bucket_balance.rs57
-rw-r--r--schist_core/schist_queries/src/utils/calculate_budgets_accrual.rs72
-rw-r--r--schist_core/schist_queries/src/utils/mod.rs4
-rw-r--r--schist_core/schist_queries/src/utils/sum_drips_for_bucket.rs80
-rw-r--r--schist_core/schist_queries/tests/category_transfers.rs130
-rw-r--r--schist_core/schist_queries/tests/drips.rs (renamed from schist_core/schist_queries/tests/budget_drips.rs)151
-rw-r--r--schist_core/schist_queries/tests/pipes.rs151
-rw-r--r--schist_core/schist_queries/tests/transaction_categorisations.rs130
-rw-r--r--schist_desktop_gui/Cargo.toml6
-rw-r--r--schist_desktop_gui/src/connection.rs20
-rw-r--r--schist_desktop_gui/src/dummy_data.rs70
-rw-r--r--schist_desktop_gui/src/gui.rs47
-rw-r--r--schist_desktop_gui/src/gui/components/bucket_name_and_balance.rs6
-rw-r--r--schist_desktop_gui/src/gui/components/transactions_view.rs2
-rw-r--r--schist_desktop_gui/src/main.rs32
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/schist_state.rs32
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/mod.rs4
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_account_transfers.rs92
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_budget_drips.rs179
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_categories.rs208
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_category_transfers.rs188
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_state.rs50
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_transactions.rs194
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_zero_budgets.rs6
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/account_transfer_matchers.rs21
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/bucket_matchers.rs32
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/bucket_transfer_matchers.rs19
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/budget_drip_matchers.rs38
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/mod.rs10
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/transaction_categorisation_matchers.rs141
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/transaction_matchers.rs88
-rw-r--r--transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/run.rs48
73 files changed, 1618 insertions, 1494 deletions
diff --git a/.gitignore b/.gitignore
index c141a33..b6f52a1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@ target
*.keep
.zed
.vscode
+**/*.sqlite
diff --git a/Cargo.lock b/Cargo.lock
index 1879c81..0334664 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -132,7 +132,7 @@ dependencies = [
"ndk-context",
"ndk-sys 0.6.0+11769913",
"num_enum",
- "thiserror",
+ "thiserror 1.0.69",
]
[[package]]
@@ -483,7 +483,7 @@ dependencies = [
"polling",
"rustix 0.38.44",
"slab",
- "thiserror",
+ "thiserror 1.0.69",
]
[[package]]
@@ -583,7 +583,7 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4274ea815e013e0f9f04a2633423e14194e408a0576c943ce3d14ca56c50031c"
dependencies = [
- "thiserror",
+ "thiserror 1.0.69",
"x11rb",
]
@@ -834,7 +834,7 @@ checksum = "2a76fa97167fa740dcdbfe18e8895601e1bc36525f09b044e00916e717c03a3c"
dependencies = [
"dconf_rs",
"detect-desktop-environment",
- "dirs",
+ "dirs 4.0.0",
"objc",
"rust-ini",
"web-sys",
@@ -989,7 +989,16 @@ version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
dependencies = [
- "dirs-sys",
+ "dirs-sys 0.3.7",
+]
+
+[[package]]
+name = "dirs"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
+dependencies = [
+ "dirs-sys 0.5.0",
]
[[package]]
@@ -999,11 +1008,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
dependencies = [
"libc",
- "redox_users",
+ "redox_users 0.4.6",
"winapi",
]
[[package]]
+name = "dirs-sys"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
+dependencies = [
+ "libc",
+ "option-ext",
+ "redox_users 0.5.2",
+ "windows-sys 0.60.2",
+]
+
+[[package]]
name = "dispatch"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1497,7 +1518,7 @@ checksum = "6f56f6318968d03c18e1bcf4857ff88c61157e9da8e47c5f29055d60e1228884"
dependencies = [
"log",
"presser",
- "thiserror",
+ "thiserror 1.0.69",
"winapi",
"windows",
]
@@ -1577,7 +1598,7 @@ dependencies = [
"com",
"libc",
"libloading 0.8.8",
- "thiserror",
+ "thiserror 1.0.69",
"widestring",
"winapi",
]
@@ -1641,7 +1662,7 @@ dependencies = [
"iced_renderer",
"iced_widget",
"iced_winit",
- "thiserror",
+ "thiserror 1.0.69",
]
[[package]]
@@ -1660,7 +1681,7 @@ dependencies = [
"palette",
"rustc-hash 2.1.1",
"smol_str",
- "thiserror",
+ "thiserror 1.0.69",
"web-time",
]
@@ -1707,7 +1728,7 @@ dependencies = [
"once_cell",
"raw-window-handle",
"rustc-hash 2.1.1",
- "thiserror",
+ "thiserror 1.0.69",
"unicode-segmentation",
]
@@ -1721,7 +1742,7 @@ dependencies = [
"iced_tiny_skia",
"iced_wgpu",
"log",
- "thiserror",
+ "thiserror 1.0.69",
]
[[package]]
@@ -1734,7 +1755,7 @@ dependencies = [
"iced_core",
"iced_futures",
"raw-window-handle",
- "thiserror",
+ "thiserror 1.0.69",
]
[[package]]
@@ -1769,7 +1790,7 @@ dependencies = [
"log",
"once_cell",
"rustc-hash 2.1.1",
- "thiserror",
+ "thiserror 1.0.69",
"wgpu",
]
@@ -1784,7 +1805,7 @@ dependencies = [
"num-traits",
"once_cell",
"rustc-hash 2.1.1",
- "thiserror",
+ "thiserror 1.0.69",
"unicode-segmentation",
]
@@ -1799,7 +1820,7 @@ dependencies = [
"iced_runtime",
"log",
"rustc-hash 2.1.1",
- "thiserror",
+ "thiserror 1.0.69",
"tracing",
"wasm-bindgen-futures",
"web-sys",
@@ -1859,7 +1880,7 @@ dependencies = [
"combine",
"jni-sys",
"log",
- "thiserror",
+ "thiserror 1.0.69",
"walkdir",
"windows-sys 0.45.0",
]
@@ -2106,7 +2127,7 @@ dependencies = [
"rustc-hash 1.1.0",
"spirv",
"termcolor",
- "thiserror",
+ "thiserror 1.0.69",
"unicode-xid",
]
@@ -2122,7 +2143,7 @@ dependencies = [
"ndk-sys 0.6.0+11769913",
"num_enum",
"raw-window-handle",
- "thiserror",
+ "thiserror 1.0.69",
]
[[package]]
@@ -2447,6 +2468,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
+name = "option-ext"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
+
+[[package]]
name = "orbclient"
version = "0.3.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2874,7 +2901,18 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
dependencies = [
"getrandom 0.2.16",
"libredox",
- "thiserror",
+ "thiserror 1.0.69",
+]
+
+[[package]]
+name = "redox_users"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
+dependencies = [
+ "getrandom 0.2.16",
+ "libredox",
+ "thiserror 2.0.14",
]
[[package]]
@@ -2981,11 +3019,15 @@ version = "0.1.0"
dependencies = [
"anyhow",
"diesel",
+ "diesel_migrations",
+ "dirs 6.0.0",
"iced",
"itertools",
+ "libsqlite3-sys",
"schist_fakes",
"schist_models",
"schist_queries",
+ "schist_schema",
]
[[package]]
@@ -3191,7 +3233,7 @@ dependencies = [
"log",
"memmap2",
"rustix 0.38.44",
- "thiserror",
+ "thiserror 1.0.69",
"wayland-backend",
"wayland-client",
"wayland-csd-frame",
@@ -3357,7 +3399,16 @@ version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [
- "thiserror-impl",
+ "thiserror-impl 1.0.69",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b0949c3a6c842cbde3f1686d6eea5a010516deb7085f79db747562d4102f41e"
+dependencies = [
+ "thiserror-impl 2.0.14",
]
[[package]]
@@ -3372,6 +3423,17 @@ dependencies = [
]
[[package]]
+name = "thiserror-impl"
+version = "2.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc5b44b4ab9c2fdd0e0512e6bece8388e214c0749f5862b114cc5b7a25daf227"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.104",
+]
+
+[[package]]
name = "time"
version = "0.3.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3935,7 +3997,7 @@ dependencies = [
"raw-window-handle",
"rustc-hash 1.1.0",
"smallvec",
- "thiserror",
+ "thiserror 1.0.69",
"web-sys",
"wgpu-hal",
"wgpu-types",
@@ -3979,7 +4041,7 @@ dependencies = [
"renderdoc-sys",
"rustc-hash 1.1.0",
"smallvec",
- "thiserror",
+ "thiserror 1.0.69",
"wasm-bindgen",
"web-sys",
"wgpu-types",
@@ -4045,7 +4107,7 @@ dependencies = [
"clipboard_wayland",
"clipboard_x11",
"raw-window-handle",
- "thiserror",
+ "thiserror 1.0.69",
]
[[package]]
diff --git a/Cargo.toml b/Cargo.toml
index 29fd49a..f9bb9fc 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -20,6 +20,7 @@ chrono = { version = "0.4.38" }
derive_builder = { version = "0.20.2" }
diesel = { version = "2.2.0" }
diesel_migrations = "2.2.0"
+dirs = "6.0"
dotenvy = "0.15.7"
iced = "0.13.1"
itertools = "0.13.0"
diff --git a/schist_core/schist_models/diesel.toml b/diesel.toml
index 2b8ebd8..07f4552 100644
--- a/schist_core/schist_models/diesel.toml
+++ b/diesel.toml
@@ -2,8 +2,8 @@
# see https://diesel.rs/guides/configuring-diesel-cli
[print_schema]
-file = "src/schema.rs"
+file = "schist_core/schist_models/src/schema.rs"
custom_type_derives = ["diesel::query_builder::QueryId", "Clone"]
[migrations_directory]
-dir = "/home/joeac/src/schist/rust/schist_models/migrations"
+dir = "schist_core/schist_models/migrations"
diff --git a/requirements/kanban.md b/requirements/kanban.md
index 4f0ebde..95a1994 100644
--- a/requirements/kanban.md
+++ b/requirements/kanban.md
@@ -4,7 +4,6 @@
| -------- | -------- | -------- |
| | | epic-000 |
| ======== | ======== | ======== |
-| | task-012 | |
| | task-001 | |
| | task-064 | |
| | task-072 | |
diff --git a/requirements/tasks/epic-000.md b/requirements/tasks/epic-000.md
index 7b6e21c..239c612 100644
--- a/requirements/tasks/epic-000.md
+++ b/requirements/tasks/epic-000.md
@@ -3,13 +3,13 @@
For this Epic, there should be a desktop GUI with basic functionality to meet
the most important user needs.
-Status: not ready
+Status: in progress
## Ordered backlog
- [x] task-010 (hello, world)
- [x] task-073 (UI layout & nav)
-- [ ] task-012 (SQLite)
+- [x] task-012 (SQLite)
- [ ] task-001 (inserting transactions)
- [ ] task-064 (deleting transactions)
- [ ] task-072 (import from Actualbudget)
diff --git a/requirements/tasks/task-012.md b/requirements/tasks/task-012.md
index e45c74b..13e3b88 100644
--- a/requirements/tasks/task-012.md
+++ b/requirements/tasks/task-012.md
@@ -7,6 +7,8 @@ the pattern is ready to be used in other tasks. As this blocks using actual
domain entities, then, a good place to start would be storing a database schema
version number.
+Status: done
+
Source: ard-001
Epic: epic-000
diff --git a/schist_core/schist_fakes/src/account_transfer.rs b/schist_core/schist_fakes/src/account_transfer.rs
index f762c2f..703d7ce 100644
--- a/schist_core/schist_fakes/src/account_transfer.rs
+++ b/schist_core/schist_fakes/src/account_transfer.rs
@@ -1,17 +1,20 @@
-use schist_models::{date_utc::DateUtc, account_transfer::{AccountTransfer, AccountTransferBuilder}};
+use schist_models::{
+ account_transfer::{AccountTransfer, AccountTransferBuilder},
+ date_utc::DateUtc,
+};
use schist_traits::nowlike::Nowlike;
pub fn make_fake_account_transfer(id: i32) -> AccountTransfer {
make_fake_account_transfer_builder(id).build().unwrap()
}
-pub fn make_fake_account_transfer_builder(id: i32) -> AccountTransferBuilder {
+pub fn make_fake_account_transfer_builder(id: i32) -> AccountTransferBuilder {
let mut builder = AccountTransferBuilder::default();
builder
.id(id)
.date(DateUtc::now())
.description(String::from("Fake account transfer"))
- .quantity(0)
+ .amount(0)
.from_account_id(0)
.to_account_id(1);
builder
diff --git a/schist_core/schist_fakes/src/bucket.rs b/schist_core/schist_fakes/src/bucket.rs
index 1b447b2..fe03a83 100644
--- a/schist_core/schist_fakes/src/bucket.rs
+++ b/schist_core/schist_fakes/src/bucket.rs
@@ -1,9 +1,4 @@
-use schist_models::{
- bucket::{Bucket, BucketBuilder},
- budget_period_unit::BudgetPeriodUnit,
- date_utc::DateUtc,
-};
-use schist_traits::nowlike::Nowlike;
+use schist_models::bucket::{Bucket, BucketBuilder};
pub fn make_fake_bucket(id: i32) -> Bucket {
make_fake_bucket_builder(id).build().unwrap()
@@ -14,11 +9,8 @@ pub fn make_fake_bucket_builder(id: i32) -> BucketBuilder {
builder
.id(id)
.name(String::from("Fake bucket"))
- .balance(0)
- .balance_date(DateUtc::now())
- .budget_period(0)
- .budget_period_unit(BudgetPeriodUnit::Day)
- .budget_quantity(0)
+ .balance(None)
+ .balance_cache_key(None)
.group(String::from("Fake group"));
builder
}
diff --git a/schist_core/schist_fakes/src/bucket_transfer.rs b/schist_core/schist_fakes/src/bucket_transfer.rs
index 9bc1f80..bf5e71b 100644
--- a/schist_core/schist_fakes/src/bucket_transfer.rs
+++ b/schist_core/schist_fakes/src/bucket_transfer.rs
@@ -9,7 +9,7 @@ pub fn make_fake_bucket_transfer_builder(id: i32) -> BucketTransferBuilder {
builder
.id(id)
.description(String::from("Fake bucket transfer"))
- .quantity(0)
+ .amount(0)
.from_bucket_id(0)
.to_bucket_id(1);
builder
diff --git a/schist_core/schist_fakes/src/budget_drip.rs b/schist_core/schist_fakes/src/budget_drip.rs
deleted file mode 100644
index 498dd76..0000000
--- a/schist_core/schist_fakes/src/budget_drip.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-use schist_models::{budget_drip::{BudgetDrip, BudgetDripBuilder}, date_utc::DateUtc};
-use schist_traits::nowlike::Nowlike;
-
-pub fn make_fake_budget_drip(id: i32) -> BudgetDrip {
- make_fake_budget_drip_builder(id).build().unwrap()
-}
-
-pub fn make_fake_budget_drip_builder(id: i32) -> BudgetDripBuilder {
- let mut builder = BudgetDripBuilder::default();
- builder
- .id(id)
- .bucket_id(0)
- .date(DateUtc::now())
- .quantity(0);
- builder
-}
diff --git a/schist_core/schist_fakes/src/drip.rs b/schist_core/schist_fakes/src/drip.rs
new file mode 100644
index 0000000..88f0b05
--- /dev/null
+++ b/schist_core/schist_fakes/src/drip.rs
@@ -0,0 +1,15 @@
+use schist_models::{
+ date_utc::DateUtc,
+ drip::{Drip, DripBuilder},
+};
+use schist_traits::nowlike::Nowlike;
+
+pub fn make_fake_drip(id: i32) -> Drip {
+ make_fake_drip_builder(id).build().unwrap()
+}
+
+pub fn make_fake_drip_builder(id: i32) -> DripBuilder {
+ let mut builder = DripBuilder::default();
+ builder.id(id).amount(0).bucket_id(0).date(DateUtc::now());
+ builder
+}
diff --git a/schist_core/schist_fakes/src/lib.rs b/schist_core/schist_fakes/src/lib.rs
index ba88fb5..0e4cbb4 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 budget_drip;
pub mod bucket_transfer;
+pub mod drip;
+pub mod pipe;
pub mod transaction;
-pub mod transaction_categorisation;
diff --git a/schist_core/schist_fakes/src/pipe.rs b/schist_core/schist_fakes/src/pipe.rs
new file mode 100644
index 0000000..6e96401
--- /dev/null
+++ b/schist_core/schist_fakes/src/pipe.rs
@@ -0,0 +1,21 @@
+use schist_models::{
+ budget_period_unit::BudgetPeriodUnit,
+ date_utc::DateUtc,
+ pipe::{Pipe, PipeBuilder},
+};
+use schist_traits::nowlike::Nowlike;
+
+pub fn make_fake_pipe(id: i32) -> Pipe {
+ make_fake_pipe_builder(id).build().unwrap()
+}
+
+pub fn make_fake_pipe_builder(id: i32) -> PipeBuilder {
+ let mut builder = PipeBuilder::default();
+ builder
+ .id(id)
+ .amount(0)
+ .bucket_id(0)
+ .period(BudgetPeriodUnit::Day)
+ .start_date(DateUtc::now());
+ builder
+}
diff --git a/schist_core/schist_fakes/src/transaction.rs b/schist_core/schist_fakes/src/transaction.rs
index cee7e00..bce02e5 100644
--- a/schist_core/schist_fakes/src/transaction.rs
+++ b/schist_core/schist_fakes/src/transaction.rs
@@ -1,18 +1,23 @@
-use schist_models::{date_utc::DateUtc, transaction::{Transaction, TransactionBuilder}};
+use schist_models::{
+ date_utc::DateUtc,
+ transaction::{Transaction, TransactionBuilder},
+};
use schist_traits::nowlike::Nowlike;
pub fn make_fake_transaction(id: i32) -> Transaction {
make_fake_transaction_builder(id).build().unwrap()
}
-pub fn make_fake_transaction_builder(id: i32) -> TransactionBuilder {
+pub fn make_fake_transaction_builder(id: i32) -> TransactionBuilder {
let mut builder = TransactionBuilder::default();
builder
.id(id)
- .description(String::from("Fake bucket transfer"))
- .payee(String::from("Fake payee"))
- .quantity(0)
+ .account_id(0)
+ .amount(0)
+ .bucket_id(None)
+ .counterparty(String::from("Fake payee"))
.date(DateUtc::now())
+ .description(String::from("Fake transaction"))
.account_id(0);
builder
}
diff --git a/schist_core/schist_fakes/src/transaction_categorisation.rs b/schist_core/schist_fakes/src/transaction_categorisation.rs
deleted file mode 100644
index 11b50c2..0000000
--- a/schist_core/schist_fakes/src/transaction_categorisation.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-use schist_models::transaction_categorisation::{TransactionCategorisation, TransactionCategorisationBuilder};
-
-pub fn make_fake_transaction_categorisation(id: i32) -> TransactionCategorisation {
- make_fake_transaction_categorisation_builder(id).build().unwrap()
-}
-
-pub fn make_fake_transaction_categorisation_builder(id: i32) -> TransactionCategorisationBuilder {
- let mut builder = TransactionCategorisationBuilder::default();
- builder
- .id(id)
- .description(String::from("Fake bucket transfer"))
- .quantity(0)
- .transaction_id(0)
- .bucket_id(0);
- builder
-}
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 ba65012..3b2c73e 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 budget_drips;
-DROP TABLE categories;
-DROP TABLE transaction_categorisations;
-DROP TABLE category_transfers;
+DROP TABLE buckets;
+DROP TABLE bucket_transfers;
+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 a09bf7b..275f280 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
@@ -9,9 +9,9 @@ CREATE TABLE accounts(
CREATE TABLE account_transfers(
id INTEGER NOT NULL PRIMARY KEY,
+ amount INTEGER NOT NULL,
date TEXT NOT NULL,
description TEXT NOT NULL,
- quantity INTEGER NOT NULL,
from_account_id INTEGER NOT NULL,
to_account_id INTEGER NOT NULL,
FOREIGN KEY (from_account_id)
@@ -24,70 +24,66 @@ CREATE TABLE account_transfers(
ON DELETE RESTRICT
);
-
-CREATE TABLE budget_drips(
+CREATE TABLE buckets(
id INTEGER NOT NULL PRIMARY KEY,
- category_id INTEGER NOT NULL,
- date TEXT NOT NULL,
- quantity INTEGER NOT NULL,
- FOREIGN KEY (category_id)
- REFERENCES categories (id)
- ON UPDATE CASCADE
- ON DELETE RESTRICT,
- UNIQUE(category_id, date)
+ balance INTEGER,
+ balance_cache_key TEXT,
+ bucket_group TEXT NOT NULL,
+ name TEXT NOT NULL
);
-CREATE TABLE categories(
- id INTEGER NOT NULL PRIMARY KEY,
- name TEXT NOT NULL,
- balance INTEGER NOT NULL,
- balance_date TEXT NOT NULL,
- budget_period INTEGER NOT NULL,
- budget_period_unit TEXT NOT NULL,
- budget_quantity INTEGER NOT NULL
-);
-
-CREATE TABLE category_transfers(
+CREATE TABLE bucket_transfers(
id INTEGER NOT NULL PRIMARY KEY,
+ amount INTEGER NOT NULL,
description TEXT NOT NULL,
- quantity INTEGER NOT NULL,
- from_category_id INTEGER NOT NULL,
- to_category_id INTEGER NOT NULL,
- FOREIGN KEY (from_category_id)
- REFERENCES categories (id)
+ 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_category_id)
- REFERENCES categories (id)
+ FOREIGN KEY (to_bucket_id)
+ REFERENCES buckets (id)
ON UPDATE CASCADE
ON DELETE RESTRICT
);
-CREATE TABLE transactions(
+CREATE TABLE drips(
id INTEGER NOT NULL PRIMARY KEY,
- description TEXT NOT NULL,
- payee TEXT NOT NULL,
- quantity INTEGER NOT NULL,
+ amount INTEGER NOT NULL,
+ bucket_id INTEGER NOT NULL,
date TEXT NOT NULL,
- account_id INTEGER NOT NULL,
- FOREIGN KEY (account_id)
- REFERENCES accounts (id)
+ inserted_at_unix_seconds INTEGER NOT NULL,
+ pipe_id INTEGER NOT NULL,
+ FOREIGN KEY (bucket_id)
+ REFERENCES buckets (id)
+ ON UPDATE CASCADE
+ ON DELETE RESTRICT,
+ UNIQUE(bucket_id, date)
+);
+
+CREATE TABLE pipes(
+ id INTEGER NOT NULL PRIMARY KEY,
+ amount INTEGER NOT NULL,
+ bucket_id INTEGER NOT NULL,
+ period TEXT NOT NULL,
+ start_date TEXT NOT NULL,
+ FOREIGN KEY (bucket_id)
+ REFERENCES buckets (id)
ON UPDATE CASCADE
ON DELETE RESTRICT
);
-CREATE TABLE transaction_categorisations(
+CREATE TABLE transactions(
id INTEGER NOT NULL PRIMARY KEY,
+ account_id INTEGER NOT NULL,
+ amount INTEGER NOT NULL,
+ bucket_id INTEGER,
+ counterparty TEXT NOT NULL,
+ date TEXT NOT NULL,
description TEXT NOT NULL,
- quantity INTEGER NOT NULL,
- transaction_id INTEGER NOT NULL,
- category_id INTEGER NOT NULL,
- FOREIGN KEY (transaction_id)
- REFERENCES transactions (id)
- ON UPDATE CASCADE
- ON DELETE RESTRICT,
- FOREIGN KEY (category_id)
- REFERENCES categories (id)
+ FOREIGN KEY (account_id)
+ REFERENCES accounts (id)
ON UPDATE CASCADE
ON DELETE RESTRICT
);
diff --git a/schist_core/schist_models/migrations/2025-08-15-090859_dummy_data/down.sql b/schist_core/schist_models/migrations/2025-08-15-090859_dummy_data/down.sql
new file mode 100644
index 0000000..8050572
--- /dev/null
+++ b/schist_core/schist_models/migrations/2025-08-15-090859_dummy_data/down.sql
@@ -0,0 +1,39 @@
+DELETE FROM accounts
+ WHERE id=0
+ AND name="Nationwide bank account"
+ AND opening_balance=0
+ AND opening_date="2024-01-01";
+
+DELETE FROM accounts
+ WHERE id=1
+ AND name="cash account"
+ AND opening_balance=0
+ AND opening_date="2024-01-01";
+
+DELETE FROM accounts
+ WHERE id=2
+ AND name="YBS savings account"
+ AND opening_balance=0
+ AND opening_date="2024-01-01";
+
+DELETE FROM buckets
+ WHERE id=0
+ AND balance IS NULL
+ AND balance_cache_key IS NULL
+ AND bucket_group="normal expenses"
+ AND name="groceries";
+
+DELETE FROM buckets
+ WHERE id=1
+ AND balance IS NULL
+ AND balance_cache_key IS NULL
+ AND bucket_group="luxuries"
+ AND name="bevvy";
+
+DELETE FROM buckets
+ WHERE id=2
+ AND balance IS NULL
+ AND balance_cache_key IS NULL
+ AND bucket_group="income"
+ AND name="salary";
+
diff --git a/schist_core/schist_models/migrations/2025-08-15-090859_dummy_data/up.sql b/schist_core/schist_models/migrations/2025-08-15-090859_dummy_data/up.sql
new file mode 100644
index 0000000..f5c97d0
--- /dev/null
+++ b/schist_core/schist_models/migrations/2025-08-15-090859_dummy_data/up.sql
@@ -0,0 +1,14 @@
+INSERT INTO accounts
+ (id, name, opening_balance, opening_date)
+ VALUES
+ (0, "Nationwide bank account", 0, "2024-01-01"),
+ (1, "cash account", 0, "2024-01-01"),
+ (2, "YBS savings account", 0, "2024-01-01");
+
+INSERT INTO buckets
+ (id, balance, balance_cache_key, bucket_group, name)
+ VALUES
+ (0, NULL, NULL, "normal expenses", "groceries"),
+ (1, NULL, NULL, "luxuries", "bevvy"),
+ (2, NULL, NULL, "income", "salary");
+
diff --git a/schist_core/schist_models/src/account_transfer.rs b/schist_core/schist_models/src/account_transfer.rs
index 06c51ac..ba33dee 100644
--- a/schist_core/schist_models/src/account_transfer.rs
+++ b/schist_core/schist_models/src/account_transfer.rs
@@ -7,9 +7,9 @@ use crate::date_utc::DateUtc;
#[diesel(table_name = crate::schema::account_transfers)]
pub struct AccountTransfer {
pub id: i32,
+ pub amount: i32,
pub date: DateUtc,
pub description: String,
- pub quantity: i32,
pub from_account_id: i32,
pub to_account_id: i32,
}
diff --git a/schist_core/schist_models/src/bucket.rs b/schist_core/schist_models/src/bucket.rs
index 1ee6a13..1a78628 100644
--- a/schist_core/schist_models/src/bucket.rs
+++ b/schist_core/schist_models/src/bucket.rs
@@ -2,8 +2,6 @@ use derive_builder::Builder;
use diesel::prelude::*;
use serde::{Deserialize, Serialize};
-use crate::{budget_period_unit::BudgetPeriodUnit, date_utc::DateUtc};
-
#[derive(
Builder,
Clone,
@@ -19,11 +17,9 @@ use crate::{budget_period_unit::BudgetPeriodUnit, date_utc::DateUtc};
#[diesel(table_name = crate::schema::buckets)]
pub struct Bucket {
pub id: i32,
- pub name: String,
- pub balance: i32,
- pub balance_date: DateUtc,
- pub budget_period: i32,
- pub budget_period_unit: BudgetPeriodUnit,
- pub budget_quantity: i32,
+ pub balance: Option<i32>,
+ pub balance_cache_key: Option<String>,
+ #[column_name = "bucket_group"]
pub group: String,
+ pub name: String,
}
diff --git a/schist_core/schist_models/src/bucket_transfer.rs b/schist_core/schist_models/src/bucket_transfer.rs
index bdf95d9..7c3a9d2 100644
--- a/schist_core/schist_models/src/bucket_transfer.rs
+++ b/schist_core/schist_models/src/bucket_transfer.rs
@@ -5,8 +5,8 @@ use diesel::prelude::*;
#[diesel(table_name = crate::schema::bucket_transfers)]
pub struct BucketTransfer {
pub id: i32,
+ pub amount: i32,
pub description: String,
- pub quantity: i32,
pub from_bucket_id: i32,
pub to_bucket_id: i32,
}
diff --git a/schist_core/schist_models/src/budget_drip.rs b/schist_core/schist_models/src/budget_drip.rs
deleted file mode 100644
index 419c8f9..0000000
--- a/schist_core/schist_models/src/budget_drip.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-use derive_builder::Builder;
-use diesel::prelude::{Identifiable, Insertable, Queryable, Selectable};
-use serde::{Deserialize, Serialize};
-
-use crate::date_utc::DateUtc;
-
-#[derive(Builder, Clone, Copy, Queryable, Identifiable, Selectable, Debug, PartialEq, Serialize, Deserialize, Insertable)]
-#[diesel(table_name = crate::schema::budget_drips)]
-pub struct BudgetDrip {
- pub id: i32,
- pub bucket_id: i32,
- pub date: DateUtc,
- pub quantity: i32,
-}
diff --git a/schist_core/schist_models/src/drip.rs b/schist_core/schist_models/src/drip.rs
new file mode 100644
index 0000000..f092ae9
--- /dev/null
+++ b/schist_core/schist_models/src/drip.rs
@@ -0,0 +1,28 @@
+use derive_builder::Builder;
+use diesel::prelude::{Identifiable, Insertable, Queryable, Selectable};
+use serde::{Deserialize, Serialize};
+
+use crate::date_utc::DateUtc;
+
+#[derive(
+ Builder,
+ Clone,
+ Copy,
+ Queryable,
+ Identifiable,
+ Insertable,
+ Selectable,
+ Debug,
+ PartialEq,
+ Serialize,
+ Deserialize,
+)]
+#[diesel(table_name = crate::schema::drips)]
+pub struct Drip {
+ pub id: i32,
+ pub amount: i32,
+ pub bucket_id: i32,
+ pub date: DateUtc,
+ pub inserted_at_unix_seconds: i32,
+ pub pipe_id: i32,
+}
diff --git a/schist_core/schist_models/src/lib.rs b/schist_core/schist_models/src/lib.rs
index db5c593..503db17 100644
--- a/schist_core/schist_models/src/lib.rs
+++ b/schist_core/schist_models/src/lib.rs
@@ -2,11 +2,11 @@ pub mod account;
pub mod account_transfer;
pub mod bucket;
pub mod bucket_transfer;
-pub mod budget_drip;
pub mod budget_period_unit;
pub mod date_utc;
pub mod datetime_utc;
+pub mod drip;
pub mod migrations;
+pub mod pipe;
pub mod schema;
pub mod transaction;
-pub mod transaction_categorisation;
diff --git a/schist_core/schist_models/src/pipe.rs b/schist_core/schist_models/src/pipe.rs
new file mode 100644
index 0000000..fb66a20
--- /dev/null
+++ b/schist_core/schist_models/src/pipe.rs
@@ -0,0 +1,27 @@
+use derive_builder::Builder;
+use diesel::prelude::*;
+use serde::{Deserialize, Serialize};
+
+use crate::{budget_period_unit::BudgetPeriodUnit, date_utc::DateUtc};
+
+#[derive(
+ Builder,
+ Insertable,
+ Queryable,
+ Identifiable,
+ Selectable,
+ Debug,
+ PartialEq,
+ Clone,
+ Serialize,
+ Deserialize,
+)]
+#[diesel(table_name = crate::schema::pipes)]
+#[diesel(belongs_to(Bucket))]
+pub struct Pipe {
+ pub id: i32,
+ pub amount: i32,
+ pub bucket_id: i32,
+ pub period: BudgetPeriodUnit,
+ pub start_date: DateUtc,
+}
diff --git a/schist_core/schist_models/src/schema.rs b/schist_core/schist_models/src/schema.rs
index 1c9fc62..3799479 100644
--- a/schist_core/schist_models/src/schema.rs
+++ b/schist_core/schist_models/src/schema.rs
@@ -3,9 +3,9 @@
diesel::table! {
account_transfers (id) {
id -> Integer,
+ amount -> Integer,
date -> Text,
description -> Text,
- quantity -> Integer,
from_account_id -> Integer,
to_account_id -> Integer,
}
@@ -21,69 +21,68 @@ diesel::table! {
}
diesel::table! {
- budget_drips (id) {
+ bucket_transfers (id) {
id -> Integer,
- bucket_id -> Integer,
- date -> Text,
- quantity -> Integer,
+ amount -> Integer,
+ description -> Text,
+ from_bucket_id -> Integer,
+ to_bucket_id -> Integer,
}
}
diesel::table! {
buckets (id) {
id -> Integer,
+ balance -> Nullable<Integer>,
+ balance_cache_key -> Nullable<Text>,
+ bucket_group -> Text,
name -> Text,
- balance -> Integer,
- balance_date -> Text,
- budget_period -> Integer,
- budget_period_unit -> Text,
- budget_quantity -> Integer,
- group -> Text,
}
}
diesel::table! {
- bucket_transfers (id) {
+ drips (id) {
id -> Integer,
- description -> Text,
- quantity -> Integer,
- from_bucket_id -> Integer,
- to_bucket_id -> Integer,
+ amount -> Integer,
+ bucket_id -> Integer,
+ date -> Text,
+ inserted_at_unix_seconds -> Integer,
+ pipe_id -> Integer,
}
}
diesel::table! {
- transaction_categorisations (id) {
+ pipes (id) {
id -> Integer,
- description -> Text,
- quantity -> Integer,
- transaction_id -> Integer,
+ amount -> Integer,
bucket_id -> Integer,
+ period -> Text,
+ start_date -> Text,
}
}
diesel::table! {
transactions (id) {
id -> Integer,
- description -> Text,
- payee -> Text,
- quantity -> Integer,
- date -> Text,
account_id -> Integer,
+ amount -> Integer,
+ bucket_id -> Nullable<Integer>,
+ counterparty -> Text,
+ date -> Text,
+ description -> Text,
}
}
-diesel::joinable!(budget_drips -> buckets (bucket_id));
-diesel::joinable!(transaction_categorisations -> buckets (bucket_id));
-diesel::joinable!(transaction_categorisations -> transactions (transaction_id));
+diesel::joinable!(drips -> buckets (bucket_id));
+diesel::joinable!(pipes -> buckets (bucket_id));
diesel::joinable!(transactions -> accounts (account_id));
diesel::allow_tables_to_appear_in_same_query!(
account_transfers,
accounts,
- budget_drips,
- buckets,
bucket_transfers,
- transaction_categorisations,
+ buckets,
+ drips,
+ pipes,
transactions,
);
diff --git a/schist_core/schist_models/src/transaction.rs b/schist_core/schist_models/src/transaction.rs
index 9e983f5..7e754be 100644
--- a/schist_core/schist_models/src/transaction.rs
+++ b/schist_core/schist_models/src/transaction.rs
@@ -3,14 +3,17 @@ use diesel::prelude::{Associations, Identifiable, Insertable, Queryable, Selecta
use crate::{account::Account, date_utc::DateUtc};
-#[derive(Builder, Clone, Queryable, Identifiable, Selectable, Insertable, Associations, Debug, PartialEq)]
+#[derive(
+ Builder, Clone, Queryable, Identifiable, Selectable, Insertable, Associations, Debug, PartialEq,
+)]
#[diesel(table_name = crate::schema::transactions)]
#[diesel(belongs_to(Account))]
pub struct Transaction {
pub id: i32,
- pub description: String,
- pub payee: String,
- pub quantity: i32,
- pub date: DateUtc,
pub account_id: i32,
+ pub amount: i32,
+ pub bucket_id: Option<i32>,
+ pub counterparty: String,
+ pub date: DateUtc,
+ pub description: String,
}
diff --git a/schist_core/schist_models/src/transaction_categorisation.rs b/schist_core/schist_models/src/transaction_categorisation.rs
deleted file mode 100644
index 36752ee..0000000
--- a/schist_core/schist_models/src/transaction_categorisation.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-use derive_builder::Builder;
-use diesel::prelude::*;
-
-#[derive(Builder, Queryable, Identifiable, Selectable, Insertable, Debug, PartialEq)]
-#[diesel(table_name = crate::schema::transaction_categorisations)]
-pub struct TransactionCategorisation {
- pub id: i32,
- pub description: String,
- pub quantity: i32,
- pub transaction_id: i32,
- pub bucket_id: i32,
-}
diff --git a/schist_core/schist_models/user_data.sqlite b/schist_core/schist_models/user_data.sqlite
index a428ff0..175ce60 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/accounts.rs b/schist_core/schist_queries/src/accounts.rs
index ead281a..289faf6 100644
--- a/schist_core/schist_queries/src/accounts.rs
+++ b/schist_core/schist_queries/src/accounts.rs
@@ -11,16 +11,14 @@ pub fn delete_all_accounts(connection: &mut SqliteConnection) -> Result<usize> {
}
pub fn get_all_accounts(connection: &mut SqliteConnection) -> Result<Vec<Account>> {
- let all_accounts = accounts_table.select(Account::as_select())
+ let all_accounts = accounts_table
+ .select(Account::as_select())
.load(connection)
.with_context(|| "failed to get all accounts")?;
Ok(all_accounts)
}
-pub fn insert_accounts(
- accounts: &[Account],
- connection: &mut SqliteConnection,
-) -> Result<usize> {
+pub fn insert_accounts(accounts: &[Account], connection: &mut SqliteConnection) -> Result<usize> {
let num_accounts_inserted = diesel::insert_into(accounts_table)
.values(accounts)
.execute(connection)
diff --git a/schist_core/schist_queries/src/bucket_transfers.rs b/schist_core/schist_queries/src/bucket_transfers.rs
index 2145944..923867f 100644
--- a/schist_core/schist_queries/src/bucket_transfers.rs
+++ b/schist_core/schist_queries/src/bucket_transfers.rs
@@ -1,10 +1,9 @@
use anyhow::{Context, Result};
use diesel::{dsl::sum, QueryDsl, RunQueryDsl, SelectableHelper, SqliteConnection};
+use schist_models::bucket_transfer::BucketTransfer;
use schist_schema::schema::bucket_transfers::{
- self as bucket_transfers_schema,
- dsl::bucket_transfers as bucket_transfers_table,
+ self as bucket_transfers_schema, dsl::bucket_transfers as bucket_transfers_table,
};
-use schist_models::bucket_transfer::BucketTransfer;
pub fn delete_all_bucket_transfers(connection: &mut SqliteConnection) -> Result<usize> {
let num_rows_deleted = diesel::delete(bucket_transfers_table)
@@ -50,10 +49,15 @@ pub fn sum_bucket_transfer_quantity_per_from_bucket_id(
.group_by(bucket_transfers_schema::from_bucket_id)
.select((
bucket_transfers_schema::from_bucket_id,
- sum(bucket_transfers_schema::quantity),
+ sum(bucket_transfers_schema::amount),
))
.load::<(i32, Option<i64>)>(connection)
- .map(|result| result.iter().map(|sum| (sum.0, sum.1.unwrap_or(0))).collect())
+ .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)
}
@@ -65,10 +69,14 @@ pub fn sum_bucket_transfer_quantity_per_to_bucket_id(
.group_by(bucket_transfers_schema::to_bucket_id)
.select((
bucket_transfers_schema::to_bucket_id,
- sum(bucket_transfers_schema::quantity),
+ sum(bucket_transfers_schema::amount),
))
.load::<(i32, Option<i64>)>(connection)
- .map(|vec| vec.iter().map(|(id, sum)| (*id, sum.unwrap_or(0))).collect())
+ .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/buckets.rs b/schist_core/schist_queries/src/buckets.rs
index c7cf213..29270af 100644
--- a/schist_core/schist_queries/src/buckets.rs
+++ b/schist_core/schist_queries/src/buckets.rs
@@ -26,10 +26,7 @@ pub fn get_all_bucket_ids(connection: &mut SqliteConnection) -> Result<Vec<i32>>
Ok(all_bucket_ids)
}
-pub fn insert_buckets(
- buckets: &[Bucket],
- connection: &mut SqliteConnection,
-) -> Result<usize> {
+pub fn insert_buckets(buckets: &[Bucket], connection: &mut SqliteConnection) -> Result<usize> {
let num_buckets_inserted = diesel::insert_into(buckets_table)
.values(buckets)
.execute(connection)
diff --git a/schist_core/schist_queries/src/budget_drips.rs b/schist_core/schist_queries/src/budget_drips.rs
deleted file mode 100644
index b6f9372..0000000
--- a/schist_core/schist_queries/src/budget_drips.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-use anyhow::{Context, Result};
-use diesel::{QueryDsl, RunQueryDsl, SelectableHelper, SqliteConnection};
-use schist_models::budget_drip::BudgetDrip;
-use schist_schema::schema::budget_drips::dsl::budget_drips as budget_drips_table;
-
-pub fn delete_all_budget_drips(connection: &mut SqliteConnection) -> Result<usize> {
- let num_rows_deleted = diesel::delete(budget_drips_table)
- .execute(connection)
- .with_context(|| "failed to delete all budget drips")?;
- Ok(num_rows_deleted)
-}
-
-pub fn get_all_budget_drips(connection: &mut SqliteConnection) -> Result<Vec<BudgetDrip>> {
- let all_budget_drips = budget_drips_table.select(BudgetDrip::as_select())
- .load(connection)
- .with_context(|| "failed to get all budget drips")?;
- Ok(all_budget_drips)
-}
-
-pub fn insert_budget_drips(
- budget_drips: &[BudgetDrip],
- connection: &mut SqliteConnection,
-) -> Result<usize> {
- let num_budget_drips_inserted = diesel::insert_into(budget_drips_table)
- .values(budget_drips)
- .execute(connection)
- .with_context(|| insert_err_msg(budget_drips))?;
- Ok(num_budget_drips_inserted)
-}
-
-fn insert_err_msg(budget_drips: &[BudgetDrip]) -> String {
- format!(
- "failed to insert budget drips: [{}]",
- budget_drips
- .iter()
- .map(|a| a.id.to_string())
- .collect::<Vec<String>>()
- .join(", ")
- )
-}
diff --git a/schist_core/schist_queries/src/clear.rs b/schist_core/schist_queries/src/clear.rs
index 6d2894d..04d22d9 100644
--- a/schist_core/schist_queries/src/clear.rs
+++ b/schist_core/schist_queries/src/clear.rs
@@ -2,15 +2,17 @@ use anyhow::Result;
use diesel::SqliteConnection;
use crate::{
- accounts::delete_all_accounts, budget_drips::delete_all_budget_drips, buckets::delete_all_buckets, bucket_transfers::delete_all_bucket_transfers, transaction_categorisations::delete_all_transaction_categorisations, transactions::delete_all_transactions
+ 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,
};
pub fn clear(connection: &mut SqliteConnection) -> Result<()> {
delete_all_accounts(connection)?;
- delete_all_budget_drips(connection)?;
+ delete_all_drips(connection)?;
delete_all_buckets(connection)?;
delete_all_bucket_transfers(connection)?;
delete_all_transactions(connection)?;
- delete_all_transaction_categorisations(connection)?;
+ delete_all_pipes(connection)?;
Ok(())
}
diff --git a/schist_core/schist_queries/src/drips.rs b/schist_core/schist_queries/src/drips.rs
new file mode 100644
index 0000000..d9e33a8
--- /dev/null
+++ b/schist_core/schist_queries/src/drips.rs
@@ -0,0 +1,38 @@
+use anyhow::{Context, Result};
+use diesel::{QueryDsl, RunQueryDsl, SelectableHelper, SqliteConnection};
+use schist_models::drip::Drip;
+use schist_schema::schema::drips::dsl::drips as drips_table;
+
+pub fn delete_all_drips(connection: &mut SqliteConnection) -> Result<usize> {
+ let num_rows_deleted = diesel::delete(drips_table)
+ .execute(connection)
+ .with_context(|| "failed to delete all drips")?;
+ Ok(num_rows_deleted)
+}
+
+pub fn get_all_drips(connection: &mut SqliteConnection) -> Result<Vec<Drip>> {
+ let all_drips = drips_table
+ .select(Drip::as_select())
+ .load(connection)
+ .with_context(|| "failed to get all drips")?;
+ Ok(all_drips)
+}
+
+pub fn insert_drips(drips: &[Drip], connection: &mut SqliteConnection) -> Result<usize> {
+ let num_drips_inserted = diesel::insert_into(drips_table)
+ .values(drips)
+ .execute(connection)
+ .with_context(|| insert_err_msg(drips))?;
+ Ok(num_drips_inserted)
+}
+
+fn insert_err_msg(drips: &[Drip]) -> String {
+ format!(
+ "failed to insert drips: [{}]",
+ drips
+ .iter()
+ .map(|a| a.id.to_string())
+ .collect::<Vec<String>>()
+ .join(", ")
+ )
+}
diff --git a/schist_core/schist_queries/src/lib.rs b/schist_core/schist_queries/src/lib.rs
index e3e5488..ccd558d 100644
--- a/schist_core/schist_queries/src/lib.rs
+++ b/schist_core/schist_queries/src/lib.rs
@@ -1,10 +1,10 @@
-pub mod accounts;
pub mod account_transfers;
-pub mod budget_drips;
-pub mod buckets;
+pub mod accounts;
pub mod bucket_transfers;
+pub mod buckets;
pub mod clear;
+pub mod drips;
+pub mod pipes;
pub mod transactions;
-pub mod transaction_categorisations;
mod utils;
diff --git a/schist_core/schist_queries/src/pipes.rs b/schist_core/schist_queries/src/pipes.rs
new file mode 100644
index 0000000..188d193
--- /dev/null
+++ b/schist_core/schist_queries/src/pipes.rs
@@ -0,0 +1,55 @@
+use anyhow::{Context, Result};
+use diesel::{dsl::sum, QueryDsl, RunQueryDsl, SelectableHelper, SqliteConnection};
+use schist_models::pipe::Pipe;
+use schist_schema::schema::pipes::{self as pipes_schema, dsl::pipes as pipes_table};
+
+pub fn delete_all_pipes(connection: &mut SqliteConnection) -> Result<usize> {
+ let num_rows_deleted = diesel::delete(pipes_table)
+ .execute(connection)
+ .with_context(|| "failed to delete all pipes")?;
+ Ok(num_rows_deleted)
+}
+
+pub fn get_all_pipes(connection: &mut SqliteConnection) -> Result<Vec<Pipe>> {
+ let all_pipes = pipes_table
+ .select(Pipe::as_select())
+ .load(connection)
+ .with_context(|| "failed to get all pipes")?;
+ Ok(all_pipes)
+}
+
+pub fn insert_pipes(
+ pipes: &[Pipe],
+ connection: &mut SqliteConnection,
+) -> Result<usize> {
+ let num_rows_inserted = diesel::insert_into(pipes_table)
+ .values(pipes)
+ .execute(connection)
+ .with_context(|| insert_err_msg(&pipes))?;
+ Ok(num_rows_inserted)
+}
+
+fn insert_err_msg(pipes: &[Pipe]) -> String {
+ format!(
+ "failed to insert pipes: [{}]",
+ pipes
+ .iter()
+ .map(|tc| tc.id.to_string())
+ .collect::<Vec<String>>()
+ .join(", ")
+ )
+}
+
+pub fn sum_pipes_flow_per_bucket_id(connection: &mut SqliteConnection) -> Result<Vec<(i32, i64)>> {
+ let sum = pipes_table
+ .group_by(pipes_schema::bucket_id)
+ .select((pipes_schema::bucket_id, sum(pipes_schema::amount)))
+ .load::<(i32, Option<i64>)>(connection)
+ .map(|vec| {
+ vec.iter()
+ .map(|(bucket_id, sum)| (*bucket_id, sum.unwrap_or(0)))
+ .collect()
+ })
+ .with_context(|| "failed to sum pipes flow per bucket ID")?;
+ Ok(sum)
+}
diff --git a/schist_core/schist_queries/src/transaction_categorisations.rs b/schist_core/schist_queries/src/transaction_categorisations.rs
deleted file mode 100644
index 95aaf8d..0000000
--- a/schist_core/schist_queries/src/transaction_categorisations.rs
+++ /dev/null
@@ -1,59 +0,0 @@
-use anyhow::{Context, Result};
-use diesel::{dsl::sum, QueryDsl, RunQueryDsl, SelectableHelper, SqliteConnection};
-use schist_models::transaction_categorisation::TransactionCategorisation;
-use schist_schema::schema::transaction_categorisations::{
- self as transaction_categorisations_schema,
- dsl::transaction_categorisations as transaction_categorisations_table,
-};
-
-pub fn delete_all_transaction_categorisations(connection: &mut SqliteConnection) -> Result<usize> {
- let num_rows_deleted = diesel::delete(transaction_categorisations_table)
- .execute(connection)
- .with_context(|| "failed to delete all transaction categorisations")?;
- Ok(num_rows_deleted)
-}
-
-pub fn get_all_transaction_categorisations(connection: &mut SqliteConnection) -> Result<Vec<TransactionCategorisation>> {
- let all_transaction_categorisations = transaction_categorisations_table
- .select(TransactionCategorisation::as_select())
- .load(connection)
- .with_context(|| "failed to get all transaction categorisations")?;
- Ok(all_transaction_categorisations)
-}
-
-pub fn insert_transaction_categorisations(
- transaction_categorisations: &[TransactionCategorisation],
- connection: &mut SqliteConnection,
-) -> Result<usize> {
- let num_rows_inserted = diesel::insert_into(transaction_categorisations_table)
- .values(transaction_categorisations)
- .execute(connection)
- .with_context(|| insert_err_msg(&transaction_categorisations))?;
- Ok(num_rows_inserted)
-}
-
-fn insert_err_msg(transaction_categorisations: &[TransactionCategorisation]) -> String {
- format!(
- "failed to insert transaction categorisations: [{}]",
- transaction_categorisations
- .iter()
- .map(|tc| tc.id.to_string())
- .collect::<Vec<String>>()
- .join(", ")
- )
-}
-
-pub fn sum_transaction_categorisation_quantity_per_bucket_id(
- connection: &mut SqliteConnection,
-) -> Result<Vec<(i32, i64)>> {
- let sum = transaction_categorisations_table
- .group_by(transaction_categorisations_schema::bucket_id)
- .select((
- transaction_categorisations_schema::bucket_id,
- sum(transaction_categorisations_schema::quantity),
- ))
- .load::<(i32, Option<i64>)>(connection)
- .map(|vec| vec.iter().map(|(bucket_id, sum)| (*bucket_id, sum.unwrap_or(0))).collect())
- .with_context(|| "failed to sum transaction categorisation quantity per bucket ID")?;
- Ok(sum)
-}
diff --git a/schist_core/schist_queries/src/transactions.rs b/schist_core/schist_queries/src/transactions.rs
index 5941ebc..3abacfb 100644
--- a/schist_core/schist_queries/src/transactions.rs
+++ b/schist_core/schist_queries/src/transactions.rs
@@ -14,7 +14,7 @@ pub fn get_all_transactions(connection: &mut SqliteConnection) -> Result<Vec<Tra
let all_transactions = transactions_table
.select(Transaction::as_select())
.load(connection)
- .with_context(|| "failed to get all bucket transfers")?;
+ .with_context(|| "failed to get all transactions")?;
Ok(all_transactions)
}
diff --git a/schist_core/schist_queries/src/utils/calculate_bucket_balance.rs b/schist_core/schist_queries/src/utils/calculate_bucket_balance.rs
index 5194084..e238613 100644
--- a/schist_core/schist_queries/src/utils/calculate_bucket_balance.rs
+++ b/schist_core/schist_queries/src/utils/calculate_bucket_balance.rs
@@ -1,31 +1,26 @@
use anyhow::Result;
-use schist_models::{bucket::Bucket, budget_drip::BudgetDrip};
+use schist_models::{bucket::Bucket, drip::Drip};
-use super::{calculate_budgets_accrual, find_by_id_or};
+use super::{find_by_id_or, sum_drips_for_bucket};
pub fn calculate_bucket_balance(
bucket: &Bucket,
transaction_sums: &[(i32, i64)],
bucket_transfer_from_sums: &[(i32, i64)],
bucket_transfer_to_sums: &[(i32, i64)],
- budget_drips: &[BudgetDrip],
+ budget_drips: &[Drip],
) -> Result<i64> {
let transaction_sum = find_by_id_or(transaction_sums, bucket.id, 0);
let bucket_transfer_from_sum = find_by_id_or(bucket_transfer_from_sums, bucket.id, 0);
let bucket_transfer_to_sum = find_by_id_or(bucket_transfer_to_sums, bucket.id, 0);
- let budget_accruals_sum = calculate_budgets_accrual(bucket, budget_drips)?;
-
- Ok(
- transaction_sum
- + budget_accruals_sum
- + bucket_transfer_to_sum
- - bucket_transfer_from_sum
- )
+ let budget_accruals_sum = sum_drips_for_bucket(bucket, budget_drips)?;
+
+ Ok(transaction_sum + budget_accruals_sum + bucket_transfer_to_sum - bucket_transfer_from_sum)
}
#[cfg(test)]
mod test {
- use schist_fakes::{budget_drip::make_fake_budget_drip_builder, bucket::make_fake_bucket};
+ use schist_fakes::{bucket::make_fake_bucket, drip::make_fake_drip_builder};
use super::calculate_bucket_balance;
@@ -45,9 +40,11 @@ mod test {
let transaction_sums = [(1, 100)];
let bucket_transfer_from_sums = [(1, 91)];
let bucket_transfer_to_sums = [(2, 79)];
- let budget_drips = [
- make_fake_budget_drip_builder(0).quantity(100).bucket_id(1).build().unwrap(),
- ];
+ let budget_drips = [make_fake_drip_builder(0)
+ .amount(100)
+ .bucket_id(1)
+ .build()
+ .unwrap()];
let result = calculate_bucket_balance(
&bucket,
@@ -108,11 +105,31 @@ mod test {
let bucket_transfer_from_sums = [(0, 91)];
let bucket_transfer_to_sums = [(0, 79)];
let budget_drips = [
- make_fake_budget_drip_builder(0).quantity(77).bucket_id(0).build().unwrap(),
- make_fake_budget_drip_builder(0).quantity(77).bucket_id(0).build().unwrap(),
- make_fake_budget_drip_builder(0).quantity(77).bucket_id(0).build().unwrap(),
- make_fake_budget_drip_builder(0).quantity(77).bucket_id(0).build().unwrap(),
- make_fake_budget_drip_builder(0).quantity(77).bucket_id(0).build().unwrap(),
+ make_fake_drip_builder(0)
+ .amount(77)
+ .bucket_id(0)
+ .build()
+ .unwrap(),
+ make_fake_drip_builder(0)
+ .amount(77)
+ .bucket_id(0)
+ .build()
+ .unwrap(),
+ make_fake_drip_builder(0)
+ .amount(77)
+ .bucket_id(0)
+ .build()
+ .unwrap(),
+ make_fake_drip_builder(0)
+ .amount(77)
+ .bucket_id(0)
+ .build()
+ .unwrap(),
+ make_fake_drip_builder(0)
+ .amount(77)
+ .bucket_id(0)
+ .build()
+ .unwrap(),
];
let result = calculate_bucket_balance(
diff --git a/schist_core/schist_queries/src/utils/calculate_budgets_accrual.rs b/schist_core/schist_queries/src/utils/calculate_budgets_accrual.rs
deleted file mode 100644
index cbf7180..0000000
--- a/schist_core/schist_queries/src/utils/calculate_budgets_accrual.rs
+++ /dev/null
@@ -1,72 +0,0 @@
-use anyhow::Result;
-use schist_models::{
- budget_drip::BudgetDrip,
- bucket::Bucket,
-};
-
-pub fn calculate_budgets_accrual(bucket: &Bucket, budget_drips: &[BudgetDrip]) -> Result<i64> {
- Ok(budget_drips
- .iter()
- .filter(|bd| bd.bucket_id == bucket.id)
- .map(|bd| Into::<i64>::into(bd.quantity))
- .sum()
- )
-}
-
-#[cfg(test)]
-mod test {
- use schist_fakes::{budget_drip::make_fake_budget_drip_builder, bucket::make_fake_bucket};
-
- use super::calculate_budgets_accrual;
-
- #[test]
- fn when_no_budget_drips_then_return_zero() {
- let bucket = make_fake_bucket(0);
- let budget_drips = [];
-
- let result = calculate_budgets_accrual(&bucket, &budget_drips);
-
- assert!(result.is_ok());
- assert_eq!(result.unwrap(), 0_i64);
- }
-
- #[test]
- fn when_one_budget_drip_for_another_bucket_then_return_zero() {
- let bucket = make_fake_bucket(0);
- let budget_drips = [
- make_fake_budget_drip_builder(0).quantity(100).bucket_id(1).build().unwrap(),
- ];
-
- let result = calculate_budgets_accrual(&bucket, &budget_drips);
-
- assert!(result.is_ok());
- assert_eq!(result.unwrap(), 0_i64);
- }
-
- #[test]
- fn when_one_budget_drip_then_return_quantity() {
- let bucket = make_fake_bucket(0);
- let budget_drips = [
- make_fake_budget_drip_builder(0).quantity(100).bucket_id(0).build().unwrap(),
- ];
-
- let result = calculate_budgets_accrual(&bucket, &budget_drips);
-
- assert!(result.is_ok());
- assert_eq!(result.unwrap(), 100);
- }
-
- #[test]
- fn when_two_budget_drips_then_return_sum() {
- let bucket = make_fake_bucket(0);
- let budget_drips = [
- make_fake_budget_drip_builder(0).quantity(100).bucket_id(0).build().unwrap(),
- make_fake_budget_drip_builder(1).quantity(120).bucket_id(0).build().unwrap(),
- ];
-
- let result = calculate_budgets_accrual(&bucket, &budget_drips);
-
- assert!(result.is_ok());
- assert_eq!(result.unwrap(), 220);
- }
-}
diff --git a/schist_core/schist_queries/src/utils/mod.rs b/schist_core/schist_queries/src/utils/mod.rs
index c006a9b..6b47b48 100644
--- a/schist_core/schist_queries/src/utils/mod.rs
+++ b/schist_core/schist_queries/src/utils/mod.rs
@@ -1,8 +1,8 @@
-mod calculate_budgets_accrual;
mod calculate_bucket_balance;
mod find_by_id_or;
+mod sum_drips_for_bucket;
-use calculate_budgets_accrual::calculate_budgets_accrual;
+use sum_drips_for_bucket::sum_drips_for_bucket;
pub use calculate_bucket_balance::calculate_bucket_balance;
pub use find_by_id_or::find_by_id_or;
diff --git a/schist_core/schist_queries/src/utils/sum_drips_for_bucket.rs b/schist_core/schist_queries/src/utils/sum_drips_for_bucket.rs
new file mode 100644
index 0000000..76f7988
--- /dev/null
+++ b/schist_core/schist_queries/src/utils/sum_drips_for_bucket.rs
@@ -0,0 +1,80 @@
+use anyhow::Result;
+use schist_models::{bucket::Bucket, drip::Drip};
+
+pub fn sum_drips_for_bucket(bucket: &Bucket, budget_drips: &[Drip]) -> Result<i64> {
+ Ok(budget_drips
+ .iter()
+ .filter(|bd| bd.bucket_id == bucket.id)
+ .map(|bd| Into::<i64>::into(bd.amount))
+ .sum())
+}
+
+#[cfg(test)]
+mod test {
+ use schist_fakes::{bucket::make_fake_bucket, drip::make_fake_drip_builder};
+
+ use super::sum_drips_for_bucket;
+
+ #[test]
+ fn when_no_budget_drips_then_return_zero() {
+ let bucket = make_fake_bucket(0);
+ let budget_drips = [];
+
+ let result = sum_drips_for_bucket(&bucket, &budget_drips);
+
+ assert!(result.is_ok());
+ assert_eq!(result.unwrap(), 0_i64);
+ }
+
+ #[test]
+ fn when_one_budget_drip_for_another_bucket_then_return_zero() {
+ let bucket = make_fake_bucket(0);
+ let budget_drips = [make_fake_drip_builder(0)
+ .amount(100)
+ .bucket_id(1)
+ .build()
+ .unwrap()];
+
+ let result = sum_drips_for_bucket(&bucket, &budget_drips);
+
+ assert!(result.is_ok());
+ assert_eq!(result.unwrap(), 0_i64);
+ }
+
+ #[test]
+ fn when_one_budget_drip_then_return_quantity() {
+ let bucket = make_fake_bucket(0);
+ let budget_drips = [make_fake_drip_builder(0)
+ .amount(100)
+ .bucket_id(0)
+ .build()
+ .unwrap()];
+
+ let result = sum_drips_for_bucket(&bucket, &budget_drips);
+
+ assert!(result.is_ok());
+ assert_eq!(result.unwrap(), 100);
+ }
+
+ #[test]
+ fn when_two_budget_drips_then_return_sum() {
+ let bucket = make_fake_bucket(0);
+ let budget_drips = [
+ make_fake_drip_builder(0)
+ .amount(100)
+ .bucket_id(0)
+ .build()
+ .unwrap(),
+ make_fake_drip_builder(1)
+ .amount(120)
+ .bucket_id(0)
+ .build()
+ .unwrap(),
+ ];
+
+ let result = sum_drips_for_bucket(&bucket, &budget_drips);
+
+ assert!(result.is_ok());
+ assert_eq!(result.unwrap(), 220);
+ }
+}
diff --git a/schist_core/schist_queries/tests/category_transfers.rs b/schist_core/schist_queries/tests/category_transfers.rs
index e913dcb..13b9866 100644
--- a/schist_core/schist_queries/tests/category_transfers.rs
+++ b/schist_core/schist_queries/tests/category_transfers.rs
@@ -11,12 +11,21 @@ fn when_insert_bucket_transfers_then_returns_num_bucket_transfers() {
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(),
+ 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();
+ let num_bucket_transfers_inserted =
+ queries::bucket_transfers::insert_bucket_transfers(&bucket_transfers, connection).unwrap();
assert_eq!(num_bucket_transfers_inserted, 2);
}
@@ -27,20 +36,34 @@ fn given_bucket_transfers_when_get_all_bucket_transfers_then_return_bucket_trans
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(),
+ 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::insert_bucket_transfers(&bucket_transfers, connection).unwrap();
- let bucket_transfers_in_db = queries::bucket_transfers::get_all_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)));
+ 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)));
+ assert!(bucket_transfers
+ .iter()
+ .any(|bucket_transfer| bucket_transfer.eq(&bucket_transfer_in_db)));
}
}
@@ -50,13 +73,23 @@ fn given_bucket_transfers_when_delete_all_bucket_transfers_then_return_num_of_bu
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(),
+ 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::insert_bucket_transfers(&bucket_transfers, connection).unwrap();
- let num_bucket_transfers_deleted = queries::bucket_transfers::delete_all_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());
}
@@ -67,32 +100,60 @@ fn given_deleted_bucket_transfers_when_get_all_bucket_transfers_then_return_empt
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(),
+ 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::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();
+ 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() {
+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).quantity(1).build().unwrap(),
- make_fake_bucket_transfer_builder(1).from_bucket_id(0).to_bucket_id(1).quantity(2).build().unwrap(),
- make_fake_bucket_transfer_builder(2).from_bucket_id(1).to_bucket_id(0).quantity(4).build().unwrap(),
+ 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 _ =
+ queries::bucket_transfers::insert_bucket_transfers(&bucket_transfers, connection).unwrap();
- let sums = queries::bucket_transfers::sum_bucket_transfer_quantity_per_from_bucket_id(connection);
+ let sums =
+ queries::bucket_transfers::sum_bucket_transfer_quantity_per_from_bucket_id(connection);
assert!(sums.is_ok());
let mut sums = sums.unwrap();
@@ -108,12 +169,27 @@ fn given_bucket_transfers_when_sum_quantity_per_to_bucket_id_then_returns_sum_pe
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).quantity(1).build().unwrap(),
- make_fake_bucket_transfer_builder(1).from_bucket_id(0).to_bucket_id(1).quantity(2).build().unwrap(),
- make_fake_bucket_transfer_builder(2).from_bucket_id(1).to_bucket_id(0).quantity(4).build().unwrap(),
+ 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)
+ .build()
+ .unwrap(),
];
let _ = queries::buckets::insert_buckets(&buckets, connection);
- let _ = queries::bucket_transfers::insert_bucket_transfers(&bucket_transfers, connection).unwrap();
+ 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);
diff --git a/schist_core/schist_queries/tests/budget_drips.rs b/schist_core/schist_queries/tests/drips.rs
index 7c5bd4d..dccdbf4 100644
--- a/schist_core/schist_queries/tests/budget_drips.rs
+++ b/schist_core/schist_queries/tests/drips.rs
@@ -2,7 +2,7 @@ mod common;
use common::test_context::TestContext;
use diesel::{Connection, SqliteConnection};
-use schist_fakes::{budget_drip::make_fake_budget_drip_builder, bucket::make_fake_bucket};
+use schist_fakes::{bucket::make_fake_bucket, drip::make_fake_drip_builder};
use schist_models::{bucket::Bucket, date_utc::DateUtc};
use schist_queries as queries;
@@ -18,17 +18,20 @@ fn when_insert_budget_drips_then_returns_num_budget_drips() {
let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
let _buckets = given_buckets(connection);
let budget_drips = [
- make_fake_budget_drip_builder(0)
+ make_fake_drip_builder(0)
.date(DateUtc::from_ymd(2020, 12, 25).unwrap())
.bucket_id(0)
- .build().unwrap(),
- make_fake_budget_drip_builder(1)
+ .build()
+ .unwrap(),
+ make_fake_drip_builder(1)
.date(DateUtc::from_ymd(2020, 12, 26).unwrap())
.bucket_id(0)
- .build().unwrap(),
+ .build()
+ .unwrap(),
];
- let num_budget_drips_inserted = queries::budget_drips::insert_budget_drips(&budget_drips, connection).unwrap();
+ let num_budget_drips_inserted =
+ queries::drips::insert_drips(&budget_drips, connection).unwrap();
assert_eq!(num_budget_drips_inserted, 2);
}
@@ -39,72 +42,68 @@ fn given_budget_drip_when_insert_budget_drip_same_bucket_and_same_date_then_retu
let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
let _buckets = given_buckets(connection);
- let budget_drips_1 = [
- make_fake_budget_drip_builder(0)
- .bucket_id(0)
- .date(DateUtc::from_ymd(2020, 12, 25).unwrap())
- .build().unwrap()
- ];
- let _ = queries::budget_drips::insert_budget_drips(&budget_drips_1, connection);
+ let budget_drips_1 = [make_fake_drip_builder(0)
+ .bucket_id(0)
+ .date(DateUtc::from_ymd(2020, 12, 25).unwrap())
+ .build()
+ .unwrap()];
+ let _ = queries::drips::insert_drips(&budget_drips_1, connection);
- let budget_drips_2 = [
- make_fake_budget_drip_builder(1)
- .bucket_id(0)
- .date(DateUtc::from_ymd(2020, 12, 25).unwrap())
- .build().unwrap()
- ];
- let result = queries::budget_drips::insert_budget_drips(&budget_drips_2, connection);
+ let budget_drips_2 = [make_fake_drip_builder(1)
+ .bucket_id(0)
+ .date(DateUtc::from_ymd(2020, 12, 25).unwrap())
+ .build()
+ .unwrap()];
+ let result = queries::drips::insert_drips(&budget_drips_2, connection);
assert!(result.is_err());
}
#[test]
-fn given_budget_drip_when_insert_budget_drip_different_bucket_and_same_date_then_return_num_budget_drips_inserted() {
+fn given_budget_drip_when_insert_budget_drip_different_bucket_and_same_date_then_return_num_budget_drips_inserted(
+) {
let context = TestContext::new();
let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
let _buckets = given_buckets(connection);
- let budget_drips_1 = [
- make_fake_budget_drip_builder(0)
- .bucket_id(0)
- .date(DateUtc::from_ymd(2020, 12, 25).unwrap())
- .build().unwrap()
- ];
- let _ = queries::budget_drips::insert_budget_drips(&budget_drips_1, connection);
+ let budget_drips_1 = [make_fake_drip_builder(0)
+ .bucket_id(0)
+ .date(DateUtc::from_ymd(2020, 12, 25).unwrap())
+ .build()
+ .unwrap()];
+ let _ = queries::drips::insert_drips(&budget_drips_1, connection);
- let budget_drips_2 = [
- make_fake_budget_drip_builder(1)
- .bucket_id(1)
- .date(DateUtc::from_ymd(2020, 12, 25).unwrap())
- .build().unwrap()
- ];
- let result = queries::budget_drips::insert_budget_drips(&budget_drips_2, connection);
+ let budget_drips_2 = [make_fake_drip_builder(1)
+ .bucket_id(1)
+ .date(DateUtc::from_ymd(2020, 12, 25).unwrap())
+ .build()
+ .unwrap()];
+ let result = queries::drips::insert_drips(&budget_drips_2, connection);
assert!(result.is_ok());
assert_eq!(result.unwrap(), 1);
}
#[test]
-fn given_budget_drip_when_insert_budget_drip_same_bucket_and_different_date_then_return_num_budget_drips_inserted() {
+fn given_budget_drip_when_insert_budget_drip_same_bucket_and_different_date_then_return_num_budget_drips_inserted(
+) {
let context = TestContext::new();
let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
let _buckets = given_buckets(connection);
- let budget_drips_1 = [
- make_fake_budget_drip_builder(0)
- .bucket_id(0)
- .date(DateUtc::from_ymd(2020, 12, 25).unwrap())
- .build().unwrap()
- ];
- let _ = queries::budget_drips::insert_budget_drips(&budget_drips_1, connection);
+ let budget_drips_1 = [make_fake_drip_builder(0)
+ .bucket_id(0)
+ .date(DateUtc::from_ymd(2020, 12, 25).unwrap())
+ .build()
+ .unwrap()];
+ let _ = queries::drips::insert_drips(&budget_drips_1, connection);
- let budget_drips_2 = [
- make_fake_budget_drip_builder(1)
- .bucket_id(0)
- .date(DateUtc::from_ymd(2020, 12, 26).unwrap())
- .build().unwrap()
- ];
- let result = queries::budget_drips::insert_budget_drips(&budget_drips_2, connection);
+ let budget_drips_2 = [make_fake_drip_builder(1)
+ .bucket_id(0)
+ .date(DateUtc::from_ymd(2020, 12, 26).unwrap())
+ .build()
+ .unwrap()];
+ let result = queries::drips::insert_drips(&budget_drips_2, connection);
assert!(result.is_ok());
assert_eq!(result.unwrap(), 1);
@@ -116,27 +115,33 @@ fn given_budget_drips_when_get_all_budget_drips_then_return_budget_drips() {
let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
let _buckets = given_buckets(connection);
let budget_drips = [
- make_fake_budget_drip_builder(0)
+ make_fake_drip_builder(0)
.date(DateUtc::from_ymd(2020, 12, 25).unwrap())
.bucket_id(0)
- .build().unwrap(),
- make_fake_budget_drip_builder(1)
+ .build()
+ .unwrap(),
+ make_fake_drip_builder(1)
.date(DateUtc::from_ymd(2020, 12, 26).unwrap())
.bucket_id(0)
- .build().unwrap(),
+ .build()
+ .unwrap(),
];
- let _ = queries::budget_drips::insert_budget_drips(&budget_drips, connection).unwrap();
+ let _ = queries::drips::insert_drips(&budget_drips, connection).unwrap();
- let budget_drips_in_db = queries::budget_drips::get_all_budget_drips(connection).unwrap();
+ let budget_drips_in_db = queries::drips::get_all_drips(connection).unwrap();
assert_eq!(budget_drips_in_db.len(), budget_drips.len());
assert_eq!(budget_drips_in_db[0], budget_drips[0]);
assert_eq!(budget_drips_in_db[1], budget_drips[1]);
for budget_drip in &budget_drips {
- assert!(budget_drips_in_db.iter().any(|budget_drip_in_db| budget_drip_in_db.eq(&budget_drip)));
+ assert!(budget_drips_in_db
+ .iter()
+ .any(|budget_drip_in_db| budget_drip_in_db.eq(&budget_drip)));
}
for budget_drip_in_db in budget_drips_in_db {
- assert!(budget_drips.iter().any(|budget_drip| budget_drip.eq(&budget_drip_in_db)));
+ assert!(budget_drips
+ .iter()
+ .any(|budget_drip| budget_drip.eq(&budget_drip_in_db)));
}
}
@@ -146,18 +151,20 @@ fn given_budget_drips_when_delete_all_budget_drips_then_return_num_of_budget_dri
let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
let _buckets = given_buckets(connection);
let budget_drips = [
- make_fake_budget_drip_builder(0)
+ make_fake_drip_builder(0)
.date(DateUtc::from_ymd(2020, 12, 25).unwrap())
.bucket_id(0)
- .build().unwrap(),
- make_fake_budget_drip_builder(1)
+ .build()
+ .unwrap(),
+ make_fake_drip_builder(1)
.date(DateUtc::from_ymd(2020, 12, 26).unwrap())
.bucket_id(0)
- .build().unwrap(),
+ .build()
+ .unwrap(),
];
- let _ = queries::budget_drips::insert_budget_drips(&budget_drips, connection).unwrap();
+ let _ = queries::drips::insert_drips(&budget_drips, connection).unwrap();
- let num_budget_drips_deleted = queries::budget_drips::delete_all_budget_drips(connection).unwrap();
+ let num_budget_drips_deleted = queries::drips::delete_all_drips(connection).unwrap();
assert_eq!(num_budget_drips_deleted, budget_drips.len());
}
@@ -168,19 +175,21 @@ fn given_deleted_budget_drips_when_get_all_budget_drips_then_return_empty() {
let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
let _buckets = given_buckets(connection);
let budget_drips = [
- make_fake_budget_drip_builder(0)
+ make_fake_drip_builder(0)
.date(DateUtc::from_ymd(2020, 12, 25).unwrap())
.bucket_id(0)
- .build().unwrap(),
- make_fake_budget_drip_builder(1)
+ .build()
+ .unwrap(),
+ make_fake_drip_builder(1)
.date(DateUtc::from_ymd(2020, 12, 26).unwrap())
.bucket_id(0)
- .build().unwrap(),
+ .build()
+ .unwrap(),
];
- let _ = queries::budget_drips::insert_budget_drips(&budget_drips, connection).unwrap();
- let _ = queries::budget_drips::delete_all_budget_drips(connection).unwrap();
+ let _ = queries::drips::insert_drips(&budget_drips, connection).unwrap();
+ let _ = queries::drips::delete_all_drips(connection).unwrap();
- let budget_drips_returned = queries::budget_drips::get_all_budget_drips(connection).unwrap();
+ let budget_drips_returned = queries::drips::get_all_drips(connection).unwrap();
assert_eq!(budget_drips_returned.len(), 0);
}
diff --git a/schist_core/schist_queries/tests/pipes.rs b/schist_core/schist_queries/tests/pipes.rs
new file mode 100644
index 0000000..abd5a5e
--- /dev/null
+++ b/schist_core/schist_queries/tests/pipes.rs
@@ -0,0 +1,151 @@
+mod common;
+
+use common::test_context::TestContext;
+use diesel::{Connection, SqliteConnection};
+use schist_fakes::{
+ account::make_fake_account, bucket::make_fake_bucket, pipe::make_fake_pipe_builder,
+ transaction::make_fake_transaction_builder,
+};
+use schist_models::{account::Account, bucket::Bucket, transaction::Transaction};
+use schist_queries as queries;
+
+fn given_accounts(connection: &mut SqliteConnection) -> Vec<Account> {
+ let accounts = vec![make_fake_account(0)];
+ let _ = queries::accounts::insert_accounts(&accounts, connection);
+ accounts
+}
+
+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);
+ buckets
+}
+
+fn given_transactions(connection: &mut SqliteConnection) -> Vec<Transaction> {
+ let transactions = vec![
+ make_fake_transaction_builder(0)
+ .account_id(0)
+ .build()
+ .unwrap(),
+ make_fake_transaction_builder(1)
+ .account_id(0)
+ .build()
+ .unwrap(),
+ ];
+ let _ = queries::transactions::insert_transactions(&transactions, connection);
+ transactions
+}
+
+#[test]
+fn when_insert_pipes_then_returns_num_pipes() {
+ let context = TestContext::new();
+ let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
+ given_accounts(connection);
+ given_buckets(connection);
+ given_transactions(connection);
+ let pipes = [
+ make_fake_pipe_builder(0).bucket_id(0).build().unwrap(),
+ make_fake_pipe_builder(1).bucket_id(0).build().unwrap(),
+ ];
+
+ let num_pipes_inserted = queries::pipes::insert_pipes(&pipes, connection).unwrap();
+
+ assert_eq!(num_pipes_inserted, 2);
+}
+
+#[test]
+fn given_pipes_when_get_all_pipes_then_return_pipes() {
+ let context = TestContext::new();
+ let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
+ given_accounts(connection);
+ given_buckets(connection);
+ given_transactions(connection);
+ let pipes = [
+ make_fake_pipe_builder(0).bucket_id(0).build().unwrap(),
+ make_fake_pipe_builder(1).bucket_id(0).build().unwrap(),
+ ];
+ let _ = queries::pipes::insert_pipes(&pipes, connection);
+
+ let pipes_in_db = queries::pipes::get_all_pipes(connection).unwrap();
+
+ assert_eq!(pipes_in_db.len(), pipes.len());
+ for pipe in &pipes {
+ assert!(pipes_in_db.iter().any(|pipe_in_db| pipe_in_db.eq(&pipe)));
+ }
+ for pipe_in_db in pipes_in_db {
+ assert!(pipes.iter().any(|pipe| pipe.eq(&pipe_in_db)));
+ }
+}
+
+#[test]
+fn given_pipes_when_delete_all_pipes_then_return_num_of_pipes() {
+ let context = TestContext::new();
+ let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
+ given_accounts(connection);
+ given_buckets(connection);
+ given_transactions(connection);
+ let pipes = [
+ make_fake_pipe_builder(0).bucket_id(0).build().unwrap(),
+ make_fake_pipe_builder(1).bucket_id(0).build().unwrap(),
+ ];
+ let _ = queries::pipes::insert_pipes(&pipes, connection);
+
+ let num_pipes_deleted = queries::pipes::delete_all_pipes(connection).unwrap();
+
+ assert_eq!(num_pipes_deleted, pipes.len());
+}
+
+#[test]
+fn given_deleted_pipes_when_get_all_pipes_then_return_empty() {
+ let context = TestContext::new();
+ let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
+ given_accounts(connection);
+ given_buckets(connection);
+ given_transactions(connection);
+ let pipes = [
+ make_fake_pipe_builder(0).bucket_id(0).build().unwrap(),
+ make_fake_pipe_builder(1).bucket_id(0).build().unwrap(),
+ ];
+ let _ = queries::pipes::insert_pipes(&pipes, connection);
+ let _ = queries::pipes::delete_all_pipes(connection);
+
+ let pipes_returned = queries::pipes::get_all_pipes(connection).unwrap();
+
+ assert_eq!(pipes_returned.len(), 0);
+}
+
+#[test]
+fn given_pipes_when_sum_quantity_per_bucket_id_then_returns_sum_quantity_per_bucket_id() {
+ let context = TestContext::new();
+ let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
+ given_accounts(connection);
+ let buckets = given_buckets(connection);
+ given_transactions(connection);
+ let pipes = [
+ make_fake_pipe_builder(0)
+ .bucket_id(0)
+ .amount(1)
+ .build()
+ .unwrap(),
+ make_fake_pipe_builder(1)
+ .bucket_id(0)
+ .amount(2)
+ .build()
+ .unwrap(),
+ make_fake_pipe_builder(2)
+ .bucket_id(1)
+ .amount(4)
+ .build()
+ .unwrap(),
+ ];
+ let _ = queries::pipes::insert_pipes(&pipes, connection);
+
+ let sums = queries::pipes::sum_pipes_flow_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/transaction_categorisations.rs b/schist_core/schist_queries/tests/transaction_categorisations.rs
deleted file mode 100644
index bb88896..0000000
--- a/schist_core/schist_queries/tests/transaction_categorisations.rs
+++ /dev/null
@@ -1,130 +0,0 @@
-mod common;
-
-use common::test_context::TestContext;
-use diesel::{Connection, SqliteConnection};
-use schist_fakes::{account::make_fake_account, bucket::make_fake_bucket, transaction::make_fake_transaction_builder, transaction_categorisation::make_fake_transaction_categorisation_builder};
-use schist_models::{account::Account, bucket::Bucket, transaction::Transaction};
-use schist_queries as queries;
-
-fn given_accounts(connection: &mut SqliteConnection) -> Vec<Account> {
- let accounts = vec![make_fake_account(0)];
- let _ = queries::accounts::insert_accounts(&accounts, connection);
- accounts
-}
-
-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);
- buckets
-}
-
-fn given_transactions(connection: &mut SqliteConnection) -> Vec<Transaction> {
- let transactions = vec![
- make_fake_transaction_builder(0).account_id(0).build().unwrap(),
- make_fake_transaction_builder(1).account_id(0).build().unwrap(),
- ];
- let _ = queries::transactions::insert_transactions(&transactions, connection);
- transactions
-}
-
-#[test]
-fn when_insert_transaction_categorisations_then_returns_num_transaction_categorisations() {
- let context = TestContext::new();
- let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
- given_accounts(connection);
- given_buckets(connection);
- given_transactions(connection);
- let transaction_categorisations = [
- make_fake_transaction_categorisation_builder(0).bucket_id(0).build().unwrap(),
- make_fake_transaction_categorisation_builder(1).bucket_id(0).build().unwrap(),
- ];
-
- let num_transaction_categorisations_inserted = queries::transaction_categorisations::insert_transaction_categorisations(&transaction_categorisations, connection).unwrap();
-
- assert_eq!(num_transaction_categorisations_inserted, 2);
-}
-
-#[test]
-fn given_transaction_categorisations_when_get_all_transaction_categorisations_then_return_transaction_categorisations() {
- let context = TestContext::new();
- let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
- given_accounts(connection);
- given_buckets(connection);
- given_transactions(connection);
- let transaction_categorisations = [
- make_fake_transaction_categorisation_builder(0).bucket_id(0).build().unwrap(),
- make_fake_transaction_categorisation_builder(1).bucket_id(0).build().unwrap(),
- ];
- let _ = queries::transaction_categorisations::insert_transaction_categorisations(&transaction_categorisations, connection);
-
- let transaction_categorisations_in_db = queries::transaction_categorisations::get_all_transaction_categorisations(connection).unwrap();
-
- assert_eq!(transaction_categorisations_in_db.len(), transaction_categorisations.len());
- for transaction_categorisation in &transaction_categorisations {
- assert!(transaction_categorisations_in_db.iter().any(|transaction_categorisation_in_db| transaction_categorisation_in_db.eq(&transaction_categorisation)));
- }
- for transaction_categorisation_in_db in transaction_categorisations_in_db {
- assert!(transaction_categorisations.iter().any(|transaction_categorisation| transaction_categorisation.eq(&transaction_categorisation_in_db)));
- }
-}
-
-#[test]
-fn given_transaction_categorisations_when_delete_all_transaction_categorisations_then_return_num_of_transaction_categorisations() {
- let context = TestContext::new();
- let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
- given_accounts(connection);
- given_buckets(connection);
- given_transactions(connection);
- let transaction_categorisations = [
- make_fake_transaction_categorisation_builder(0).bucket_id(0).build().unwrap(),
- make_fake_transaction_categorisation_builder(1).bucket_id(0).build().unwrap(),
- ];
- let _ = queries::transaction_categorisations::insert_transaction_categorisations(&transaction_categorisations, connection);
-
- let num_transaction_categorisations_deleted = queries::transaction_categorisations::delete_all_transaction_categorisations(connection).unwrap();
-
- assert_eq!(num_transaction_categorisations_deleted, transaction_categorisations.len());
-}
-
-#[test]
-fn given_deleted_transaction_categorisations_when_get_all_transaction_categorisations_then_return_empty() {
- let context = TestContext::new();
- let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
- given_accounts(connection);
- given_buckets(connection);
- given_transactions(connection);
- let transaction_categorisations = [
- make_fake_transaction_categorisation_builder(0).bucket_id(0).build().unwrap(),
- make_fake_transaction_categorisation_builder(1).bucket_id(0).build().unwrap(),
- ];
- let _ = queries::transaction_categorisations::insert_transaction_categorisations(&transaction_categorisations, connection);
- let _ = queries::transaction_categorisations::delete_all_transaction_categorisations(connection);
-
- let transaction_categorisations_returned = queries::transaction_categorisations::get_all_transaction_categorisations(connection).unwrap();
-
- assert_eq!(transaction_categorisations_returned.len(), 0);
-}
-
-#[test]
-fn given_transaction_categorisations_when_sum_quantity_per_bucket_id_then_returns_sum_quantity_per_bucket_id() {
- let context = TestContext::new();
- let connection = &mut SqliteConnection::establish(&context.db_url).unwrap();
- given_accounts(connection);
- let buckets = given_buckets(connection);
- given_transactions(connection);
- let transaction_categorisations = [
- make_fake_transaction_categorisation_builder(0).bucket_id(0).quantity(1).build().unwrap(),
- make_fake_transaction_categorisation_builder(1).bucket_id(0).quantity(2).build().unwrap(),
- make_fake_transaction_categorisation_builder(2).bucket_id(1).quantity(4).build().unwrap(),
- ];
- let _ = queries::transaction_categorisations::insert_transaction_categorisations(&transaction_categorisations, connection);
-
- let sums = queries::transaction_categorisations::sum_transaction_categorisation_quantity_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_desktop_gui/Cargo.toml b/schist_desktop_gui/Cargo.toml
index b7b80da..35e6521 100644
--- a/schist_desktop_gui/Cargo.toml
+++ b/schist_desktop_gui/Cargo.toml
@@ -5,7 +5,13 @@ edition = "2021"
[dependencies]
anyhow = { workspace = true }
+diesel = { workspace = true }
+diesel_migrations = { workspace = true }
+dirs = { workspace = true }
iced = { workspace = true }
itertools = { workspace = true }
+libsqlite3-sys = { workspace = true }
schist_fakes = { workspace = true }
schist_models = { workspace = true }
+schist_queries = { workspace = true }
+schist_schema = { workspace = true }
diff --git a/schist_desktop_gui/src/connection.rs b/schist_desktop_gui/src/connection.rs
new file mode 100644
index 0000000..5a88083
--- /dev/null
+++ b/schist_desktop_gui/src/connection.rs
@@ -0,0 +1,20 @@
+use std::{fs::create_dir_all, path::Path};
+
+use anyhow::Context;
+use diesel::{Connection, SqliteConnection};
+
+const SCHIST_DATA_DIR: &'static str = "schist";
+const SCHIST_DATABASE_FILENAME: &'static str = "schist.sqlite";
+
+pub fn establish_connection() -> anyhow::Result<SqliteConnection> {
+ let data_dir = dirs::data_dir().context("Failed to get local app data directory")?;
+ let schist_local_dir = data_dir.join(Path::new(SCHIST_DATA_DIR));
+ create_dir_all(&schist_local_dir)
+ .context(format!("Failed to create local files directory at {}", schist_local_dir.display()))?;
+ let db_path = schist_local_dir.join(Path::new(SCHIST_DATABASE_FILENAME));
+ let db_path = db_path
+ .to_str()
+ .context("Failed to construct database path")?;
+ Ok(SqliteConnection::establish(db_path)
+ .with_context(|| format!("Failed to connect to database at {}", db_path))?)
+}
diff --git a/schist_desktop_gui/src/dummy_data.rs b/schist_desktop_gui/src/dummy_data.rs
deleted file mode 100644
index 079b687..0000000
--- a/schist_desktop_gui/src/dummy_data.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-use schist_models::{
- account::Account, bucket::Bucket, budget_period_unit::BudgetPeriodUnit, date_utc::DateUtc,
-};
-
-#[derive(Clone, Debug)]
-pub struct Error {}
-
-impl From<anyhow::Error> for Error {
- fn from(_value: anyhow::Error) -> Self {
- Error {}
- }
-}
-
-pub async fn fetch_accounts() -> Result<Vec<Account>, Error> {
- Ok(vec![
- Account {
- id: 0,
- name: String::from("Nationwide current account"),
- opening_balance: 0,
- opening_date: DateUtc::from_ymd(2024, 06, 12)?,
- },
- Account {
- id: 1,
- name: String::from("cash account"),
- opening_balance: 0,
- opening_date: DateUtc::from_ymd(2024, 06, 12)?,
- },
- Account {
- id: 2,
- name: String::from("YBS savings account"),
- opening_balance: 0,
- opening_date: DateUtc::from_ymd(2024, 06, 12)?,
- },
- ])
-}
-
-pub async fn fetch_buckets() -> Result<Vec<Bucket>, Error> {
- Ok(vec![
- Bucket {
- id: 0,
- name: String::from("groceries"),
- balance: 123,
- balance_date: DateUtc::from_ymd(2025, 8, 10)?,
- budget_period: 1,
- budget_period_unit: BudgetPeriodUnit::Month,
- budget_quantity: 300,
- group: String::from("normal expenses"),
- },
- Bucket {
- id: 1,
- name: String::from("outdoor trips"),
- balance: -11,
- balance_date: DateUtc::from_ymd(2025, 8, 10)?,
- budget_period: 1,
- budget_period_unit: BudgetPeriodUnit::Month,
- budget_quantity: 110,
- group: String::from("outdoors"),
- },
- Bucket {
- id: 2,
- name: String::from("salary"),
- balance: 1018,
- balance_date: DateUtc::from_ymd(2025, 8, 10)?,
- budget_period: 1,
- budget_period_unit: BudgetPeriodUnit::Month,
- budget_quantity: -2196,
- group: String::from("income"),
- },
- ])
-}
diff --git a/schist_desktop_gui/src/gui.rs b/schist_desktop_gui/src/gui.rs
index 0f84f41..d22e999 100644
--- a/schist_desktop_gui/src/gui.rs
+++ b/schist_desktop_gui/src/gui.rs
@@ -1,12 +1,13 @@
pub mod components;
pub mod screens;
+use diesel::SqliteConnection;
use iced::Element;
use schist_models::{account::Account, bucket::Bucket};
+use schist_queries::{accounts::get_all_accounts, buckets::get_all_buckets};
use crate::{
config::Config,
- dummy_data::{self, fetch_accounts, fetch_buckets},
gui::screens::{main_screen, MainScreen, Screen},
shortcut::KeyBind,
traits::{Component, Viewable},
@@ -16,8 +17,23 @@ use crate::{
pub enum Message {
Event(iced::Event),
MainScreenMessage(main_screen::Message),
- RefetchedAccounts(Result<Vec<Account>, dummy_data::Error>),
- RefetchedBuckets(Result<Vec<Bucket>, dummy_data::Error>),
+ RefetchedAccounts(FetchResult<Vec<Account>>),
+ RefetchedBuckets(FetchResult<Vec<Bucket>>),
+}
+
+pub type FetchResult<T> = std::result::Result<T, FetchError>;
+
+#[derive(Clone, Debug)]
+pub struct FetchError {
+ pub message: String,
+}
+
+impl FetchError {
+ pub fn new(err: anyhow::Error) -> Self {
+ Self {
+ message: format!("{}", err),
+ }
+ }
}
pub struct Gui {
@@ -28,25 +44,30 @@ pub struct Gui {
}
impl Gui {
- pub fn new() -> (Self, iced::Task<Message>) {
- let tasks = vec![
- iced::Task::perform(fetch_buckets(), Message::RefetchedBuckets),
- iced::Task::perform(fetch_accounts(), Message::RefetchedAccounts),
- ];
+ pub fn new(connection: &mut SqliteConnection) -> (Self, iced::Task<Message>) {
let buckets = Vec::new();
let accounts = Vec::new();
- let gui = Self {
+ let mut gui = Self {
active_screen: Screen::Main,
buckets: buckets.clone(),
main_screen: MainScreen::new(buckets, accounts),
config: Config::default(),
};
- (gui, iced::Task::batch(tasks))
+
+ let buckets = get_all_buckets(connection).map_err(FetchError::new);
+ let accounts = get_all_accounts(connection).map_err(FetchError::new);
+
+ let tasks = iced::Task::batch(vec![
+ gui.update(Message::RefetchedBuckets(buckets)),
+ gui.update(Message::RefetchedAccounts(accounts)),
+ ]);
+
+ (gui, tasks)
}
}
impl Gui {
- pub fn view(&self) -> Element<Message> {
+ pub fn view<'a>(&'a self) -> Element<'a, Message> {
match self.active_screen {
Screen::Main => self.main_screen.view().map(Message::MainScreenMessage),
}
@@ -109,7 +130,7 @@ impl Gui {
self.main_screen
.update(main_screen::Message::SetBuckets(buckets));
}
- Err(err) => println!("Failed to get buckets: {:?}", err),
+ Err(err) => println!("Failed to get buckets: {:?}", err.message),
};
iced::Task::none()
}
@@ -119,7 +140,7 @@ impl Gui {
self.main_screen
.update(main_screen::Message::SetAccounts(accounts));
}
- Err(err) => println!("Failed to get accounts: {:?}", err),
+ Err(err) => println!("Failed to get accounts: {:?}", err.message),
}
iced::Task::none()
}
diff --git a/schist_desktop_gui/src/gui/components/bucket_name_and_balance.rs b/schist_desktop_gui/src/gui/components/bucket_name_and_balance.rs
index fa2dcac..b31e0e2 100644
--- a/schist_desktop_gui/src/gui/components/bucket_name_and_balance.rs
+++ b/schist_desktop_gui/src/gui/components/bucket_name_and_balance.rs
@@ -19,6 +19,10 @@ impl BucketNameAndBalance {
impl<'a> Into<Element<'a, navigation::Message<BucketNameAndBalance>>> for BucketNameAndBalance {
fn into(self) -> Element<'a, navigation::Message<BucketNameAndBalance>> {
- row![text(self.bucket.name.clone()), text(self.bucket.balance)].into()
+ row![
+ text(self.bucket.name.clone()),
+ text(self.bucket.balance.unwrap_or(0))
+ ]
+ .into()
}
}
diff --git a/schist_desktop_gui/src/gui/components/transactions_view.rs b/schist_desktop_gui/src/gui/components/transactions_view.rs
index 6181a14..3a8333c 100644
--- a/schist_desktop_gui/src/gui/components/transactions_view.rs
+++ b/schist_desktop_gui/src/gui/components/transactions_view.rs
@@ -43,7 +43,7 @@ impl TransactionsView {
}
impl<'a> Viewable<'a, Message> for TransactionsView {
- fn view(&self) -> Element<Message> {
+ fn view(&'a self) -> Element<'a, Message> {
let navigation = self.navigation.view().map(Message::NavigationMessage);
let main_content = column![iced::widget::text(self.greeting.clone())];
row![
diff --git a/schist_desktop_gui/src/main.rs b/schist_desktop_gui/src/main.rs
index 7e54ddb..24aedc0 100644
--- a/schist_desktop_gui/src/main.rs
+++ b/schist_desktop_gui/src/main.rs
@@ -1,5 +1,5 @@
mod config;
-mod dummy_data;
+mod connection;
mod gui;
mod settings;
mod shortcut;
@@ -8,17 +8,31 @@ mod theme;
mod traits;
mod window_settings;
+use anyhow::Context;
+use diesel_migrations::MigrationHarness;
+use schist_schema::migrations::MIGRATIONS;
+
use crate::{
- config::Config, gui::Gui, settings::make_settings, theme::make_theme,
+ config::Config,
+ connection::establish_connection,
+ gui::Gui,
+ settings::make_settings,
+ theme::make_theme,
window_settings::make_window_settings,
};
-fn main() -> iced::Result {
+fn main() -> anyhow::Result<()> {
let config = Config::default();
- iced::application("Schist", Gui::update, Gui::view)
- .settings(make_settings(&config.clone()))
- .subscription(gui::subscription)
- .theme(make_theme)
- .window(make_window_settings(&config.clone()))
- .run_with(Gui::new)
+ let mut connection = establish_connection()
+ .context("Failed to establish database connection")?;
+ connection.run_pending_migrations(MIGRATIONS)
+ .expect("Failed to run pending database migrations");
+
+iced::application("Schist", Gui::update, Gui::view)
+ .settings(make_settings(&config.clone()))
+ .subscription(gui::subscription)
+ .theme(make_theme)
+ .window(make_window_settings(&config.clone()))
+ .run_with(move || Gui::new(&mut connection))
+ .context("Failed to run Schist GUI")
}
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 a6c850e..d5f7e6f 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,9 @@
use anyhow::Result;
use diesel::SqliteConnection;
use schist_models::{
- account::Account, account_transfer::AccountTransfer, budget_drip::BudgetDrip, bucket::Bucket, bucket_transfer::BucketTransfer, date_utc::DateUtc, transaction::Transaction, transaction_categorisation::TransactionCategorisation
+ account::Account, account_transfer::AccountTransfer, bucket::Bucket,
+ bucket_transfer::BucketTransfer, date_utc::DateUtc, drip::Drip, pipe::Pipe,
+ transaction::Transaction,
};
pub struct SchistState {
@@ -9,20 +11,32 @@ pub struct SchistState {
pub accounts: Vec<Account>,
pub account_transfers: Vec<AccountTransfer>,
pub buckets: Vec<Bucket>,
- pub budget_drips: Vec<BudgetDrip>,
+ pub budget_drips: Vec<Drip>,
pub transactions: Vec<Transaction>,
- pub transaction_categorisations: Vec<TransactionCategorisation>,
+ pub pipes: Vec<Pipe>,
pub bucket_transfers: Vec<BucketTransfer>,
}
-pub fn export_schist_state(schist_state: &SchistState, schist_connection: &mut SqliteConnection) -> Result<()> {
+pub fn export_schist_state(
+ schist_state: &SchistState,
+ schist_connection: &mut SqliteConnection,
+) -> Result<()> {
schist_queries::clear::clear(schist_connection)?;
schist_queries::accounts::insert_accounts(&schist_state.accounts, schist_connection)?;
- schist_queries::account_transfers::insert_account_transfers(&schist_state.account_transfers, schist_connection)?;
+ schist_queries::account_transfers::insert_account_transfers(
+ &schist_state.account_transfers,
+ schist_connection,
+ )?;
schist_queries::buckets::insert_buckets(&schist_state.buckets, schist_connection)?;
- schist_queries::budget_drips::insert_budget_drips(&schist_state.budget_drips, schist_connection)?;
- schist_queries::transactions::insert_transactions(&schist_state.transactions, schist_connection)?;
- schist_queries::transaction_categorisations::insert_transaction_categorisations(&schist_state.transaction_categorisations, schist_connection)?;
- schist_queries::bucket_transfers::insert_bucket_transfers(&schist_state.bucket_transfers, schist_connection)?;
+ schist_queries::drips::insert_drips(&schist_state.budget_drips, schist_connection)?;
+ schist_queries::transactions::insert_transactions(
+ &schist_state.transactions,
+ schist_connection,
+ )?;
+ schist_queries::pipes::insert_pipes(&schist_state.pipes, schist_connection)?;
+ schist_queries::bucket_transfers::insert_bucket_transfers(
+ &schist_state.bucket_transfers,
+ schist_connection,
+ )?;
Ok(())
}
diff --git a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/mod.rs b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/mod.rs
index 8787699..5fadc2c 100644
--- a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/mod.rs
+++ b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/mod.rs
@@ -9,17 +9,19 @@ mod transform_date;
mod transform_id;
mod transform_state;
mod transform_transactions;
+mod transform_zero_budgets;
use is_account_transfer::is_account_transfer;
use is_account_transfer::is_not_account_transfer;
use is_category_transfer::is_category_transfer;
use is_category_transfer::is_not_category_transfer;
-use transform_accounts::transform_accounts;
use transform_account_transfers::transform_account_transfers;
+use transform_accounts::transform_accounts;
use transform_categories::transform_categories;
use transform_category_transfers::transform_category_transfers;
use transform_date::transform_date;
use transform_id::transform_id;
use transform_transactions::transform_transactions;
+use transform_zero_budgets::transform_zero_budgets;
pub use transform_state::transform_state;
diff --git a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_account_transfers.rs b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_account_transfers.rs
index a0c426d..3a9d4b2 100644
--- a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_account_transfers.rs
+++ b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_account_transfers.rs
@@ -3,7 +3,10 @@ use anyhow::{Context, Result};
use itertools::Itertools;
use schist_models::account_transfer::AccountTransfer;
-use super::{is_account_transfer, is_not_account_transfer, transform_date::transform_date, transform_id::transform_id};
+use super::{
+ is_account_transfer, is_not_account_transfer, transform_date::transform_date,
+ transform_id::transform_id,
+};
pub fn transform_account_transfers(
actualbudget_transactions: &[ActualbudgetTransaction],
@@ -15,7 +18,10 @@ pub fn transform_account_transfers(
pub fn transform_account_transfers_without_context(
actualbudget_transactions: &[ActualbudgetTransaction],
) -> Result<(Vec<ActualbudgetTransaction>, Vec<AccountTransfer>)> {
- let mut account_transfer_transaction_pairs: Vec<(ActualbudgetTransaction, ActualbudgetTransaction)> = Vec::new();
+ let mut account_transfer_transaction_pairs: Vec<(
+ ActualbudgetTransaction,
+ ActualbudgetTransaction,
+ )> = Vec::new();
let mut transactions_not_transformed: Vec<ActualbudgetTransaction> = Vec::new();
let account_transfer_transactions = actualbudget_transactions
.iter()
@@ -28,9 +34,11 @@ pub fn transform_account_transfers_without_context(
continue;
}
- let is_already_transformed = |t: &ActualbudgetTransaction|
+ let is_already_transformed = |t: &ActualbudgetTransaction| {
account_transfer_transaction_pairs
- .iter().any(|(t1, t2)| *t1 == *t || *t2 == *t);
+ .iter()
+ .any(|(t1, t2)| *t1 == *t || *t2 == *t)
+ };
if is_already_transformed(actualbudget_transaction) {
continue;
@@ -38,10 +46,12 @@ pub fn transform_account_transfers_without_context(
let companion = account_transfer_transactions
.clone()
- .filter(|t| !is_already_transformed(t)
- && t.date == actualbudget_transaction.date
- && t.amount == -actualbudget_transaction.amount
- ).last();
+ .filter(|t| {
+ !is_already_transformed(t)
+ && t.date == actualbudget_transaction.date
+ && t.amount == -actualbudget_transaction.amount
+ })
+ .last();
if companion.is_none() {
transactions_not_transformed.push(actualbudget_transaction.clone());
@@ -68,23 +78,31 @@ pub fn transform_account_transfers_without_context(
}
fn transform_account_transfer(
- (actualbudget_transaction_from, actualbudget_transaction_to):
- &(ActualbudgetTransaction, ActualbudgetTransaction),
+ (actualbudget_transaction_from, actualbudget_transaction_to): &(
+ ActualbudgetTransaction,
+ ActualbudgetTransaction,
+ ),
) -> Result<AccountTransfer> {
- let context = || format!(
- "failed to transform account transfer from transactions ({:?}, {:?})",
- actualbudget_transaction_from,
- actualbudget_transaction_to,
- );
+ let context = || {
+ format!(
+ "failed to transform account transfer from transactions ({:?}, {:?})",
+ actualbudget_transaction_from, actualbudget_transaction_to,
+ )
+ };
Ok(AccountTransfer {
id: transform_id(&actualbudget_transaction_from.id),
- date: transform_date(&actualbudget_transaction_from.date)
- .with_context(context)?,
- description: actualbudget_transaction_from.notes.clone().unwrap_or_else(||
- actualbudget_transaction_to.notes.clone().unwrap_or_else(String::new)
- ),
- quantity: actualbudget_transaction_to.amount,
+ date: transform_date(&actualbudget_transaction_from.date).with_context(context)?,
+ description: actualbudget_transaction_from
+ .notes
+ .clone()
+ .unwrap_or_else(|| {
+ actualbudget_transaction_to
+ .notes
+ .clone()
+ .unwrap_or_else(String::new)
+ }),
+ amount: actualbudget_transaction_to.amount,
from_account_id: transform_id(actualbudget_transaction_from.account_id.as_str()),
to_account_id: transform_id(actualbudget_transaction_to.account_id.as_str()),
})
@@ -129,9 +147,12 @@ mod test {
assert_eq!(0, remaining_transactions.len());
assert_eq!(1, account_transfers.len());
let account_transfer = account_transfers.get(0).unwrap();
- assert_eq!("2024-08-01".parse::<DateUtc>().unwrap(), account_transfer.date);
+ assert_eq!(
+ "2024-08-01".parse::<DateUtc>().unwrap(),
+ account_transfer.date
+ );
assert_eq!("My notes", account_transfer.description);
- assert_eq!(100, account_transfer.quantity);
+ assert_eq!(100, account_transfer.amount);
assert_eq!(transform_id("0"), account_transfer.from_account_id);
assert_eq!(transform_id("1"), account_transfer.to_account_id);
}
@@ -165,9 +186,12 @@ mod test {
assert_eq!(0, remaining_transactions.len());
assert_eq!(1, account_transfers.len());
let account_transfer = account_transfers.get(0).unwrap();
- assert_eq!("2024-08-01".parse::<DateUtc>().unwrap(), account_transfer.date);
+ assert_eq!(
+ "2024-08-01".parse::<DateUtc>().unwrap(),
+ account_transfer.date
+ );
assert_eq!("My notes", account_transfer.description);
- assert_eq!(100, account_transfer.quantity);
+ assert_eq!(100, account_transfer.amount);
assert_eq!(transform_id("0"), account_transfer.from_account_id);
assert_eq!(transform_id("1"), account_transfer.to_account_id);
}
@@ -219,20 +243,26 @@ mod test {
let account_transfer_0 = account_transfers
.iter()
- .filter(|at| at.quantity == 100)
+ .filter(|at| at.amount == 100)
.last()
.unwrap();
- assert_eq!("2024-08-01".parse::<DateUtc>().unwrap(), account_transfer_0.date);
+ assert_eq!(
+ "2024-08-01".parse::<DateUtc>().unwrap(),
+ account_transfer_0.date
+ );
assert_eq!(transform_id("0"), account_transfer_0.from_account_id);
assert_eq!(transform_id("1"), account_transfer_0.to_account_id);
assert_eq!("My notes 1", account_transfer_0.description);
let account_transfer_1 = account_transfers
.iter()
- .filter(|at| at.quantity == 200)
+ .filter(|at| at.amount == 200)
.last()
.unwrap();
- assert_eq!("2024-08-01".parse::<DateUtc>().unwrap(), account_transfer_1.date);
+ assert_eq!(
+ "2024-08-01".parse::<DateUtc>().unwrap(),
+ account_transfer_1.date
+ );
assert_eq!(transform_id("0"), account_transfer_1.from_account_id);
assert_eq!(transform_id("1"), account_transfer_1.to_account_id);
assert_eq!("My notes 2", account_transfer_1.description);
@@ -288,7 +318,7 @@ mod test {
.filter(|at| at.date == "2024-08-01".parse().unwrap())
.last()
.unwrap();
- assert_eq!(100, account_transfer_0.quantity);
+ assert_eq!(100, account_transfer_0.amount);
assert_eq!(transform_id("0"), account_transfer_0.from_account_id);
assert_eq!(transform_id("1"), account_transfer_0.to_account_id);
assert_eq!("My notes 1", account_transfer_0.description);
@@ -298,7 +328,7 @@ mod test {
.filter(|at| at.date == "2024-08-02".parse().unwrap())
.last()
.unwrap();
- assert_eq!(100, account_transfer_1.quantity);
+ assert_eq!(100, account_transfer_1.amount);
assert_eq!(transform_id("0"), account_transfer_1.from_account_id);
assert_eq!(transform_id("1"), account_transfer_1.to_account_id);
assert_eq!("My notes 2", account_transfer_1.description);
diff --git a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_budget_drips.rs b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_budget_drips.rs
index 01289a0..6fd7610 100644
--- a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_budget_drips.rs
+++ b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_budget_drips.rs
@@ -3,40 +3,46 @@ use std::hash::{DefaultHasher, Hash, Hasher};
use actualbudget_models::ActualbudgetZeroBudget;
use anyhow::{Context, Result};
use itertools::Itertools;
-use schist_models::{budget_drip::BudgetDrip, date_utc::DateUtc};
+use schist_models::{date_utc::DateUtc, drip::Drip};
use schist_traits::dateable::Dateable;
use super::{transform_date::transform_date, transform_id::transform_id};
-pub fn transform_budget_drips(actualbudget_zero_budgets: &[ActualbudgetZeroBudget]) -> Result<Vec<BudgetDrip>> {
+pub fn transform_budget_drips(
+ actualbudget_zero_budgets: &[ActualbudgetZeroBudget],
+) -> Result<Vec<Drip>> {
let non_zero_actualbudget_zero_budgets: Vec<ActualbudgetZeroBudget> = actualbudget_zero_budgets
.iter()
.filter(|zb| zb.amount != 0)
.cloned()
.collect();
- let budget_drips = group_actualbudget_zero_budgets_by_category_id(
- &non_zero_actualbudget_zero_budgets,
- ).iter()
- .map(sort_actualbudget_zero_budgets_by_month)
- .flat_map(|sorted_actualbudget_zero_budgets| sorted_actualbudget_zero_budgets
+ let budget_drips =
+ group_actualbudget_zero_budgets_by_category_id(&non_zero_actualbudget_zero_budgets)
.iter()
- .map(map_actualbudget_zero_budget_to_budget_drips)
- .collect::<Result<Vec<Vec<BudgetDrip>>>>()
- ).flatten()
- .flatten()
- .filter(|bd| bd.quantity != 0)
- .collect();
+ .map(sort_actualbudget_zero_budgets_by_month)
+ .flat_map(|sorted_actualbudget_zero_budgets| {
+ sorted_actualbudget_zero_budgets
+ .iter()
+ .map(map_actualbudget_zero_budget_to_budget_drips)
+ .collect::<Result<Vec<Vec<Drip>>>>()
+ })
+ .flatten()
+ .flatten()
+ .filter(|bd| bd.amount != 0)
+ .collect();
Ok(budget_drips)
}
fn map_actualbudget_zero_budget_to_budget_drips(
actualbudget_zero_budget: &ActualbudgetZeroBudget,
-) -> Result<Vec<BudgetDrip>> {
+) -> Result<Vec<Drip>> {
let context = || "failed to map actualbudget zero budgets to budget drips";
- let first_day_of_month: DateUtc = Into::<DateUtc>::into(transform_date(&actualbudget_zero_budget.month).with_context(context)?);
+ let first_day_of_month: DateUtc = Into::<DateUtc>::into(
+ transform_date(&actualbudget_zero_budget.month).with_context(context)?,
+ );
let month = first_day_of_month.month();
let days_in_month: Vec<DateUtc> = (0..31)
.map(|i| first_day_of_month.add_days(i))
@@ -52,21 +58,29 @@ fn map_actualbudget_zero_budget_to_budget_drips(
// 31 elements, so we should be grand
let num_days_in_month: i32 = days_in_month.len().try_into().unwrap();
- let quantity = actualbudget_zero_budget.amount / num_days_in_month;
- let remainder_quantity = actualbudget_zero_budget.amount - (quantity * num_days_in_month);
+ let amount = actualbudget_zero_budget.amount / num_days_in_month;
+ let remainder_amount = actualbudget_zero_budget.amount - (amount * num_days_in_month);
- let budget_drips: Vec<BudgetDrip> = days_in_month.iter().map(|&date|
- BudgetDrip {
+ let budget_drips: Vec<Drip> = days_in_month
+ .iter()
+ .map(|&date| Drip {
id: transform_budget_drip_id(&actualbudget_zero_budget, &date),
bucket_id: transform_id(&actualbudget_zero_budget.category_id),
date,
- quantity: if date == first_day_of_month {
- quantity + remainder_quantity
+ amount: if date == first_day_of_month {
+ amount + remainder_amount
} else {
- quantity
- }
- }
- ).collect();
+ amount
+ },
+ inserted_at_unix_seconds: std::time::SystemTime::now()
+ .duration_since(std::time::UNIX_EPOCH)
+ .expect("The current time should be after the Unix epoch")
+ .as_secs()
+ .try_into()
+ .expect("The current time's timestamp in seconds should fit into a 32-bit signed integer"),
+ pipe_id: 0,
+ })
+ .collect();
Ok(budget_drips)
}
@@ -88,12 +102,14 @@ fn group_actualbudget_zero_budgets_by_category_id(
.unique();
category_ids
- .map(|category_id| actualbudget_zero_budgets
- .iter()
- .filter(|zb| zb.category_id == category_id)
- .map(ActualbudgetZeroBudget::clone)
- .collect()
- ).collect()
+ .map(|category_id| {
+ actualbudget_zero_budgets
+ .iter()
+ .filter(|zb| zb.category_id == category_id)
+ .map(ActualbudgetZeroBudget::clone)
+ .collect()
+ })
+ .collect()
}
fn transform_budget_drip_id(
@@ -112,7 +128,7 @@ fn transform_budget_drip_id(
mod test {
use actualbudget_fakes::actualbudget_zero_budget::make_fake_actualbudget_zero_budget_builder;
use actualbudget_models::ActualbudgetDate;
- use schist_models::budget_drip::BudgetDrip;
+ use schist_models::drip::Drip;
use schist_traits::dateable::Dateable;
use crate::transform_state::transform_id::transform_id;
@@ -122,7 +138,7 @@ mod test {
mod map_actualbudget_zero_budget_to_budget_drips {
use actualbudget_fakes::actualbudget_zero_budget::make_fake_actualbudget_zero_budget_builder;
use actualbudget_models::ActualbudgetDate;
- use schist_models::budget_drip::BudgetDrip;
+ use schist_models::drip::Drip;
use schist_traits::dateable::Dateable;
use crate::transform_state::transform_budget_drips::map_actualbudget_zero_budget_to_budget_drips;
@@ -141,10 +157,13 @@ mod test {
assert!(result.is_ok());
let mut budget_drips = result.unwrap();
assert_eq!(31, budget_drips.len());
- assert!(budget_drips.iter().all(|bd| bd.quantity == 100));
+ assert!(budget_drips.iter().all(|bd| bd.amount == 100));
budget_drips.sort_by_key(|bd| bd.date);
for i in 1..31 {
- assert_eq!(Ok(i), budget_drips.get(i - 1).unwrap().date.day().try_into());
+ assert_eq!(
+ Ok(i),
+ budget_drips.get(i - 1).unwrap().date.day().try_into()
+ );
}
}
@@ -163,16 +182,12 @@ mod test {
let budget_drips = result.unwrap();
assert_eq!(31, budget_drips.len());
- let budget_drips_quantity_not_floored: Vec<&BudgetDrip> = budget_drips
- .iter()
- .filter(|bd| bd.quantity != 100)
- .collect();
- assert_eq!(1, budget_drips_quantity_not_floored.len());
+ let budget_drips_amount_not_floored: Vec<&Drip> =
+ budget_drips.iter().filter(|bd| bd.amount != 100).collect();
+ assert_eq!(1, budget_drips_amount_not_floored.len());
- let budget_drips_floored: Vec<&BudgetDrip> = budget_drips
- .iter()
- .filter(|bd| bd.quantity == 100)
- .collect();
+ let budget_drips_floored: Vec<&Drip> =
+ budget_drips.iter().filter(|bd| bd.amount == 100).collect();
assert_eq!(30, budget_drips_floored.len());
}
}
@@ -187,37 +202,36 @@ mod test {
#[test]
fn when_one_zero_budget_with_integer_budget_per_day_then_evenly_divided_budget_drips() {
- let actualbudget_zero_budgets = [
- make_fake_actualbudget_zero_budget_builder("0")
- .amount(31 * 100)
- .category_id(String::from("0"))
- .month(ActualbudgetDate::from_i32(202401))
- .build()
- .unwrap()
- ];
+ let actualbudget_zero_budgets = [make_fake_actualbudget_zero_budget_builder("0")
+ .amount(31 * 100)
+ .category_id(String::from("0"))
+ .month(ActualbudgetDate::from_i32(202401))
+ .build()
+ .unwrap()];
let result = transform_budget_drips(&actualbudget_zero_budgets);
assert!(result.is_ok());
let mut budget_drips = result.unwrap();
assert_eq!(31, budget_drips.len());
- assert!(budget_drips.iter().all(|bd| bd.quantity == 100));
+ assert!(budget_drips.iter().all(|bd| bd.amount == 100));
budget_drips.sort_by_key(|bd| bd.date);
for i in 1..31 {
- assert_eq!(Ok(i), budget_drips.get(i - 1).unwrap().date.day().try_into());
+ assert_eq!(
+ Ok(i),
+ budget_drips.get(i - 1).unwrap().date.day().try_into()
+ );
}
}
#[test]
fn when_one_zero_budgets_with_non_integer_budget_per_day_then_remainder_on_one_day() {
- let actualbudget_zero_budgets = [
- make_fake_actualbudget_zero_budget_builder("0")
- .amount(31 * 100 + 30)
- .category_id(String::from("0"))
- .month(ActualbudgetDate::from_i32(202401))
- .build()
- .unwrap()
- ];
+ let actualbudget_zero_budgets = [make_fake_actualbudget_zero_budget_builder("0")
+ .amount(31 * 100 + 30)
+ .category_id(String::from("0"))
+ .month(ActualbudgetDate::from_i32(202401))
+ .build()
+ .unwrap()];
let result = transform_budget_drips(&actualbudget_zero_budgets);
@@ -225,21 +239,18 @@ mod test {
let budget_drips = result.unwrap();
assert_eq!(31, budget_drips.len());
- let budget_drips_quantity_not_floored: Vec<&BudgetDrip> = budget_drips
- .iter()
- .filter(|bd| bd.quantity != 100)
- .collect();
- assert_eq!(1, budget_drips_quantity_not_floored.len());
+ let budget_drips_amount_not_floored: Vec<&Drip> =
+ budget_drips.iter().filter(|bd| bd.amount != 100).collect();
+ assert_eq!(1, budget_drips_amount_not_floored.len());
- let budget_drips_floored: Vec<&BudgetDrip> = budget_drips
- .iter()
- .filter(|bd| bd.quantity == 100)
- .collect();
+ let budget_drips_floored: Vec<&Drip> =
+ budget_drips.iter().filter(|bd| bd.amount == 100).collect();
assert_eq!(30, budget_drips_floored.len());
}
#[test]
- fn when_multiple_zero_budgets_with_integer_budget_per_day_across_multiple_categories_then_evenly_divided_budget_drips() {
+ fn when_multiple_zero_budgets_with_integer_budget_per_day_across_multiple_categories_then_evenly_divided_budget_drips(
+ ) {
let actualbudget_zero_budgets = [
make_fake_actualbudget_zero_budget_builder("0")
.amount(31 * 100)
@@ -275,32 +286,40 @@ mod test {
let budget_drips = result.unwrap();
assert_eq!(31 + 31 + 29 + 29, budget_drips.len());
- let budget_drips_jan_category_0: Vec<&BudgetDrip> = budget_drips
+ let budget_drips_jan_category_0: Vec<&Drip> = budget_drips
.iter()
.filter(|bd| bd.bucket_id == category_0_id && bd.date.month() == 1)
.collect();
assert_eq!(31, budget_drips_jan_category_0.len());
- assert!(budget_drips_jan_category_0.iter().all(|bd| bd.quantity == 100));
+ assert!(budget_drips_jan_category_0
+ .iter()
+ .all(|bd| bd.amount == 100));
- let budget_drips_jan_category_1: Vec<&BudgetDrip> = budget_drips
+ let budget_drips_jan_category_1: Vec<&Drip> = budget_drips
.iter()
.filter(|bd| bd.bucket_id == category_1_id && bd.date.month() == 1)
.collect();
assert_eq!(31, budget_drips_jan_category_1.len());
- assert!(budget_drips_jan_category_1.iter().all(|bd| bd.quantity == 200));
+ assert!(budget_drips_jan_category_1
+ .iter()
+ .all(|bd| bd.amount == 200));
- let budget_drips_feb_category_0: Vec<&BudgetDrip> = budget_drips
+ let budget_drips_feb_category_0: Vec<&Drip> = budget_drips
.iter()
.filter(|bd| bd.bucket_id == category_0_id && bd.date.month() == 2)
.collect();
assert_eq!(29, budget_drips_feb_category_0.len());
- assert!(budget_drips_feb_category_0.iter().all(|bd| bd.quantity == 110));
+ assert!(budget_drips_feb_category_0
+ .iter()
+ .all(|bd| bd.amount == 110));
- let budget_drips_feb_category_1: Vec<&BudgetDrip> = budget_drips
+ let budget_drips_feb_category_1: Vec<&Drip> = budget_drips
.iter()
.filter(|bd| bd.bucket_id == category_1_id && bd.date.month() == 2)
.collect();
assert_eq!(29, budget_drips_feb_category_1.len());
- assert!(budget_drips_feb_category_1.iter().all(|bd| bd.quantity == 210));
+ assert!(budget_drips_feb_category_1
+ .iter()
+ .all(|bd| bd.amount == 210));
}
}
diff --git a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_categories.rs b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_categories.rs
index 2a21860..ccc8639 100644
--- a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_categories.rs
+++ b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_categories.rs
@@ -1,48 +1,24 @@
use actualbudget_models::{ActualbudgetCategory, ActualbudgetZeroBudget};
-use itertools::Itertools;
-use schist_models::{budget_period_unit::BudgetPeriodUnit, bucket::Bucket, date_utc::DateUtc};
+use schist_models::bucket::Bucket;
use super::transform_id;
-pub fn transform_categories(
- actualbudget_categories: &[ActualbudgetCategory],
- actualbudget_zero_budgets: &[ActualbudgetZeroBudget],
- before_first_activity: &DateUtc,
-) -> Vec<Bucket> {
- let last_non_zero_month = actualbudget_zero_budgets
+pub fn transform_categories(actualbudget_categories: &[ActualbudgetCategory]) -> Vec<Bucket> {
+ actualbudget_categories
.iter()
- .map(|zb| zb.month.clone())
- .unique()
- .filter(|month| actualbudget_zero_budgets
- .iter()
- .any(|zb| zb.month == *month && zb.amount != 0)
- ).max();
-
- let actualbudget_zero_budgets = if let Some(last_non_zero_month) = last_non_zero_month {
- &actualbudget_zero_budgets
- .iter()
- .filter(|zb| zb.month == last_non_zero_month)
- .cloned()
- .collect::<Vec<_>>()
- } else {
- actualbudget_zero_budgets
- };
-
- actualbudget_categories.iter().map(|actualbudget_category| Bucket {
- id: transform_id(&actualbudget_category.id.clone()),
- name: actualbudget_category.name.clone(),
- balance: 0,
- balance_date: before_first_activity.clone(),
- budget_period: 1,
- budget_period_unit: BudgetPeriodUnit::Month,
- budget_quantity: get_budget_quantity(actualbudget_category, actualbudget_zero_budgets),
- group: String::from("un-named group"),
- }).collect()
+ .map(|actualbudget_category| Bucket {
+ id: transform_id(&actualbudget_category.id.clone()),
+ balance: None,
+ balance_cache_key: None,
+ group: String::from("un-named group"),
+ name: actualbudget_category.name.clone(),
+ })
+ .collect()
}
fn get_budget_quantity(
actualbudget_category: &ActualbudgetCategory,
- actualbudget_zero_budgets: &[ActualbudgetZeroBudget]
+ actualbudget_zero_budgets: &[ActualbudgetZeroBudget],
) -> i32 {
let latest_zero_budget_for_category = actualbudget_zero_budgets
.iter()
@@ -57,10 +33,7 @@ fn get_budget_quantity(
#[cfg(test)]
mod test {
- use actualbudget_fakes::{actualbudget_category::make_fake_actualbudget_category_builder, actualbudget_zero_budget::make_fake_actualbudget_zero_budget_builder};
- use actualbudget_models::ActualbudgetDate;
- use schist_models::{budget_period_unit::BudgetPeriodUnit, date_utc::DateUtc};
- use schist_traits::nowlike::Nowlike;
+ use actualbudget_fakes::actualbudget_category::make_fake_actualbudget_category_builder;
use crate::transform_state::transform_id::transform_id;
@@ -68,138 +41,103 @@ mod test {
#[test]
fn when_one_category_one_zero_budget_then_transforms_category() {
- let actualbudget_categories = [
- make_fake_actualbudget_category_builder("0").name(String::from("Food")).build().unwrap(),
- ];
- let actualbudget_zero_budgets = [
- make_fake_actualbudget_zero_budget_builder("0").amount(100).build().unwrap(),
- ];
- let before_first_transaction = DateUtc::now();
+ let actualbudget_categories = [make_fake_actualbudget_category_builder("0")
+ .name(String::from("Food"))
+ .build()
+ .unwrap()];
- let buckets = transform_categories(
- &actualbudget_categories,
- &actualbudget_zero_budgets,
- &before_first_transaction,
- );
+ let buckets = transform_categories(&actualbudget_categories);
assert_eq!(1, buckets.len());
let bucket = buckets.get(0).unwrap();
+ assert_eq!(None, bucket.balance);
+ assert_eq!(None, bucket.balance_cache_key);
assert_eq!("Food", bucket.name);
- assert_eq!(0, bucket.balance);
- assert_eq!(before_first_transaction, bucket.balance_date);
- assert_eq!(1, bucket.budget_period);
- assert_eq!(BudgetPeriodUnit::Month, bucket.budget_period_unit);
- assert_eq!(100, bucket.budget_quantity);
}
#[test]
fn when_one_category_no_zero_budget_then_transforms_category() {
- let actualbudget_categories = [
- make_fake_actualbudget_category_builder("0").name(String::from("Food")).build().unwrap(),
- ];
- let actualbudget_zero_budgets = [];
- let before_first_transaction = DateUtc::now();
+ let actualbudget_categories = [make_fake_actualbudget_category_builder("0")
+ .name(String::from("Food"))
+ .build()
+ .unwrap()];
- let buckets = transform_categories(
- &actualbudget_categories,
- &actualbudget_zero_budgets,
- &before_first_transaction,
- );
+ let buckets = transform_categories(&actualbudget_categories);
assert_eq!(1, buckets.len());
let bucket = buckets.get(0).unwrap();
assert_eq!("Food", bucket.name);
- assert_eq!(0, bucket.balance);
- assert_eq!(before_first_transaction, bucket.balance_date);
- assert_eq!(1, bucket.budget_period);
- assert_eq!(BudgetPeriodUnit::Month, bucket.budget_period_unit);
- assert_eq!(0, bucket.budget_quantity);
+ assert_eq!(None, bucket.balance);
+ assert_eq!(None, bucket.balance_cache_key);
+ assert_eq!("un-named group", bucket.group);
}
#[test]
fn when_one_category_multiple_zero_budgets_then_transforms_category() {
- let actualbudget_categories = [
- make_fake_actualbudget_category_builder("0").name(String::from("Food")).build().unwrap(),
- ];
- let jan = ActualbudgetDate::from_i32(202401);
- let feb = ActualbudgetDate::from_i32(202402);
- let mar = ActualbudgetDate::from_i32(202403);
- let actualbudget_zero_budgets = [
- make_fake_actualbudget_zero_budget_builder("0").amount(100).month(jan).build().unwrap(),
- make_fake_actualbudget_zero_budget_builder("1").amount(200).month(feb).build().unwrap(),
- make_fake_actualbudget_zero_budget_builder("2").amount(300).month(mar).build().unwrap(),
- ];
- let before_first_transaction = DateUtc::now();
+ let actualbudget_categories = [make_fake_actualbudget_category_builder("0")
+ .name(String::from("Food"))
+ .build()
+ .unwrap()];
- let buckets = transform_categories(
- &actualbudget_categories,
- &actualbudget_zero_budgets,
- &before_first_transaction,
- );
+ let buckets = transform_categories(&actualbudget_categories);
assert_eq!(1, buckets.len());
let bucket = buckets.get(0).unwrap();
assert_eq!("Food", bucket.name);
- assert_eq!(0, bucket.balance);
- assert_eq!(before_first_transaction, bucket.balance_date);
- assert_eq!(1, bucket.budget_period);
- assert_eq!(BudgetPeriodUnit::Month, bucket.budget_period_unit);
- assert_eq!(300, bucket.budget_quantity);
+ assert_eq!(None, bucket.balance);
+ assert_eq!(None, bucket.balance_cache_key);
+ assert_eq!("un-named group", bucket.group);
}
#[test]
fn when_multiple_categories_multiple_zero_budgets_then_transforms_category() {
let actualbudget_categories = [
- make_fake_actualbudget_category_builder("0").name(String::from("Food")).build().unwrap(),
- make_fake_actualbudget_category_builder("1").name(String::from("Clothes")).build().unwrap(),
- make_fake_actualbudget_category_builder("2").name(String::from("Rent")).build().unwrap(),
+ make_fake_actualbudget_category_builder("0")
+ .name(String::from("Food"))
+ .build()
+ .unwrap(),
+ make_fake_actualbudget_category_builder("1")
+ .name(String::from("Clothes"))
+ .build()
+ .unwrap(),
+ make_fake_actualbudget_category_builder("2")
+ .name(String::from("Rent"))
+ .build()
+ .unwrap(),
];
- let jan = ActualbudgetDate::from_i32(202401);
- let feb = ActualbudgetDate::from_i32(202402);
- let mar = ActualbudgetDate::from_i32(202403);
- let actualbudget_zero_budgets = [
- make_fake_actualbudget_zero_budget_builder("0").amount(100).month(jan.clone()).category_id(String::from("0")).build().unwrap(),
- make_fake_actualbudget_zero_budget_builder("1").amount(200).month(feb.clone()).category_id(String::from("0")).build().unwrap(),
- make_fake_actualbudget_zero_budget_builder("2").amount(300).month(mar.clone()).category_id(String::from("0")).build().unwrap(),
- make_fake_actualbudget_zero_budget_builder("3").amount(110).month(jan.clone()).category_id(String::from("1")).build().unwrap(),
- make_fake_actualbudget_zero_budget_builder("4").amount(210).month(feb.clone()).category_id(String::from("1")).build().unwrap(),
- make_fake_actualbudget_zero_budget_builder("5").amount(310).month(mar.clone()).category_id(String::from("1")).build().unwrap(),
- make_fake_actualbudget_zero_budget_builder("6").amount(120).month(jan.clone()).category_id(String::from("2")).build().unwrap(),
- make_fake_actualbudget_zero_budget_builder("7").amount(220).month(feb.clone()).category_id(String::from("2")).build().unwrap(),
- make_fake_actualbudget_zero_budget_builder("8").amount(320).month(mar.clone()).category_id(String::from("2")).build().unwrap(),
- ];
- let before_first_transaction = DateUtc::now();
- let buckets = transform_categories(
- &actualbudget_categories,
- &actualbudget_zero_budgets,
- &before_first_transaction,
- );
+ let buckets = transform_categories(&actualbudget_categories);
assert_eq!(3, buckets.len());
- let bucket_0 = buckets.iter().filter(|c| c.id == transform_id("0")).last().unwrap();
+ let bucket_0 = buckets
+ .iter()
+ .filter(|c| c.id == transform_id("0"))
+ .last()
+ .unwrap();
assert_eq!("Food", bucket_0.name);
- assert_eq!(0, bucket_0.balance);
- assert_eq!(before_first_transaction, bucket_0.balance_date);
- assert_eq!(1, bucket_0.budget_period);
- assert_eq!(BudgetPeriodUnit::Month, bucket_0.budget_period_unit);
- assert_eq!(300, bucket_0.budget_quantity);
+ assert_eq!(None, bucket_0.balance);
+ assert_eq!(None, bucket_0.balance_cache_key);
+ assert_eq!("un-named group", bucket_0.group);
- let bucket_1 = buckets.iter().filter(|c| c.id == transform_id("1")).last().unwrap();
+ let bucket_1 = buckets
+ .iter()
+ .filter(|c| c.id == transform_id("1"))
+ .last()
+ .unwrap();
assert_eq!("Clothes", bucket_1.name);
- assert_eq!(0, bucket_1.balance);
- assert_eq!(before_first_transaction, bucket_1.balance_date);
- assert_eq!(1, bucket_1.budget_period);
- assert_eq!(BudgetPeriodUnit::Month, bucket_1.budget_period_unit);
- assert_eq!(310, bucket_1.budget_quantity);
+ assert_eq!(None, bucket_1.balance);
+ assert_eq!(None, bucket_1.balance_cache_key);
+ assert_eq!("un-named group", bucket_1.group);
- let bucket_2 = buckets.iter().filter(|c| c.id == transform_id("2")).last().unwrap();
+ let bucket_2 = buckets
+ .iter()
+ .filter(|c| c.id == transform_id("2"))
+ .last()
+ .unwrap();
assert_eq!("Rent", bucket_2.name);
- assert_eq!(0, bucket_2.balance);
- assert_eq!(before_first_transaction, bucket_2.balance_date);
- assert_eq!(1, bucket_2.budget_period);
- assert_eq!(BudgetPeriodUnit::Month, bucket_2.budget_period_unit);
- assert_eq!(320, bucket_2.budget_quantity);
+ assert_eq!(None, bucket_2.balance);
+ assert_eq!(None, bucket_2.balance_cache_key);
+ assert_eq!("un-named group", bucket_2.group);
}
}
diff --git a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_category_transfers.rs b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_category_transfers.rs
index 11ed2e3..bfbf7ac 100644
--- a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_category_transfers.rs
+++ b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_category_transfers.rs
@@ -1,7 +1,4 @@
-use actualbudget_models::{
- ActualbudgetAccount,
- ActualbudgetTransaction,
-};
+use actualbudget_models::{ActualbudgetAccount, ActualbudgetTransaction};
use anyhow::{bail, Context, Result};
use itertools::Itertools;
use schist_models::bucket_transfer::BucketTransfer;
@@ -12,20 +9,20 @@ pub fn transform_category_transfers(
actualbudget_transactions: &[ActualbudgetTransaction],
actualbudget_category_transfers_account: &Option<ActualbudgetAccount>,
) -> Result<Vec<BucketTransfer>> {
- let actualbudget_category_transfers = actualbudget_transactions
- .iter()
- .filter(|transaction|
- is_category_transfer(transaction, actualbudget_category_transfers_account)
- );
- 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 actualbudget_category_transfers = actualbudget_transactions.iter().filter(|transaction| {
+ is_category_transfer(transaction, actualbudget_category_transfers_account)
+ });
+ 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();
Ok(actualbudget_parent_category_transfers
.iter()
@@ -33,8 +30,7 @@ pub fn transform_category_transfers(
.filter_ok(Option::is_some)
.map_ok(Option::unwrap)
.collect::<Result<Vec<BucketTransfer>>>()
- .with_context(|| "failed to transform category transfers")?
- )
+ .with_context(|| "failed to transform category transfers")?)
}
fn transform_category_transfer(
@@ -44,7 +40,8 @@ fn transform_category_transfer(
transform_category_transfer_without_context(
actualbudget_parent_category_transfer,
actualbudget_child_category_transfers,
- ).with_context(|| "failed to transform category transfer")
+ )
+ .with_context(|| "failed to transform category transfer")
}
fn transform_category_transfer_without_context(
@@ -53,11 +50,12 @@ fn transform_category_transfer_without_context(
) -> Result<Option<BucketTransfer>> {
let actualbudget_child_category_transfers = actualbudget_child_category_transfers
.iter()
- .filter(|t|
+ .filter(|t| {
t.parent_id
.clone()
.is_some_and(|parent_id| parent_id == actualbudget_parent_category_transfer.id)
- ).map(ActualbudgetTransaction::clone);
+ })
+ .map(ActualbudgetTransaction::clone);
let from_transfers: Vec<ActualbudgetTransaction> = actualbudget_child_category_transfers
.clone()
@@ -73,7 +71,10 @@ fn transform_category_transfer_without_context(
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);
+ 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());
@@ -91,12 +92,14 @@ fn transform_category_transfer_without_context(
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);
+ 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
- {
+ if from_transfer.amount != -to_transfer.amount {
bail!("actualbudget category transfer amounts did not sum to zero");
}
@@ -106,7 +109,7 @@ fn transform_category_transfer_without_context(
.notes
.clone()
.unwrap_or_else(String::new),
- quantity: to_transfer.amount.try_into().unwrap(),
+ amount: to_transfer.amount.try_into().unwrap(),
from_bucket_id: from_category_id,
to_bucket_id: to_category_id,
}))
@@ -114,7 +117,10 @@ fn transform_category_transfer_without_context(
#[cfg(test)]
mod test {
- use actualbudget_fakes::{actualbudget_account::make_fake_actualbudget_account, actualbudget_transaction::make_fake_actualbudget_transaction_builder};
+ use actualbudget_fakes::{
+ actualbudget_account::make_fake_actualbudget_account,
+ actualbudget_transaction::make_fake_actualbudget_transaction_builder,
+ };
use actualbudget_models::{ActualbudgetTransaction, ActualbudgetTransactionBuilder};
use schist_models::bucket_transfer::BucketTransfer;
@@ -140,7 +146,7 @@ mod test {
let bucket_transfers = result.unwrap();
assert_eq!(1, bucket_transfers.len());
let bucket_transfer = bucket_transfers.get(0).unwrap();
- assert_eq!(100, bucket_transfer.quantity);
+ 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);
@@ -151,13 +157,31 @@ mod test {
let actualbudget_category_transfers_account = make_fake_actualbudget_account("0");
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_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(),
+ 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_category_transfers(
@@ -171,7 +195,7 @@ mod test {
let bucket_transfer_0: Vec<&BucketTransfer> = bucket_transfers
.iter()
- .filter(|ct| ct.quantity == 100)
+ .filter(|ct| ct.amount == 100)
.collect();
assert_eq!(1, bucket_transfer_0.len());
let bucket_transfer_0 = bucket_transfer_0.get(0).unwrap();
@@ -180,7 +204,7 @@ mod test {
let bucket_transfer_1: Vec<&BucketTransfer> = bucket_transfers
.iter()
- .filter(|ct| ct.quantity == 200)
+ .filter(|ct| ct.amount == 200)
.collect();
assert_eq!(1, bucket_transfer_1.len());
let bucket_transfer_1 = bucket_transfer_1.get(0).unwrap();
@@ -193,9 +217,15 @@ mod test {
let actualbudget_category_transfers_account = make_fake_actualbudget_account("0");
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(),
+ 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_category_transfers(
@@ -211,9 +241,15 @@ mod test {
let actualbudget_category_transfers_account = make_fake_actualbudget_account("0");
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(),
+ 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_category_transfers(
@@ -261,8 +297,12 @@ mod test {
let actualbudget_category_transfers_account = make_fake_actualbudget_account("0");
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(),
+ 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_category_transfers(
@@ -278,13 +318,23 @@ mod test {
let actualbudget_category_transfers_account = make_fake_actualbudget_account("0");
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(),
+ 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(),
+ 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_category_transfers(
@@ -314,25 +364,37 @@ mod test {
}
fn make_fake_from_child_transaction(id: &str, parent_id: &str) -> ActualbudgetTransaction {
- make_fake_from_child_transaction_builder(id, 100, parent_id).build().unwrap()
+ 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_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()
+ 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 {
+ 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"))
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 575e624..7d7f90b 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,9 +1,16 @@
use anyhow::{bail, Context, Result};
-use schist_models::{account::Account, bucket::Bucket, bucket_transfer::BucketTransfer, date_utc::DateUtc, transaction::Transaction, transaction_categorisation::TransactionCategorisation};
+use schist_models::{
+ account::Account, bucket::Bucket, bucket_transfer::BucketTransfer, date_utc::DateUtc,
+ pipe::Pipe, transaction::Transaction,
+};
use crate::{actualbudget_state::ActualbudgetState, schist_state::SchistState};
-use super::{transform_account_transfers, transform_accounts, transform_budget_drips::transform_budget_drips, transform_categories, transform_category_transfers, transform_date, transform_transactions};
+use super::{
+ transform_account_transfers, transform_accounts,
+ transform_budget_drips::transform_budget_drips, transform_categories,
+ transform_category_transfers, transform_date, transform_transactions, transform_zero_budgets,
+};
pub fn transform_state(actualbudget_state: ActualbudgetState) -> Result<SchistState> {
transform_state_without_context(actualbudget_state)
@@ -11,30 +18,23 @@ pub fn transform_state(actualbudget_state: ActualbudgetState) -> Result<SchistSt
}
fn transform_state_without_context(actualbudget_state: ActualbudgetState) -> Result<SchistState> {
- let (remaining_transactions, account_transfers) = transform_account_transfers(
- &actualbudget_state.actualbudget_transactions,
- )?;
- let first_activity_date =
- transform_date(&actualbudget_state.actualbudget_first_activity_date)?;
+ let (remaining_transactions, account_transfers) =
+ transform_account_transfers(&actualbudget_state.actualbudget_transactions)?;
+ let first_activity_date = transform_date(&actualbudget_state.actualbudget_first_activity_date)?;
let before_first_activity_date = find_date_before(&first_activity_date)?;
- let accounts: Vec<Account> =
- transform_accounts(
- &actualbudget_state.actualbudget_accounts,
- &actualbudget_state.actualbudget_category_transfers_account,
- &first_activity_date,
- );
- let budget_drips = transform_budget_drips(&actualbudget_state.actualbudget_zero_budgets)?;
- let buckets: Vec<Bucket> = transform_categories(
- &actualbudget_state.actualbudget_categories,
- &actualbudget_state.actualbudget_zero_budgets,
- &before_first_activity_date,
+ let accounts: Vec<Account> = transform_accounts(
+ &actualbudget_state.actualbudget_accounts,
+ &actualbudget_state.actualbudget_category_transfers_account,
+ &first_activity_date,
);
- let (transactions, transaction_categorisations): (Vec<Transaction>, Vec<TransactionCategorisation>) =
- transform_transactions(
- &remaining_transactions,
- &actualbudget_state.actualbudget_category_transfers_account,
- &actualbudget_state.actualbudget_payees,
- )?;
+ let budget_drips = transform_budget_drips(&actualbudget_state.actualbudget_zero_budgets)?;
+ let buckets: Vec<Bucket> = transform_categories(&actualbudget_state.actualbudget_categories);
+ let pipes: Vec<Pipe> = transform_zero_budgets(&actualbudget_state.actualbudget_zero_budgets);
+ let transactions: Vec<Transaction> = transform_transactions(
+ &remaining_transactions,
+ &actualbudget_state.actualbudget_category_transfers_account,
+ &actualbudget_state.actualbudget_payees,
+ )?;
let bucket_transfers: Vec<BucketTransfer> = transform_category_transfers(
&remaining_transactions,
&actualbudget_state.actualbudget_category_transfers_account,
@@ -46,8 +46,8 @@ fn transform_state_without_context(actualbudget_state: ActualbudgetState) -> Res
account_transfers,
buckets,
budget_drips,
+ pipes: pipes,
transactions,
- transaction_categorisations,
bucket_transfers,
})
}
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 f24e8b6..a1b7c4d 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
@@ -1,6 +1,6 @@
-use anyhow::{Context, Result};
use actualbudget_models::{ActualbudgetAccount, ActualbudgetPayee, ActualbudgetTransaction};
-use schist_models::{transaction::Transaction, transaction_categorisation::TransactionCategorisation};
+use anyhow::{Context, Result};
+use schist_models::transaction::Transaction;
use super::{is_not_category_transfer, transform_date, transform_id};
@@ -8,22 +8,21 @@ pub fn transform_transactions(
actualbudget_transactions: &[ActualbudgetTransaction],
actualbudget_category_transfers_account: &Option<ActualbudgetAccount>,
actualbudget_payees: &[ActualbudgetPayee],
-) -> Result<(Vec<Transaction>, Vec<TransactionCategorisation>)> {
+) -> Result<Vec<Transaction>> {
transform_transactions_without_context(
actualbudget_transactions,
actualbudget_category_transfers_account,
actualbudget_payees,
)
- .with_context(|| "failed to transform actualbudget transactions to schist transactions")
+ .with_context(|| "failed to transform actualbudget transactions to schist transactions")
}
fn transform_transactions_without_context(
actualbudget_transactions: &[ActualbudgetTransaction],
actualbudget_category_transfers_account: &Option<ActualbudgetAccount>,
actualbudget_payees: &[ActualbudgetPayee],
-) -> Result<(Vec<Transaction>, Vec<TransactionCategorisation>)> {
+) -> Result<Vec<Transaction>> {
let mut transactions = Vec::<Transaction>::new();
- let mut transaction_categorisations = Vec::<TransactionCategorisation>::new();
let actualbudget_transactions = actualbudget_transactions
.iter()
@@ -32,10 +31,6 @@ fn transform_transactions_without_context(
.clone()
.filter(|t| t.is_parent)
.collect();
- let child_actualbudget_transactions: Vec<&ActualbudgetTransaction> = actualbudget_transactions
- .clone()
- .filter(|t| t.is_child)
- .collect();
let atomic_actualbudget_transactions: Vec<&ActualbudgetTransaction> = actualbudget_transactions
.filter(|t| !t.is_parent && !t.is_child)
.collect();
@@ -46,84 +41,59 @@ fn transform_transactions_without_context(
let payee_name = atomic_actualbudget_transaction
.payee
.clone()
- .map(|p| actualbudget_payees
- .iter()
- .find(|pp| pp.id == p)
- .map(|pp| pp.name.clone())
- ).unwrap_or(None)
+ .map(|p| {
+ actualbudget_payees
+ .iter()
+ .find(|pp| pp.id == p)
+ .map(|pp| pp.name.clone())
+ })
+ .unwrap_or(None)
.unwrap_or_else(String::new);
transactions.push(Transaction {
id: transaction_id,
- description: atomic_actualbudget_transaction.notes.clone().unwrap_or_else(String::new),
- payee: payee_name,
- quantity: atomic_actualbudget_transaction.amount.try_into().unwrap(),
+ description: atomic_actualbudget_transaction
+ .notes
+ .clone()
+ .unwrap_or_else(String::new),
+ counterparty: payee_name,
+ amount: atomic_actualbudget_transaction.amount.try_into().unwrap(),
date: transform_date(&atomic_actualbudget_transaction.date)?,
account_id: transform_id(&atomic_actualbudget_transaction.account_id),
- });
-
- let actualbudget_category_id = atomic_actualbudget_transaction
- .category_id
- .clone()
- .with_context(|| format!(
- "atomic actualbudget transaction {} did not have a category ID",
- atomic_actualbudget_transaction.id,
- ))?;
-
- transaction_categorisations.push(TransactionCategorisation {
- id: transaction_id,
- description: String::new(),
- quantity: atomic_actualbudget_transaction.amount.try_into().unwrap(),
- transaction_id,
- bucket_id: transform_id(&actualbudget_category_id),
+ bucket_id: None,
});
}
for parent_actualbudget_transaction in parent_actualbudget_transactions {
- let child_actualbudget_transactions = child_actualbudget_transactions
- .iter()
- .filter(|t| t
- .parent_id
- .clone()
- .is_some_and(|parent_id| parent_id == parent_actualbudget_transaction.id.clone())
- );
-
let transaction_id = transform_id(&parent_actualbudget_transaction.id);
transactions.push(Transaction {
id: transaction_id,
- description: parent_actualbudget_transaction.notes.clone().unwrap_or_else(String::new),
- payee: parent_actualbudget_transaction.payee.clone().unwrap_or_else(String::new),
- quantity: parent_actualbudget_transaction.amount.try_into().unwrap(),
+ bucket_id: None,
+ description: parent_actualbudget_transaction
+ .notes
+ .clone()
+ .unwrap_or_else(String::new),
+ counterparty: parent_actualbudget_transaction
+ .payee
+ .clone()
+ .unwrap_or_else(String::new),
+ amount: parent_actualbudget_transaction.amount.try_into().unwrap(),
date: transform_date(&parent_actualbudget_transaction.date)?,
account_id: transform_id(&parent_actualbudget_transaction.account_id),
});
-
- for child_actualbudget_transaction in child_actualbudget_transactions {
- let actualbudget_category_id = child_actualbudget_transaction
- .category_id
- .clone()
- .with_context(|| format!(
- "actualbudget child transaction {} had no category ID",
- child_actualbudget_transaction.id,
- ))?;
-
- transaction_categorisations.push(TransactionCategorisation {
- id: transform_id(&child_actualbudget_transaction.id),
- description: child_actualbudget_transaction.notes.clone().unwrap_or_else(String::new),
- quantity: child_actualbudget_transaction.amount.try_into().unwrap(),
- transaction_id,
- bucket_id: transform_id(&actualbudget_category_id),
- });
- }
}
- Ok((transactions, transaction_categorisations))
+ Ok(transactions)
}
#[cfg(test)]
mod test {
- use actualbudget_fakes::{actualbudget_account::make_fake_actualbudget_account, actualbudget_payee::{make_fake_actualbudget_payee, make_fake_actualbudget_payee_builder}, actualbudget_transaction::make_fake_actualbudget_transaction_builder};
+ use actualbudget_fakes::{
+ actualbudget_account::make_fake_actualbudget_account,
+ actualbudget_payee::{make_fake_actualbudget_payee, make_fake_actualbudget_payee_builder},
+ actualbudget_transaction::make_fake_actualbudget_transaction_builder,
+ };
use actualbudget_models::ActualbudgetDate;
use schist_models::date_utc::DateUtc;
@@ -133,65 +103,50 @@ mod test {
#[test]
fn when_one_category_transfer_transaction_then_returns_empty() {
- let actualbudget_transactions = [
- make_fake_actualbudget_transaction_builder("0")
- .category_id(Some(String::from("0")))
- .build()
- .unwrap(),
- ];
+ let actualbudget_transactions = [make_fake_actualbudget_transaction_builder("0")
+ .category_id(Some(String::from("0")))
+ .build()
+ .unwrap()];
let actualbudget_category_transfers_account = make_fake_actualbudget_account("0");
let actualbudget_payees = [make_fake_actualbudget_payee("0")];
- let (transactions, transaction_categorisations) = transform_transactions(
+ let transactions = transform_transactions(
&actualbudget_transactions,
&Some(actualbudget_category_transfers_account),
&actualbudget_payees,
- ).unwrap();
+ )
+ .unwrap();
assert_eq!(0, transactions.len());
- assert_eq!(0, transaction_categorisations.len());
}
#[test]
fn when_one_atomic_transaction_then_returns_transformed_transaction() {
- let actualbudget_transactions = [
- make_fake_actualbudget_transaction_builder("0")
- .account_id(String::from("0"))
- .amount(100)
- .category_id(Some(String::from("0")))
- .payee(Some(String::from("0")))
- .notes(Some(String::from("Savings")))
- .date(ActualbudgetDate::from_i32(19700101))
- .build()
- .unwrap(),
- ];
- let actualbudget_payees = [
- make_fake_actualbudget_payee_builder("0")
- .name(String::from("Gringotts"))
- .build()
- .unwrap(),
- ];
-
- let (transactions, transaction_categorisations) = transform_transactions(
- &actualbudget_transactions,
- &None,
- &actualbudget_payees,
- ).unwrap();
+ let actualbudget_transactions = [make_fake_actualbudget_transaction_builder("0")
+ .account_id(String::from("0"))
+ .amount(100)
+ .category_id(Some(String::from("0")))
+ .payee(Some(String::from("0")))
+ .notes(Some(String::from("Savings")))
+ .date(ActualbudgetDate::from_i32(19700101))
+ .build()
+ .unwrap()];
+ let actualbudget_payees = [make_fake_actualbudget_payee_builder("0")
+ .name(String::from("Gringotts"))
+ .build()
+ .unwrap()];
+
+ let transactions =
+ transform_transactions(&actualbudget_transactions, &None, &actualbudget_payees)
+ .unwrap();
assert_eq!(1, transactions.len());
let transaction = transactions.get(0).unwrap();
assert_eq!("Savings", transaction.description);
- assert_eq!("Gringotts", transaction.payee);
- assert_eq!(100, transaction.quantity);
+ assert_eq!("Gringotts", transaction.counterparty);
+ assert_eq!(100, transaction.amount);
assert_eq!(DateUtc::from_ymd(1970, 1, 1).unwrap(), transaction.date);
assert_eq!(transform_id("0"), transaction.account_id);
-
- assert_eq!(1, transaction_categorisations.len());
- let transaction_categorisation = transaction_categorisations.get(0).unwrap();
- assert_eq!("", transaction_categorisation.description);
- assert_eq!(100, transaction_categorisation.quantity);
- assert_eq!(transaction.id, transaction_categorisation.transaction_id);
- assert_eq!(transform_id("0"), transaction_categorisation.bucket_id);
}
#[test]
@@ -220,34 +175,11 @@ mod test {
.unwrap(),
];
- let (transactions, transaction_categorisations) = transform_transactions(
- &actualbudget_transactions,
- &None,
- &[],
- ).unwrap();
+ let transactions = transform_transactions(&actualbudget_transactions, &None, &[]).unwrap();
assert_eq!(1, transactions.len());
- assert_eq!(2, transaction_categorisations.len());
let transaction = transactions.get(0).unwrap();
- assert_eq!(100, transaction.quantity);
-
- let transaction_categorisation_0 = transaction_categorisations
- .iter()
- .filter(|tc| tc.quantity == 200)
- .last()
- .unwrap();
- assert_eq!(transaction.id, transaction_categorisation_0.transaction_id);
- assert_eq!(transform_id("0"), transaction_categorisation_0.bucket_id);
- assert_eq!("notes A", transaction_categorisation_0.description);
-
- let transaction_categorisation_1 = transaction_categorisations
- .iter()
- .filter(|tc| tc.quantity == 300)
- .last()
- .unwrap();
- assert_eq!(transaction.id, transaction_categorisation_1.transaction_id);
- assert_eq!(transform_id("0"), transaction_categorisation_1.bucket_id);
- assert_eq!("notes B", transaction_categorisation_1.description);
+ assert_eq!(100, transaction.amount);
}
}
diff --git a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_zero_budgets.rs b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_zero_budgets.rs
new file mode 100644
index 0000000..07ecd56
--- /dev/null
+++ b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/src/transform_state/transform_zero_budgets.rs
@@ -0,0 +1,6 @@
+use actualbudget_models::ActualbudgetZeroBudget;
+use schist_models::pipe::Pipe;
+
+pub fn transform_zero_budgets(_actualbudget_zero_budgets: &[ActualbudgetZeroBudget]) -> Vec<Pipe> {
+ todo!()
+}
diff --git a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/account_transfer_matchers.rs b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/account_transfer_matchers.rs
index ea3180e..f3e3037 100644
--- a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/account_transfer_matchers.rs
+++ b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/account_transfer_matchers.rs
@@ -3,11 +3,10 @@ use schist_models::{account::Account, account_transfer::AccountTransfer};
use super::ACCOUNT_NAMES_DICT;
-pub fn get_account_transfer_matchers(
-) -> Vec<Box<dyn Fn(&AccountTransfer, &[Account]) -> bool>> {
- vec![
- Box::new(|at, a| matches_cash_withdrawal_10_sept_2024(at, a)),
- ]
+pub fn get_account_transfer_matchers() -> Vec<Box<dyn Fn(&AccountTransfer, &[Account]) -> bool>> {
+ vec![Box::new(|at, a| {
+ matches_cash_withdrawal_10_sept_2024(at, a)
+ })]
}
fn matches_cash_withdrawal_10_sept_2024(
@@ -33,13 +32,15 @@ fn matches_cash_withdrawal_10_sept_2024(
id: _id,
date,
description,
- quantity: 80_00,
+ amount: 80_00,
from_account_id,
to_account_id,
- } => *date == "2024-09-10".parse().unwrap()
- && *description == ""
- && *from_account_id == bank_account.id
- && *to_account_id == cash_account.id,
+ } => {
+ *date == "2024-09-10".parse().unwrap()
+ && *description == ""
+ && *from_account_id == bank_account.id
+ && *to_account_id == cash_account.id
+ }
_ => false,
}
}
diff --git a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/bucket_matchers.rs b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/bucket_matchers.rs
index 76189d3..5f5ef4f 100644
--- a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/bucket_matchers.rs
+++ b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/bucket_matchers.rs
@@ -1,34 +1,16 @@
-use schist_models::{budget_period_unit::BudgetPeriodUnit, bucket::Bucket};
+use schist_models::bucket::Bucket;
-use super::bucket_names::{BUCKET_NAMES, BUCKET_NAME_BILLS, BUCKET_NAME_BILLS_FLEXIBLE, BUCKET_NAME_FOOD, BUCKET_NAME_GENERAL, BUCKET_NAME_INCOME, BUCKET_NAME_SAVINGS, BUCKET_NAME_STARTING_BALANCES};
+use super::bucket_names::BUCKET_NAMES;
-pub fn get_bucket_matchers(
-) -> Vec<Box<dyn Fn(&Bucket) -> bool>> {
+pub fn get_bucket_matchers() -> Vec<Box<dyn Fn(&Bucket) -> bool>> {
BUCKET_NAMES
.iter()
.map(|bucket_name| -> Box<dyn Fn(&Bucket) -> bool> {
Box::new(|c| matches_bucket(c, bucket_name))
- }).collect()
+ })
+ .collect()
}
-fn matches_bucket(bucket: &Bucket, bucket_name: &str,) -> bool {
- bucket.name == bucket_name
- && bucket.balance == 0
- && bucket.balance_date < "2024-08-01".parse().unwrap()
- && bucket.budget_period == 1
- && bucket.budget_period_unit == BudgetPeriodUnit::Month
- && bucket.budget_quantity == get_expected_budget_quantity(bucket_name)
-}
-
-fn get_expected_budget_quantity(bucket_name: &str) -> i32 {
- match bucket_name {
- BUCKET_NAME_FOOD => 200_00,
- BUCKET_NAME_GENERAL => 100_00,
- BUCKET_NAME_BILLS => 125_00,
- BUCKET_NAME_BILLS_FLEXIBLE => 25_00,
- BUCKET_NAME_SAVINGS => 400_00,
- BUCKET_NAME_STARTING_BALANCES => 0,
- BUCKET_NAME_INCOME => 0,
- _ => panic!("unexpected bucket name {}", bucket_name),
- }
+fn matches_bucket(bucket: &Bucket, bucket_name: &str) -> bool {
+ bucket.name == bucket_name && bucket.balance == None && bucket.balance_cache_key == None
}
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 3b46d76..038e4f7 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
@@ -2,11 +2,10 @@ use schist_models::{bucket::Bucket, bucket_transfer::BucketTransfer};
use super::bucket_names::{BUCKET_NAME_GENERAL, BUCKET_NAME_SAVINGS};
-pub fn get_bucket_transfer_matchers(
-) -> Vec<Box<dyn Fn(&BucketTransfer, &[Bucket]) -> bool>> {
- vec![
- Box::new(|ct, c| matches_120_savings_to_general_23_oct_2024(ct, c)),
- ]
+pub fn get_bucket_transfer_matchers() -> Vec<Box<dyn Fn(&BucketTransfer, &[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(
@@ -27,12 +26,14 @@ fn matches_120_savings_to_general_23_oct_2024(
BucketTransfer {
id: _id,
description,
- quantity: 120_00,
+ amount: 120_00,
from_bucket_id,
to_bucket_id,
- } => *from_bucket_id == savings_bucket.id
- && *to_bucket_id == general_bucket.id
- && description.as_str() == "",
+ } => {
+ *from_bucket_id == savings_bucket.id
+ && *to_bucket_id == general_bucket.id
+ && description.as_str() == ""
+ }
_ => false,
}
}
diff --git a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/budget_drip_matchers.rs b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/budget_drip_matchers.rs
index 97f81a2..bd42d76 100644
--- a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/budget_drip_matchers.rs
+++ b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/budget_drip_matchers.rs
@@ -1,9 +1,12 @@
use std::sync::LazyLock;
-use schist_models::{budget_drip::BudgetDrip, bucket::Bucket, date_utc::DateUtc};
+use schist_models::{bucket::Bucket, date_utc::DateUtc, drip::Drip};
use schist_traits::dateable::Dateable;
-use crate::common::bucket_names::{BUCKET_NAME_BILLS, BUCKET_NAME_BILLS_FLEXIBLE, BUCKET_NAME_FOOD, BUCKET_NAME_GENERAL, BUCKET_NAME_SAVINGS};
+use crate::common::bucket_names::{
+ BUCKET_NAME_BILLS, BUCKET_NAME_BILLS_FLEXIBLE, BUCKET_NAME_FOOD, BUCKET_NAME_GENERAL,
+ BUCKET_NAME_SAVINGS,
+};
pub fn get_num_expected_budget_drips() -> usize {
let num_expected_dates = DATES.len();
@@ -11,12 +14,11 @@ pub fn get_num_expected_budget_drips() -> usize {
num_expected_dates * num_expected_buckets
}
-pub fn assert_budget_drip_matches(
- budget_drip: &BudgetDrip,
- buckets: &[Bucket],
-) {
+pub fn assert_budget_drip_matches(budget_drip: &Drip, buckets: &[Bucket]) {
assert!(
- DATES.iter().any(|date| *LazyLock::force(date) == budget_drip.date),
+ DATES
+ .iter()
+ .any(|date| *LazyLock::force(date) == budget_drip.date),
"budget drip had unexpected date: {:?}",
budget_drip,
);
@@ -25,11 +27,13 @@ pub fn assert_budget_drip_matches(
.iter()
.find(|c| c.id == budget_drip.bucket_id)
.map(|c| c.name.clone())
- .expect(format!(
- "budget drip {:?} had unexpected bucket ID. buckets were: {:?}",
- budget_drip,
- buckets,
- ).as_str());
+ .expect(
+ format!(
+ "budget drip {:?} had unexpected bucket ID. buckets were: {:?}",
+ budget_drip, buckets,
+ )
+ .as_str(),
+ );
let expected_quantity = match (
bucket_name.as_str(),
@@ -58,7 +62,9 @@ pub fn assert_budget_drip_matches(
(BUCKET_NAME_BILLS_FLEXIBLE, 8 | 10, _) => 80,
(BUCKET_NAME_BILLS_FLEXIBLE, 9 | 11, 1) => 93,
(BUCKET_NAME_BILLS_FLEXIBLE, 9 | 11, _) => 83,
- (BUCKET_NAME_BILLS_FLEXIBLE, _, _) => panic!("budget drip {:?} had unexpected date", budget_drip),
+ (BUCKET_NAME_BILLS_FLEXIBLE, _, _) => {
+ panic!("budget drip {:?} had unexpected date", budget_drip)
+ }
(BUCKET_NAME_SAVINGS, 8 | 10, 1) => 13_00,
(BUCKET_NAME_SAVINGS, 8 | 10, _) => 12_90,
@@ -68,14 +74,12 @@ pub fn assert_budget_drip_matches(
(_, _, _) => panic!(
"budget drip {:?} had unexpected bucket name {}",
- budget_drip,
- bucket_name,
+ budget_drip, bucket_name,
),
};
assert_eq!(
- expected_quantity,
- budget_drip.quantity,
+ expected_quantity, budget_drip.amount,
"budget drip {:?} had unexpected quantity",
budget_drip,
);
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 62255b0..f067d0d 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
@@ -1,23 +1,22 @@
mod account_matchers;
mod account_names;
mod account_transfer_matchers;
-mod budget_drip_matchers;
mod bucket_matchers;
mod bucket_names;
mod bucket_transfer_matchers;
+mod budget_drip_matchers;
mod db_url;
mod test_context;
mod transaction_matchers;
-mod transaction_categorisation_matchers;
pub use account_matchers::get_account_matchers;
pub use account_names::ACCOUNT_NAMES_DICT;
pub use account_transfer_matchers::get_account_transfer_matchers;
-pub use budget_drip_matchers::assert_budget_drip_matches;
-pub use budget_drip_matchers::get_num_expected_budget_drips;
-pub use bucket_names::BUCKET_NAMES_DICT;
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 budget_drip_matchers::assert_budget_drip_matches;
+pub use budget_drip_matchers::get_num_expected_budget_drips;
pub use db_url::TEST_IN_DB_URL;
pub use db_url::TEST_OUT_DB_URL;
pub use test_context::TestContext;
@@ -26,4 +25,3 @@ pub use transaction_matchers::matches_bank_account_initial_transaction;
pub use transaction_matchers::matches_cash_account_initial_transaction;
pub use transaction_matchers::matches_food_transaction;
pub use transaction_matchers::matches_income_transaction;
-pub use transaction_categorisation_matchers::get_transaction_categorisation_matchers;
diff --git a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/transaction_categorisation_matchers.rs b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/transaction_categorisation_matchers.rs
deleted file mode 100644
index 8082055..0000000
--- a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/transaction_categorisation_matchers.rs
+++ /dev/null
@@ -1,141 +0,0 @@
-use schist_models::{account::Account, bucket::Bucket, transaction::Transaction, transaction_categorisation::TransactionCategorisation};
-
-use super::{bucket_names::{BUCKET_NAME_FOOD, BUCKET_NAME_INCOME, BUCKET_NAME_STARTING_BALANCES}, matches_bank_account_initial_transaction, matches_cash_account_initial_transaction, matches_food_transaction, matches_income_transaction};
-
-pub fn get_transaction_categorisation_matchers(
-) -> Vec<Box<dyn Fn(&TransactionCategorisation, &[Transaction], &[Bucket], &[Account]) -> bool>> {
- vec![
- Box::new(|tc, t, c, a| matches_bank_account_initial_transaction_categorisation(tc, t, c, a)),
- Box::new(|tc, t, c, a| matches_cash_account_initial_transaction_categorisation(tc, t, c, a)),
- Box::new(|tc, t, c, a| matches_income_transaction_categorisation(tc, t, c, a, "08")),
- Box::new(|tc, t, c, a| matches_income_transaction_categorisation(tc, t, c, a, "09")),
- Box::new(|tc, t, c, a| matches_income_transaction_categorisation(tc, t, c, a, "10")),
- Box::new(|tc, t, c, a| matches_income_transaction_categorisation(tc, t, c, a, "11")),
- Box::new(|tc, t, c, a| matches_food_transaction_categorisation(tc, t, c, a, "08")),
- Box::new(|tc, t, c, a| matches_food_transaction_categorisation(tc, t, c, a, "09")),
- Box::new(|tc, t, c, a| matches_food_transaction_categorisation(tc, t, c, a, "10")),
- Box::new(|tc, t, c, a| matches_food_transaction_categorisation(tc, t, c, a, "11")),
- ]
-}
-
-fn matches_bank_account_initial_transaction_categorisation(
- transaction_categorisation: &TransactionCategorisation,
- transactions: &[Transaction],
- buckets: &[Bucket],
- accounts: &[Account],
-) -> bool {
- let bank_account_initial_transaction = transactions
- .iter()
- .find(|t| matches_bank_account_initial_transaction(t, accounts))
- .expect("failed to find bank account initial transaction");
-
- let starting_balance_bucket = buckets
- .iter()
- .find(|c| c.name == BUCKET_NAME_STARTING_BALANCES)
- .expect("failed to find starting balance bucket");
-
- match transaction_categorisation {
- TransactionCategorisation {
- id: _id,
- description,
- quantity: 1200_00,
- transaction_id,
- bucket_id,
- } => description == ""
- && *transaction_id == bank_account_initial_transaction.id
- && *bucket_id == starting_balance_bucket.id,
- _ => false,
- }
-}
-
-fn matches_cash_account_initial_transaction_categorisation(
- transaction_categorisation: &TransactionCategorisation,
- transactions: &[Transaction],
- buckets: &[Bucket],
- accounts: &[Account],
-) -> bool {
- let cash_account_initial_transaction = transactions
- .iter()
- .find(|t| matches_cash_account_initial_transaction(t, accounts))
- .expect("failed to find cash account initial transaction");
-
- let starting_balance_bucket = buckets
- .iter()
- .find(|c| c.name == BUCKET_NAME_STARTING_BALANCES)
- .expect("failed to find starting balance bucket");
-
- match transaction_categorisation {
- TransactionCategorisation {
- id: _id,
- description,
- quantity: 45_10,
- transaction_id,
- bucket_id,
- } => description == ""
- && *transaction_id == cash_account_initial_transaction.id
- && *bucket_id == starting_balance_bucket.id,
- _ => false,
- }
-}
-
-fn matches_income_transaction_categorisation(
- transaction_categorisation: &TransactionCategorisation,
- transactions: &[Transaction],
- buckets: &[Bucket],
- accounts: &[Account],
- month: &str,
-) -> bool {
- let income_transaction = transactions
- .iter()
- .find(|t| matches_income_transaction(t, accounts, month))
- .expect(format!("failed to find income transaction for month {}", month).as_str());
-
- let income_bucket = buckets
- .iter()
- .find(|c| c.name == BUCKET_NAME_INCOME)
- .expect("failed to find income bucket");
-
- match transaction_categorisation {
- TransactionCategorisation {
- id: _id,
- description,
- quantity: 846_46,
- transaction_id,
- bucket_id,
- } => description == ""
- && *transaction_id == income_transaction.id
- && *bucket_id == income_bucket.id,
- _ => false,
- }
-}
-
-fn matches_food_transaction_categorisation(
- transaction_categorisation: &TransactionCategorisation,
- transactions: &[Transaction],
- buckets: &[Bucket],
- accounts: &[Account],
- month: &str,
-) -> bool {
- let food_transaction = transactions
- .iter()
- .find(|t| matches_food_transaction(t, accounts, month))
- .expect(format!("failed to find food transaction for month {}", month).as_str());
-
- let food_bucket = buckets
- .iter()
- .find(|c| c.name == BUCKET_NAME_FOOD)
- .expect("failed to find food bucket");
-
- match transaction_categorisation {
- TransactionCategorisation {
- id: _id,
- description,
- quantity: -200_00,
- transaction_id,
- bucket_id,
- } => description == ""
- && *transaction_id == food_transaction.id
- && *bucket_id == food_bucket.id,
- _ => false,
- }
-}
diff --git a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/transaction_matchers.rs b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/transaction_matchers.rs
index c3763c1..ea22054 100644
--- a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/transaction_matchers.rs
+++ b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/common/transaction_matchers.rs
@@ -2,8 +2,7 @@ use schist_models::{account::Account, transaction::Transaction};
use super::ACCOUNT_NAMES_DICT;
-pub fn get_transaction_matchers(
-) -> Vec<Box<dyn Fn(&Transaction, &[Account]) -> bool>> {
+pub fn get_transaction_matchers() -> Vec<Box<dyn Fn(&Transaction, &[Account]) -> bool>> {
vec![
Box::new(|t, a| matches_bank_account_initial_transaction(t, a)),
Box::new(|t, a| matches_cash_account_initial_transaction(t, a)),
@@ -18,10 +17,7 @@ pub fn get_transaction_matchers(
]
}
-pub fn matches_bank_account_initial_transaction(
- t: &Transaction,
- accounts: &[Account],
-) -> bool {
+pub fn matches_bank_account_initial_transaction(t: &Transaction, accounts: &[Account]) -> bool {
let bank_account_id = accounts
.iter()
.find(|a| a.name == ACCOUNT_NAMES_DICT.bank_account)
@@ -32,23 +28,24 @@ pub fn matches_bank_account_initial_transaction(
match t {
Transaction {
account_id,
+ bucket_id,
date,
id: _id,
description,
- payee,
- quantity: 1200_00,
- } => *account_id == bank_account_id
- && *date == "2024-08-01".parse().unwrap()
- && description == ""
- && payee == "Starting Balance",
+ counterparty: payee,
+ amount: 1200_00,
+ } => {
+ *account_id == bank_account_id
+ && *bucket_id == get_bucket_id()
+ && *date == "2024-08-01".parse().unwrap()
+ && description == ""
+ && payee == "Starting Balance"
+ }
_ => false,
}
}
-pub fn matches_cash_account_initial_transaction(
- t: &Transaction,
- accounts: &[Account],
-) -> bool {
+pub fn matches_cash_account_initial_transaction(t: &Transaction, accounts: &[Account]) -> bool {
let bank_account_id = accounts
.iter()
.find(|a| a.name == ACCOUNT_NAMES_DICT.cash_account)
@@ -59,24 +56,24 @@ pub fn matches_cash_account_initial_transaction(
match t {
Transaction {
account_id,
+ bucket_id,
date,
id: _id,
description,
- payee,
- quantity: 45_10,
- } => *account_id == bank_account_id
- && *date == "2024-08-01".parse().unwrap()
- && description == ""
- && payee == "Starting Balance",
+ counterparty: payee,
+ amount: 45_10,
+ } => {
+ *account_id == bank_account_id
+ && *bucket_id == get_bucket_id()
+ && *date == "2024-08-01".parse().unwrap()
+ && description == ""
+ && payee == "Starting Balance"
+ }
_ => false,
}
}
-pub fn matches_income_transaction(
- t: &Transaction,
- accounts: &[Account],
- month: &str,
-) -> bool {
+pub fn matches_income_transaction(t: &Transaction, accounts: &[Account], month: &str) -> bool {
let bank_account_id = accounts
.iter()
.find(|a| a.name == ACCOUNT_NAMES_DICT.bank_account)
@@ -87,25 +84,24 @@ pub fn matches_income_transaction(
match t {
Transaction {
account_id,
+ bucket_id,
date,
description,
id: _id,
- payee,
- quantity: 846_46,
- } =>
+ counterparty: payee,
+ amount: 846_46,
+ } => {
*account_id == bank_account_id
+ && *bucket_id == get_bucket_id()
&& *date == format!("2024-{}-21", month).parse().unwrap()
&& description == "Salary"
- && payee == "Employer Ltd",
+ && payee == "Employer Ltd"
+ }
_ => false,
}
}
-pub fn matches_food_transaction(
- t: &Transaction,
- accounts: &[Account],
- month: &str,
-) -> bool {
+pub fn matches_food_transaction(t: &Transaction, accounts: &[Account], month: &str) -> bool {
let bank_account_id = accounts
.iter()
.find(|a| a.name == ACCOUNT_NAMES_DICT.bank_account)
@@ -116,15 +112,23 @@ pub fn matches_food_transaction(
match t {
Transaction {
account_id,
+ bucket_id,
date,
description,
id: _id,
- payee,
- quantity: -200_00,
- } => *account_id == bank_account_id
- && *date == format!("2024-{}-08", month).parse().unwrap()
- && description == ""
- && payee == "Tesco",
+ counterparty: payee,
+ amount: -200_00,
+ } => {
+ *account_id == bank_account_id
+ && *bucket_id == get_bucket_id()
+ && *date == format!("2024-{}-08", month).parse().unwrap()
+ && description == ""
+ && payee == "Tesco"
+ }
_ => false,
}
}
+
+fn get_bucket_id() -> Option<i32> {
+ todo!()
+}
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 4c13d55..62e1159 100644
--- a/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/run.rs
+++ b/transformers/actualbudget_transformer/actualbudget_to_schist_transformer/tests/run.rs
@@ -1,9 +1,18 @@
pub mod common;
use actualbudget_to_schist_transformer::run::run;
-use common::{assert_budget_drip_matches, get_account_matchers, get_account_transfer_matchers, get_bucket_matchers, get_bucket_transfer_matchers, get_num_expected_budget_drips, get_transaction_categorisation_matchers, get_transaction_matchers, TestContext, TEST_IN_DB_URL, TEST_OUT_DB_URL};
+use common::{
+ assert_budget_drip_matches, get_account_matchers, get_account_transfer_matchers,
+ get_bucket_matchers, get_bucket_transfer_matchers, get_num_expected_budget_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, budget_drips::get_all_budget_drips, buckets::get_all_buckets, bucket_transfers::get_all_bucket_transfers, transaction_categorisations::get_all_transaction_categorisations, transactions::get_all_transactions};
+use schist_models::pipe::Pipe;
+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,
+};
#[test]
fn given_test_database_when_run_then_exports_expected_schist_state() {
@@ -12,11 +21,11 @@ fn given_test_database_when_run_then_exports_expected_schist_state() {
let connection = &mut SqliteConnection::establish(TEST_OUT_DB_URL).unwrap();
let accounts = get_all_accounts(connection).unwrap();
let account_transfers = get_all_account_transfers(connection).unwrap();
- let budget_drips = get_all_budget_drips(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 pipes = get_all_pipes(connection).unwrap();
let transactions = get_all_transactions(connection).unwrap();
- let transaction_categorisations = get_all_transaction_categorisations(connection).unwrap();
let account_matchers = get_account_matchers();
assert_eq!(account_matchers.len(), accounts.len());
@@ -32,14 +41,16 @@ fn given_test_database_when_run_then_exports_expected_schist_state() {
assert_eq!(account_transfer_matchers.len(), account_transfers.len());
for account_transfer in account_transfers {
assert!(
- account_transfer_matchers.iter().any(|m| m(&account_transfer, &accounts)),
+ account_transfer_matchers
+ .iter()
+ .any(|m| m(&account_transfer, &accounts)),
"no match found for account_transfer {:?}",
account_transfer,
);
}
- assert_eq!(get_num_expected_budget_drips(), budget_drips.len());
- for budget_drip in budget_drips {
+ assert_eq!(get_num_expected_budget_drips(), drips.len());
+ for budget_drip in drips {
assert_budget_drip_matches(&budget_drip, &buckets);
}
@@ -57,7 +68,9 @@ fn given_test_database_when_run_then_exports_expected_schist_state() {
assert_eq!(bucket_transfer_matchers.len(), bucket_transfers.len());
for bucket_transfer in bucket_transfers {
assert!(
- bucket_transfer_matchers.iter().any(|m| m(&bucket_transfer, &buckets)),
+ bucket_transfer_matchers
+ .iter()
+ .any(|m| m(&bucket_transfer, &buckets)),
"no match found for bucket_transfer {:?}",
bucket_transfer,
);
@@ -67,24 +80,13 @@ fn given_test_database_when_run_then_exports_expected_schist_state() {
assert_eq!(transaction_matchers.len(), transactions.len());
for transaction in transactions.clone() {
assert!(
- transaction_matchers.iter().any(|m| m(&transaction, &accounts)),
+ transaction_matchers
+ .iter()
+ .any(|m| m(&transaction, &accounts)),
"no match found for transaction {:?}",
transaction,
);
}
- let transaction_categorisation_matchers = get_transaction_categorisation_matchers();
- assert_eq!(transaction_categorisation_matchers.len(), transaction_categorisations.len());
- for transaction_categorisation in transaction_categorisations {
- assert!(
- transaction_categorisation_matchers.iter().any(|m| m(
- &transaction_categorisation,
- &transactions,
- &buckets,
- &accounts,
- )),
- "no match found for transaction_categorisation {:?}",
- transaction_categorisation,
- );
- }
+ assert_eq!(Vec::<Pipe>::new(), pipes);
}