diff options
| author | Joe Carstairs <jcarstairs@scottlogic.com> | 2025-07-28 13:22:53 +0100 |
|---|---|---|
| committer | Joe Carstairs <jcarstairs@scottlogic.com> | 2025-07-28 13:30:27 +0100 |
| commit | 2361adeb0ca77904138e3466d51c2f44cf6df613 (patch) | |
| tree | f6e7192908f99fab62061913d8a1e9d2b918414b /schist_models | |
| parent | c7ed1e61ce2218be0b9e60577454124c4e43a366 (diff) | |
Tidier folders
Diffstat (limited to 'schist_models')
23 files changed, 0 insertions, 1466 deletions
diff --git a/schist_models/Cargo.toml b/schist_models/Cargo.toml deleted file mode 100644 index 51ac324..0000000 --- a/schist_models/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "schist_models" -version = "0.1.0" -edition = "2021" - -[dependencies] -anyhow = { workspace = true } -chrono = { workspace = true, features = ["serde"] } -derive_builder = { workspace = true } -diesel = { workspace = true, features = ["sqlite"] } -diesel_migrations = { workspace = true } -schist_traits = { path = "../schist_traits" } -serde = { workspace = true, features = ["derive"] } - -[dev-dependencies] -libsqlite3-sys = { workspace = true, features = ["bundled"] } -schist_queries = { path = "../schist_queries" } diff --git a/schist_models/diesel.toml b/schist_models/diesel.toml deleted file mode 100644 index 2b8ebd8..0000000 --- a/schist_models/diesel.toml +++ /dev/null @@ -1,9 +0,0 @@ -# For documentation on how to configure this file, -# see https://diesel.rs/guides/configuring-diesel-cli - -[print_schema] -file = "src/schema.rs" -custom_type_derives = ["diesel::query_builder::QueryId", "Clone"] - -[migrations_directory] -dir = "/home/joeac/src/schist/rust/schist_models/migrations" diff --git a/schist_models/migrations/2024-08-31-084439_initial_setup/down.sql b/schist_models/migrations/2024-08-31-084439_initial_setup/down.sql deleted file mode 100644 index ba65012..0000000 --- a/schist_models/migrations/2024-08-31-084439_initial_setup/down.sql +++ /dev/null @@ -1,7 +0,0 @@ -DROP TABLE accounts; -DROP TABLE account_transfers; -DROP TABLE budget_drips; -DROP TABLE categories; -DROP TABLE transaction_categorisations; -DROP TABLE category_transfers; -DROP TABLE transactions; diff --git a/schist_models/migrations/2024-08-31-084439_initial_setup/up.sql b/schist_models/migrations/2024-08-31-084439_initial_setup/up.sql deleted file mode 100644 index a09bf7b..0000000 --- a/schist_models/migrations/2024-08-31-084439_initial_setup/up.sql +++ /dev/null @@ -1,93 +0,0 @@ -PRAGMA foreign_keys = ON; - -CREATE TABLE accounts( - id INTEGER NOT NULL PRIMARY KEY, - name TEXT NOT NULL, - opening_balance INTEGER NOT NULL, - opening_date TEXT NOT NULL -); - -CREATE TABLE account_transfers( - id INTEGER NOT NULL PRIMARY KEY, - 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) - REFERENCES accounts (id) - ON UPDATE CASCADE - ON DELETE RESTRICT, - FOREIGN KEY (to_account_id) - REFERENCES accounts (id) - ON UPDATE CASCADE - ON DELETE RESTRICT -); - - -CREATE TABLE budget_drips( - 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) -); - -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( - id INTEGER NOT NULL PRIMARY KEY, - 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) - ON UPDATE CASCADE - ON DELETE RESTRICT, - FOREIGN KEY (to_category_id) - REFERENCES categories (id) - ON UPDATE CASCADE - ON DELETE RESTRICT -); - -CREATE TABLE transactions( - id INTEGER NOT NULL PRIMARY KEY, - description TEXT NOT NULL, - payee TEXT NOT NULL, - quantity INTEGER NOT NULL, - date TEXT NOT NULL, - account_id INTEGER NOT NULL, - FOREIGN KEY (account_id) - REFERENCES accounts (id) - ON UPDATE CASCADE - ON DELETE RESTRICT -); - -CREATE TABLE transaction_categorisations( - id INTEGER NOT NULL PRIMARY KEY, - 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) - ON UPDATE CASCADE - ON DELETE RESTRICT -); diff --git a/schist_models/src/account.rs b/schist_models/src/account.rs deleted file mode 100644 index 05dceae..0000000 --- a/schist_models/src/account.rs +++ /dev/null @@ -1,15 +0,0 @@ -use diesel::prelude::*; -use serde::{Deserialize, Serialize}; - -use crate::date_utc::DateUtc; - -#[derive( - Insertable, Queryable, Identifiable, Selectable, Debug, PartialEq, Clone, Serialize, Deserialize, -)] -#[diesel(table_name = crate::schema::accounts)] -pub struct Account { - pub id: i32, - pub name: String, - pub opening_balance: i32, - pub opening_date: DateUtc, -} diff --git a/schist_models/src/account_transfer.rs b/schist_models/src/account_transfer.rs deleted file mode 100644 index 06c51ac..0000000 --- a/schist_models/src/account_transfer.rs +++ /dev/null @@ -1,15 +0,0 @@ -use derive_builder::Builder; -use diesel::prelude::{Identifiable, Insertable, Queryable, Selectable}; - -use crate::date_utc::DateUtc; - -#[derive(Builder, Queryable, Identifiable, Selectable, Debug, PartialEq, Insertable)] -#[diesel(table_name = crate::schema::account_transfers)] -pub struct AccountTransfer { - pub id: i32, - pub date: DateUtc, - pub description: String, - pub quantity: i32, - pub from_account_id: i32, - pub to_account_id: i32, -} diff --git a/schist_models/src/budget_drip.rs b/schist_models/src/budget_drip.rs deleted file mode 100644 index 2cc2c63..0000000 --- a/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 category_id: i32, - pub date: DateUtc, - pub quantity: i32, -} diff --git a/schist_models/src/budget_period_unit.rs b/schist_models/src/budget_period_unit.rs deleted file mode 100644 index 77d8641..0000000 --- a/schist_models/src/budget_period_unit.rs +++ /dev/null @@ -1,112 +0,0 @@ -use core::fmt; -use std::str::FromStr; - -use anyhow::{Result, bail}; -use diesel::{backend::Backend, deserialize::{self, FromSql, FromSqlRow}, expression::AsExpression, serialize::{self, ToSql}, sql_types::Text, sqlite::Sqlite}; -use serde::{Deserialize, Serialize}; - -#[derive( - Eq, - PartialEq, - Serialize, - Deserialize, - Clone, - Debug, - AsExpression, - FromSqlRow, -)] -#[diesel(sql_type=Text)] -pub enum BudgetPeriodUnit { - Day, - Month, - Year, -} - -impl fmt::Display for BudgetPeriodUnit { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - BudgetPeriodUnit::Day => "DAY".fmt(f), - BudgetPeriodUnit::Month => "MONTH".fmt(f), - BudgetPeriodUnit::Year => "YEAR".fmt(f), - } - } -} - -impl FromStr for BudgetPeriodUnit { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result<Self> { - match s { - "DAY" => Ok(BudgetPeriodUnit::Day), - "MONTH" => Ok(BudgetPeriodUnit::Month), - "YEAR" => Ok(BudgetPeriodUnit::Year), - _ => bail!("\"{}\" is not a valid budget period unit. Valid values are: DAY, MONTH, YEAR", s), - } - } -} - -impl ToSql<Text, Sqlite> for BudgetPeriodUnit { - fn to_sql<'b>( - &'b self, - out: &mut diesel::serialize::Output<'b, '_, Sqlite>, - ) -> serialize::Result { - out.set_value(self.to_string()); - Ok(serialize::IsNull::No) - } -} - -impl FromSql<Text, Sqlite> for BudgetPeriodUnit { - fn from_sql(bytes: <Sqlite as Backend>::RawValue<'_>) -> deserialize::Result<BudgetPeriodUnit> { - let str = <String as FromSql<Text, Sqlite>>::from_sql(bytes)?; - Ok(str.parse()?) - } -} - -#[cfg(test)] -mod test { - use anyhow::Result; - - use super::BudgetPeriodUnit; - - #[test] - fn display_when_day_then_day() { - assert_eq!("DAY", format!("{}", BudgetPeriodUnit::Day)); - } - - #[test] - fn display_when_month_then_month() { - assert_eq!("MONTH", format!("{}", BudgetPeriodUnit::Month)); - } - - #[test] - fn display_when_year_then_year() { - assert_eq!("YEAR", format!("{}", BudgetPeriodUnit::Year)); - } - - #[test] - fn from_str_when_day_then_day() { - let result: Result<BudgetPeriodUnit> = "DAY".parse(); - assert!(result.is_ok()); - assert_eq!(BudgetPeriodUnit::Day, result.unwrap()); - } - - #[test] - fn from_str_when_month_then_month() { - let result: Result<BudgetPeriodUnit> = "MONTH".parse(); - assert!(result.is_ok()); - assert_eq!(BudgetPeriodUnit::Month, result.unwrap()); - } - - #[test] - fn from_str_when_year_then_year() { - let result: Result<BudgetPeriodUnit> = "YEAR".parse(); - assert!(result.is_ok()); - assert_eq!(BudgetPeriodUnit::Year, result.unwrap()); - } - - #[test] - fn from_str_when_sentence_case_day_then_err() { - let result: Result<BudgetPeriodUnit> = "Day".parse(); - assert!(result.is_err()); - } -} diff --git a/schist_models/src/category.rs b/schist_models/src/category.rs deleted file mode 100644 index e3c9938..0000000 --- a/schist_models/src/category.rs +++ /dev/null @@ -1,17 +0,0 @@ -use derive_builder::Builder; -use diesel::prelude::*; -use serde::{Deserialize, Serialize}; - -use crate::{budget_period_unit::BudgetPeriodUnit, date_utc::DateUtc}; - -#[derive(Builder, Clone, Queryable, Identifiable, Selectable, Debug, PartialEq, Serialize, Deserialize, Insertable)] -#[diesel(table_name = crate::schema::categories)] -pub struct Category { - 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, -} diff --git a/schist_models/src/category_transfer.rs b/schist_models/src/category_transfer.rs deleted file mode 100644 index 7b36054..0000000 --- a/schist_models/src/category_transfer.rs +++ /dev/null @@ -1,12 +0,0 @@ -use derive_builder::Builder; -use diesel::prelude::*; - -#[derive(Builder, Queryable, Identifiable, Selectable, Debug, PartialEq, Insertable)] -#[diesel(table_name = crate::schema::category_transfers)] -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/schist_models/src/date_utc.rs b/schist_models/src/date_utc.rs deleted file mode 100644 index 2b36ec0..0000000 --- a/schist_models/src/date_utc.rs +++ /dev/null @@ -1,547 +0,0 @@ -use std::{borrow::Borrow, fmt, str::FromStr}; - -use anyhow::{Context, Error, Result}; -use chrono::{DateTime, Datelike, NaiveDate, NaiveTime, Utc}; -use diesel::{ - backend::Backend, - deserialize::{self, FromSql, FromSqlRow}, - expression::AsExpression, - serialize::{self, ToSql}, - sql_types::Text, - sqlite::Sqlite, -}; -use serde::{Deserialize, Serialize}; - -use schist_traits::{dateable::Dateable, nowlike::Nowlike}; - -use crate::datetime_utc::DatetimeUtc; - -#[derive( - Eq, - PartialEq, - Ord, - PartialOrd, - Serialize, - Deserialize, - Clone, - Copy, - Debug, - AsExpression, - FromSqlRow, -)] -#[diesel(sql_type=Text)] -pub struct DateUtc { - chrono_datetime_utc: DateTime<Utc>, -} - -impl DateUtc { - pub fn from_ymd(year: i32, month: u32, day: u32) -> Result<Self> { - Ok(Self { - chrono_datetime_utc: NaiveDate::from_ymd_opt(year, month, day) - .with_context(|| format!("failed to construct date from ymd {:04}-{:02}-{:02}", year, month, day))? - .and_hms_opt(0, 0, 0).unwrap() - .and_utc() - }) - } - - pub fn with_hms(&mut self, hour: u32, min: u32, sec: u32) -> Result<DatetimeUtc> { - DatetimeUtc::from_ymd_and_hms( - self.year(), self.month(), self.day(), hour, min, sec, - ) - } - - pub fn day_diff(&self, other: &DateUtc) -> u32 { - self.chrono_datetime_utc - .num_days_from_ce() - .abs_diff(other.chrono_datetime_utc.num_days_from_ce()) - } - - pub fn days_in_month(&self) -> u32 { - self.first_day_in_next_month().day_diff(&self.first_day_in_month()) - } - - pub fn add_days(&self, days: u64) -> Result<Self> { - let chrono_datetime_utc = self - .chrono_datetime_utc - .checked_add_days(chrono::Days::new(days)) - .with_context(|| format!("failed to add {} days to {}", days, self)) - .unwrap(); - Ok(Self { chrono_datetime_utc }) - } - - pub fn sub_days(&self, days: u64) -> Result<Self> { - let chrono_datetime_utc = self - .chrono_datetime_utc - .checked_sub_days(chrono::Days::new(days)) - .with_context(|| format!("failed to subtract {} days from {}", days, self)) - .unwrap(); - Ok(Self { chrono_datetime_utc }) - } - - fn is_day_str(str: &str) -> bool { - if str.len() != 10 { - return false; - } - for (ix, ch) in str.chars().enumerate() { - if ix == 4 || ix == 7 { - if ch != '-' { - return false; - } - } else { - if ch < '0' || ch > '9' { - return false; - } - } - } - return true; - } - - fn first_day_in_next_month(&self) -> Self { - let month = self.month(); - let mut curr_guess: Option<DateTime<Utc>> = None; - let mut curr_add = 1; - while curr_guess.is_none() || curr_guess.unwrap().month() == month { - curr_guess = self.chrono_datetime_utc.checked_add_days(chrono::Days::new(curr_add)); - curr_add = curr_add + 1; - }; - return Self { chrono_datetime_utc: curr_guess.unwrap() }; - } - - fn first_day_in_month(&self) -> Self { - let month = self.month(); - let mut prev_guess = self.clone(); - let mut curr_guess = self.clone(); - let mut curr_subtractor = 1; - while curr_guess.month() == month { - prev_guess = curr_guess.clone(); - - let mut next: Option<DateTime<Utc>> = None; - while next.is_none() { - if curr_subtractor > 31 { - return prev_guess; - } - next = self.chrono_datetime_utc.checked_sub_days(chrono::Days::new(curr_subtractor)); - curr_subtractor = curr_subtractor + 1; - } - let next = next.unwrap(); - - curr_guess = Self { - chrono_datetime_utc: next, - }; - }; - return prev_guess; - } -} - -impl Nowlike for DateUtc { - fn now() -> Self { - let now = Utc::now(); - Self::from_ymd( - now.year(), - now.month(), - now.day(), - ).unwrap() - } -} - -impl Dateable for DateUtc { - fn year(&self) -> i32 { - self.chrono_datetime_utc.year() - } - - fn month(&self) -> u32 { - self.chrono_datetime_utc.month() - } - - fn day(&self) -> u32 { - self.chrono_datetime_utc.day() - } -} - -impl From<DatetimeUtc> for DateUtc { - fn from(datetime_utc: DatetimeUtc) -> Self { - Self::from(&datetime_utc) - } -} - -impl From<&DatetimeUtc> for DateUtc { - fn from(datetime_utc: &DatetimeUtc) -> Self { - Self { - chrono_datetime_utc: datetime_utc - .to_string() - .parse::<DateTime<Utc>>().unwrap() - .with_time(NaiveTime::from_hms_opt(0, 0, 0).unwrap()).unwrap(), - } - } -} - -impl<T> From<T> for DateUtc where T: Borrow<DateTime<Utc>> { - fn from(chrono_datetime_utc: T) -> Self { - Self { - chrono_datetime_utc: chrono_datetime_utc - .borrow() - .with_time(NaiveTime::from_hms_opt(0, 0, 0).unwrap()).unwrap(), - } - } -} - -impl fmt::Display for DateUtc { - /// Converts to a day string, YYYY-MM-DD, in UTC - /// Example: 10.30am 24 Oct 2024 UTC -> "2024-10-24" - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - let date_str = self.chrono_datetime_utc.to_rfc3339(); - let day_str = date_str - .split_at_checked(10) - .unwrap() - .0; - write!(f, "{}", day_str) - } -} - -impl FromStr for DateUtc { - type Err = anyhow::Error; - - /// Constructs DatetimeUtc from a day string, YYYY-MM-DD, in UTC - /// Example: "2024-10-24" -> Midnight 24 Oct 2024 UTC - fn from_str(date_str: &str) -> Result<Self> { - if !Self::is_day_str(&date_str) { - Err(Error::msg(format!("{} is not a day string in YYYY-MM-DD format", date_str))) - } else { - let mut datetime_str = String::from(date_str); - datetime_str.push_str("T00:00:00.000Z"); - Ok(Self { - chrono_datetime_utc: datetime_str.parse()?, - }) - } - } -} - -impl ToSql<Text, Sqlite> for DateUtc { - fn to_sql<'b>( - &'b self, - out: &mut diesel::serialize::Output<'b, '_, Sqlite>, - ) -> serialize::Result { - out.set_value(self.to_string()); - Ok(serialize::IsNull::No) - } -} - -impl FromSql<Text, Sqlite> for DateUtc { - fn from_sql(bytes: <Sqlite as Backend>::RawValue<'_>) -> deserialize::Result<DateUtc> { - let str = <String as FromSql<Text, Sqlite>>::from_sql(bytes)?; - Ok(str.parse()?) - } -} - -#[cfg(test)] -mod test { - use schist_traits::timeable::Timeable; - - use super::*; - - #[test] - fn when_from_ymd_then_ymd_are_as_expected() { - let date_utc = DateUtc::from_ymd(1970, 11, 23); - - assert!(date_utc.is_ok()); - let date_utc = date_utc.unwrap(); - assert_eq!(date_utc.year(), 1970); - assert_eq!(date_utc.month(), 11); - assert_eq!(date_utc.day(), 23); - } - - #[test] - fn when_from_ymd_then_to_string_as_expected() { - let date_utc = DateUtc::from_ymd(1970, 11, 23); - - assert!(date_utc.is_ok()); - assert_eq!(date_utc.unwrap().to_string(), "1970-11-23"); - } - - #[test] - fn when_from_invalid_ymd_then_err() { - let date_utc_1 = DateUtc::from_ymd(1970, 0, 23); - let date_utc_2 = DateUtc::from_ymd(1970, 13, 23); - let date_utc_3 = DateUtc::from_ymd(1970, 11, 0); - let date_utc_4 = DateUtc::from_ymd(1970, 11, 31); - let date_utc_5 = DateUtc::from_ymd(1971, 2, 29); - - assert!(date_utc_1.is_err()); - assert_eq!(date_utc_1.unwrap_err().to_string(), "failed to construct date from ymd 1970-00-23"); - assert!(date_utc_2.is_err()); - assert_eq!(date_utc_2.unwrap_err().to_string(), "failed to construct date from ymd 1970-13-23"); - assert!(date_utc_3.is_err()); - assert_eq!(date_utc_3.unwrap_err().to_string(), "failed to construct date from ymd 1970-11-00"); - assert!(date_utc_4.is_err()); - assert_eq!(date_utc_4.unwrap_err().to_string(), "failed to construct date from ymd 1970-11-31"); - assert!(date_utc_5.is_err()); - assert_eq!(date_utc_5.unwrap_err().to_string(), "failed to construct date from ymd 1971-02-29"); - } - - #[test] - fn when_from_string_then_ymd_are_as_expected() { - let date_utc: Result<DateUtc> = "1970-11-23".parse(); - - assert!(date_utc.is_ok()); - let date_utc = date_utc.unwrap(); - assert_eq!(date_utc.year(), 1970); - assert_eq!(date_utc.month(), 11); - assert_eq!(date_utc.day(), 23); - } - - #[test] - fn when_from_string_then_to_string_as_expected() { - let date_utc: Result<DateUtc> = "1970-11-23".parse(); - - assert!(date_utc.is_ok()); - assert_eq!(date_utc.unwrap().to_string(), "1970-11-23"); - } - - #[test] - fn when_from_invalid_string_then_err() { - let date_utc_1: Result<DateUtc> = "1970-00-23".parse(); - let date_utc_2: Result<DateUtc> = "1970-13-23".parse(); - let date_utc_3: Result<DateUtc> = "1970-11-0".parse(); - let date_utc_4: Result<DateUtc> = "1970-11-31".parse(); - let date_utc_5: Result<DateUtc> = "1971-02-29".parse(); - - assert!(date_utc_1.is_err()); - assert!(date_utc_2.is_err()); - assert!(date_utc_3.is_err()); - assert!(date_utc_4.is_err()); - assert!(date_utc_5.is_err()); - } - - #[test] - fn with_with_hms_then_ymd_hms_are_as_expected() { - let datetime_utc = DateUtc::from_ymd(1970, 11, 23).unwrap().with_hms(12, 55, 16); - - assert!(datetime_utc.is_ok()); - let datetime_utc = datetime_utc.unwrap(); - assert_eq!(datetime_utc.year(), 1970); - assert_eq!(datetime_utc.month(), 11); - assert_eq!(datetime_utc.day(), 23); - assert_eq!(datetime_utc.hour(), 12); - assert_eq!(datetime_utc.minute(), 55); - assert_eq!(datetime_utc.second(), 16); - } - - #[test] - fn when_with_invalid_hms_then_err() { - let datetime_utc_1 = DateUtc::from_ymd(1970, 11, 23).unwrap().with_hms(25, 0, 0); - let datetime_utc_2 = DateUtc::from_ymd(1970, 11, 23).unwrap().with_hms(0, 61, 0); - let datetime_utc_3 = DateUtc::from_ymd(1970, 11, 23).unwrap().with_hms(0, 0, 61); - - assert!(datetime_utc_1.is_err()); - assert!(datetime_utc_2.is_err()); - assert!(datetime_utc_3.is_err()); - } - - #[test] - fn when_from_datetime_utc_at_different_times_on_same_day_then_eq() { - let datetime_utc1 = DateUtc::from_ymd(1970, 11, 23).unwrap().with_hms(0, 0, 0).unwrap(); - let datetime_utc2 = DateUtc::from_ymd(1970, 11, 23).unwrap().with_hms(23, 59, 59).unwrap(); - let date_utc1 = DateUtc::from(datetime_utc1); - let date_utc2 = DateUtc::from(datetime_utc2); - - assert_eq!(date_utc1, date_utc2); - } - - #[test] - fn given_today_when_day_diff_today_then_return_0() { - let start = DateUtc::from_ymd(2000, 1, 1).unwrap(); - let end = DateUtc::from_ymd(2000, 1, 1).unwrap(); - - let day_diff = start.day_diff(&end); - let neg_day_diff = end.day_diff(&start); - - assert_eq!(day_diff, 0); - assert_eq!(day_diff, neg_day_diff); - } - - #[test] - fn given_today_when_day_diff_tomorrow_then_return_1() { - let start = DateUtc::from_ymd(2000, 1, 1).unwrap(); - let end = DateUtc::from_ymd(2000, 1, 2).unwrap(); - - let day_diff = start.day_diff(&end); - let neg_day_diff = end.day_diff(&start); - - assert_eq!(day_diff, 1); - assert_eq!(day_diff, neg_day_diff); - } - - #[test] - fn when_any_date_in_2024_then_first_day_in_month_is_correct() { - let jan_1_2024: DateUtc = "2024-01-01".parse().unwrap(); - for date in get_dates_in_jan_2024() { - assert_eq!(jan_1_2024, date.first_day_in_month()); - } - - let feb_1_2024: DateUtc = "2024-02-01".parse().unwrap(); - for date in get_dates_in_feb_2024() { - assert_eq!(feb_1_2024, date.first_day_in_month()); - } - - let mar_1_2024: DateUtc = "2024-03-01".parse().unwrap(); - for date in get_dates_in_mar_2024() { - assert_eq!(mar_1_2024, date.first_day_in_month()); - } - - let apr_1_2024: DateUtc = "2024-04-01".parse().unwrap(); - for date in get_dates_in_apr_2024() { - assert_eq!(apr_1_2024, date.first_day_in_month()); - } - - let may_1_2024: DateUtc = "2024-05-01".parse().unwrap(); - for date in get_dates_in_may_2024() { - assert_eq!(may_1_2024, date.first_day_in_month()); - } - - let jun_1_2024: DateUtc = "2024-06-01".parse().unwrap(); - for date in get_dates_in_jun_2024() { - assert_eq!(jun_1_2024, date.first_day_in_month()); - } - - let jul_1_2024: DateUtc = "2024-07-01".parse().unwrap(); - for date in get_dates_in_jul_2024() { - assert_eq!(jul_1_2024, date.first_day_in_month()); - } - - let aug_1_2024: DateUtc = "2024-08-01".parse().unwrap(); - for date in get_dates_in_aug_2024() { - assert_eq!(aug_1_2024, date.first_day_in_month()); - } - - let sep_1_2024: DateUtc = "2024-09-01".parse().unwrap(); - for date in get_dates_in_sep_2024() { - assert_eq!(sep_1_2024, date.first_day_in_month()); - } - - let oct_1_2024: DateUtc = "2024-10-01".parse().unwrap(); - for date in get_dates_in_oct_2024() { - assert_eq!(oct_1_2024, date.first_day_in_month()); - } - - let nov_1_2024: DateUtc = "2024-11-01".parse().unwrap(); - for date in get_dates_in_nov_2024() { - assert_eq!(nov_1_2024, date.first_day_in_month()); - } - - let dec_1_2024: DateUtc = "2024-12-01".parse().unwrap(); - for date in get_dates_in_dec_2024() { - assert_eq!(dec_1_2024, date.first_day_in_month()); - } - } - - #[test] - fn when_any_date_in_2024_then_first_day_in_next_month_is_correct() { - let feb_1_2024: DateUtc = "2024-02-01".parse().unwrap(); - for date in get_dates_in_jan_2024() { - assert_eq!(feb_1_2024, date.first_day_in_next_month()); - } - - let mar_1_2024: DateUtc = "2024-03-01".parse().unwrap(); - for date in get_dates_in_feb_2024() { - assert_eq!(mar_1_2024, date.first_day_in_next_month()); - } - - let apr_1_2024: DateUtc = "2024-04-01".parse().unwrap(); - for date in get_dates_in_mar_2024() { - assert_eq!(apr_1_2024, date.first_day_in_next_month()); - } - - let may_1_2024: DateUtc = "2024-05-01".parse().unwrap(); - for date in get_dates_in_apr_2024() { - assert_eq!(may_1_2024, date.first_day_in_next_month()); - } - - let jun_1_2024: DateUtc = "2024-06-01".parse().unwrap(); - for date in get_dates_in_may_2024() { - assert_eq!(jun_1_2024, date.first_day_in_next_month()); - } - - let jul_1_2024: DateUtc = "2024-07-01".parse().unwrap(); - for date in get_dates_in_jun_2024() { - assert_eq!(jul_1_2024, date.first_day_in_next_month()); - } - - let aug_1_2024: DateUtc = "2024-08-01".parse().unwrap(); - for date in get_dates_in_jul_2024() { - assert_eq!(aug_1_2024, date.first_day_in_next_month()); - } - - let sep_1_2024: DateUtc = "2024-09-01".parse().unwrap(); - for date in get_dates_in_aug_2024() { - assert_eq!(sep_1_2024, date.first_day_in_next_month()); - } - - let oct_1_2024: DateUtc = "2024-10-01".parse().unwrap(); - for date in get_dates_in_sep_2024() { - assert_eq!(oct_1_2024, date.first_day_in_next_month()); - } - - let nov_1_2024: DateUtc = "2024-11-01".parse().unwrap(); - for date in get_dates_in_oct_2024() { - assert_eq!(nov_1_2024, date.first_day_in_next_month()); - } - - let dec_1_2024: DateUtc = "2024-12-01".parse().unwrap(); - for date in get_dates_in_nov_2024() { - assert_eq!(dec_1_2024, date.first_day_in_next_month()); - } - - let jan_1_2025: DateUtc = "2025-01-01".parse().unwrap(); - for date in get_dates_in_dec_2024() { - assert_eq!(jan_1_2025, date.first_day_in_next_month()); - } - } - - fn get_dates_in_jan_2024() -> Vec<DateUtc> { - (1..31).map(|day| format!("2024-01-{:02}", day).parse::<DateUtc>().unwrap()).collect::<Vec<DateUtc>>() - } - - fn get_dates_in_feb_2024() -> Vec<DateUtc> { - (1..29).map(|day| format!("2024-02-{:02}", day).parse::<DateUtc>().unwrap()).collect::<Vec<DateUtc>>() - } - - fn get_dates_in_mar_2024() -> Vec<DateUtc> { - (1..31).map(|day| format!("2024-03-{:02}", day).parse::<DateUtc>().unwrap()).collect::<Vec<DateUtc>>() - } - - fn get_dates_in_apr_2024() -> Vec<DateUtc> { - (1..30).map(|day| format!("2024-04-{:02}", day).parse::<DateUtc>().unwrap()).collect::<Vec<DateUtc>>() - } - - fn get_dates_in_may_2024() -> Vec<DateUtc> { - (1..31).map(|day| format!("2024-05-{:02}", day).parse::<DateUtc>().unwrap()).collect::<Vec<DateUtc>>() - } - - fn get_dates_in_jun_2024() -> Vec<DateUtc> { - (1..30).map(|day| format!("2024-06-{:02}", day).parse::<DateUtc>().unwrap()).collect::<Vec<DateUtc>>() - } - - fn get_dates_in_jul_2024() -> Vec<DateUtc> { - (1..31).map(|day| format!("2024-07-{:02}", day).parse::<DateUtc>().unwrap()).collect::<Vec<DateUtc>>() - } - - fn get_dates_in_aug_2024() -> Vec<DateUtc> { - (1..31).map(|day| format!("2024-08-{:02}", day).parse::<DateUtc>().unwrap()).collect::<Vec<DateUtc>>() - } - - fn get_dates_in_sep_2024() -> Vec<DateUtc> { - (1..30).map(|day| format!("2024-09-{:02}", day).parse::<DateUtc>().unwrap()).collect::<Vec<DateUtc>>() - } - - fn get_dates_in_oct_2024() -> Vec<DateUtc> { - (1..31).map(|day| format!("2024-10-{:02}", day).parse::<DateUtc>().unwrap()).collect::<Vec<DateUtc>>() - } - - fn get_dates_in_nov_2024() -> Vec<DateUtc> { - (1..30).map(|day| format!("2024-11-{:02}", day).parse::<DateUtc>().unwrap()).collect::<Vec<DateUtc>>() - } - - fn get_dates_in_dec_2024() -> Vec<DateUtc> { - (1..31).map(|day| format!("2024-12-{:02}", day).parse::<DateUtc>().unwrap()).collect::<Vec<DateUtc>>() - } -} diff --git a/schist_models/src/datetime_utc.rs b/schist_models/src/datetime_utc.rs deleted file mode 100644 index 9b63145..0000000 --- a/schist_models/src/datetime_utc.rs +++ /dev/null @@ -1,223 +0,0 @@ -use std::{fmt::Display, str::FromStr}; - -use anyhow::{Context, Result}; -use chrono::{DateTime, Datelike as ChronoDatelike, NaiveDate, Timelike as ChronoTimelike, Utc}; -use diesel::{ - backend::Backend, - deserialize::{self, FromSql, FromSqlRow}, - expression::AsExpression, - serialize::{self, ToSql}, - sql_types::Text, - sqlite::Sqlite, -}; -use serde::{Deserialize, Serialize}; - -use schist_traits::{dateable::Dateable, nowlike::Nowlike, timeable::Timeable}; - -#[derive( - PartialEq, - Eq, - PartialOrd, - Ord, - Serialize, - Deserialize, - Clone, - Debug, - AsExpression, - FromSqlRow, -)] -#[diesel(sql_type=Text)] -pub struct DatetimeUtc { - chrono_datetime_utc: DateTime<Utc>, -} - -impl DatetimeUtc { - pub fn from_ymd_and_hms(year: i32, month: u32, day: u32, hour: u32, min: u32, sec: u32) -> Result<Self> { - Ok(Self { chrono_datetime_utc: NaiveDate - ::from_ymd_opt(year, month, day) - .with_context(|| format!("failed to construct datetime from ymd {:04}-{:02}-{:02}", year, month, day))? - .and_hms_opt(hour, min, sec) - .with_context(|| format!("failed to construct datetime from hms {:02}:{:02}:{:02}", hour, min, sec))? - .and_utc() - }) - } -} - -impl FromStr for DatetimeUtc { - type Err = anyhow::Error; - - /// Constructs DatetimeUtc from a date string in ISO format, in UTC - /// Example: "2024-10-24T10:30:00.000" -> 10.30am 24 Oct 2024 UTC - fn from_str(datetime_str: &str) -> Result<Self> { - let chrono_datetime_utc = datetime_str.parse::<DateTime<Utc>>()?; - Ok(Self { - chrono_datetime_utc, - }) - } -} - -impl Display for DatetimeUtc { - /// Converts to a date string in ISO format, in UTC - /// Example: 10.30am 24 Oct 2024 UTC -> "2024-10-24T10:30:00.000Z" - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}", self.chrono_datetime_utc.to_rfc3339_opts(chrono::SecondsFormat::Millis, true)) - } -} - -impl Nowlike for DatetimeUtc { - fn now() -> Self { - let now = Utc::now(); - Self::from_ymd_and_hms( - now.year(), - now.month(), - now.day(), - now.hour(), - now.minute(), - now.second(), - ).unwrap() - } -} - -impl Dateable for DatetimeUtc { - fn year(&self) -> i32 { - self.chrono_datetime_utc.year() - } - - fn month(&self) -> u32 { - self.chrono_datetime_utc.month() - } - - fn day(&self) -> u32 { - self.chrono_datetime_utc.day() - } -} - -impl Timeable for DatetimeUtc { - fn hour(&self) -> u32 { - self.chrono_datetime_utc.hour() - } - - fn minute(&self) -> u32 { - self.chrono_datetime_utc.minute() - } - - fn second(&self) -> u32 { - self.chrono_datetime_utc.second() - } -} - -impl ToSql<Text, Sqlite> for DatetimeUtc { - fn to_sql<'b>( - &'b self, - out: &mut diesel::serialize::Output<'b, '_, Sqlite>, - ) -> serialize::Result { - out.set_value::<String>(self.to_string()); - Ok(serialize::IsNull::No) - } -} - -impl FromSql<Text, Sqlite> for DatetimeUtc { - fn from_sql(bytes: <Sqlite as Backend>::RawValue<'_>) -> deserialize::Result<DatetimeUtc> { - let str = <String as FromSql<Text, Sqlite>>::from_sql(bytes)?; - Ok(str.parse()?) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn when_from_ymd_and_hms_then_ymd_and_hms_are_as_expected() { - let datetime_utc = DatetimeUtc::from_ymd_and_hms(1970, 11, 23, 12, 55, 16); - - assert!(datetime_utc.is_ok()); - let date_utc = datetime_utc.unwrap(); - assert_eq!(date_utc.year(), 1970); - assert_eq!(date_utc.month(), 11); - assert_eq!(date_utc.day(), 23); - assert_eq!(date_utc.hour(), 12); - assert_eq!(date_utc.minute(), 55); - assert_eq!(date_utc.second(), 16); - } - - #[test] - fn when_from_ymd_and_hms_then_to_string_as_expected() { - let date_utc = DatetimeUtc::from_ymd_and_hms(1970, 11, 23, 12, 55, 16); - - assert!(date_utc.is_ok()); - assert_eq!(date_utc.unwrap().to_string(), "1970-11-23T12:55:16.000Z") - } - - #[test] - fn when_with_invalid_ymd_and_hms_then_err() { - let datetime_utc_1 = DatetimeUtc::from_ymd_and_hms(1970, 0, 23, 12, 55, 16); - let datetime_utc_2 = DatetimeUtc::from_ymd_and_hms(1970, 13, 23, 12, 55, 16); - let datetime_utc_3 = DatetimeUtc::from_ymd_and_hms(1970, 11, 0, 12, 55, 16); - let datetime_utc_4 = DatetimeUtc::from_ymd_and_hms(1970, 11, 31, 12, 55, 16); - let datetime_utc_5 = DatetimeUtc::from_ymd_and_hms(1971, 2, 29, 12, 55, 16); - let datetime_utc_6 = DatetimeUtc::from_ymd_and_hms(1970, 11, 23, 25, 0, 0); - let datetime_utc_7 = DatetimeUtc::from_ymd_and_hms(1970, 11, 23, 0, 61, 0); - let datetime_utc_8 = DatetimeUtc::from_ymd_and_hms(1970, 11, 23, 0, 0, 61); - - assert!(datetime_utc_1.is_err()); - assert_eq!(datetime_utc_1.unwrap_err().to_string(), "failed to construct datetime from ymd 1970-00-23"); - assert!(datetime_utc_2.is_err()); - assert_eq!(datetime_utc_2.unwrap_err().to_string(), "failed to construct datetime from ymd 1970-13-23"); - assert!(datetime_utc_3.is_err()); - assert_eq!(datetime_utc_3.unwrap_err().to_string(), "failed to construct datetime from ymd 1970-11-00"); - assert!(datetime_utc_4.is_err()); - assert_eq!(datetime_utc_4.unwrap_err().to_string(), "failed to construct datetime from ymd 1970-11-31"); - assert!(datetime_utc_5.is_err()); - assert_eq!(datetime_utc_5.unwrap_err().to_string(), "failed to construct datetime from ymd 1971-02-29"); - assert!(datetime_utc_6.is_err()); - assert_eq!(datetime_utc_6.unwrap_err().to_string(), "failed to construct datetime from hms 25:00:00"); - assert!(datetime_utc_7.is_err()); - assert_eq!(datetime_utc_7.unwrap_err().to_string(), "failed to construct datetime from hms 00:61:00"); - assert!(datetime_utc_8.is_err()); - assert_eq!(datetime_utc_8.unwrap_err().to_string(), "failed to construct datetime from hms 00:00:61"); - } - - #[test] - fn when_from_string_then_ymd_and_hms_are_as_expected() { - let date_utc: Result<DatetimeUtc> = "1970-11-23T12:55:16.000Z".parse(); - - assert!(date_utc.is_ok()); - let datetime_utc = date_utc.unwrap(); - assert_eq!(datetime_utc.year(), 1970); - assert_eq!(datetime_utc.month(), 11); - assert_eq!(datetime_utc.day(), 23); - assert_eq!(datetime_utc.hour(), 12); - assert_eq!(datetime_utc.minute(), 55); - assert_eq!(datetime_utc.second(), 16); - } - - #[test] - fn when_from_string_then_to_string_as_expected() { - let datetime_utc: Result<DatetimeUtc> = "1970-11-23T12:55:16.000Z".parse(); - - assert!(datetime_utc.is_ok()); - assert_eq!(datetime_utc.unwrap().to_string(), "1970-11-23T12:55:16.000Z") - } - - #[test] - fn when_from_invalid_string_then_err() { - let datetime_utc_1: Result<DatetimeUtc> = "1970-00-23T00:00:00.000Z".parse(); - let datetime_utc_2: Result<DatetimeUtc> = "1970-13-23T00:00:00.000Z".parse(); - let datetime_utc_3: Result<DatetimeUtc> = "1970-11-0T00:00:00.000Z".parse(); - let datetime_utc_4: Result<DatetimeUtc> = "1970-11-31T00:00:00.000Z".parse(); - let datetime_utc_5: Result<DatetimeUtc> = "1971-02-29T00:00:00.000Z".parse(); - let datetime_utc_6: Result<DatetimeUtc> = "1970-11-23T25:00:00.000Z".parse(); - let datetime_utc_7: Result<DatetimeUtc> = "1970-11-23T00:61:00.000Z".parse(); - let datetime_utc_8: Result<DatetimeUtc> = "1970-11-23T00:00:61.000Z".parse(); - - assert!(datetime_utc_1.is_err()); - assert!(datetime_utc_2.is_err()); - assert!(datetime_utc_3.is_err()); - assert!(datetime_utc_4.is_err()); - assert!(datetime_utc_5.is_err()); - assert!(datetime_utc_6.is_err()); - assert!(datetime_utc_7.is_err()); - assert!(datetime_utc_8.is_err()); - } -} diff --git a/schist_models/src/lib.rs b/schist_models/src/lib.rs deleted file mode 100644 index d9e93c4..0000000 --- a/schist_models/src/lib.rs +++ /dev/null @@ -1,12 +0,0 @@ -pub mod account; -pub mod account_transfer; -pub mod budget_drip; -pub mod budget_period_unit; -pub mod category; -pub mod category_transfer; -pub mod date_utc; -pub mod datetime_utc; -pub mod migrations; -pub mod transaction; -pub mod transaction_categorisation; -pub mod schema; diff --git a/schist_models/src/migrations.rs b/schist_models/src/migrations.rs deleted file mode 100644 index d10cb83..0000000 --- a/schist_models/src/migrations.rs +++ /dev/null @@ -1,3 +0,0 @@ -use diesel_migrations::{embed_migrations, EmbeddedMigrations}; - -pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations"); diff --git a/schist_models/src/schema.rs b/schist_models/src/schema.rs deleted file mode 100644 index 1dd1391..0000000 --- a/schist_models/src/schema.rs +++ /dev/null @@ -1,88 +0,0 @@ -// @generated automatically by Diesel CLI. - -diesel::table! { - account_transfers (id) { - id -> Integer, - date -> Text, - description -> Text, - quantity -> Integer, - from_account_id -> Integer, - to_account_id -> Integer, - } -} - -diesel::table! { - accounts (id) { - id -> Integer, - name -> Text, - opening_balance -> Integer, - opening_date -> Text, - } -} - -diesel::table! { - budget_drips (id) { - id -> Integer, - category_id -> Integer, - date -> Text, - quantity -> Integer, - } -} - -diesel::table! { - categories (id) { - id -> Integer, - name -> Text, - balance -> Integer, - balance_date -> Text, - budget_period -> Integer, - budget_period_unit -> Text, - budget_quantity -> Integer, - } -} - -diesel::table! { - category_transfers (id) { - id -> Integer, - description -> Text, - quantity -> Integer, - from_category_id -> Integer, - to_category_id -> Integer, - } -} - -diesel::table! { - transaction_categorisations (id) { - id -> Integer, - description -> Text, - quantity -> Integer, - transaction_id -> Integer, - category_id -> Integer, - } -} - -diesel::table! { - transactions (id) { - id -> Integer, - description -> Text, - payee -> Text, - quantity -> Integer, - date -> Text, - account_id -> Integer, - } -} - -diesel::joinable!(budget_drips -> categories (category_id)); -diesel::joinable!(transaction_categorisations -> categories (category_id)); -diesel::joinable!(transaction_categorisations -> transactions (transaction_id)); -diesel::joinable!(transactions -> accounts (account_id)); - -diesel::allow_tables_to_appear_in_same_query!( - account_transfers, - accounts, - budget_drips, - categories, - category_transfers, - transaction_categorisations, - transactions, -); diff --git a/schist_models/src/transaction.rs b/schist_models/src/transaction.rs deleted file mode 100644 index 9e983f5..0000000 --- a/schist_models/src/transaction.rs +++ /dev/null @@ -1,16 +0,0 @@ -use derive_builder::Builder; -use diesel::prelude::{Associations, Identifiable, Insertable, Queryable, Selectable}; - -use crate::{account::Account, date_utc::DateUtc}; - -#[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, -} diff --git a/schist_models/src/transaction_categorisation.rs b/schist_models/src/transaction_categorisation.rs deleted file mode 100644 index c6ac6ea..0000000 --- a/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 category_id: i32, -} diff --git a/schist_models/tests/budget_period_unit.rs b/schist_models/tests/budget_period_unit.rs deleted file mode 100644 index 6e8928a..0000000 --- a/schist_models/tests/budget_period_unit.rs +++ /dev/null @@ -1,86 +0,0 @@ -mod common; - -use anyhow::Result; -use common::test_context::TestContext; -use diesel::{sql_query, Connection, ExpressionMethods, QueryDsl, RunQueryDsl, Selectable, SelectableHelper, SqliteConnection}; -use diesel::prelude::{Insertable, Queryable}; -use schist_models::budget_period_unit::BudgetPeriodUnit; - -diesel::table! { - budget_period_unit_test (id) { - id -> Integer, - budget_period_unit -> Text, - } -} - -#[derive(Insertable, Queryable, Selectable, Clone)] -#[diesel(table_name = budget_period_unit_test)] -pub struct BudgetPeriodUnitTest { - pub id: i32, - pub budget_period_unit: BudgetPeriodUnit, -} - -fn new_test_context() -> Result<TestContext> { - let test_context = TestContext::new(); - let connection = &mut SqliteConnection::establish(&test_context.db_url)?; - let query = "CREATE TABLE budget_period_unit_test(id INTEGER PRIMARY KEY, budget_period_unit TEXT);"; - sql_query(query).execute(connection)?; - Ok(test_context) -} - -fn insert_budget_period_unit(id: i32, budget_period_unit: &BudgetPeriodUnit, connection: &mut SqliteConnection) -> Result<usize> { - let model = BudgetPeriodUnitTest { - id, - budget_period_unit: budget_period_unit.clone(), - }; - let num_rows_inserted = diesel::insert_into(budget_period_unit_test::dsl::budget_period_unit_test) - .values(&[model]) - .execute(connection)?; - Ok(num_rows_inserted) -} - -fn get_budget_period_unit(id: i32, connection: &mut SqliteConnection) -> Result<BudgetPeriodUnitTest> { - let budget_period_unit: Vec<BudgetPeriodUnitTest> = budget_period_unit_test::dsl::budget_period_unit_test - .select(BudgetPeriodUnitTest::as_select()) - .filter(budget_period_unit_test::id.eq(id)) - .load(connection)?; - Ok(budget_period_unit[0].clone()) -} - -#[test] -fn when_insert_day_and_select_then_returns_day() { - let test_context = new_test_context().unwrap(); - let connection = &mut SqliteConnection::establish(&test_context.db_url).unwrap(); - - let budget_period_unit = BudgetPeriodUnit::Day; - let num_rows_inserted = insert_budget_period_unit(0, &budget_period_unit, connection); - - assert!(num_rows_inserted.is_ok()); - let num_rows_inserted = num_rows_inserted.unwrap(); - assert_eq!(num_rows_inserted, 1); - - let budget_period_unit_returned = get_budget_period_unit(0, connection); - - assert!(budget_period_unit_returned.is_ok()); - let budget_period_unit_returned = budget_period_unit_returned.unwrap(); - assert_eq!(BudgetPeriodUnit::Day, budget_period_unit_returned.budget_period_unit); -} - -#[test] -fn when_insert_month_and_select_then_returns_month() { - let test_context = new_test_context().unwrap(); - let connection = &mut SqliteConnection::establish(&test_context.db_url).unwrap(); - - let budget_period_unit = BudgetPeriodUnit::Month; - let num_rows_inserted = insert_budget_period_unit(0, &budget_period_unit, connection); - - assert!(num_rows_inserted.is_ok()); - let num_rows_inserted = num_rows_inserted.unwrap(); - assert_eq!(num_rows_inserted, 1); - - let budget_period_unit_returned = get_budget_period_unit(0, connection); - - assert!(budget_period_unit_returned.is_ok()); - let budget_period_unit_returned = budget_period_unit_returned.unwrap(); - assert_eq!(BudgetPeriodUnit::Month, budget_period_unit_returned.budget_period_unit); -} diff --git a/schist_models/tests/common/mod.rs b/schist_models/tests/common/mod.rs deleted file mode 100644 index 5ff67da..0000000 --- a/schist_models/tests/common/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod test_context; diff --git a/schist_models/tests/common/test_context.rs b/schist_models/tests/common/test_context.rs deleted file mode 100644 index fb4112d..0000000 --- a/schist_models/tests/common/test_context.rs +++ /dev/null @@ -1,44 +0,0 @@ -use std::sync::atomic::{AtomicU64, Ordering}; - -use diesel::{Connection, SqliteConnection}; -use diesel_migrations::MigrationHarness; -use schist_queries::clear::clear; -use schist_models::migrations::MIGRATIONS; - -pub struct TestContext { - pub db_url: String, -} - -static ID_COUNTER: AtomicU64 = AtomicU64::new(0); - -impl TestContext { - pub fn new() -> Self { - let db_url = Self::next_id() + ".sqlite"; - - let connection = &mut SqliteConnection - ::establish(&db_url) - .expect("failed to connect to database"); - - connection - .run_pending_migrations(MIGRATIONS) - .expect("failed to run migrations"); - - clear(connection) - .expect("failed to clear database"); - - Self { - db_url, - } - } - - fn next_id() -> String { - ID_COUNTER.fetch_add(1, Ordering::Relaxed).to_string() - } -} - -impl Drop for TestContext { - fn drop(&mut self) { - std::fs::remove_file(&self.db_url) - .expect(format!("failed to delete database {}", self.db_url).as_str()); - } -} diff --git a/schist_models/tests/date_utc.rs b/schist_models/tests/date_utc.rs deleted file mode 100644 index c5ad82e..0000000 --- a/schist_models/tests/date_utc.rs +++ /dev/null @@ -1,61 +0,0 @@ -mod common; - -use anyhow::Result; -use common::test_context::TestContext; -use diesel::{sql_query, Connection, ExpressionMethods, QueryDsl, RunQueryDsl, Selectable, SelectableHelper, SqliteConnection}; -use diesel::prelude::{Insertable, Queryable}; -use schist_models::date_utc::DateUtc; -use schist_traits::nowlike::Nowlike; - -diesel::table! { - date_utc_test (id) { - id -> Integer, - date_utc -> Text, - } -} - -#[derive(Insertable, Queryable, Selectable, Clone)] -#[diesel(table_name = date_utc_test)] -pub struct DateUtcTest { - pub id: i32, - pub date_utc: DateUtc, -} - -fn new_test_context() -> Result<TestContext> { - let test_context = TestContext::new(); - let connection = &mut SqliteConnection::establish(&test_context.db_url)?; - let query = "CREATE TABLE date_utc_test(id INTEGER PRIMARY KEY, date_utc TEXT);"; - sql_query(query).execute(connection)?; - Ok(test_context) -} - -fn insert_date_utc(id: i32, date_utc: &DateUtc, connection: &mut SqliteConnection) -> Result<usize> { - let model = DateUtcTest { - id, - date_utc: date_utc.clone(), - }; - let num_rows_inserted = diesel::insert_into(date_utc_test::dsl::date_utc_test) - .values(&[model]) - .execute(connection)?; - Ok(num_rows_inserted) -} - -fn get_date_utc(id: i32, connection: &mut SqliteConnection) -> Result<DateUtcTest> { - let date_utc: Vec<DateUtcTest> = date_utc_test::dsl::date_utc_test - .select(DateUtcTest::as_select()) - .filter(date_utc_test::id.eq(id)) - .load(connection)?; - Ok(date_utc[0].clone()) -} - -#[test] -fn when_insert_date_utc_and_select_then_returns_original_value() -> Result<()> { - let date_utc = DateUtc::now(); - let test_context = new_test_context()?; - let connection = &mut SqliteConnection::establish(&test_context.db_url)?; - let num_rows_inserted = insert_date_utc(0, &date_utc, connection)?; - assert_eq!(num_rows_inserted, 1); - let date_utc_returned = get_date_utc(0, connection)?; - assert_eq!(date_utc_returned.date_utc, date_utc); - Ok(()) -} diff --git a/schist_models/tests/datetime_utc.rs b/schist_models/tests/datetime_utc.rs deleted file mode 100644 index 27182ff..0000000 --- a/schist_models/tests/datetime_utc.rs +++ /dev/null @@ -1,62 +0,0 @@ -mod common; - -use anyhow::Result; -use common::test_context::TestContext; -use diesel::{sql_query, Connection, ExpressionMethods, QueryDsl, RunQueryDsl, Selectable, SelectableHelper, SqliteConnection}; -use diesel::prelude::{Insertable, Queryable}; -use schist_models::datetime_utc::DatetimeUtc; -use schist_traits::nowlike::Nowlike; - - -diesel::table! { - datetime_utc_test (id) { - id -> Integer, - datetime_utc -> Text, - } -} - -#[derive(Insertable, Queryable, Selectable, Clone)] -#[diesel(table_name = datetime_utc_test)] -pub struct DatetimeUtcTest { - pub id: i32, - pub datetime_utc: DatetimeUtc, -} - -fn new_test_context() -> Result<TestContext> { - let test_context = TestContext::new(); - let connection = &mut SqliteConnection::establish(&test_context.db_url)?; - let query = "CREATE TABLE datetime_utc_test(id INTEGER PRIMARY KEY, datetime_utc TEXT);"; - sql_query(query).execute(connection)?; - Ok(test_context) -} - -fn insert_datetime_utc(id: i32, datetime_utc: &DatetimeUtc, connection: &mut SqliteConnection) -> Result<usize> { - let model = DatetimeUtcTest { - id, - datetime_utc: datetime_utc.clone(), - }; - let num_rows_inserted = diesel::insert_into(datetime_utc_test::dsl::datetime_utc_test) - .values(&[model]) - .execute(connection)?; - Ok(num_rows_inserted) -} - -fn get_datetime_utc(id: i32, connection: &mut SqliteConnection) -> Result<DatetimeUtcTest> { - let datetime_utc: Vec<DatetimeUtcTest> = datetime_utc_test::dsl::datetime_utc_test - .select(DatetimeUtcTest::as_select()) - .filter(datetime_utc_test::id.eq(id)) - .load(connection)?; - Ok(datetime_utc[0].clone()) -} - -#[test] -fn when_insert_datetime_utc_and_select_then_returns_original_value() -> Result<()> { - let datetime_utc = DatetimeUtc::now(); - let test_context = new_test_context()?; - let connection = &mut SqliteConnection::establish(&test_context.db_url)?; - let num_rows_inserted = insert_datetime_utc(0, &datetime_utc, connection)?; - assert_eq!(num_rows_inserted, 1); - let datetime_utc_returned = get_datetime_utc(0, connection)?; - assert_eq!(datetime_utc_returned.datetime_utc, datetime_utc); - Ok(()) -} diff --git a/schist_models/user_data.sqlite b/schist_models/user_data.sqlite Binary files differdeleted file mode 100644 index a428ff0..0000000 --- a/schist_models/user_data.sqlite +++ /dev/null |
