Skip to main content

finance/
account.rs

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    /// Context for keeping environment intact
39    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}