1use super::*;
23use async_trait::async_trait;
24use std::collections::HashMap;
25
26#[async_trait]
27pub trait DMSCORMRepository<E: for<'de> serde::Deserialize<'de> + serde::Serialize + Clone + Send + Sync>: Send + Sync {
28 fn table_name(&self) -> &'static str;
29
30 async fn find_all(&self, db: &dyn DMSCDatabase) -> DMSCResult<Vec<E>>;
31 async fn find_by_id(&self, db: &dyn DMSCDatabase, id: &str) -> DMSCResult<Option<E>>;
32 async fn find_one(&self, db: &dyn DMSCDatabase, criteria: &Criteria) -> DMSCResult<Option<E>>;
33 async fn find_many(&self, db: &dyn DMSCDatabase, criteria: Vec<Criteria>) -> DMSCResult<Vec<E>>;
34 async fn find_paginated(&self, db: &dyn DMSCDatabase, pagination: Pagination, criteria: Vec<Criteria>) -> DMSCResult<(Vec<E>, u64)>;
35 async fn count(&self, db: &dyn DMSCDatabase, criteria: Vec<Criteria>) -> DMSCResult<u64>;
36
37 async fn save(&self, db: &dyn DMSCDatabase, entity: &E) -> DMSCResult<E>;
38 async fn save_many(&self, db: &dyn DMSCDatabase, entities: &[E]) -> DMSCResult<Vec<E>>;
39 async fn update(&self, db: &dyn DMSCDatabase, entity: &E) -> DMSCResult<E>;
40 async fn delete(&self, db: &dyn DMSCDatabase, entity: &E) -> DMSCResult<()>;
41 async fn delete_by_id(&self, db: &dyn DMSCDatabase, id: &str) -> DMSCResult<()>;
42 async fn delete_many(&self, db: &dyn DMSCDatabase, criteria: Vec<Criteria>) -> DMSCResult<u64>;
43
44 async fn exists(&self, db: &dyn DMSCDatabase, id: &str) -> DMSCResult<bool>;
45 async fn exists_by(&self, db: &dyn DMSCDatabase, criteria: &Criteria) -> DMSCResult<bool>;
46
47 async fn batch_insert(&self, db: &dyn DMSCDatabase, entities: &[E], batch_size: usize) -> DMSCResult<Vec<E>>;
48 async fn upsert(&self, db: &dyn DMSCDatabase, entity: &E, conflict_columns: &[&str]) -> DMSCResult<E>;
49}
50
51#[async_trait]
52pub trait DMSCORMCrudRepository<E: for<'de> serde::Deserialize<'de> + serde::Serialize + Clone + Send + Sync>: Send + Sync {
53 fn table_name(&self) -> &'static str;
54
55 async fn find_all(&self) -> DMSCResult<Vec<E>>;
56 async fn find_by_id(&self, id: &str) -> DMSCResult<Option<E>>;
57 async fn save(&self, entity: &E) -> DMSCResult<E>;
58 async fn delete(&self, entity: &E) -> DMSCResult<()>;
59}
60
61#[derive(Debug, Clone)]
62pub struct DMSCORMSimpleRepository<E: for<'de> serde::Deserialize<'de> + serde::Serialize + Clone + Send + Sync> {
63 table_name: &'static str,
64 _phantom: std::marker::PhantomData<E>,
65}
66
67impl<E: for<'de> serde::Deserialize<'de> + serde::Serialize + Clone + Send + Sync> DMSCORMSimpleRepository<E> {
68 pub fn new(table_name: &'static str) -> Self {
69 Self {
70 table_name,
71 _phantom: std::marker::PhantomData,
72 }
73 }
74}
75
76#[async_trait]
77impl<E: for<'de> serde::Deserialize<'de> + serde::Serialize + Clone + Send + Sync> DMSCORMRepository<E> for DMSCORMSimpleRepository<E> {
78 fn table_name(&self) -> &'static str {
79 self.table_name
80 }
81
82 async fn find_all(&self, db: &dyn DMSCDatabase) -> DMSCResult<Vec<E>> {
83 let sql = format!("SELECT * FROM {}", self.table_name);
84 let result = db.query(&sql).await?;
85
86 let mut entities = Vec::new();
87 for row in result {
88 let json_value = serde_json::to_value(row.to_map())?;
89 let entity: E = serde_json::from_value(json_value)?;
90 entities.push(entity);
91 }
92
93 Ok(entities)
94 }
95
96 async fn find_by_id(&self, db: &dyn DMSCDatabase, id: &str) -> DMSCResult<Option<E>> {
97 let sql = format!("SELECT * FROM {} WHERE id = ?", self.table_name);
98
99 let result = db.query_with_params(&sql, &[serde_json::json!(id)]).await?;
100
101 if let Some(row) = result.first() {
102 let json_value = serde_json::to_value(row.to_map())?;
103 let entity: E = serde_json::from_value(json_value)?;
104 Ok(Some(entity))
105 } else {
106 Ok(None)
107 }
108 }
109
110 async fn find_one(&self, db: &dyn DMSCDatabase, criteria: &Criteria) -> DMSCResult<Option<E>> {
111 let mut query = QueryBuilder::new(self.table_name);
112 query.where_criteria(criteria.clone());
113
114 let (sql, params) = query.build();
115 let result = db.query_with_params(&sql, ¶ms).await?;
116
117 if let Some(row) = result.first() {
118 let json_value = serde_json::to_value(row.to_map())?;
119 let entity: E = serde_json::from_value(json_value)?;
120 Ok(Some(entity))
121 } else {
122 Ok(None)
123 }
124 }
125
126 async fn find_many(&self, db: &dyn DMSCDatabase, criteria: Vec<Criteria>) -> DMSCResult<Vec<E>> {
127 let mut query = QueryBuilder::new(self.table_name);
128
129 for criteria in criteria {
130 query.and_where(criteria);
131 }
132
133 let (sql, params) = query.build();
134 let result = db.query_with_params(&sql, ¶ms).await?;
135
136 let mut entities = Vec::new();
137 for row in result {
138 let json_value = serde_json::to_value(row.to_map())?;
139 let entity: E = serde_json::from_value(json_value)?;
140 entities.push(entity);
141 }
142
143 Ok(entities)
144 }
145
146 async fn find_paginated(&self, db: &dyn DMSCDatabase, pagination: Pagination, criteria: Vec<Criteria>) -> DMSCResult<(Vec<E>, u64)> {
147 let count_sql = format!("SELECT COUNT(*) as total FROM {}", self.table_name);
148
149 let total: u64 = if criteria.is_empty() {
150 if let Some(row) = db.query_one(&count_sql).await? {
151 row.get::<i64>("total").map(|v| v as u64).unwrap_or(0)
152 } else {
153 0
154 }
155 } else {
156 let mut count_query = QueryBuilder::new(self.table_name);
157 for c in &criteria {
158 count_query.and_where(c.clone());
159 }
160 let (sql, params) = count_query.build();
161 let count_sql = format!("SELECT COUNT(*) as total FROM ({}) as subquery", sql);
162
163 let result = db.query_with_params(&count_sql, ¶ms).await?;
164 let row = result.first().ok_or_else(|| DMSCError::Other("Query returned no rows".to_string()))?;
165 row.get_i64("total").map(|v| v as u64).unwrap_or(0)
166 };
167
168 let mut data_query = QueryBuilder::new(self.table_name);
169 for c in criteria {
170 data_query.and_where(c);
171 }
172 data_query.paginate(pagination.page, pagination.page_size);
173
174 let (sql, params) = data_query.build();
175 let result = db.query_with_params(&sql, ¶ms).await?;
176
177 let mut entities = Vec::new();
178 for row in result {
179 let json_value = serde_json::to_value(row.to_map())?;
180 let entity: E = serde_json::from_value(json_value)?;
181 entities.push(entity);
182 }
183
184 Ok((entities, total))
185 }
186
187 async fn count(&self, db: &dyn DMSCDatabase, criteria: Vec<Criteria>) -> DMSCResult<u64> {
188 let mut query = QueryBuilder::new(self.table_name);
189 for c in criteria {
190 query.and_where(c);
191 }
192 let (sql, _) = query.build();
193 let count_sql = sql.replace("*", "COUNT(*) as total");
194
195 if let Some(row) = db.query_one(&count_sql).await? {
196 row.get::<i64>("total").map(|v| v as u64).ok_or_else(|| DMSCError::Other("Failed to get count".to_string()))
197 } else {
198 Ok(0)
199 }
200 }
201
202 async fn save(&self, db: &dyn DMSCDatabase, entity: &E) -> DMSCResult<E> {
203 let json_value = serde_json::to_value(entity)?;
204 let values: HashMap<String, serde_json::Value> = serde_json::from_value(json_value)?;
205
206 let columns: Vec<&str> = values.keys().map(|s| s.as_str()).collect();
207 let placeholders: Vec<String> = (0..columns.len()).map(|_| "?".to_string()).collect();
208
209 let sql = format!(
210 "INSERT INTO {} ({}) VALUES ({})",
211 self.table_name,
212 columns.join(", "),
213 placeholders.join(", ")
214 );
215
216 let params: Vec<serde_json::Value> = columns.iter()
217 .map(|&col| values.get(col).cloned().unwrap_or(serde_json::Value::Null))
218 .collect();
219
220 db.execute_with_params(&sql, ¶ms).await?;
221
222 Ok(entity.clone())
223 }
224
225 async fn save_many(&self, db: &dyn DMSCDatabase, entities: &[E]) -> DMSCResult<Vec<E>> {
226 let mut saved = Vec::with_capacity(entities.len());
227
228 for entity in entities {
229 saved.push(self.save(db, entity).await?);
230 }
231
232 Ok(saved)
233 }
234
235 async fn update(&self, db: &dyn DMSCDatabase, entity: &E) -> DMSCResult<E> {
236 let json_value = serde_json::to_value(entity)?;
237 let values: HashMap<String, serde_json::Value> = serde_json::from_value(json_value)?;
238
239 let updates: Vec<String> = values.keys()
240 .filter(|&col| col != "id")
241 .map(|col| format!("{} = ?", col))
242 .collect();
243
244 if updates.is_empty() {
245 return Ok(entity.clone());
246 }
247
248 let sql = format!(
249 "UPDATE {} SET {} WHERE id = ?",
250 self.table_name,
251 updates.join(", ")
252 );
253
254 let mut params: Vec<serde_json::Value> = values.iter()
255 .filter(|(col, _)| *col != "id")
256 .map(|(_, v)| v.clone())
257 .collect();
258
259 if let Some(id) = values.get("id") {
260 params.push(id.clone());
261 }
262
263 db.execute_with_params(&sql, ¶ms).await?;
264
265 Ok(entity.clone())
266 }
267
268 async fn delete(&self, db: &dyn DMSCDatabase, entity: &E) -> DMSCResult<()> {
269 let json_value = serde_json::to_value(entity)?;
270 let values: HashMap<String, serde_json::Value> = serde_json::from_value(json_value)?;
271
272 if let Some(id) = values.get("id") {
273 self.delete_by_id(db, &id.to_string()).await
274 } else {
275 Err(DMSCError::Other("Entity has no id field".to_string()))
276 }
277 }
278
279 async fn delete_by_id(&self, db: &dyn DMSCDatabase, id: &str) -> DMSCResult<()> {
280 let sql = format!("DELETE FROM {} WHERE id = ?", self.table_name);
281
282 db.execute_with_params(&sql, &[serde_json::json!(id)]).await?;
283 Ok(())
284 }
285
286 async fn delete_many(&self, db: &dyn DMSCDatabase, criteria: Vec<Criteria>) -> DMSCResult<u64> {
287 if criteria.is_empty() {
288 return Err(DMSCError::Other("Criteria required for delete_many operation".to_string()));
289 }
290
291 let mut query = QueryBuilder::new(self.table_name);
292 for c in criteria {
293 query.and_where(c);
294 }
295
296 let (sql, params) = query.build();
297 let delete_sql = format!("DELETE FROM {}", sql.split("FROM").nth(1).unwrap_or(&sql));
298
299 db.execute_with_params(&delete_sql, ¶ms).await.map_err(|e| e.into())
300 }
301
302 async fn batch_insert(&self, db: &dyn DMSCDatabase, entities: &[E], batch_size: usize) -> DMSCResult<Vec<E>> {
303 let mut inserted = Vec::with_capacity(entities.len());
304
305 for chunk in entities.chunks(batch_size) {
306 let json_values: Vec<serde_json::Value> = chunk.iter()
307 .map(|e| serde_json::to_value(e))
308 .collect::<Result<_, _>>()?;
309
310 let mut all_columns: std::collections::HashSet<&str> = std::collections::HashSet::new();
311 for json_value in &json_values {
312 if let serde_json::Value::Object(map) = json_value {
313 for key in map.keys() {
314 all_columns.insert(key);
315 }
316 }
317 }
318
319 let columns: Vec<&str> = all_columns.iter().copied().collect();
320 let placeholders: Vec<String> = (0..columns.len()).map(|_| "?".to_string()).collect();
321
322 let sql = format!(
323 "INSERT INTO {} ({}) VALUES ({})",
324 self.table_name,
325 columns.join(", "),
326 placeholders.join(", ")
327 );
328
329 for json_value in chunk {
330 let json_val = serde_json::to_value(json_value)?;
331 let values: HashMap<String, serde_json::Value> = serde_json::from_value(json_val)?;
332
333 let params: Vec<serde_json::Value> = columns.iter()
334 .map(|&col| values.get(col).cloned().unwrap_or(serde_json::Value::Null))
335 .collect();
336
337 db.execute_with_params(&sql, ¶ms).await?;
338 inserted.push(json_value.clone());
339 }
340 }
341
342 Ok(inserted)
343 }
344
345 async fn upsert(&self, db: &dyn DMSCDatabase, entity: &E, conflict_columns: &[&str]) -> DMSCResult<E> {
346 let json_value = serde_json::to_value(entity)?;
347 let values: HashMap<String, serde_json::Value> = serde_json::from_value(json_value)?;
348
349 let columns: Vec<&str> = values.keys().map(|s| s.as_str()).collect();
350 let placeholders: Vec<String> = (0..columns.len()).map(|_| "?".to_string()).collect();
351
352 let update_parts: Vec<String> = columns.iter()
353 .filter(|&&col| !conflict_columns.contains(&col))
354 .map(|col| format!("{} = EXCLUDED.{}", col, col))
355 .collect();
356
357 let conflict_cols = conflict_columns.join(", ");
358 let update_set = if update_parts.is_empty() {
359 String::new()
360 } else {
361 format!("ON CONFLICT ({}) DO UPDATE SET {}", conflict_cols, update_parts.join(", "))
362 };
363
364 let sql = format!(
365 "INSERT INTO {} ({}) VALUES ({}) {}",
366 self.table_name,
367 columns.join(", "),
368 placeholders.join(", "),
369 update_set
370 );
371
372 let params: Vec<serde_json::Value> = columns.iter()
373 .map(|&col| values.get(col).cloned().unwrap_or(serde_json::Value::Null))
374 .collect();
375
376 db.execute_with_params(&sql, ¶ms).await?;
377
378 Ok(entity.clone())
379 }
380
381 async fn exists(&self, db: &dyn DMSCDatabase, id: &str) -> DMSCResult<bool> {
382 let sql = format!("SELECT 1 FROM {} WHERE id = ? LIMIT 1", self.table_name);
383
384 let result = db.query_with_params(&sql, &[serde_json::json!(id)]).await?;
385 Ok(!result.is_empty())
386 }
387
388 async fn exists_by(&self, db: &dyn DMSCDatabase, criteria: &Criteria) -> DMSCResult<bool> {
389 let mut query = QueryBuilder::new(self.table_name);
390 query.select(vec!["1"]);
391 query.where_criteria(criteria.clone());
392
393 let (sql, params) = query.build();
394 let sql = format!("{} LIMIT 1", sql);
395
396 let result = db.query_with_params(&sql, ¶ms).await?;
397 Ok(!result.is_empty())
398 }
399}
400
401impl<E: for<'de> serde::Deserialize<'de> + serde::Serialize + Clone + Send + Sync> DMSCORMSimpleRepository<E> {
402 pub fn default() -> Self {
403 Self::new("unknown")
404 }
405}