summaryrefslogtreecommitdiff
path: root/backend/src/models
diff options
context:
space:
mode:
Diffstat (limited to 'backend/src/models')
-rw-r--r--backend/src/models/account.rs4
-rw-r--r--backend/src/models/budget.rs44
-rw-r--r--backend/src/models/budget_update.rs6
-rw-r--r--backend/src/models/category.rs5
-rw-r--r--backend/src/models/category_balance.rs7
-rw-r--r--backend/src/models/category_budget.rs9
-rw-r--r--backend/src/models/date_time_utc.rs111
-rw-r--r--backend/src/models/mod.rs4
-rw-r--r--backend/src/models/transaction.rs3
9 files changed, 187 insertions, 6 deletions
diff --git a/backend/src/models/account.rs b/backend/src/models/account.rs
index 1a2aa41..c10bd5f 100644
--- a/backend/src/models/account.rs
+++ b/backend/src/models/account.rs
@@ -1,6 +1,8 @@
use diesel::prelude::*;
use serde::{Deserialize, Serialize};
+use super::date_time_utc::DateTimeUtc;
+
#[derive(
Insertable, Queryable, Identifiable, Selectable, Debug, PartialEq, Clone, Serialize, Deserialize,
)]
@@ -9,5 +11,5 @@ pub struct Account {
pub id: i32,
pub name: String,
pub opening_balance: i32,
- pub opening_date: String,
+ pub opening_date: DateTimeUtc,
}
diff --git a/backend/src/models/budget.rs b/backend/src/models/budget.rs
new file mode 100644
index 0000000..cc18f2e
--- /dev/null
+++ b/backend/src/models/budget.rs
@@ -0,0 +1,44 @@
+use serde::Serialize;
+
+use super::budget_update::BudgetUpdate;
+
+#[derive(Debug, Eq, PartialEq, Serialize)]
+pub struct Budget {
+ pub quantity: i32,
+ pub period: i32,
+}
+
+impl From<&BudgetUpdate> for Budget {
+ fn from(budget_update: &BudgetUpdate) -> Self {
+ Self {
+ quantity: budget_update.new_budget,
+ period: budget_update.new_period,
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use chrono::Utc;
+
+ use crate::models::date_time_utc::DateTimeUtc;
+
+ use super::*;
+
+ #[test]
+ fn when_from_budget_update_then_returns_budget() {
+ let quantity = 2;
+ let period = 3;
+ let budget_update = BudgetUpdate {
+ id: 0,
+ category_id: 1,
+ date: DateTimeUtc::new(Utc::now()),
+ new_budget: quantity,
+ new_period: period,
+ };
+
+ let budget = Budget::from(&budget_update);
+
+ assert_eq!(budget, Budget { quantity, period });
+ }
+}
diff --git a/backend/src/models/budget_update.rs b/backend/src/models/budget_update.rs
index 3843455..ea93c16 100644
--- a/backend/src/models/budget_update.rs
+++ b/backend/src/models/budget_update.rs
@@ -2,13 +2,15 @@ use diesel::prelude::*;
use crate::models::category::Category;
-#[derive(Queryable, Identifiable, Selectable, Associations, Debug, PartialEq)]
+use super::date_time_utc::DateTimeUtc;
+
+#[derive(Clone, Queryable, Identifiable, Selectable, Associations, Debug, PartialEq)]
#[diesel(table_name = crate::schema::budget_updates)]
#[diesel(belongs_to(Category))]
pub struct BudgetUpdate {
pub id: i32,
pub category_id: i32,
- pub date: String,
+ pub date: DateTimeUtc,
pub new_budget: i32,
pub new_period: i32,
}
diff --git a/backend/src/models/category.rs b/backend/src/models/category.rs
index d7e25aa..5cb2609 100644
--- a/backend/src/models/category.rs
+++ b/backend/src/models/category.rs
@@ -1,10 +1,9 @@
use diesel::prelude::*;
+use serde::{Deserialize, Serialize};
-#[derive(Queryable, Identifiable, Selectable, Debug, PartialEq)]
+#[derive(Queryable, Identifiable, Selectable, Debug, PartialEq, Serialize, Deserialize)]
#[diesel(table_name = crate::schema::categories)]
pub struct Category {
pub id: i32,
pub name: String,
- pub initial_budget: i32,
- pub initial_period: i32,
}
diff --git a/backend/src/models/category_balance.rs b/backend/src/models/category_balance.rs
new file mode 100644
index 0000000..796b40b
--- /dev/null
+++ b/backend/src/models/category_balance.rs
@@ -0,0 +1,7 @@
+use serde::Serialize;
+
+#[derive(Serialize)]
+pub struct CategoryBalance {
+ pub category_id: i32,
+ pub balance: i32,
+}
diff --git a/backend/src/models/category_budget.rs b/backend/src/models/category_budget.rs
new file mode 100644
index 0000000..9796261
--- /dev/null
+++ b/backend/src/models/category_budget.rs
@@ -0,0 +1,9 @@
+use serde::Serialize;
+
+use super::budget::Budget;
+
+#[derive(Serialize)]
+pub struct CategoryBudget {
+ pub category_id: i32,
+ pub budget: Option<Budget>,
+}
diff --git a/backend/src/models/date_time_utc.rs b/backend/src/models/date_time_utc.rs
new file mode 100644
index 0000000..6c5dc33
--- /dev/null
+++ b/backend/src/models/date_time_utc.rs
@@ -0,0 +1,111 @@
+use chrono::{DateTime, Datelike, Utc};
+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,
+ 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)
+ }
+
+ pub fn now() -> Self {
+ Self(Utc::now())
+ }
+}
+
+impl ToSql<Text, Sqlite> for DateTimeUtc {
+ fn to_sql<'b>(
+ &'b self,
+ out: &mut diesel::serialize::Output<'b, '_, Sqlite>,
+ ) -> 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 Backend>::RawValue<'_>) -> deserialize::Result<DateTimeUtc> {
+ let str: String = FromSql::<Text, Sqlite>::from_sql(bytes)?;
+ let date_time = str.as_str().parse::<DateTime<Utc>>()?;
+ Ok(DateTimeUtc(date_time))
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use chrono::TimeZone;
+
+ use super::*;
+
+ #[test]
+ fn given_midnight_when_day_diff_next_midnight_less_1s_then_return_0() {
+ let start = DateTimeUtc::new(Utc.with_ymd_and_hms(2000, 1, 1, 0, 0, 0).unwrap().to_utc());
+ let end = DateTimeUtc::new(
+ Utc.with_ymd_and_hms(2000, 1, 1, 23, 59, 59)
+ .unwrap()
+ .to_utc(),
+ );
+
+ 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_midnight_when_day_diff_next_midnight_then_return_1() {
+ let start = DateTimeUtc::new(Utc.with_ymd_and_hms(2000, 1, 1, 0, 0, 0).unwrap().to_utc());
+ let end = DateTimeUtc::new(Utc.with_ymd_and_hms(2000, 1, 2, 0, 0, 0).unwrap().to_utc());
+
+ 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 given_midnight_less_1s_when_day_diff_midnight_then_return_1() {
+ let start = DateTimeUtc::new(
+ Utc.with_ymd_and_hms(2000, 1, 1, 23, 59, 59)
+ .unwrap()
+ .to_utc(),
+ );
+ let end = DateTimeUtc::new(Utc.with_ymd_and_hms(2000, 1, 2, 0, 0, 0).unwrap().to_utc());
+
+ 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);
+ }
+}
diff --git a/backend/src/models/mod.rs b/backend/src/models/mod.rs
index 68f5209..b790fcb 100644
--- a/backend/src/models/mod.rs
+++ b/backend/src/models/mod.rs
@@ -1,6 +1,10 @@
pub mod account;
+pub mod budget;
pub mod budget_update;
pub mod category;
+pub mod category_balance;
+pub mod category_budget;
pub mod category_transfer;
+pub mod date_time_utc;
pub mod transaction;
pub mod transaction_categorisation;
diff --git a/backend/src/models/transaction.rs b/backend/src/models/transaction.rs
index a83a0ad..36f33f8 100644
--- a/backend/src/models/transaction.rs
+++ b/backend/src/models/transaction.rs
@@ -2,6 +2,8 @@ use diesel::prelude::*;
use crate::models::account::Account;
+use super::date_time_utc::DateTimeUtc;
+
#[derive(Queryable, Identifiable, Selectable, Associations, Debug, PartialEq)]
#[diesel(table_name = crate::schema::transactions)]
#[diesel(belongs_to(Account))]
@@ -10,5 +12,6 @@ pub struct Transaction {
pub description: String,
pub payee: String,
pub quantity: i32,
+ pub date: DateTimeUtc,
pub account_id: i32,
}