elif_orm/model/
abstraction.rs1use std::sync::Arc;
7
8use crate::backends::{DatabasePool, DatabaseValue};
9use crate::error::{ModelError, ModelResult};
10use crate::model::core_trait::Model;
11
12#[allow(async_fn_in_trait)]
16pub trait ModelAbstracted: Model {
17 async fn find_abstracted(
19 pool: &Arc<dyn DatabasePool>,
20 id: Self::PrimaryKey,
21 ) -> ModelResult<Option<Self>>
22 where
23 Self: Sized,
24 {
25 let sql = format!(
26 "SELECT * FROM {} WHERE {} = $1",
27 Self::table_name(),
28 Self::primary_key_name()
29 );
30 let params = vec![DatabaseValue::String(id.to_string())];
31
32 let row = pool.fetch_optional(&sql, ¶ms).await.map_err(|e| {
33 ModelError::Database(format!("Failed to find {}: {}", Self::table_name(), e))
34 })?;
35
36 match row {
37 Some(row) => {
38 let model = Self::from_database_row(row.as_ref())?;
39 Ok(Some(model))
40 }
41 None => Ok(None),
42 }
43 }
44
45 async fn all_abstracted(pool: &Arc<dyn DatabasePool>) -> ModelResult<Vec<Self>>
47 where
48 Self: Sized,
49 {
50 let sql = if Self::uses_soft_deletes() {
51 format!(
52 "SELECT * FROM {} WHERE deleted_at IS NULL",
53 Self::table_name()
54 )
55 } else {
56 format!("SELECT * FROM {}", Self::table_name())
57 };
58 let params = vec![];
59
60 let rows = pool.fetch_all(&sql, ¶ms).await.map_err(|e| {
61 ModelError::Database(format!("Failed to fetch {}: {}", Self::table_name(), e))
62 })?;
63
64 let mut models = Vec::new();
65 for row in rows {
66 let model = Self::from_database_row(row.as_ref())?;
67 models.push(model);
68 }
69
70 Ok(models)
71 }
72
73 async fn count_abstracted(pool: &Arc<dyn DatabasePool>) -> ModelResult<i64>
75 where
76 Self: Sized,
77 {
78 let sql = if Self::uses_soft_deletes() {
79 format!(
80 "SELECT COUNT(*) FROM {} WHERE deleted_at IS NULL",
81 Self::table_name()
82 )
83 } else {
84 format!("SELECT COUNT(*) FROM {}", Self::table_name())
85 };
86 let params = vec![];
87
88 let row = pool.fetch_optional(&sql, ¶ms).await.map_err(|e| {
89 ModelError::Database(format!("Failed to count {}: {}", Self::table_name(), e))
90 })?;
91
92 match row {
93 Some(row) => {
94 let count_value = row.get_by_index(0).map_err(|e| {
95 ModelError::Database(format!("Failed to get count value: {}", e))
96 })?;
97
98 match count_value {
99 DatabaseValue::Int64(count) => Ok(count),
100 DatabaseValue::Int32(count) => Ok(count as i64),
101 _ => Err(ModelError::Database("Invalid count value type".to_string())),
102 }
103 }
104 None => Ok(0),
105 }
106 }
107
108 async fn create_abstracted(pool: &Arc<dyn DatabasePool>, model: Self) -> ModelResult<Self>
110 where
111 Self: Sized,
112 {
113 let fields = model.to_fields();
114
115 if fields.is_empty() {
116 let insert_sql = format!(
117 "INSERT INTO {} DEFAULT VALUES RETURNING *",
118 Self::table_name()
119 );
120 let params = vec![];
121
122 let row = pool
123 .fetch_optional(&insert_sql, ¶ms)
124 .await
125 .map_err(|e| {
126 ModelError::Database(format!("Failed to create {}: {}", Self::table_name(), e))
127 })?;
128
129 match row {
130 Some(row) => Self::from_database_row(row.as_ref()),
131 None => Err(ModelError::Database(
132 "Failed to get inserted row".to_string(),
133 )),
134 }
135 } else {
136 let field_names: Vec<String> = fields.keys().cloned().collect();
137 let field_placeholders: Vec<String> =
138 (1..=field_names.len()).map(|i| format!("${}", i)).collect();
139
140 let insert_sql = format!(
141 "INSERT INTO {} ({}) VALUES ({}) RETURNING *",
142 Self::table_name(),
143 field_names.join(", "),
144 field_placeholders.join(", ")
145 );
146
147 let params: Vec<DatabaseValue> = field_names
148 .iter()
149 .filter_map(|name| fields.get(name))
150 .map(DatabaseValue::from_json_value)
151 .collect();
152
153 let row = pool
154 .fetch_optional(&insert_sql, ¶ms)
155 .await
156 .map_err(|e| {
157 ModelError::Database(format!("Failed to create {}: {}", Self::table_name(), e))
158 })?;
159
160 match row {
161 Some(row) => Self::from_database_row(row.as_ref()),
162 None => Err(ModelError::Database(
163 "Failed to get inserted row".to_string(),
164 )),
165 }
166 }
167 }
168
169 async fn update_abstracted(&self, pool: &Arc<dyn DatabasePool>) -> ModelResult<()>
171 where
172 Self: Sized,
173 {
174 if let Some(pk) = self.primary_key() {
175 let fields = self.to_fields();
176 let pk_name = Self::primary_key_name();
177
178 let update_fields: Vec<String> = fields
179 .keys()
180 .filter(|&field| field != pk_name)
181 .enumerate()
182 .map(|(i, field)| format!("{} = ${}", field, i + 1))
183 .collect();
184
185 if update_fields.is_empty() {
186 return Ok(());
187 }
188
189 let update_sql = format!(
190 "UPDATE {} SET {} WHERE {} = ${}",
191 Self::table_name(),
192 update_fields.join(", "),
193 pk_name,
194 update_fields.len() + 1
195 );
196
197 let mut params: Vec<DatabaseValue> = fields
198 .iter()
199 .filter(|(field, _)| *field != pk_name)
200 .map(|(_, value)| DatabaseValue::from_json_value(value))
201 .collect();
202
203 params.push(DatabaseValue::String(pk.to_string()));
204
205 pool.execute(&update_sql, ¶ms).await.map_err(|e| {
206 ModelError::Database(format!("Failed to update {}: {}", Self::table_name(), e))
207 })?;
208
209 Ok(())
210 } else {
211 Err(ModelError::MissingPrimaryKey)
212 }
213 }
214
215 async fn delete_abstracted(self, pool: &Arc<dyn DatabasePool>) -> ModelResult<()>
217 where
218 Self: Sized,
219 {
220 if let Some(pk) = self.primary_key() {
221 let sql = if Self::uses_soft_deletes() {
222 format!(
223 "UPDATE {} SET deleted_at = NOW() WHERE {} = $1",
224 Self::table_name(),
225 Self::primary_key_name()
226 )
227 } else {
228 format!(
229 "DELETE FROM {} WHERE {} = $1",
230 Self::table_name(),
231 Self::primary_key_name()
232 )
233 };
234
235 let params = vec![DatabaseValue::String(pk.to_string())];
236
237 pool.execute(&sql, ¶ms).await.map_err(|e| {
238 ModelError::Database(format!("Failed to delete {}: {}", Self::table_name(), e))
239 })?;
240
241 Ok(())
242 } else {
243 Err(ModelError::MissingPrimaryKey)
244 }
245 }
246}
247
248impl<T: Model> ModelAbstracted for T {}
250
251impl DatabaseValue {
252 pub fn from_json_value(value: &serde_json::Value) -> DatabaseValue {
254 match value {
255 serde_json::Value::Null => DatabaseValue::Null,
256 serde_json::Value::Bool(b) => DatabaseValue::Bool(*b),
257 serde_json::Value::Number(n) => {
258 if let Some(i) = n.as_i64() {
259 if i >= i32::MIN as i64 && i <= i32::MAX as i64 {
261 DatabaseValue::Int32(i as i32)
262 } else {
263 DatabaseValue::Int64(i)
264 }
265 } else if let Some(f) = n.as_f64() {
266 DatabaseValue::Float64(f)
267 } else {
268 DatabaseValue::String(n.to_string())
269 }
270 }
271 serde_json::Value::String(s) => DatabaseValue::String(s.clone()),
272 serde_json::Value::Array(_) | serde_json::Value::Object(_) => {
273 DatabaseValue::Json(value.clone())
274 }
275 }
276 }
277}