burncloud_database_client/
repository.rs

1use 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, &params, 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, &params, 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, &params, 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, &params, 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, &params, 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, &params, context).await?;
162        Ok(!result.rows.is_empty())
163    }
164}