1#[macro_export]
2#[doc(hidden)]
3macro_rules! __eager_load_belongs_to {
4 ($relation_name:ident, $fk:ident, $lk:ident, $related_model:path, $db:expr, $models:expr) => {
5 let ids: Vec<_> = $models.iter()
6 .map(|m| $crate::serde_json::to_value(&m.$fk).unwrap_or($crate::serde_json::Value::Null))
7 .filter(|v| !v.is_null())
8 .collect();
9 let related = <$related_model>::query($db).where_in(stringify!($lk), ids).get::<$related_model>().await?;
10 for m in &mut *$models {
11 m.$relation_name = related.iter().find(|r| {
12 let r_val = $crate::serde_json::to_value(&r.$lk).unwrap_or($crate::serde_json::Value::Null);
13 let m_val = $crate::serde_json::to_value(&m.$fk).unwrap_or($crate::serde_json::Value::Null);
14 r_val == m_val && !r_val.is_null()
15 }).cloned();
16 }
17 };
18}
19
20#[macro_export]
21#[doc(hidden)]
22macro_rules! __eager_load_has_many {
23 ($relation_name:ident, $fk:ident, $lk:ident, $related_model:path, $db:expr, $models:expr) => {
24 let ids: Vec<_> = $models.iter()
25 .map(|m| $crate::serde_json::to_value(&m.$lk).unwrap_or($crate::serde_json::Value::Null))
26 .filter(|v| !v.is_null())
27 .collect();
28 let related = <$related_model>::query($db).where_in(stringify!($fk), ids).get::<$related_model>().await?;
29 for m in &mut *$models {
30 let matched: Vec<$related_model> = related.iter().filter(|r| {
31 let r_val = $crate::serde_json::to_value(&r.$fk).unwrap_or($crate::serde_json::Value::Null);
32 let m_val = $crate::serde_json::to_value(&m.$lk).unwrap_or($crate::serde_json::Value::Null);
33 r_val == m_val && !r_val.is_null()
34 }).cloned().collect();
35 m.$relation_name = Some(matched);
36 }
37 };
38}
39
40#[macro_export]
41#[doc(hidden)]
42macro_rules! __eager_load_dispatcher {
43 (belongs_to, $relation_name:ident, $fk:ident, $lk:ident, $related_model:path, $db:expr, $models:expr) => {
44 $crate::__eager_load_belongs_to!($relation_name, $fk, $lk, $related_model, $db, $models);
45 };
46 (has_many, $relation_name:ident, $fk:ident, $lk:ident, $related_model:path, $db:expr, $models:expr) => {
47 $crate::__eager_load_has_many!($relation_name, $fk, $lk, $related_model, $db, $models);
48 };
49}
50
51#[macro_export]
52macro_rules! model {
53 (
54 table: $table_name:expr,
55 $(timestamps: $ts:expr,)?
56 $(soft_deletes: $sd:expr,)?
57 $(fillable: [ $($fill:ident),* ],)?
58 $(guarded: [ $($guard:ident),* ],)?
59 $(scopes: {
60 $( $scope_name:ident ( $($arg_name:ident : $arg_type:ty),* ) => $scope_body:expr ),* $(,)?
61 },)?
62 $(global_scopes: {
63 $( $gs_name:ident => $gs_body:expr ),* $(,)?
64 },)?
65 $(relations: {
66 $( $relation_name:ident ( $rel_type:ident, foreign_key: $fk:ident, local_key: $lk:ident ) => $related_model:path ),* $(,)?
67 },)?
68 Model {
69 $($(#[$field_meta:meta])* $field_vis:vis $field_name:ident : $field_type:ty),* $(,)?
70 }
71 ) => {
72 use $crate::serde as _serde;
73
74 #[derive(Clone, Debug, PartialEq, _serde::Serialize, _serde::Deserialize)]
75 #[serde(crate = "_serde")]
76 pub struct Model {
77 $($(#[$field_meta])* $field_vis $field_name : $field_type,)*
78 }
79
80 pub type Entity = Model;
81
82 $(
83 pub trait ModelScopes<'a> {
84 $(
85 fn $scope_name(self, $($arg_name: $arg_type),*) -> Self;
86 )*
87 }
88
89 impl<'a> ModelScopes<'a> for $crate::database::QueryBuilder<'a> {
90 $(
91 fn $scope_name(self, $($arg_name: $arg_type),*) -> Self {
92 let f: fn($crate::database::QueryBuilder<'a>, $($arg_type),*) -> $crate::database::QueryBuilder<'a> = $scope_body;
93 f(self, $($arg_name),*)
94 }
95 )*
96 }
97 )?
98
99 pub struct ModelQuery<'a> {
100 builder: $crate::database::QueryBuilder<'a>,
101 relations: Vec<String>,
102 }
103
104 impl<'a> ModelQuery<'a> {
105 pub fn new(db: &'a $crate::sql::AnyPool) -> Self {
106 Self {
107 builder: Model::query(db),
108 relations: Vec::new(),
109 }
110 }
111
112 pub fn with(mut self, relations: &[&str]) -> Self {
113 self.relations.extend(relations.iter().map(|r| r.to_string()));
114 self
115 }
116
117 pub fn where_(mut self, column: &str, value: impl $crate::serde::Serialize) -> Self {
118 self.builder = self.builder.where_(column, value);
119 self
120 }
121
122 pub fn where_op(mut self, column: &str, operator: &str, value: impl $crate::serde::Serialize) -> Self {
123 self.builder = self.builder.where_op(column, operator, value);
124 self
125 }
126
127 pub fn where_raw(mut self, sql: &str, binds: Vec<$crate::serde_json::Value>) -> Self {
128 self.builder = self.builder.where_raw(sql, binds);
129 self
130 }
131
132 pub fn order_by(mut self, column: &str, direction: &str) -> Self {
133 self.builder = self.builder.order_by(column, direction);
134 self
135 }
136
137 pub fn limit(mut self, limit: usize) -> Self {
138 self.builder = self.builder.limit(limit);
139 self
140 }
141
142 pub async fn get(self) -> Result<Vec<Model>, $crate::sql::Error> {
143 let db = self.builder.pool();
144 let mut models = self.builder.get::<Model>().await?;
145
146 $(
148 for rel in &self.relations {
149 match rel.as_str() {
150 $(
151 stringify!($relation_name) => {
152 $crate::__eager_load_dispatcher!($rel_type, $relation_name, $fk, $lk, $related_model, db, &mut models);
153 }
154 )*
155 _ => {}
156 }
157 }
158 )?
159
160 Ok(models)
161 }
162
163 pub async fn first(self) -> Result<Option<Model>, $crate::sql::Error> {
164 let mut models = self.get().await?;
165 if models.is_empty() {
166 Ok(None)
167 } else {
168 Ok(Some(models.remove(0)))
169 }
170 }
171 }
172
173 impl Model {
174 pub fn with<'a>(db: &'a $crate::sql::AnyPool, relations: &[&str]) -> ModelQuery<'a> {
176 ModelQuery::new(db).with(relations)
177 }
178
179 pub fn query<'a>(db: &'a $crate::sql::AnyPool) -> $crate::database::QueryBuilder<'a> {
181 let mut q = $crate::database::DB::table(db, $table_name);
182 let mut has_soft_deletes = false;
183 $(
184 if $sd {
185 has_soft_deletes = true;
186 }
187 )?
188 if has_soft_deletes {
189 q = q.where_raw("`deleted_at` IS NULL", vec![]);
190 }
191
192 $(
194 $(
195 q = {
196 let f: fn($crate::database::QueryBuilder<'a>) -> $crate::database::QueryBuilder<'a> = $gs_body;
197 f(q)
198 };
199 )*
200 )?
201
202 q
203 }
204
205 pub fn query_without_global_scopes<'a>(db: &'a $crate::sql::AnyPool) -> $crate::database::QueryBuilder<'a> {
207 $crate::database::DB::table(db, $table_name)
208 }
209
210 pub async fn all(db: &$crate::sql::AnyPool) -> Result<Vec<Self>, $crate::sql::Error> {
212 Self::query(db).get::<Self>().await
213 }
214
215 pub async fn first(db: &$crate::sql::AnyPool) -> Result<Option<Self>, $crate::sql::Error> {
217 Self::query(db).first::<Self>().await
218 }
219
220 pub async fn find(db: &$crate::sql::AnyPool, id: i32) -> Result<Option<Self>, $crate::sql::Error> {
222 Self::query(db).where_("id", id).first::<Self>().await
223 }
224
225 pub async fn count(db: &$crate::sql::AnyPool) -> Result<i64, $crate::sql::Error> {
227 Self::query(db).count().await
228 }
229
230 pub async fn destroy(db: &$crate::sql::AnyPool, id: i32) -> Result<u64, $crate::sql::Error> {
232 let mut has_soft_deletes = false;
233 $(
234 if $sd {
235 has_soft_deletes = true;
236 }
237 )?
238 if has_soft_deletes {
239 $crate::database::DB::table(db, $table_name)
240 .where_("id", id)
241 .update($crate::serde_json::json!({
242 "deleted_at": $crate::chrono::Utc::now().naive_utc()
243 }))
244 .await
245 } else {
246 $crate::database::DB::table(db, $table_name).where_("id", id).delete().await
247 }
248 }
249
250 pub fn query_with_trashed<'a>(db: &'a $crate::sql::AnyPool) -> $crate::database::QueryBuilder<'a> {
252 $crate::database::DB::table(db, $table_name)
253 }
254
255 pub fn query_only_trashed<'a>(db: &'a $crate::sql::AnyPool) -> $crate::database::QueryBuilder<'a> {
257 $crate::database::DB::table(db, $table_name).where_raw("`deleted_at` IS NOT NULL", vec![])
258 }
259
260 pub async fn restore(db: &$crate::sql::AnyPool, id: i32) -> Result<u64, $crate::sql::Error> {
262 $crate::database::DB::table(db, $table_name)
263 .where_("id", id)
264 .update($crate::serde_json::json!({
265 "deleted_at": $crate::serde_json::Value::Null
266 }))
267 .await
268 }
269
270 pub async fn force_destroy(db: &$crate::sql::AnyPool, id: i32) -> Result<u64, $crate::sql::Error> {
272 $crate::database::DB::table(db, $table_name).where_("id", id).delete().await
273 }
274
275 $(
276 $(
277 pub fn $scope_name<'a>(db: &'a $crate::sql::AnyPool, $($arg_name: $arg_type),*) -> $crate::database::QueryBuilder<'a> {
278 use self::ModelScopes;
279 Self::query(db).$scope_name($($arg_name),*)
280 }
281 )*
282 )?
283
284 pub async fn create(db: &$crate::sql::AnyPool, mut data: $crate::serde_json::Value) -> Result<Self, $crate::sql::Error> {
285 let mut data_to_insert = data.clone();
286
287 $(
289 let fillable_keys: Vec<&str> = vec![ $( stringify!($fill) ),* ];
290 if let Some(obj) = data.as_object() {
291 let mut filtered_obj = $crate::serde_json::Map::new();
292 for key in fillable_keys {
293 if let Some(val) = obj.get(key) {
294 filtered_obj.insert(key.to_string(), val.clone());
295 }
296 }
297 data_to_insert = $crate::serde_json::Value::Object(filtered_obj);
298 }
299 )?
300
301 $(
303 let guarded_keys: Vec<&str> = vec![ $( stringify!($guard) ),* ];
304 if let Some(obj) = data_to_insert.as_object_mut() {
305 for key in guarded_keys {
306 obj.remove(key);
307 }
308 }
309 )?
310
311 let res = $crate::database::DB::table(db, $table_name).insert_get_id(data_to_insert.clone()).await;
312 match res {
313 Ok(id) => {
314 if let Some(obj) = data.as_object_mut() {
315 if !obj.contains_key("id") {
316 obj.insert("id".to_string(), $crate::serde_json::json!(id));
317 }
318 }
319 }
320 Err(e) => {
321 println!("insert_get_id failed: {:?}", e);
322 $crate::database::DB::table(db, $table_name).insert(data_to_insert.clone()).await?;
323 }
324 }
325 let parsed = $crate::serde_json::from_value::<Self>(data)
326 .map_err(|e| $crate::sql::Error::Protocol(format!("Deserialization error: {}", e)))?;
327 Ok(parsed)
328 }
329 }
330 };
331}
332
333#[macro_export]
334macro_rules! seeder {
335 (
336 $name:ident,
337 run($db:ident) $body:block
338 ) => {
339 pub struct $name;
340
341 #[$crate::async_trait]
342 impl $crate::seeder::SeederTrait for $name {
343 async fn run<'a>(&'a self, $db: &'a $crate::sql::AnyPool) -> Result<(), $crate::sql::Error> $body
344 }
345 };
346
347 (
348 run($db:ident) $body:block
349 ) => {
350 $crate::seeder! {
351 DatabaseSeeder,
352 run($db) $body
353 }
354 };
355}