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