1use crate::error::{AccountError, FinanceError};
2use sqlx::{Connection, query_file, types::Uuid};
3use supp_macro::Builder;
4
5#[derive(Debug, sqlx::FromRow, Builder)]
6#[builder(error_kind = "FinanceError")]
7pub struct Account {
8 pub id: Uuid,
9 pub parent: Option<Uuid>,
10}
11
12impl Account {
13 pub async fn commit<E>(&self, conn: &mut E) -> Result<(), FinanceError>
14 where
15 E: Connection<Database = sqlx::Postgres>,
16 {
17 let mut tr = conn.begin().await?;
18 query_file!("sql/account_insert.sql", &self.id, self.parent,)
19 .execute(&mut *tr)
20 .await?;
21 tr.commit().await?;
22
23 Ok(())
24 }
25}
26
27#[cfg(test)]
28mod account_tests {
29 use super::*;
30 use crate::commodity::{Commodity, CommodityBuilder};
31 #[cfg(feature = "testlog")]
32 use env_logger;
33 #[cfg(feature = "testlog")]
34 use log;
35 use sqlx::PgPool;
36 use tokio::sync::OnceCell;
37
38 static CONTEXT: OnceCell<()> = OnceCell::const_new();
40
41 static COMMODITY: OnceCell<Commodity> = OnceCell::const_new();
42
43 async fn setup(pool: &PgPool) {
44 CONTEXT
45 .get_or_init(|| async {
46 #[cfg(feature = "testlog")]
47 let _ = env_logger::builder()
48 .is_test(true)
49 .filter_level(log::LevelFilter::Trace)
50 .try_init();
51 })
52 .await;
53 COMMODITY
54 .get_or_init(|| async { CommodityBuilder::new().id(Uuid::new_v4()).build().unwrap() })
55 .await;
56 let mut conn = pool.acquire().await.unwrap();
57 COMMODITY.get().unwrap().commit(&mut *conn).await.unwrap();
58 }
59
60 #[sqlx::test(migrations = "../migrations")]
61 async fn test_account_store(pool: PgPool) {
62 setup(&pool).await;
63
64 let account = Account {
65 id: Uuid::new_v4(),
66 parent: None,
67 };
68
69 let mut conn = pool.acquire().await.unwrap();
70 sqlx::query!("INSERT INTO accounts (id) VALUES ($1)", &account.id)
71 .execute(&mut *conn)
72 .await
73 .unwrap();
74
75 let mut conn = pool.acquire().await.unwrap();
76 let result = sqlx::query!("SELECT id FROM accounts WHERE id = $1", &account.id)
77 .fetch_one(&mut *conn)
78 .await
79 .unwrap();
80
81 assert_eq!(account.id, result.id);
82 }
83
84 #[sqlx::test(migrations = "../migrations")]
85 async fn test_account_builder(pool: PgPool) -> anyhow::Result<()> {
86 setup(&pool).await;
87 let build = Account::builder().build();
88 assert!(build.is_err());
89 let build = Account::builder().id(Uuid::new_v4()).build();
90 assert!(build.is_ok());
91 Ok(())
92 }
93
94 #[sqlx::test(migrations = "../migrations")]
95 async fn test_account_commit(pool: PgPool) -> anyhow::Result<()> {
96 setup(&pool).await;
97 let account = Account::builder().id(Uuid::new_v4()).build().unwrap();
98
99 let mut conn = pool.acquire().await.unwrap();
100 account.commit(&mut *conn).await.unwrap();
101
102 let mut conn = pool.acquire().await.unwrap();
103 let result = sqlx::query!("SELECT id FROM accounts WHERE id = $1", &account.id)
104 .fetch_one(&mut *conn)
105 .await
106 .unwrap();
107
108 assert_eq!(account.id, result.id);
109 Ok(())
110 }
111}