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