1use crate::error::{FinanceError, TagError};
2use sqlx::{Connection, types::Uuid};
3use supp_macro::Builder;
4
5#[derive(Debug, sqlx::FromRow, Builder)]
6#[builder(error_kind = "TagError")]
7pub struct Tag {
8 pub id: Uuid,
9 pub tag_name: String,
10 pub tag_value: String,
11 pub description: Option<String>,
12}
13
14impl Tag {
15 pub async fn commit<E>(&self, conn: &mut E) -> Result<Uuid, FinanceError>
23 where
24 E: Connection<Database = sqlx::Postgres>,
25 {
26 let mut tr = conn.begin().await?;
27
28 let row = sqlx::query_file!(
29 "sql/tag_insert.sql",
30 &self.id,
31 &self.tag_name,
32 &self.tag_value,
33 self.description
34 )
35 .fetch_one(&mut *tr)
36 .await?;
37 tr.commit().await?;
38
39 Ok(row.id)
40 }
41}
42
43#[cfg(test)]
44mod tag_tests {
45 use super::*;
46 #[cfg(feature = "testlog")]
47 use env_logger;
48 #[cfg(feature = "testlog")]
49 use log;
50 use sqlx::PgPool;
51 use tokio::sync::OnceCell;
52
53 static CONTEXT: OnceCell<()> = OnceCell::const_new();
55
56 async fn setup() {
57 CONTEXT
58 .get_or_init(|| async {
59 #[cfg(feature = "testlog")]
60 let _ = env_logger::builder()
61 .is_test(true)
62 .filter_level(log::LevelFilter::Trace)
63 .try_init();
64 })
65 .await;
66 }
67
68 #[sqlx::test(migrations = "../migrations")]
69 async fn test_tag_store(pool: PgPool) -> anyhow::Result<()> {
70 setup().await;
71 let mut conn = pool.acquire().await?;
72
73 let tag = Tag {
74 id: Uuid::new_v4(),
75 tag_name: "Category".to_string(),
76 tag_value: "test".to_string(),
77 description: None,
78 };
79
80 sqlx::query!(
81 "INSERT INTO tags (id, tag_name, tag_value, description) \
82 VALUES ($1, $2, $3, $4)",
83 &tag.id,
84 &tag.tag_name,
85 &tag.tag_value,
86 tag.description
87 )
88 .execute(&mut *conn)
89 .await?;
90
91 let result = sqlx::query!("SELECT id, tag_value FROM tags WHERE tag_name = 'Category'")
92 .fetch_one(&mut *conn)
93 .await?;
94
95 assert_eq!(tag.id, result.id);
96 assert_eq!(tag.tag_value, "test".to_string());
97
98 let tag2 = Tag {
99 id: Uuid::new_v4(),
100 tag_name: "Cat2".to_string(),
101 ..tag
102 };
103 let mut conn = pool.acquire().await?;
104 tag2.commit(&mut *conn).await?;
105 let mut conn = pool.acquire().await?;
106 let result = sqlx::query!("SELECT id, tag_value FROM tags WHERE tag_name = 'Cat2'")
107 .fetch_one(&mut *conn)
108 .await?;
109
110 assert_eq!(tag2.id, result.id);
111 assert_eq!(tag2.tag_value, "test".to_string());
112
113 Ok(())
114 }
115
116 #[tokio::test]
117 async fn test_tag_builder() -> anyhow::Result<()> {
118 setup().await;
119 let build = Tag::builder().id(Uuid::new_v4()).build();
120 assert!(build.is_err());
121 let build = Tag::builder()
122 .id(Uuid::new_v4())
123 .tag_name("name")
124 .tag_value("type")
125 .build();
126
127 assert!(build.is_ok());
128 Ok(())
129 }
130}