1#[macro_export]
2#[doc(hidden)]
3macro_rules! model_timestamps_fields {
4 (true) => {
5 pub created_at: Option<DateTime>,
6 pub updated_at: Option<DateTime>,
7 };
8 (false) => {};
9}
10
11#[macro_export]
12#[doc(hidden)]
13macro_rules! model_behavior_impl {
14 (true) => {
15 #[$crate::async_trait]
16 impl $crate::sea_orm::entity::prelude::ActiveModelBehavior for ActiveModel {
17 async fn before_save<C>(mut self, _db: &C, insert: bool) -> Result<Self, $crate::sea_orm::DbErr>
18 where
19 C: $crate::sea_orm::ConnectionTrait,
20 {
21 let now = $crate::chrono::Local::now().naive_local();
22 if insert {
23 self.created_at = $crate::sea_orm::ActiveValue::Set(Some(now));
24 }
25 self.updated_at = $crate::sea_orm::ActiveValue::Set(Some(now));
26 Ok(self)
27 }
28 }
29 };
30 (false) => {
31 impl $crate::sea_orm::entity::prelude::ActiveModelBehavior for ActiveModel {}
32 };
33}
34
35#[macro_export]
36#[doc(hidden)]
37macro_rules! model_impl {
38 (
40 table: $table_name:expr,
41 timestamps: true,
42 fillable: [ $($fill:ident),* ],
43 guarded: [ $($guard:ident),* ],
44 Model {
45 $($(#[$field_meta:meta])* $field_vis:vis $field_name:ident : $field_type:ty),* $(,)?
46 }
47 ) => {
48 #[derive(Clone, Debug, PartialEq, $crate::sea_orm::entity::prelude::DeriveEntityModel, $crate::serde::Serialize, $crate::serde::Deserialize)]
49 #[sea_orm(table_name = $table_name)]
50 pub struct Model {
51 $($(#[$field_meta])* $field_vis $field_name : $field_type,)*
52 pub created_at: Option<DateTime>,
53 pub updated_at: Option<DateTime>,
54 }
55
56 #[derive(Copy, Clone, Debug, $crate::sea_orm::entity::prelude::EnumIter, $crate::sea_orm::entity::prelude::DeriveRelation)]
57 pub enum Relation {}
58
59 $crate::model_behavior_impl!(true);
60
61 impl Entity {
62 pub async fn create<C>(db: &C, data: $crate::serde_json::Value) -> Result<Model, $crate::sea_orm::DbErr>
63 where
64 C: $crate::sea_orm::ConnectionTrait,
65 {
66 let active = ActiveModel::fill(&data)?;
67 <ActiveModel as $crate::sea_orm::ActiveModelTrait>::insert(active, db).await
68 }
69 }
70
71 impl Model {
72 pub async fn create<C>(db: &C, data: $crate::serde_json::Value) -> Result<Self, $crate::sea_orm::DbErr>
73 where
74 C: $crate::sea_orm::ConnectionTrait,
75 {
76 let active = ActiveModel::fill(&data)?;
77 <ActiveModel as $crate::sea_orm::ActiveModelTrait>::insert(active, db).await
78 }
79 }
80
81 impl ActiveModel {
82 pub fn fill(json: &$crate::serde_json::Value) -> Result<Self, $crate::sea_orm::DbErr> {
83 let mut sanitized = $crate::serde_json::Map::new();
84 if let Some(obj) = json.as_object() {
85 let fillable: Vec<&str> = vec![ $( stringify!($fill) ),* ];
86 let guarded: Vec<&str> = vec![ $( stringify!($guard) ),* ];
87
88 if !fillable.is_empty() {
89 for key in fillable {
90 if let Some(val) = obj.get(key) {
91 sanitized.insert(key.to_string(), val.clone());
92 }
93 }
94 } else if !guarded.is_empty() {
95 for (key, val) in obj {
96 if !guarded.contains(&key.as_str()) {
97 sanitized.insert(key.clone(), val.clone());
98 }
99 }
100 } else {
101 for (key, val) in obj {
102 sanitized.insert(key.clone(), val.clone());
103 }
104 }
105 }
106 Self::from_json($crate::serde_json::Value::Object(sanitized))
107 }
108 }
109 };
110
111 (
113 table: $table_name:expr,
114 timestamps: false,
115 fillable: [ $($fill:ident),* ],
116 guarded: [ $($guard:ident),* ],
117 Model {
118 $($(#[$field_meta:meta])* $field_vis:vis $field_name:ident : $field_type:ty),* $(,)?
119 }
120 ) => {
121 #[derive(Clone, Debug, PartialEq, $crate::sea_orm::entity::prelude::DeriveEntityModel, $crate::serde::Serialize, $crate::serde::Deserialize)]
122 #[sea_orm(table_name = $table_name)]
123 pub struct Model {
124 $($(#[$field_meta])* $field_vis $field_name : $field_type,)*
125 }
126
127 #[derive(Copy, Clone, Debug, $crate::sea_orm::entity::prelude::EnumIter, $crate::sea_orm::entity::prelude::DeriveRelation)]
128 pub enum Relation {}
129
130 $crate::model_behavior_impl!(false);
131
132 impl Entity {
133 pub async fn create<C>(db: &C, data: $crate::serde_json::Value) -> Result<Model, $crate::sea_orm::DbErr>
134 where
135 C: $crate::sea_orm::ConnectionTrait,
136 {
137 let active = ActiveModel::fill(&data)?;
138 <ActiveModel as $crate::sea_orm::ActiveModelTrait>::insert(active, db).await
139 }
140 }
141
142 impl Model {
143 pub async fn create<C>(db: &C, data: $crate::serde_json::Value) -> Result<Self, $crate::sea_orm::DbErr>
144 where
145 C: $crate::sea_orm::ConnectionTrait,
146 {
147 let active = ActiveModel::fill(&data)?;
148 <ActiveModel as $crate::sea_orm::ActiveModelTrait>::insert(active, db).await
149 }
150 }
151
152 impl ActiveModel {
153 pub fn fill(json: &$crate::serde_json::Value) -> Result<Self, $crate::sea_orm::DbErr> {
154 let mut sanitized = $crate::serde_json::Map::new();
155 if let Some(obj) = json.as_object() {
156 let fillable: Vec<&str> = vec![ $( stringify!($fill) ),* ];
157 let guarded: Vec<&str> = vec![ $( stringify!($guard) ),* ];
158
159 if !fillable.is_empty() {
160 for key in fillable {
161 if let Some(val) = obj.get(key) {
162 sanitized.insert(key.to_string(), val.clone());
163 }
164 }
165 } else if !guarded.is_empty() {
166 for (key, val) in obj {
167 if !guarded.contains(&key.as_str()) {
168 sanitized.insert(key.clone(), val.clone());
169 }
170 }
171 } else {
172 for (key, val) in obj {
173 sanitized.insert(key.clone(), val.clone());
174 }
175 }
176 }
177 Self::from_json($crate::serde_json::Value::Object(sanitized))
178 }
179 }
180 };
181}
182
183#[macro_export]
184macro_rules! model {
185 (
187 table: $table_name:expr,
188 timestamps: true,
189 fillable: [ $($fill:ident),* ],
190 guarded: [ $($guard:ident),* ],
191 Model {
192 $($(#[$field_meta:meta])* $field_vis:vis $field_name:ident : $field_type:ty),* $(,)?
193 }
194 ) => {
195 $crate::model_impl! {
196 table: $table_name,
197 timestamps: true,
198 fillable: [ $($fill),* ],
199 guarded: [ $($guard),* ],
200 Model {
201 $($(#[$field_meta])* $field_vis $field_name : $field_type,)*
202 }
203 }
204 };
205
206 (
208 table: $table_name:expr,
209 timestamps: false,
210 fillable: [ $($fill:ident),* ],
211 guarded: [ $($guard:ident),* ],
212 Model {
213 $($(#[$field_meta:meta])* $field_vis:vis $field_name:ident : $field_type:ty),* $(,)?
214 }
215 ) => {
216 $crate::model_impl! {
217 table: $table_name,
218 timestamps: false,
219 fillable: [ $($fill),* ],
220 guarded: [ $($guard),* ],
221 Model {
222 $($(#[$field_meta])* $field_vis $field_name : $field_type,)*
223 }
224 }
225 };
226
227 (
229 table: $table_name:expr,
230 timestamps: $ts:ident,
231 fillable: [ $($fill:ident),* ],
232 Model {
233 $($(#[$field_meta:meta])* $field_vis:vis $field_name:ident : $field_type:ty),* $(,)?
234 }
235 ) => {
236 $crate::model! {
237 table: $table_name,
238 timestamps: $ts,
239 fillable: [ $($fill),* ],
240 guarded: [ ],
241 Model {
242 $($(#[$field_meta])* $field_vis $field_name : $field_type,)*
243 }
244 }
245 };
246
247 (
249 table: $table_name:expr,
250 timestamps: $ts:ident,
251 guarded: [ $($guard:ident),* ],
252 Model {
253 $($(#[$field_meta:meta])* $field_vis:vis $field_name:ident : $field_type:ty),* $(,)?
254 }
255 ) => {
256 $crate::model! {
257 table: $table_name,
258 timestamps: $ts,
259 fillable: [ ],
260 guarded: [ $($guard),* ],
261 Model {
262 $($(#[$field_meta])* $field_vis $field_name : $field_type,)*
263 }
264 }
265 };
266
267 (
269 table: $table_name:expr,
270 timestamps: $ts:ident,
271 Model {
272 $($(#[$field_meta:meta])* $field_vis:vis $field_name:ident : $field_type:ty),* $(,)?
273 }
274 ) => {
275 $crate::model! {
276 table: $table_name,
277 timestamps: $ts,
278 fillable: [ ],
279 guarded: [ ],
280 Model {
281 $($(#[$field_meta])* $field_vis $field_name : $field_type,)*
282 }
283 }
284 };
285
286 (
288 table: $table_name:expr,
289 fillable: [ $($fill:ident),* ],
290 guarded: [ $($guard:ident),* ],
291 Model {
292 $($(#[$field_meta:meta])* $field_vis:vis $field_name:ident : $field_type:ty),* $(,)?
293 }
294 ) => {
295 $crate::model! {
296 table: $table_name,
297 timestamps: true,
298 fillable: [ $($fill),* ],
299 guarded: [ $($guard),* ],
300 Model {
301 $($(#[$field_meta])* $field_vis $field_name : $field_type,)*
302 }
303 }
304 };
305
306 (
308 table: $table_name:expr,
309 fillable: [ $($fill:ident),* ],
310 Model {
311 $($(#[$field_meta:meta])* $field_vis:vis $field_name:ident : $field_type:ty),* $(,)?
312 }
313 ) => {
314 $crate::model! {
315 table: $table_name,
316 timestamps: true,
317 fillable: [ $($fill),* ],
318 guarded: [ ],
319 Model {
320 $($(#[$field_meta])* $field_vis $field_name : $field_type,)*
321 }
322 }
323 };
324
325 (
327 table: $table_name:expr,
328 guarded: [ $($guard:ident),* ],
329 Model {
330 $($(#[$field_meta:meta])* $field_vis:vis $field_name:ident : $field_type:ty),* $(,)?
331 }
332 ) => {
333 $crate::model! {
334 table: $table_name,
335 timestamps: true,
336 fillable: [ ],
337 guarded: [ $($guard),* ],
338 Model {
339 $($(#[$field_meta])* $field_vis $field_name : $field_type,)*
340 }
341 }
342 };
343
344 (
346 table: $table_name:expr,
347 Model {
348 $($(#[$field_meta:meta])* $field_vis:vis $field_name:ident : $field_type:ty),* $(,)?
349 }
350 ) => {
351 $crate::model! {
352 table: $table_name,
353 timestamps: true,
354 fillable: [ ],
355 guarded: [ ],
356 Model {
357 $($(#[$field_meta])* $field_vis $field_name : $field_type,)*
358 }
359 }
360 };
361}
362
363#[macro_export]
364macro_rules! seeder {
365 (
366 $name:ident,
367 run($db:ident) $body:block
368 ) => {
369 pub struct $name;
370
371 #[$crate::async_trait]
372 impl $crate::seeder::SeederTrait for $name {
373 async fn run(&self, $db: &$crate::sea_orm::DatabaseConnection) -> Result<(), $crate::sea_orm::DbErr> {
374 $body
375 }
376 }
377 };
378
379 (
380 run($db:ident) $body:block
381 ) => {
382 $crate::seeder! {
383 DatabaseSeeder,
384 run($db) $body
385 }
386 };
387}