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

            
23
194
        Ok(())
24
194
    }
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
9
    async fn setup(pool: &PgPool) {
44
6
        CONTEXT
45
6
            .get_or_init(|| async {
46
                #[cfg(feature = "testlog")]
47
2
                let _ = env_logger::builder()
48
2
                    .is_test(true)
49
2
                    .filter_level(log::LevelFilter::Trace)
50
2
                    .try_init();
51
4
            })
52
6
            .await;
53
6
        COMMODITY
54
6
            .get_or_init(|| async {
55
2
                CommodityBuilder::new()
56
2
                    .fraction(1000)
57
2
                    .id(Uuid::new_v4())
58
2
                    .build()
59
2
                    .unwrap()
60
4
            })
61
6
            .await;
62
6
        let mut conn = pool.acquire().await.unwrap();
63
6
        COMMODITY.get().unwrap().commit(&mut *conn).await.unwrap();
64
6
    }
65

            
66
    #[sqlx::test(migrations = "../migrations")]
67
    async fn test_account_store(pool: PgPool) {
68
        setup(&pool).await;
69

            
70
        let account = Account {
71
            id: Uuid::new_v4(),
72
            parent: None,
73
        };
74

            
75
        let mut conn = pool.acquire().await.unwrap();
76
        sqlx::query!("INSERT INTO accounts (id) VALUES ($1)", &account.id)
77
            .execute(&mut *conn)
78
            .await
79
            .unwrap();
80

            
81
        let mut conn = pool.acquire().await.unwrap();
82
        let result = sqlx::query!("SELECT id FROM accounts WHERE id = $1", &account.id)
83
            .fetch_one(&mut *conn)
84
            .await
85
            .unwrap();
86

            
87
        assert_eq!(account.id, result.id);
88
    }
89

            
90
    #[sqlx::test(migrations = "../migrations")]
91
    async fn test_account_builder(pool: PgPool) -> anyhow::Result<()> {
92
        setup(&pool).await;
93
        let build = Account::builder().build();
94
        assert!(build.is_err());
95
        let build = Account::builder().id(Uuid::new_v4()).build();
96
        assert!(build.is_ok());
97
        Ok(())
98
    }
99

            
100
    #[sqlx::test(migrations = "../migrations")]
101
    async fn test_account_commit(pool: PgPool) -> anyhow::Result<()> {
102
        setup(&pool).await;
103
        let account = Account::builder().id(Uuid::new_v4()).build().unwrap();
104

            
105
        let mut conn = pool.acquire().await.unwrap();
106
        account.commit(&mut *conn).await.unwrap();
107

            
108
        let mut conn = pool.acquire().await.unwrap();
109
        let result = sqlx::query!("SELECT id FROM accounts WHERE id = $1", &account.id)
110
            .fetch_one(&mut *conn)
111
            .await
112
            .unwrap();
113

            
114
        assert_eq!(account.id, result.id);
115
        Ok(())
116
    }
117
}