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

            
5
#[derive(Debug, sqlx::FromRow, Builder)]
6
#[builder(error_kind = "TagError")]
7
pub struct Tag {
8
    pub id: Uuid,
9
    pub tag_name: String,
10
    pub tag_value: String,
11
    pub description: Option<String>,
12
}
13

            
14
impl Tag {
15
66
    pub async fn commit<E>(&self, conn: &mut E) -> Result<(), FinanceError>
16
66
    where
17
66
        E: Connection<Database = sqlx::Postgres>,
18
66
    {
19
66
        let mut tr = conn.begin().await?;
20

            
21
66
        query_file!(
22
            "sql/tag_insert.sql",
23
            &self.id,
24
            &self.tag_name,
25
            &self.tag_value,
26
            self.description
27
        )
28
66
        .execute(&mut *tr)
29
66
        .await?;
30
66
        tr.commit().await?;
31

            
32
66
        Ok(())
33
66
    }
34
}
35

            
36
#[cfg(test)]
37
mod tag_tests {
38
    use super::*;
39
    #[cfg(feature = "testlog")]
40
    use env_logger;
41
    #[cfg(feature = "testlog")]
42
    use log;
43
    use sqlx::PgPool;
44
    use tokio::sync::OnceCell;
45

            
46
    /// Context for keeping environment intact
47
    static CONTEXT: OnceCell<()> = OnceCell::const_new();
48

            
49
6
    async fn setup() {
50
4
        CONTEXT
51
4
            .get_or_init(|| async {
52
                #[cfg(feature = "testlog")]
53
2
                let _ = env_logger::builder()
54
2
                    .is_test(true)
55
2
                    .filter_level(log::LevelFilter::Trace)
56
2
                    .try_init();
57
4
            })
58
4
            .await;
59
4
    }
60

            
61
    #[sqlx::test(migrations = "../migrations")]
62
    async fn test_tag_store(pool: PgPool) -> anyhow::Result<()> {
63
        setup().await;
64
        let mut conn = pool.acquire().await?;
65

            
66
        let tag = Tag {
67
            id: Uuid::new_v4(),
68
            tag_name: "Category".to_string(),
69
            tag_value: "test".to_string(),
70
            description: None,
71
        };
72

            
73
        sqlx::query!(
74
            "INSERT INTO tags (id, tag_name, tag_value, description) \
75
		      VALUES ($1, $2, $3, $4)",
76
            &tag.id,
77
            &tag.tag_name,
78
            &tag.tag_value,
79
            tag.description
80
        )
81
        .execute(&mut *conn)
82
        .await?;
83

            
84
        let result = sqlx::query!("SELECT id, tag_value FROM tags WHERE tag_name = 'Category'")
85
            .fetch_one(&mut *conn)
86
            .await?;
87

            
88
        assert_eq!(tag.id, result.id);
89
        assert_eq!(tag.tag_value, "test".to_string());
90

            
91
        let tag2 = Tag {
92
            id: Uuid::new_v4(),
93
            tag_name: "Cat2".to_string(),
94
            ..tag
95
        };
96
        let mut conn = pool.acquire().await?;
97
        tag2.commit(&mut *conn).await?;
98
        let mut conn = pool.acquire().await?;
99
        let result = sqlx::query!("SELECT id, tag_value FROM tags WHERE tag_name = 'Cat2'")
100
            .fetch_one(&mut *conn)
101
            .await?;
102

            
103
        assert_eq!(tag2.id, result.id);
104
        assert_eq!(tag2.tag_value, "test".to_string());
105

            
106
        Ok(())
107
    }
108

            
109
    #[tokio::test]
110
3
    async fn test_tag_builder() -> anyhow::Result<()> {
111
2
        setup().await;
112
2
        let build = Tag::builder().id(Uuid::new_v4()).build();
113
2
        assert!(build.is_err());
114
2
        let build = Tag::builder()
115
2
            .id(Uuid::new_v4())
116
2
            .tag_name("name")
117
2
            .tag_value("type")
118
2
            .build();
119

            
120
2
        assert!(build.is_ok());
121
4
        Ok(())
122
2
    }
123
}