burncloud_database_client/
repository.rs1use burncloud_database_core::{
2 Repository, QueryContext, QueryOptions, QueryParam, QueryExecutor
3};
4use burncloud_database_core::error::DatabaseResult;
5use async_trait::async_trait;
6use serde::{Serialize, Deserialize};
7use std::sync::Arc;
8use std::marker::PhantomData;
9
10pub struct BaseRepository<T>
11where
12 T: Send + Sync + Serialize + for<'de> Deserialize<'de>,
13{
14 pub query_executor: Arc<Box<dyn QueryExecutor>>,
15 table_name: String,
16 _phantom: PhantomData<T>,
17}
18
19impl<T> BaseRepository<T>
20where
21 T: Send + Sync + Serialize + for<'de> Deserialize<'de>,
22{
23 pub fn new(query_executor: Box<dyn QueryExecutor>, table_name: String) -> Self {
24 Self {
25 query_executor: Arc::new(query_executor),
26 table_name,
27 _phantom: PhantomData,
28 }
29 }
30
31 pub fn get_table_name(&self) -> &str {
32 &self.table_name
33 }
34}
35
36#[async_trait]
37impl<T> Repository<T> for BaseRepository<T>
38where
39 T: Send + Sync + Serialize + for<'de> Deserialize<'de>,
40{
41 async fn find_by_id(&self, id: &str, context: &QueryContext) -> DatabaseResult<Option<T>> {
42 let query = format!("SELECT * FROM {} WHERE id = $1", self.get_table_name());
43 let id_param = burncloud_database_impl::StringParam(id.to_string());
44 let params: Vec<&dyn QueryParam> = vec![&id_param];
45
46 let result = self.query_executor.execute_query(&query, ¶ms, context).await?;
47
48 if result.rows.is_empty() {
49 Ok(None)
50 } else {
51 let row = &result.rows[0];
52 let entity: T = serde_json::from_value(serde_json::Value::Object(
53 row.iter().map(|(k, v)| (k.clone(), v.clone())).collect()
54 )).map_err(|e| burncloud_database_core::DatabaseError::SerializationError(e.to_string()))?;
55 Ok(Some(entity))
56 }
57 }
58
59 async fn find_all(&self, options: &QueryOptions, context: &QueryContext) -> DatabaseResult<Vec<T>> {
60 let mut query = format!("SELECT * FROM {}", self.get_table_name());
61
62 if let Some(order_by) = &options.order_by {
63 query.push_str(&format!(" ORDER BY {}", order_by));
64 if let Some(direction) = &options.order_direction {
65 match direction {
66 burncloud_database_core::OrderDirection::Asc => query.push_str(" ASC"),
67 burncloud_database_core::OrderDirection::Desc => query.push_str(" DESC"),
68 }
69 }
70 }
71
72 if let Some(limit) = options.limit {
73 query.push_str(&format!(" LIMIT {}", limit));
74 }
75
76 if let Some(offset) = options.offset {
77 query.push_str(&format!(" OFFSET {}", offset));
78 }
79
80 let params: Vec<&dyn QueryParam> = vec![];
81 let result = self.query_executor.execute_query(&query, ¶ms, context).await?;
82
83 let mut entities = Vec::new();
84 for row in result.rows {
85 let entity: T = serde_json::from_value(serde_json::Value::Object(
86 row.iter().map(|(k, v)| (k.clone(), v.clone())).collect()
87 )).map_err(|e| burncloud_database_core::DatabaseError::SerializationError(e.to_string()))?;
88 entities.push(entity);
89 }
90
91 Ok(entities)
92 }
93
94 async fn create(&self, entity: &T, context: &QueryContext) -> DatabaseResult<String> {
95 let entity_json = serde_json::to_value(entity)
96 .map_err(|e| burncloud_database_core::DatabaseError::SerializationError(e.to_string()))?;
97
98 if let serde_json::Value::Object(map) = entity_json {
99 let columns: Vec<String> = map.keys().cloned().collect();
100 let placeholders: Vec<String> = (1..=columns.len()).map(|i| format!("${}", i)).collect();
101
102 let query = format!(
103 "INSERT INTO {} ({}) VALUES ({}) RETURNING id",
104 self.get_table_name(),
105 columns.join(", "),
106 placeholders.join(", ")
107 );
108
109 let params: Vec<&dyn QueryParam> = vec![];
110 let result = self.query_executor.execute_query(&query, ¶ms, context).await?;
111
112 Ok(result.last_insert_id.unwrap_or_else(|| uuid::Uuid::new_v4().to_string()))
113 } else {
114 Err(burncloud_database_core::DatabaseError::SerializationError(
115 "Entity must be a JSON object".to_string()
116 ))
117 }
118 }
119
120 async fn update(&self, _id: &str, entity: &T, context: &QueryContext) -> DatabaseResult<()> {
121 let entity_json = serde_json::to_value(entity)
122 .map_err(|e| burncloud_database_core::DatabaseError::SerializationError(e.to_string()))?;
123
124 if let serde_json::Value::Object(map) = entity_json {
125 let set_clauses: Vec<String> = map.keys().enumerate()
126 .map(|(i, key)| format!("{} = ${}", key, i + 1))
127 .collect();
128
129 let query = format!(
130 "UPDATE {} SET {} WHERE id = ${}",
131 self.get_table_name(),
132 set_clauses.join(", "),
133 map.len() + 1
134 );
135
136 let params: Vec<&dyn QueryParam> = vec![];
137 self.query_executor.execute_query(&query, ¶ms, context).await?;
138
139 Ok(())
140 } else {
141 Err(burncloud_database_core::DatabaseError::SerializationError(
142 "Entity must be a JSON object".to_string()
143 ))
144 }
145 }
146
147 async fn delete(&self, id: &str, context: &QueryContext) -> DatabaseResult<()> {
148 let query = format!("DELETE FROM {} WHERE id = $1", self.get_table_name());
149 let id_param = burncloud_database_impl::StringParam(id.to_string());
150 let params: Vec<&dyn QueryParam> = vec![&id_param];
151
152 self.query_executor.execute_query(&query, ¶ms, context).await?;
153 Ok(())
154 }
155
156 async fn exists(&self, id: &str, context: &QueryContext) -> DatabaseResult<bool> {
157 let query = format!("SELECT 1 FROM {} WHERE id = $1 LIMIT 1", self.get_table_name());
158 let id_param = burncloud_database_impl::StringParam(id.to_string());
159 let params: Vec<&dyn QueryParam> = vec![&id_param];
160
161 let result = self.query_executor.execute_query(&query, ¶ms, context).await?;
162 Ok(!result.rows.is_empty())
163 }
164}