summaryrefslogtreecommitdiff
path: root/backend/importers
diff options
context:
space:
mode:
authorJoe Carstairs <me@joeac.net>2024-10-22 07:46:43 +0100
committerJoe Carstairs <me@joeac.net>2024-10-22 07:46:43 +0100
commit5824c353f978a5b9ab9696451ee3014c6a614ffc (patch)
treebc39754ca417e84eb00b0aa9a1ae2330da0bf282 /backend/importers
parent7adaace61a4fe983eba5ded3aaaf624ce6fb9014 (diff)
Refactors importer to use core stuff
Diffstat (limited to 'backend/importers')
-rw-r--r--backend/importers/actualbudget/Cargo.lock331
-rw-r--r--backend/importers/actualbudget/Cargo.toml5
-rw-r--r--backend/importers/actualbudget/src/getters.rs61
-rw-r--r--backend/importers/actualbudget/src/inserters.rs120
-rw-r--r--backend/importers/actualbudget/src/main.rs64
-rw-r--r--backend/importers/actualbudget/src/models/actualbudget/account.rs15
-rw-r--r--backend/importers/actualbudget/src/models/actualbudget/category.rs15
-rw-r--r--backend/importers/actualbudget/src/models/actualbudget/date.rs69
-rw-r--r--backend/importers/actualbudget/src/models/actualbudget/mod.rs5
-rw-r--r--backend/importers/actualbudget/src/models/actualbudget/transaction.rs43
-rw-r--r--backend/importers/actualbudget/src/models/actualbudget/zero_budget.rs30
-rw-r--r--backend/importers/actualbudget/src/models/actualbudget_account.rs8
-rw-r--r--backend/importers/actualbudget/src/models/actualbudget_category.rs8
-rw-r--r--backend/importers/actualbudget/src/models/actualbudget_date.rs75
-rw-r--r--backend/importers/actualbudget/src/models/actualbudget_transaction.rs18
-rw-r--r--backend/importers/actualbudget/src/models/actualbudget_zero_budget.rs13
-rw-r--r--backend/importers/actualbudget/src/models/budgeting_app/DateTimeUtc.rs57
-rw-r--r--backend/importers/actualbudget/src/models/budgeting_app/account.rs8
-rw-r--r--backend/importers/actualbudget/src/models/budgeting_app/budget_update.rs10
-rw-r--r--backend/importers/actualbudget/src/models/budgeting_app/category.rs4
-rw-r--r--backend/importers/actualbudget/src/models/budgeting_app/category_transfer.rs7
-rw-r--r--backend/importers/actualbudget/src/models/budgeting_app/date_time_utc.rs20
-rw-r--r--backend/importers/actualbudget/src/models/budgeting_app/mod.rs7
-rw-r--r--backend/importers/actualbudget/src/models/budgeting_app/transaction.rs11
-rw-r--r--backend/importers/actualbudget/src/models/budgeting_app/transaction_categorisation.rs7
-rw-r--r--backend/importers/actualbudget/src/models/mod.rs7
-rw-r--r--backend/importers/actualbudget/src/queries/actualbudget_accounts/get_all.rs6
-rw-r--r--backend/importers/actualbudget/src/queries/actualbudget_accounts/get_category_transfers_account.rs13
-rw-r--r--backend/importers/actualbudget/src/queries/actualbudget_accounts/mod.rs5
-rw-r--r--backend/importers/actualbudget/src/queries/actualbudget_categories/get_all.rs6
-rw-r--r--backend/importers/actualbudget/src/queries/actualbudget_categories/mod.rs3
-rw-r--r--backend/importers/actualbudget/src/queries/actualbudget_transactions/get_all.rs6
-rw-r--r--backend/importers/actualbudget/src/queries/actualbudget_transactions/get_first_date.rs13
-rw-r--r--backend/importers/actualbudget/src/queries/actualbudget_transactions/mod.rs5
-rw-r--r--backend/importers/actualbudget/src/queries/actualbudget_zero_budgets/get_all.rs6
-rw-r--r--backend/importers/actualbudget/src/queries/actualbudget_zero_budgets/mod.rs3
-rw-r--r--backend/importers/actualbudget/src/queries/mod.rs4
-rw-r--r--backend/importers/actualbudget/src/schema.rs47
-rw-r--r--backend/importers/actualbudget/src/transformers.rs52
39 files changed, 610 insertions, 577 deletions
diff --git a/backend/importers/actualbudget/Cargo.lock b/backend/importers/actualbudget/Cargo.lock
index 63a53b9..1a461d5 100644
--- a/backend/importers/actualbudget/Cargo.lock
+++ b/backend/importers/actualbudget/Cargo.lock
@@ -6,8 +6,11 @@ version = 3
name = "actualbudget"
version = "0.1.0"
dependencies = [
+ "anyhow",
+ "budgeting_app_core",
"chrono",
- "sqlite",
+ "diesel",
+ "libsqlite3-sys",
]
[[package]]
@@ -26,12 +29,29 @@ dependencies = [
]
[[package]]
+name = "anyhow"
+version = "1.0.90"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37bf3594c4c988a53154954629820791dde498571819ae4ca50ca811e060cc95"
+
+[[package]]
name = "autocfg"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
[[package]]
+name = "budgeting_app_core"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "chrono",
+ "diesel",
+ "diesel_migrations",
+ "serde",
+]
+
+[[package]]
name = "bumpalo"
version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -74,6 +94,138 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
+name = "darling"
+version = "0.20.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
+dependencies = [
+ "darling_core",
+ "darling_macro",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.20.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.20.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
+dependencies = [
+ "darling_core",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "deranged"
+version = "0.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
+dependencies = [
+ "powerfmt",
+]
+
+[[package]]
+name = "diesel"
+version = "2.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "158fe8e2e68695bd615d7e4f3227c0727b151330d3e253b525086c348d055d5e"
+dependencies = [
+ "diesel_derives",
+ "libsqlite3-sys",
+ "time",
+]
+
+[[package]]
+name = "diesel_derives"
+version = "2.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7f2c3de51e2ba6bf2a648285696137aaf0f5f487bcbea93972fe8a364e131a4"
+dependencies = [
+ "diesel_table_macro_syntax",
+ "dsl_auto_type",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "diesel_migrations"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a73ce704bad4231f001bff3314d91dce4aba0770cee8b233991859abc15c1f6"
+dependencies = [
+ "diesel",
+ "migrations_internals",
+ "migrations_macros",
+]
+
+[[package]]
+name = "diesel_table_macro_syntax"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "209c735641a413bc68c4923a9d6ad4bcb3ca306b794edaa7eb0b3228a99ffb25"
+dependencies = [
+ "syn",
+]
+
+[[package]]
+name = "dsl_auto_type"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c5d9abe6314103864cc2d8901b7ae224e0ab1a103a0a416661b4097b0779b607"
+dependencies = [
+ "darling",
+ "either",
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "either"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
+
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "hashbrown"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
name = "iana-time-zone"
version = "0.1.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -97,6 +249,28 @@ dependencies = [
]
[[package]]
+name = "ident_case"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+
+[[package]]
+name = "indexmap"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
+
+[[package]]
name = "js-sys"
version = "0.3.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -112,12 +286,56 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
[[package]]
+name = "libsqlite3-sys"
+version = "0.30.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149"
+dependencies = [
+ "cc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
name = "log"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
+name = "memchr"
+version = "2.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
+[[package]]
+name = "migrations_internals"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd01039851e82f8799046eabbb354056283fb265c8ec0996af940f4e85a380ff"
+dependencies = [
+ "serde",
+ "toml",
+]
+
+[[package]]
+name = "migrations_macros"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffb161cc72176cb37aa47f1fc520d3ef02263d67d661f44f05d05a079e1237fd"
+dependencies = [
+ "migrations_internals",
+ "proc-macro2",
+ "quote",
+]
+
+[[package]]
+name = "num-conv"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
+
+[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -139,6 +357,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
[[package]]
+name = "powerfmt"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
+
+[[package]]
name = "proc-macro2"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -177,48 +401,100 @@ dependencies = [
]
[[package]]
+name = "serde_spanned"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
+dependencies = [
+ "serde",
+]
+
+[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
-name = "sqlite"
-version = "0.36.1"
+name = "strsim"
+version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5dfe6fb16f2bee6452feeb4d12bfa404fbcd3cfc121b2950e501d1ae9cae718e"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "syn"
+version = "2.0.77"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
dependencies = [
- "sqlite3-sys",
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
]
[[package]]
-name = "sqlite3-src"
-version = "0.6.1"
+name = "time"
+version = "0.3.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "174d4a6df77c27db281fb23de1a6d968f3aaaa4807c2a1afa8056b971f947b4a"
+checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
dependencies = [
- "cc",
- "pkg-config",
+ "deranged",
+ "itoa",
+ "num-conv",
+ "powerfmt",
+ "serde",
+ "time-core",
+ "time-macros",
]
[[package]]
-name = "sqlite3-sys"
-version = "0.17.0"
+name = "time-core"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
+
+[[package]]
+name = "time-macros"
+version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3901ada7090c3c3584dc92ec7ef1b7091868d13bfe6d7de9f0bcaffee7d0ade5"
+checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
dependencies = [
- "sqlite3-src",
+ "num-conv",
+ "time-core",
]
[[package]]
-name = "syn"
-version = "2.0.77"
+name = "toml"
+version = "0.8.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
+checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_edit",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.22.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
+dependencies = [
+ "indexmap",
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "winnow",
]
[[package]]
@@ -228,6 +504,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+
+[[package]]
name = "wasm-bindgen"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -354,3 +636,12 @@ name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "winnow"
+version = "0.6.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b"
+dependencies = [
+ "memchr",
+]
diff --git a/backend/importers/actualbudget/Cargo.toml b/backend/importers/actualbudget/Cargo.toml
index 7cc3e1b..6453e0a 100644
--- a/backend/importers/actualbudget/Cargo.toml
+++ b/backend/importers/actualbudget/Cargo.toml
@@ -4,5 +4,8 @@ version = "0.1.0"
edition = "2021"
[dependencies]
-sqlite = "0.36.1"
+anyhow = { version = "1.0.0" }
+budgeting_app_core = { path = "../../core" }
chrono = { version = "0.4.38", features = ["serde"] }
+diesel = { version = "2.2.0", features = ["sqlite"] }
+libsqlite3-sys = { version = "0.30.1", features = ["bundled"] }
diff --git a/backend/importers/actualbudget/src/getters.rs b/backend/importers/actualbudget/src/getters.rs
deleted file mode 100644
index 88a660d..0000000
--- a/backend/importers/actualbudget/src/getters.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-use crate::models::actualbudget::{
- account::Account, category::Category, date::Date, transaction::Transaction,
- zero_budget::ZeroBudget,
-};
-use sqlite::Connection;
-
-pub fn get_first_transaction_date(connection: &Connection) -> Date {
- let mut statement = connection
- .prepare("select min(date) as min_date from transactions;")
- .unwrap();
- match statement.next() {
- Ok(sqlite::State::Row) => Date::from_date_row(&statement, "min_date"),
- err => panic!("Could not find first transaction date: {:?}", err),
- }
-}
-
-pub fn get_accounts(connection: &Connection) -> Vec<Account> {
- let mut statement = connection.prepare("select * from accounts;").unwrap();
- let mut accounts = Vec::<Account>::new();
- while let Ok(sqlite::State::Row) = statement.next() {
- accounts.push(Account::from_row(&statement));
- }
- accounts
-}
-
-pub fn get_categories(connection: &Connection) -> Vec<Category> {
- let mut statement = connection.prepare("select * from categories;").unwrap();
- let mut categories = Vec::<Category>::new();
- while let Ok(sqlite::State::Row) = statement.next() {
- categories.push(Category::from_row(&statement));
- }
- categories
-}
-
-pub fn get_zero_budgets(connection: &Connection) -> Vec<ZeroBudget> {
- let mut statement = connection.prepare("select * from zero_budgets;").unwrap();
- let mut zero_budgets = Vec::<ZeroBudget>::new();
- while let Ok(sqlite::State::Row) = statement.next() {
- zero_budgets.push(ZeroBudget::from_row(&statement));
- }
- zero_budgets
-}
-
-pub fn get_category_transfers_account(connection: &Connection) -> Account {
- let mut statement = connection
- .prepare("select * from accounts where name = 'Category transfers';")
- .unwrap();
- match statement.next() {
- Ok(sqlite::State::Row) => Account::from_row(&statement),
- _ => panic!("Could not determine category transfers account"),
- }
-}
-
-pub fn get_transactions(connection: &Connection) -> Vec<Transaction> {
- let mut statement = connection.prepare("select * from transactions;").unwrap();
- let mut transactions = Vec::<Transaction>::new();
- while let Ok(sqlite::State::Row) = statement.next() {
- transactions.push(Transaction::from_row(&statement));
- }
- transactions
-}
diff --git a/backend/importers/actualbudget/src/inserters.rs b/backend/importers/actualbudget/src/inserters.rs
deleted file mode 100644
index 179de97..0000000
--- a/backend/importers/actualbudget/src/inserters.rs
+++ /dev/null
@@ -1,120 +0,0 @@
-use crate::models::budgeting_app::{
- account::Account, budget_update::BudgetUpdate, category::Category,
- category_transfer::CategoryTransfer, transaction::Transaction,
- transaction_categorisation::TransactionCategorisation,
-};
-use sqlite::Connection;
-
-pub fn insert_accounts(connection: &Connection, accounts: &[Account]) {
- for account in accounts {
- let str = format!(
- "
- insert into
- accounts(id, name, opening_balance, opening_date)
- values({0}, '{1}', {2}, '{3}');
- ",
- account.id,
- escape_str(&account.name),
- account.opening_balance,
- account.opening_date
- );
- connection.execute(str).unwrap();
- }
-}
-
-pub fn insert_categories(connection: &Connection, categories: &[Category]) {
- for category in categories {
- let str = format!(
- "
- insert into
- categories(id, name)
- values({0}, '{1}');
- ",
- category.id,
- escape_str(&category.name),
- );
- connection.execute(str).unwrap();
- }
-}
-
-pub fn insert_budget_updates(connection: &Connection, budget_updates: &[BudgetUpdate]) {
- for budget_update in budget_updates {
- let str = format!(
- "
- insert into
- budget_updates(id, category_id, date, new_budget, new_period)
- values({0}, {1}, '{2}', {3}, {4});
- ",
- budget_update.id,
- budget_update.category_id,
- budget_update.date,
- budget_update.new_budget,
- budget_update.new_period,
- );
- connection.execute(str).unwrap();
- }
-}
-
-pub fn insert_transactions(connection: &Connection, transactions: &[Transaction]) {
- for transaction in transactions {
- let str = format!(
- "
- insert into
- transactions(id, description, payee, quantity, date, account_id)
- values({0}, '{1}', '{2}', {3}, '{4}', {5});
- ",
- transaction.id,
- escape_str(&transaction.description),
- escape_str(&transaction.payee),
- transaction.quantity,
- transaction.date,
- transaction.account_id,
- );
- connection
- .execute(str.clone())
- .unwrap_or_else(|_| panic!("{}", &str.clone()));
- }
-}
-
-pub fn insert_transaction_categorisations(
- connection: &Connection,
- transaction_categorisations: &[TransactionCategorisation],
-) {
- for transaction_categorisation in transaction_categorisations {
- let str = format!(
- "
- insert into
- transaction_categorisations(id, description, quantity, transaction_id, category_id)
- values({0}, '{1}', {2}, {3}, {4});
- ",
- transaction_categorisation.id,
- escape_str(&transaction_categorisation.description),
- transaction_categorisation.quantity,
- transaction_categorisation.transaction_id,
- transaction_categorisation.category_id,
- );
- connection.execute(str).unwrap();
- }
-}
-
-pub fn insert_category_transfers(connection: &Connection, category_transfers: &[CategoryTransfer]) {
- for category_transfer in category_transfers {
- let str = format!(
- "
- insert into
- category_transfers(id, description, quantity, from_category_id, to_category_id)
- values({0}, '{1}', {2}, {3}, {4});
- ",
- category_transfer.id,
- escape_str(&category_transfer.description),
- category_transfer.quantity,
- category_transfer.from_category_id,
- category_transfer.to_category_id,
- );
- connection.execute(str).unwrap();
- }
-}
-
-fn escape_str(str: &str) -> String {
- str.replace("'", "''")
-}
diff --git a/backend/importers/actualbudget/src/main.rs b/backend/importers/actualbudget/src/main.rs
index 495216e..84f5102 100644
--- a/backend/importers/actualbudget/src/main.rs
+++ b/backend/importers/actualbudget/src/main.rs
@@ -1,57 +1,45 @@
-pub mod getters;
-pub mod inserters;
pub mod models;
+pub mod queries;
+pub mod schema;
pub mod transformers;
-use getters::*;
-use inserters::*;
-use sqlite::Connection;
+use anyhow::Result;
+use budgeting_app_core::queries as budgeting_app_queries;
+use diesel::{Connection, SqliteConnection};
+use queries::{actualbudget_accounts::{get_all_actualbudget_accounts, get_category_transfers_account}, actualbudget_categories::get_all_actualbudget_categories, actualbudget_transactions::{get_all_actualbudget_transactions, get_first_actualbudget_transaction_date}, actualbudget_zero_budgets::get_all_actualbudget_zero_budgets};
-fn main() {
- let connection_src = sqlite::open("in.sqlite").unwrap();
- let connection_dest = sqlite::open("out.sqlite").unwrap();
+fn main() -> Result<()> {
+ let connection_src = &mut SqliteConnection::establish("in.sqlite").unwrap();
+ let connection_dest = &mut SqliteConnection::establish("out.sqlite").unwrap();
- let actualbudget_first_transaction_date = get_first_transaction_date(&connection_src);
- let actualbudget_accounts = get_accounts(&connection_src);
- let actualbudget_categories = get_categories(&connection_src);
- let actualbudget_zero_budgets = get_zero_budgets(&connection_src);
- let actualbudget_category_transfers_account = get_category_transfers_account(&connection_src);
- let actualbudget_transactions = get_transactions(&connection_src);
+ let actualbudget_first_transaction_date = get_first_actualbudget_transaction_date(connection_src).map_err(|e| e.to_string())?;
+ let actualbudget_accounts = get_all_actualbudget_accounts(connection_src).map_err(|e| e.to_string())?;
+ let actualbudget_categories = get_all_actualbudget_categories(connection_src).map_err(|e| e.to_string())?;
+ let actualbudget_zero_budgets = get_all_actualbudget_zero_budgets(connection_src).map_err(|e| e.to_string())?;
+ let actualbudget_category_transfers_account = get_category_transfers_account(connection_src).map_err(|e| e.to_string())?;
+ let actualbudget_transactions = get_all_actualbudget_transactions(connection_src).map_err(|e| e.to_string())?;
- let first_transaction_date = transformers::transform_date(&actualbudget_first_transaction_date);
+ let first_transaction_date = transformers::transform_date(&actualbudget_first_transaction_date)?;
let accounts =
transformers::transform_accounts(&actualbudget_accounts, &first_transaction_date);
let categories = transformers::transform_categories(&actualbudget_categories);
- let budget_updates = transformers::transform_budget_updates(&actualbudget_zero_budgets);
+ let budget_updates = transformers::transform_budget_updates(&actualbudget_zero_budgets)?;
let (transactions, transaction_categorisations) = transformers::transform_transactions(
&actualbudget_transactions,
&actualbudget_category_transfers_account,
- );
+ )?;
let category_transfers = transformers::transform_category_transfers(
&actualbudget_transactions,
&actualbudget_category_transfers_account,
);
- clear_destination(&connection_dest);
- insert_accounts(&connection_dest, &accounts);
- insert_categories(&connection_dest, &categories);
- insert_budget_updates(&connection_dest, &budget_updates);
- insert_transactions(&connection_dest, &transactions);
- insert_transaction_categorisations(&connection_dest, &transaction_categorisations);
- insert_category_transfers(&connection_dest, &category_transfers);
-}
+ budgeting_app_queries::clear::clear(connection_dest).map_err(|e| e.to_string())?;
+ budgeting_app_queries::accounts::insert_accounts(&accounts, connection_dest).map_err(|e| e.to_string())?;
+ budgeting_app_queries::categories::insert_categories(&categories, connection_dest).map_err(|e| e.to_string())?;
+ budgeting_app_queries::budget_updates::insert_budget_updates(&budget_updates, connection_dest).map_err(|e| e.to_string())?;
+ budgeting_app_queries::transactions::insert_transactions(&transactions, connection_dest).map_err(|e| e.to_string())?;
+ budgeting_app_queries::transaction_categorisations::insert_transaction_categorisations(&transaction_categorisations, connection_dest).map_err(|e| e.to_string())?;
+ budgeting_app_queries::category_transfers::insert_category_transfers(&category_transfers, connection_dest).map_err(|e| e.to_string())?;
-fn clear_destination(connection: &Connection) {
- connection
- .execute(
- "
- delete from accounts;
- delete from budget_updates;
- delete from categories;
- delete from transaction_categorisations;
- delete from category_transfers;
- delete from transactions;
- ",
- )
- .unwrap();
+ Ok(())
}
diff --git a/backend/importers/actualbudget/src/models/actualbudget/account.rs b/backend/importers/actualbudget/src/models/actualbudget/account.rs
deleted file mode 100644
index 727c082..0000000
--- a/backend/importers/actualbudget/src/models/actualbudget/account.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-use sqlite::Statement;
-
-pub struct Account {
- pub id: String,
- pub name: String,
-}
-
-impl Account {
- pub fn from_row(statement: &Statement) -> Account {
- Account {
- id: statement.read("id").unwrap(),
- name: statement.read("name").unwrap(),
- }
- }
-}
diff --git a/backend/importers/actualbudget/src/models/actualbudget/category.rs b/backend/importers/actualbudget/src/models/actualbudget/category.rs
deleted file mode 100644
index 21fdf80..0000000
--- a/backend/importers/actualbudget/src/models/actualbudget/category.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-use sqlite::Statement;
-
-pub struct Category {
- pub id: String,
- pub name: String,
-}
-
-impl Category {
- pub fn from_row(statement: &Statement) -> Category {
- Category {
- id: statement.read("id").unwrap(),
- name: statement.read("name").unwrap(),
- }
- }
-}
diff --git a/backend/importers/actualbudget/src/models/actualbudget/date.rs b/backend/importers/actualbudget/src/models/actualbudget/date.rs
deleted file mode 100644
index bd37c46..0000000
--- a/backend/importers/actualbudget/src/models/actualbudget/date.rs
+++ /dev/null
@@ -1,69 +0,0 @@
-use sqlite::Statement;
-
-#[derive(Clone, PartialEq, Eq)]
-pub struct Date {
- value: i64,
- last_date_part: DatePart,
-}
-
-#[derive(Clone, PartialOrd, PartialEq, Eq)]
-enum DatePart {
- MonthOfYear,
- DayOfMonth,
-}
-
-// actualbudget represents dates as numbers which "look like" the corresponding
-// ISO string when written in decimal. E.g. 20240901 represents 1 Sep 2024. It
-// also uses month specifiers, e.g. 202409 to represent Sep 2024. In this case,
-// we interpret this as the first day of the month, e.g. 2024-09-01.
-
-impl Date {
- pub fn from_date_row(statement: &Statement, column: &str) -> Date {
- Date {
- value: statement.read::<i64, _>(column).unwrap(),
- last_date_part: DatePart::DayOfMonth,
- }
- }
-
- pub fn from_month_row(statement: &Statement, column: &str) -> Date {
- Date {
- value: statement.read::<i64, _>(column).unwrap() * 100 + 1,
- last_date_part: DatePart::MonthOfYear,
- }
- }
-
- pub fn to_iso(&self) -> String {
- format!("{0}-{1}-{2}", self.year(), self.month(), self.day())
- }
-
- pub fn year(&self) -> String {
- self.value.to_string()[0..4].to_string()
- }
-
- pub fn month(&self) -> String {
- self.value.to_string()[4..6].to_string()
- }
-
- pub fn day(&self) -> String {
- self.dayified_value().to_string()[6..8].to_string()
- }
-
- fn dayified_value(&self) -> i64 {
- match self.last_date_part {
- DatePart::DayOfMonth => self.value,
- DatePart::MonthOfYear => self.value * 100 + 1,
- }
- }
-}
-
-impl Ord for Date {
- fn cmp(&self, other: &Self) -> std::cmp::Ordering {
- self.dayified_value().cmp(&other.dayified_value())
- }
-}
-
-impl PartialOrd for Date {
- fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
- Some(self.cmp(other))
- }
-}
diff --git a/backend/importers/actualbudget/src/models/actualbudget/mod.rs b/backend/importers/actualbudget/src/models/actualbudget/mod.rs
deleted file mode 100644
index 5ca472f..0000000
--- a/backend/importers/actualbudget/src/models/actualbudget/mod.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-pub mod account;
-pub mod category;
-pub mod date;
-pub mod transaction;
-pub mod zero_budget;
diff --git a/backend/importers/actualbudget/src/models/actualbudget/transaction.rs b/backend/importers/actualbudget/src/models/actualbudget/transaction.rs
deleted file mode 100644
index 0a21cfe..0000000
--- a/backend/importers/actualbudget/src/models/actualbudget/transaction.rs
+++ /dev/null
@@ -1,43 +0,0 @@
-use sqlite::Statement;
-
-use super::date::Date;
-
-#[derive(Clone)]
-pub struct Transaction {
- pub id: String,
- pub is_parent: bool,
- pub is_child: bool,
- pub account_id: String,
- pub category_id: String,
- pub amount: i64,
- pub payee: String,
- pub notes: String,
- pub date: Date,
- pub parent_id: Option<String>,
-}
-
-impl Transaction {
- pub fn from_row(statement: &Statement) -> Transaction {
- Transaction {
- id: statement.read("id").unwrap(),
- is_parent: statement.read::<i64, &str>("isParent").unwrap() == 1,
- is_child: statement.read::<i64, &str>("isChild").unwrap() == 1,
- account_id: statement.read("acct").unwrap(),
- category_id: statement
- .read::<Option<String>, &str>("category")
- .map(Option::<String>::unwrap_or_default)
- .unwrap(),
- amount: statement.read("amount").unwrap(),
- payee: statement
- .read::<Option<String>, &str>("description")
- .map(Option::<String>::unwrap_or_default)
- .unwrap(),
- notes: statement
- .read::<Option<String>, &str>("notes")
- .map(Option::<String>::unwrap_or_default)
- .unwrap(),
- date: Date::from_date_row(statement, "date"),
- parent_id: statement.read("parent_id").unwrap(),
- }
- }
-}
diff --git a/backend/importers/actualbudget/src/models/actualbudget/zero_budget.rs b/backend/importers/actualbudget/src/models/actualbudget/zero_budget.rs
deleted file mode 100644
index 87c88e7..0000000
--- a/backend/importers/actualbudget/src/models/actualbudget/zero_budget.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-use sqlite::Statement;
-
-use super::date::Date;
-
-#[derive(Clone)]
-pub struct ZeroBudget {
- pub id: String,
- pub month: Date,
- pub category_id: String,
- pub amount: i64,
- pub do_carry_over: bool,
-}
-
-impl ZeroBudget {
- pub fn from_row(statement: &Statement) -> ZeroBudget {
- ZeroBudget {
- id: statement.read("id").unwrap(),
- month: Date::from_month_row(statement, "month"),
- category_id: statement.read("category").unwrap(),
- amount: statement.read("amount").unwrap(),
- do_carry_over: match statement.read::<i64, &str>("carryover").unwrap() {
- 0 => false,
- 1 => true,
- carryover => {
- panic!("carryover column was neither 0 nor 1, but instead {carryover}")
- }
- },
- }
- }
-}
diff --git a/backend/importers/actualbudget/src/models/actualbudget_account.rs b/backend/importers/actualbudget/src/models/actualbudget_account.rs
new file mode 100644
index 0000000..b3d00ac
--- /dev/null
+++ b/backend/importers/actualbudget/src/models/actualbudget_account.rs
@@ -0,0 +1,8 @@
+use diesel::prelude::{Queryable, Selectable};
+
+#[derive(Queryable, Selectable)]
+#[diesel(table_name = crate::schema::accounts)]
+pub struct ActualbudgetAccount {
+ pub id: String,
+ pub name: String,
+}
diff --git a/backend/importers/actualbudget/src/models/actualbudget_category.rs b/backend/importers/actualbudget/src/models/actualbudget_category.rs
new file mode 100644
index 0000000..cbea99b
--- /dev/null
+++ b/backend/importers/actualbudget/src/models/actualbudget_category.rs
@@ -0,0 +1,8 @@
+use diesel::{prelude::Queryable, Selectable};
+
+#[derive(Queryable, Selectable)]
+#[diesel(table_name = crate::schema::categories)]
+pub struct ActualbudgetCategory {
+ pub id: String,
+ pub name: String,
+}
diff --git a/backend/importers/actualbudget/src/models/actualbudget_date.rs b/backend/importers/actualbudget/src/models/actualbudget_date.rs
new file mode 100644
index 0000000..bef160c
--- /dev/null
+++ b/backend/importers/actualbudget/src/models/actualbudget_date.rs
@@ -0,0 +1,75 @@
+use diesel::{backend::Backend, deserialize::{FromSql, FromSqlRow}, expression::AsExpression, sql_types::Integer, sqlite::Sqlite};
+
+#[derive(Clone, PartialEq, Eq, Debug, AsExpression, FromSqlRow)]
+#[diesel(sql_type=Integer)]
+pub struct ActualbudgetDate(i32);
+
+#[derive(Clone, PartialOrd, PartialEq, Eq)]
+enum DatePart {
+ MonthOfYear,
+ DayOfMonth,
+}
+
+// actualbudget represents dates as numbers which "look like" the corresponding
+// ISO string when written in decimal. E.g. 20240901 represents 1 Sep 2024. It
+// also uses month specifiers, e.g. 202409 to represent Sep 2024. In this case,
+// we interpret this as the first day of the month, e.g. 2024-09-01.
+
+impl ActualbudgetDate {
+ pub fn to_iso(&self) -> String {
+ format!("{0}-{1}-{2}", self.year(), self.month(), self.day())
+ }
+
+ pub fn year(&self) -> String {
+ self.0.to_string()[0..4].to_string()
+ }
+
+ pub fn month(&self) -> String {
+ self.0.to_string()[4..6].to_string()
+ }
+
+ pub fn day(&self) -> String {
+ match self.date_part() {
+ DatePart::DayOfMonth => self.0.to_string()[6..8].to_string(),
+ DatePart::MonthOfYear => String::from("01"),
+ }
+ }
+
+ pub fn from_i32(i: i32) -> Self {
+ ActualbudgetDate(i)
+ }
+
+ fn date_part(&self) -> DatePart {
+ if self.0 < 10000000 {
+ DatePart::MonthOfYear
+ } else {
+ DatePart::DayOfMonth
+ }
+ }
+
+ fn dayified_value(&self) -> i32 {
+ match self.date_part() {
+ DatePart::DayOfMonth => self.0,
+ DatePart::MonthOfYear => self.0 * 100 + 1,
+ }
+ }
+}
+
+impl Ord for ActualbudgetDate {
+ fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+ self.dayified_value().cmp(&other.dayified_value())
+ }
+}
+
+impl PartialOrd for ActualbudgetDate {
+ fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl FromSql<Integer, Sqlite> for ActualbudgetDate {
+ fn from_sql(bytes: <Sqlite as Backend>::RawValue<'_>) -> diesel::deserialize::Result<Self> {
+ let int: i32 = FromSql::<Integer, Sqlite>::from_sql(bytes)?;
+ Ok(ActualbudgetDate(int))
+ }
+}
diff --git a/backend/importers/actualbudget/src/models/actualbudget_transaction.rs b/backend/importers/actualbudget/src/models/actualbudget_transaction.rs
new file mode 100644
index 0000000..be2ca1a
--- /dev/null
+++ b/backend/importers/actualbudget/src/models/actualbudget_transaction.rs
@@ -0,0 +1,18 @@
+use diesel::prelude::{Identifiable, Queryable, QueryableByName, Selectable};
+
+use crate::models::actualbudget_date::ActualbudgetDate;
+
+#[derive(Identifiable, QueryableByName, Queryable, Selectable, Clone)]
+#[diesel(table_name = crate::schema::transactions)]
+pub struct ActualbudgetTransaction {
+ pub id: String,
+ pub is_parent: bool,
+ pub is_child: bool,
+ pub account_id: String,
+ pub category_id: String,
+ pub amount: i32,
+ pub payee: String,
+ pub notes: String,
+ pub date: ActualbudgetDate,
+ pub parent_id: Option<String>,
+}
diff --git a/backend/importers/actualbudget/src/models/actualbudget_zero_budget.rs b/backend/importers/actualbudget/src/models/actualbudget_zero_budget.rs
new file mode 100644
index 0000000..6478d34
--- /dev/null
+++ b/backend/importers/actualbudget/src/models/actualbudget_zero_budget.rs
@@ -0,0 +1,13 @@
+use crate::models::actualbudget_date::ActualbudgetDate;
+use diesel::{prelude::{Identifiable, Queryable, QueryableByName, Selectable}, sqlite::Sqlite};
+
+#[derive(Identifiable, QueryableByName, Queryable, Selectable, Clone)]
+#[diesel(table_name = crate::schema::zero_budgets)]
+#[diesel(check_for_backend(Sqlite))]
+pub struct ActualbudgetZeroBudget {
+ pub id: String,
+ pub month: ActualbudgetDate,
+ pub category_id: String,
+ pub amount: i32,
+ pub do_carry_over: i32,
+}
diff --git a/backend/importers/actualbudget/src/models/budgeting_app/DateTimeUtc.rs b/backend/importers/actualbudget/src/models/budgeting_app/DateTimeUtc.rs
deleted file mode 100644
index e44fa8c..0000000
--- a/backend/importers/actualbudget/src/models/budgeting_app/DateTimeUtc.rs
+++ /dev/null
@@ -1,57 +0,0 @@
-use chrono::{DateTime, Datelike, Utc};
-use diesel::{
- deserialize::{FromSql, FromSqlRow},
- expression::AsExpression,
- serialize::ToSql,
- sql_types::Text,
- sqlite::Sqlite,
-};
-use serde::{Deserialize, Serialize};
-
-#[derive(
- Eq,
- PartialEq,
- Ord,
- PartialOrd,
- Serialize,
- Deserialize,
- Copy,
- Clone,
- Debug,
- AsExpression,
- FromSqlRow,
-)]
-#[diesel(sql_type=Text)]
-pub struct DateTimeUtc(DateTime<Utc>);
-
-impl DateTimeUtc {
- pub fn day_diff(&self, other: &DateTimeUtc) -> u32 {
- self.0
- .num_days_from_ce()
- .abs_diff(other.0.num_days_from_ce())
- }
-
- pub fn new(date_time_utc: DateTime<Utc>) -> Self {
- Self(date_time_utc)
- }
-}
-
-impl ToSql<Text, Sqlite> for DateTimeUtc {
- fn to_sql<'b>(
- &'b self,
- out: &mut diesel::serialize::Output<'b, '_, Sqlite>,
- ) -> diesel::serialize::Result {
- out.set_value((*self).0.to_rfc3339());
- Ok(diesel::serialize::IsNull::No)
- }
-}
-
-impl FromSql<Text, Sqlite> for DateTimeUtc {
- fn from_sql(
- bytes: <Sqlite as diesel::backend::Backend>::RawValue<'_>,
- ) -> diesel::deserialize::Result<Self> {
- let str: String = FromSql::<Text, Sqlite>::from_sql(bytes)?;
- let date_time = str.as_str().parse::<DateTime<Utc>>()?;
- Ok(DateTimeUtc(date_time))
- }
-}
diff --git a/backend/importers/actualbudget/src/models/budgeting_app/account.rs b/backend/importers/actualbudget/src/models/budgeting_app/account.rs
deleted file mode 100644
index 165b55c..0000000
--- a/backend/importers/actualbudget/src/models/budgeting_app/account.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-use super::date_time_utc::DateTimeUtc;
-
-pub struct Account {
- pub id: i32,
- pub name: String,
- pub opening_balance: i32,
- pub opening_date: DateTimeUtc,
-}
diff --git a/backend/importers/actualbudget/src/models/budgeting_app/budget_update.rs b/backend/importers/actualbudget/src/models/budgeting_app/budget_update.rs
deleted file mode 100644
index 9958446..0000000
--- a/backend/importers/actualbudget/src/models/budgeting_app/budget_update.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-use super::date_time_utc::DateTimeUtc;
-
-#[derive(Clone)]
-pub struct BudgetUpdate {
- pub id: i32,
- pub category_id: i32,
- pub date: DateTimeUtc,
- pub new_budget: i32,
- pub new_period: i32,
-}
diff --git a/backend/importers/actualbudget/src/models/budgeting_app/category.rs b/backend/importers/actualbudget/src/models/budgeting_app/category.rs
deleted file mode 100644
index 3f51dfd..0000000
--- a/backend/importers/actualbudget/src/models/budgeting_app/category.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-pub struct Category {
- pub id: i32,
- pub name: String,
-}
diff --git a/backend/importers/actualbudget/src/models/budgeting_app/category_transfer.rs b/backend/importers/actualbudget/src/models/budgeting_app/category_transfer.rs
deleted file mode 100644
index 0097429..0000000
--- a/backend/importers/actualbudget/src/models/budgeting_app/category_transfer.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-pub struct CategoryTransfer {
- pub id: i32,
- pub description: String,
- pub quantity: i32,
- pub from_category_id: i32,
- pub to_category_id: i32,
-}
diff --git a/backend/importers/actualbudget/src/models/budgeting_app/date_time_utc.rs b/backend/importers/actualbudget/src/models/budgeting_app/date_time_utc.rs
deleted file mode 100644
index 69cdfe2..0000000
--- a/backend/importers/actualbudget/src/models/budgeting_app/date_time_utc.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-use std::{fmt::Display, str::FromStr};
-
-use chrono::{DateTime, Utc};
-
-#[derive(Clone)]
-pub struct DateTimeUtc(DateTime<Utc>);
-
-impl DateTimeUtc {
- pub fn new(date: &str) -> Self {
- let mut date_time = String::from(date);
- date_time.push_str("T00:00:00.000Z");
- Self(DateTime::<Utc>::from_str(&date_time).unwrap())
- }
-}
-
-impl Display for DateTimeUtc {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- self.0.fmt(f)
- }
-}
diff --git a/backend/importers/actualbudget/src/models/budgeting_app/mod.rs b/backend/importers/actualbudget/src/models/budgeting_app/mod.rs
deleted file mode 100644
index bca0f99..0000000
--- a/backend/importers/actualbudget/src/models/budgeting_app/mod.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-pub mod account;
-pub mod budget_update;
-pub mod category;
-pub mod category_transfer;
-pub mod date_time_utc;
-pub mod transaction;
-pub mod transaction_categorisation;
diff --git a/backend/importers/actualbudget/src/models/budgeting_app/transaction.rs b/backend/importers/actualbudget/src/models/budgeting_app/transaction.rs
deleted file mode 100644
index e679e1e..0000000
--- a/backend/importers/actualbudget/src/models/budgeting_app/transaction.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-use super::date_time_utc::DateTimeUtc;
-
-#[derive(Clone)]
-pub struct Transaction {
- pub id: i32,
- pub description: String,
- pub payee: String,
- pub quantity: i32,
- pub date: DateTimeUtc,
- pub account_id: i32,
-}
diff --git a/backend/importers/actualbudget/src/models/budgeting_app/transaction_categorisation.rs b/backend/importers/actualbudget/src/models/budgeting_app/transaction_categorisation.rs
deleted file mode 100644
index ca7e7f5..0000000
--- a/backend/importers/actualbudget/src/models/budgeting_app/transaction_categorisation.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-pub struct TransactionCategorisation {
- pub id: i32,
- pub description: String,
- pub quantity: i32,
- pub transaction_id: i32,
- pub category_id: i32,
-}
diff --git a/backend/importers/actualbudget/src/models/mod.rs b/backend/importers/actualbudget/src/models/mod.rs
index cf1b71a..1c97c65 100644
--- a/backend/importers/actualbudget/src/models/mod.rs
+++ b/backend/importers/actualbudget/src/models/mod.rs
@@ -1,2 +1,5 @@
-pub mod actualbudget;
-pub mod budgeting_app;
+pub mod actualbudget_account;
+pub mod actualbudget_category;
+pub mod actualbudget_date;
+pub mod actualbudget_transaction;
+pub mod actualbudget_zero_budget;
diff --git a/backend/importers/actualbudget/src/queries/actualbudget_accounts/get_all.rs b/backend/importers/actualbudget/src/queries/actualbudget_accounts/get_all.rs
new file mode 100644
index 0000000..6f667de
--- /dev/null
+++ b/backend/importers/actualbudget/src/queries/actualbudget_accounts/get_all.rs
@@ -0,0 +1,6 @@
+use crate::{models::actualbudget_account::ActualbudgetAccount, schema::accounts::dsl::accounts};
+use diesel::{result::Error, QueryDsl, RunQueryDsl, SelectableHelper, SqliteConnection};
+
+pub fn get_all_actualbudget_accounts(connection: &mut SqliteConnection) -> Result<Vec<ActualbudgetAccount>, Error> {
+ accounts.select(ActualbudgetAccount::as_select()).load(connection)
+}
diff --git a/backend/importers/actualbudget/src/queries/actualbudget_accounts/get_category_transfers_account.rs b/backend/importers/actualbudget/src/queries/actualbudget_accounts/get_category_transfers_account.rs
new file mode 100644
index 0000000..f05dc78
--- /dev/null
+++ b/backend/importers/actualbudget/src/queries/actualbudget_accounts/get_category_transfers_account.rs
@@ -0,0 +1,13 @@
+use diesel::{result::Error, ExpressionMethods, QueryDsl, RunQueryDsl, SelectableHelper, SqliteConnection};
+
+use crate::{models::actualbudget_account::ActualbudgetAccount, schema::accounts::{
+ self as accounts_schema,
+ dsl::accounts as accounts_table,
+}};
+
+pub fn get_category_transfers_account(connection: &mut SqliteConnection) -> Result<ActualbudgetAccount, Error> {
+ accounts_table
+ .filter(accounts_schema::name.eq("Category transfers"))
+ .select(ActualbudgetAccount::as_select())
+ .first(connection)
+}
diff --git a/backend/importers/actualbudget/src/queries/actualbudget_accounts/mod.rs b/backend/importers/actualbudget/src/queries/actualbudget_accounts/mod.rs
new file mode 100644
index 0000000..c6d6015
--- /dev/null
+++ b/backend/importers/actualbudget/src/queries/actualbudget_accounts/mod.rs
@@ -0,0 +1,5 @@
+mod get_all;
+mod get_category_transfers_account;
+
+pub use get_all::get_all_actualbudget_accounts;
+pub use get_category_transfers_account::get_category_transfers_account;
diff --git a/backend/importers/actualbudget/src/queries/actualbudget_categories/get_all.rs b/backend/importers/actualbudget/src/queries/actualbudget_categories/get_all.rs
new file mode 100644
index 0000000..4cb7ebc
--- /dev/null
+++ b/backend/importers/actualbudget/src/queries/actualbudget_categories/get_all.rs
@@ -0,0 +1,6 @@
+use crate::{models::actualbudget_category::ActualbudgetCategory, schema::categories::dsl::categories};
+use diesel::{result::Error, QueryDsl, RunQueryDsl, SelectableHelper, SqliteConnection};
+
+pub fn get_all_actualbudget_categories(connection: &mut SqliteConnection) -> Result<Vec<ActualbudgetCategory>, Error> {
+ categories.select(ActualbudgetCategory::as_select()).load(connection)
+}
diff --git a/backend/importers/actualbudget/src/queries/actualbudget_categories/mod.rs b/backend/importers/actualbudget/src/queries/actualbudget_categories/mod.rs
new file mode 100644
index 0000000..0c04e53
--- /dev/null
+++ b/backend/importers/actualbudget/src/queries/actualbudget_categories/mod.rs
@@ -0,0 +1,3 @@
+mod get_all;
+
+pub use get_all::get_all_actualbudget_categories;
diff --git a/backend/importers/actualbudget/src/queries/actualbudget_transactions/get_all.rs b/backend/importers/actualbudget/src/queries/actualbudget_transactions/get_all.rs
new file mode 100644
index 0000000..84c8d08
--- /dev/null
+++ b/backend/importers/actualbudget/src/queries/actualbudget_transactions/get_all.rs
@@ -0,0 +1,6 @@
+use crate::{models::actualbudget_transaction::ActualbudgetTransaction, schema::transactions::dsl::transactions};
+use diesel::{result::Error, QueryDsl, RunQueryDsl, SelectableHelper, SqliteConnection};
+
+pub fn get_all_actualbudget_transactions(connection: &mut SqliteConnection) -> Result<Vec<ActualbudgetTransaction>, Error> {
+ transactions.select(ActualbudgetTransaction::as_select()).load(connection)
+}
diff --git a/backend/importers/actualbudget/src/queries/actualbudget_transactions/get_first_date.rs b/backend/importers/actualbudget/src/queries/actualbudget_transactions/get_first_date.rs
new file mode 100644
index 0000000..dabfbd6
--- /dev/null
+++ b/backend/importers/actualbudget/src/queries/actualbudget_transactions/get_first_date.rs
@@ -0,0 +1,13 @@
+use crate::{models::actualbudget_date::ActualbudgetDate, schema::transactions::{
+ self as transactions_schema,
+ dsl::transactions as transactions_table,
+}};
+use diesel::{dsl::min, result::Error, QueryDsl, RunQueryDsl, SqliteConnection};
+
+pub fn get_first_actualbudget_transaction_date(connection: &mut SqliteConnection) -> Result<ActualbudgetDate, Error> {
+ let date_as_int = transactions_table
+ .select(min(transactions_schema::date))
+ .first::<Option<i32>>(connection)
+ .map_or_else(|e| Err(e), |o| o.map_or_else(|| Err(Error::NotFound), |i| Ok(i)))?;
+ Ok(ActualbudgetDate::from_i32(date_as_int))
+}
diff --git a/backend/importers/actualbudget/src/queries/actualbudget_transactions/mod.rs b/backend/importers/actualbudget/src/queries/actualbudget_transactions/mod.rs
new file mode 100644
index 0000000..b4ed0dd
--- /dev/null
+++ b/backend/importers/actualbudget/src/queries/actualbudget_transactions/mod.rs
@@ -0,0 +1,5 @@
+mod get_all;
+mod get_first_date;
+
+pub use get_all::get_all_actualbudget_transactions;
+pub use get_first_date::get_first_actualbudget_transaction_date;
diff --git a/backend/importers/actualbudget/src/queries/actualbudget_zero_budgets/get_all.rs b/backend/importers/actualbudget/src/queries/actualbudget_zero_budgets/get_all.rs
new file mode 100644
index 0000000..0c3f695
--- /dev/null
+++ b/backend/importers/actualbudget/src/queries/actualbudget_zero_budgets/get_all.rs
@@ -0,0 +1,6 @@
+use crate::{models::actualbudget_zero_budget::ActualbudgetZeroBudget, schema::zero_budgets::dsl::zero_budgets};
+use diesel::{result::Error, QueryDsl, RunQueryDsl, SelectableHelper, SqliteConnection};
+
+pub fn get_all_actualbudget_zero_budgets(connection: &mut SqliteConnection) -> Result<Vec<ActualbudgetZeroBudget>, Error> {
+ zero_budgets.select(ActualbudgetZeroBudget::as_select()).load(connection)
+}
diff --git a/backend/importers/actualbudget/src/queries/actualbudget_zero_budgets/mod.rs b/backend/importers/actualbudget/src/queries/actualbudget_zero_budgets/mod.rs
new file mode 100644
index 0000000..ba7e21b
--- /dev/null
+++ b/backend/importers/actualbudget/src/queries/actualbudget_zero_budgets/mod.rs
@@ -0,0 +1,3 @@
+mod get_all;
+
+pub use get_all::get_all_actualbudget_zero_budgets;
diff --git a/backend/importers/actualbudget/src/queries/mod.rs b/backend/importers/actualbudget/src/queries/mod.rs
new file mode 100644
index 0000000..e16dafc
--- /dev/null
+++ b/backend/importers/actualbudget/src/queries/mod.rs
@@ -0,0 +1,4 @@
+pub mod actualbudget_accounts;
+pub mod actualbudget_categories;
+pub mod actualbudget_transactions;
+pub mod actualbudget_zero_budgets;
diff --git a/backend/importers/actualbudget/src/schema.rs b/backend/importers/actualbudget/src/schema.rs
new file mode 100644
index 0000000..a872231
--- /dev/null
+++ b/backend/importers/actualbudget/src/schema.rs
@@ -0,0 +1,47 @@
+diesel::table! {
+ accounts (id) {
+ id -> Text,
+ name -> Text,
+ }
+}
+
+diesel::table! {
+ categories (id) {
+ id -> Text,
+ name -> Text,
+ }
+}
+
+diesel::table! {
+ transactions (id) {
+ id -> Text,
+ #[sql_name = "isParent"]
+ is_parent -> Bool,
+ #[sql_name = "isChild"]
+ is_child -> Bool,
+ #[sql_name = "acct"]
+ account_id -> Text,
+ #[sql_name = "category"]
+ category_id -> Text,
+ amount -> Integer,
+ #[sql_name = "description"]
+ payee -> Text,
+ notes -> Text,
+ date -> Integer,
+ parent_id -> Nullable<Text>,
+ }
+}
+
+diesel::table! {
+ zero_budgets (id) {
+ id -> Text,
+ month -> Integer,
+ #[sql_name = "category"]
+ category_id -> Text,
+ amount -> Integer,
+ #[sql_name = "carryover"]
+ do_carry_over -> Integer,
+ // goal -> Integer,
+ // long_goal -> Integer,
+ }
+}
diff --git a/backend/importers/actualbudget/src/transformers.rs b/backend/importers/actualbudget/src/transformers.rs
index 678ea05..76001d1 100644
--- a/backend/importers/actualbudget/src/transformers.rs
+++ b/backend/importers/actualbudget/src/transformers.rs
@@ -1,21 +1,19 @@
+use budgeting_app_core::models::{
+ account::Account, budget_update::BudgetUpdate, category::Category,
+ category_transfer::CategoryTransfer, date_time_utc::DateTimeUtc, transaction::Transaction,
+ transaction_categorisation::TransactionCategorisation,
+};
use core::panic;
use std::hash::{DefaultHasher, Hash, Hasher};
-use crate::models::{
- actualbudget,
- budgeting_app::{
- account::Account, budget_update::BudgetUpdate, category::Category,
- category_transfer::CategoryTransfer, date_time_utc::DateTimeUtc, transaction::Transaction,
- transaction_categorisation::TransactionCategorisation,
- },
-};
+use crate::models::{actualbudget_account::ActualbudgetAccount, actualbudget_category::ActualbudgetCategory, actualbudget_date::ActualbudgetDate, actualbudget_transaction::ActualbudgetTransaction, actualbudget_zero_budget::ActualbudgetZeroBudget};
-pub fn transform_date(actualbudget_date: &actualbudget::date::Date) -> DateTimeUtc {
- DateTimeUtc::new(&actualbudget_date.to_iso())
+pub fn transform_date(actualbudget_date: &ActualbudgetDate) -> Result<DateTimeUtc, String> {
+ DateTimeUtc::from_date_str(&actualbudget_date.to_iso()).map_err(|e| e.to_string())
}
pub fn transform_accounts(
- actualbudget_accounts: &[actualbudget::account::Account],
+ actualbudget_accounts: &[ActualbudgetAccount],
first_transaction_date: &DateTimeUtc,
) -> Vec<Account> {
let mut accounts = Vec::<Account>::new();
@@ -26,7 +24,7 @@ pub fn transform_accounts(
}
fn transform_account(
- actualbudget_account: &actualbudget::account::Account,
+ actualbudget_account: &ActualbudgetAccount,
opening_date: &DateTimeUtc,
) -> Account {
Account {
@@ -38,7 +36,7 @@ fn transform_account(
}
pub fn transform_categories(
- actualbudget_categories: &[actualbudget::category::Category],
+ actualbudget_categories: &[ActualbudgetCategory],
) -> Vec<Category> {
let mut categories = Vec::<Category>::new();
for actualbudget_category in actualbudget_categories {
@@ -59,8 +57,8 @@ fn transform_id(actualbudget_id: &str) -> i32 {
}
pub fn transform_budget_updates(
- actualbudget_zero_budgets: &[actualbudget::zero_budget::ZeroBudget],
-) -> Vec<BudgetUpdate> {
+ actualbudget_zero_budgets: &[ActualbudgetZeroBudget],
+) -> Result<Vec<BudgetUpdate>, String> {
let mut budget_updates = Vec::<BudgetUpdate>::new();
for zero_budget in actualbudget_zero_budgets {
let first_zero_budget_in_category = get_first_zero_budget_in_category(
@@ -73,18 +71,18 @@ pub fn transform_budget_updates(
budget_updates.push(BudgetUpdate {
id: transform_id(&zero_budget.id.clone()),
category_id: transform_id(&zero_budget.category_id.clone()),
- date: transform_date(&zero_budget.month.clone()),
+ date: transform_date(&zero_budget.month.clone()).map_err(|e| e.to_string())?,
new_budget: zero_budget.amount.try_into().unwrap(),
new_period: 30,
})
}
- budget_updates
+ Ok(budget_updates)
}
fn get_first_zero_budget_in_category(
- actualbudget_zero_budgets: &[actualbudget::zero_budget::ZeroBudget],
+ actualbudget_zero_budgets: &[ActualbudgetZeroBudget],
actualbudget_category_id: &str,
-) -> Option<actualbudget::zero_budget::ZeroBudget> {
+) -> Option<ActualbudgetZeroBudget> {
let mut category_zero_budgets = actualbudget_zero_budgets.to_vec();
category_zero_budgets.retain(|zb| zb.category_id == actualbudget_category_id);
category_zero_budgets
@@ -94,9 +92,9 @@ fn get_first_zero_budget_in_category(
}
pub fn transform_transactions(
- actualbudget_transactions: &[actualbudget::transaction::Transaction],
- actualbudget_category_transfers_account: &actualbudget::account::Account,
-) -> (Vec<Transaction>, Vec<TransactionCategorisation>) {
+ actualbudget_transactions: &[ActualbudgetTransaction],
+ actualbudget_category_transfers_account: &ActualbudgetAccount,
+) -> Result<(Vec<Transaction>, Vec<TransactionCategorisation>), String> {
let mut transactions = Vec::<Transaction>::new();
let mut transaction_categorisations = Vec::<TransactionCategorisation>::new();
@@ -118,7 +116,7 @@ pub fn transform_transactions(
description: atomic_actualbudget_transaction.notes,
payee: atomic_actualbudget_transaction.payee,
quantity: atomic_actualbudget_transaction.amount.try_into().unwrap(),
- date: transform_date(&atomic_actualbudget_transaction.date),
+ date: transform_date(&atomic_actualbudget_transaction.date).map_err(|e| e.to_string())?,
account_id: transform_id(&atomic_actualbudget_transaction.account_id),
});
@@ -146,7 +144,7 @@ pub fn transform_transactions(
description: parent_actualbudget_transaction.notes,
payee: parent_actualbudget_transaction.payee,
quantity: parent_actualbudget_transaction.amount.try_into().unwrap(),
- date: transform_date(&parent_actualbudget_transaction.date),
+ date: transform_date(&parent_actualbudget_transaction.date).map_err(|e| e.to_string())?,
account_id: transform_id(&parent_actualbudget_transaction.account_id),
});
@@ -161,12 +159,12 @@ pub fn transform_transactions(
}
}
- (transactions, transaction_categorisations)
+ Ok((transactions, transaction_categorisations))
}
pub fn transform_category_transfers(
- actualbudget_transactions: &[actualbudget::transaction::Transaction],
- actualbudget_category_transfers_account: &actualbudget::account::Account,
+ actualbudget_transactions: &[ActualbudgetTransaction],
+ actualbudget_category_transfers_account: &ActualbudgetAccount,
) -> Vec<CategoryTransfer> {
let mut category_transfers = Vec::<CategoryTransfer>::new();