1
use crate::error::{AccountError, FinanceError};
2
use sqlx::{Connection, query_file, types::Uuid};
3
use supp_macro::Builder;
4

            
5
#[derive(Debug, sqlx::FromRow, Builder)]
6
#[builder(error_kind = "FinanceError")]
7
pub struct Account {
8
    pub id: Uuid,
9
    pub parent: Option<Uuid>,
10
}
11

            
12
impl Account {
13
146
    pub async fn commit<E>(&self, conn: &mut E) -> Result<(), FinanceError>
14
146
    where
15
146
        E: Connection<Database = sqlx::Postgres>,
16
146
    {
17
146
        let mut tr = conn.begin().await?;
18
146
        query_file!("sql/account_insert.sql", &self.id, self.parent,)
19
146
            .execute(&mut *tr)
20
146
            .await?;
21
146
        tr.commit().await?;
22

            
23
146
        Ok(())
24
146
    }
25
}
26

            
27
#[cfg(test)]
28
mod 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
3
    async fn setup(pool: &PgPool) {
44
3
        CONTEXT
45
3
            .get_or_init(|| async {
46
                #[cfg(feature = "testlog")]
47
1
                let _ = env_logger::builder()
48
1
                    .is_test(true)
49
1
                    .filter_level(log::LevelFilter::Trace)
50
1
                    .try_init();
51
2
            })
52
3
            .await;
53
3
        COMMODITY
54
3
            .get_or_init(|| async { CommodityBuilder::new().id(Uuid::new_v4()).build().unwrap() })
55
3
            .await;
56
3
        let mut conn = pool.acquire().await.unwrap();
57
3
        COMMODITY.get().unwrap().commit(&mut *conn).await.unwrap();
58
3
    }
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
}