1use super::{IntoSqlValue, ModelHelper, Schema};
2use std::fmt::Display;
3use zino_core::{
4 JsonValue, Map, bail,
5 datetime::DateTime,
6 error::Error,
7 extension::{JsonObjectExt, JsonValueExt},
8 model::{ModelHooks, Mutation, Query},
9 validation::Validation,
10 warn,
11};
12
13pub trait ModelAccessor<K>: Schema<PrimaryKey = K>
17where
18 K: Default + Display + PartialEq,
19{
20 fn id(&self) -> &K;
22
23 #[inline]
25 fn name(&self) -> &str {
26 ""
27 }
28
29 #[inline]
31 fn namespace(&self) -> &str {
32 ""
33 }
34
35 #[inline]
37 fn visibility(&self) -> &str {
38 "Private"
39 }
40
41 #[inline]
43 fn status(&self) -> &str {
44 "Active"
45 }
46
47 #[inline]
49 fn description(&self) -> &str {
50 ""
51 }
52
53 #[inline]
55 fn extra(&self) -> Option<&Map> {
56 None
57 }
58
59 #[inline]
61 fn created_at(&self) -> DateTime {
62 DateTime::default()
63 }
64
65 #[inline]
67 fn updated_at(&self) -> DateTime {
68 DateTime::default()
69 }
70
71 #[inline]
73 fn deleted_at(&self) -> Option<DateTime> {
74 None
75 }
76
77 #[inline]
79 fn version(&self) -> u64 {
80 0
81 }
82
83 #[inline]
85 fn edition(&self) -> u32 {
86 0
87 }
88
89 fn snapshot(&self) -> Map {
91 let mut snapshot = Map::new();
92 snapshot.upsert(Self::PRIMARY_KEY_NAME, self.primary_key_value());
93 snapshot.upsert("name", self.name());
94 snapshot.upsert("status", self.status());
95 snapshot.upsert("updated_at", self.updated_at());
96 snapshot.upsert("version", self.version());
97 snapshot
98 }
99
100 #[inline]
102 fn has_name(&self) -> bool {
103 !self.name().is_empty()
104 }
105
106 #[inline]
108 fn has_namespace_prefix(&self, namespace: &str) -> bool {
109 self.namespace()
110 .strip_prefix(namespace)
111 .is_some_and(|s| s.is_empty() || s.starts_with(':'))
112 }
113
114 #[inline]
116 fn has_namespace_suffix(&self, namespace: &str) -> bool {
117 self.namespace()
118 .strip_suffix(namespace)
119 .is_some_and(|s| s.is_empty() || s.ends_with(':'))
120 }
121
122 #[inline]
124 fn has_visibility(&self, visibility: &str) -> bool {
125 self.visibility().eq_ignore_ascii_case(visibility)
126 }
127
128 #[inline]
130 fn is_public(&self) -> bool {
131 self.visibility().eq_ignore_ascii_case("Public")
132 }
133
134 #[inline]
136 fn is_internal(&self) -> bool {
137 self.visibility().eq_ignore_ascii_case("Internal")
138 }
139
140 #[inline]
142 fn is_protected(&self) -> bool {
143 self.visibility().eq_ignore_ascii_case("Protected")
144 }
145
146 #[inline]
148 fn is_private(&self) -> bool {
149 self.visibility().eq_ignore_ascii_case("Private")
150 }
151
152 #[inline]
154 fn has_status(&self, status: &str) -> bool {
155 self.status().eq_ignore_ascii_case(status)
156 }
157
158 #[inline]
160 fn is_active(&self) -> bool {
161 self.status().eq_ignore_ascii_case("Active")
162 }
163
164 #[inline]
166 fn is_inactive(&self) -> bool {
167 self.status().eq_ignore_ascii_case("Inactive")
168 }
169
170 #[inline]
172 fn is_locked(&self) -> bool {
173 self.status().eq_ignore_ascii_case("Locked")
174 }
175
176 #[inline]
178 fn is_deleted(&self) -> bool {
179 self.status().eq_ignore_ascii_case("Deleted")
180 }
181
182 #[inline]
184 fn is_archived(&self) -> bool {
185 self.status().eq_ignore_ascii_case("Archived")
186 }
187
188 #[inline]
190 fn has_description(&self) -> bool {
191 !self.description().is_empty()
192 }
193
194 #[inline]
196 fn get_extra_value(&self, key: &str) -> Option<&JsonValue> {
197 self.extra()?.get(key)
198 }
199
200 #[inline]
202 fn next_version(&self) -> u64 {
203 self.version() + 1
204 }
205
206 fn current_version_filters(&self) -> Map {
208 let mut filters = Map::new();
209 filters.upsert(Self::PRIMARY_KEY_NAME, self.id().to_string());
210 filters.upsert("version", self.version());
211 filters
212 }
213
214 fn current_version_query(&self) -> Query {
216 let mut query = Self::default_query();
217 query.append_filters(&mut self.current_version_filters());
218 query
219 }
220
221 fn next_version_filters(&self) -> Map {
223 let mut filters = Map::new();
224 filters.upsert(Self::PRIMARY_KEY_NAME, self.id().to_string());
225 filters.upsert("version", self.next_version());
226 filters
227 }
228
229 fn next_version_updates(&self) -> Map {
231 let mut updates = Map::new();
232 updates.upsert("updated_at", DateTime::now().into_sql_value());
233 updates.upsert("version", self.next_version());
234 updates
235 }
236
237 fn next_version_mutation(&self, updates: &mut Map) -> Mutation {
239 let mut mutation = Self::default_mutation();
240 mutation.append_updates(updates);
241 mutation.append_updates(&mut self.next_version_updates());
242 mutation
243 }
244
245 #[inline]
247 fn next_edition(&self) -> u32 {
248 self.edition() + 1
249 }
250
251 fn current_edition_filters(&self) -> Map {
253 let mut filters = Map::new();
254 filters.upsert(Self::PRIMARY_KEY_NAME, self.id().to_string());
255 filters.upsert("edition", self.edition());
256 filters
257 }
258
259 fn current_edition_query(&self) -> Query {
261 let mut query = Self::default_query();
262 query.append_filters(&mut self.current_edition_filters());
263 query
264 }
265
266 fn next_edition_filters(&self) -> Map {
268 let mut filters = Map::new();
269 filters.upsert(Self::PRIMARY_KEY_NAME, self.id().to_string());
270 filters.upsert("edition", self.next_edition());
271 filters
272 }
273
274 fn next_edition_updates(&self) -> Map {
276 let mut updates = Map::new();
277 updates.upsert("updated_at", DateTime::now().into_sql_value());
278 updates.upsert("version", self.next_version());
279 updates.upsert("edition", self.next_edition());
280 updates
281 }
282
283 fn next_edition_mutation(&self, updates: &mut Map) -> Mutation {
285 let mut mutation = Self::default_mutation();
286 mutation.append_updates(updates);
287 mutation.append_updates(&mut self.next_edition_updates());
288 mutation
289 }
290
291 fn soft_delete_mutation(&self) -> Mutation {
293 let mut mutation = Self::default_mutation();
294 let mut updates = self.next_edition_updates();
295 updates.upsert("status", "Deleted");
296 mutation.append_updates(&mut updates);
297 mutation
298 }
299
300 fn lock_mutation(&self) -> Mutation {
302 let mut mutation = Self::default_mutation();
303 let mut updates = self.next_edition_updates();
304 updates.upsert("status", "Locked");
305 mutation.append_updates(&mut updates);
306 mutation
307 }
308
309 fn archive_mutation(&self) -> Mutation {
311 let mut mutation = Self::default_mutation();
312 let mut updates = self.next_edition_updates();
313 updates.upsert("status", "Archived");
314 mutation.append_updates(&mut updates);
315 mutation
316 }
317
318 fn default_snapshot_query() -> Query {
320 let mut query = Query::default();
321 let fields = [
322 Self::PRIMARY_KEY_NAME,
323 "name",
324 "status",
325 "updated_at",
326 "version",
327 ];
328 query.allow_fields(&fields);
329 query.deny_fields(Self::write_only_fields());
330 query
331 }
332
333 fn default_list_query() -> Query {
335 let mut query = Query::default();
336 let ignored_fields = [Self::write_only_fields(), &["extra"]].concat();
337 query.allow_fields(Self::fields());
338 query.deny_fields(&ignored_fields);
339 query.add_filter("status", Map::from_entry("$ne", "Deleted"));
340 query.order_desc("updated_at");
341 query
342 }
343
344 async fn check_constraints(&self) -> Result<Validation, Error> {
346 let mut validation = Validation::new();
347 if self.id() == &K::default() {
348 validation.record(Self::PRIMARY_KEY_NAME, "should not be a default value");
349 }
350 Ok(validation)
351 }
352
353 async fn fetch(query: &Query) -> Result<Vec<Map>, Error> {
355 let mut models = Self::find(query).await?;
356 let translate_enabled = query.translate_enabled();
357 for model in models.iter_mut() {
358 Self::after_decode(model).await?;
359 translate_enabled.then(|| Self::translate_model(model));
360 }
361 Ok(models)
362 }
363
364 async fn fetch_by_id(id: &K) -> Result<Map, Error> {
366 let mut model = Self::find_by_id::<Map>(id)
367 .await?
368 .ok_or_else(|| warn!("404 Not Found: cannot find the model `{}`", id))?;
369 Self::translate_model(&mut model);
370 Self::after_decode(&mut model).await?;
371 Ok(model)
372 }
373
374 async fn soft_delete_by_id(id: &K) -> Result<(), Error> {
376 let mut model = Self::try_get_model(id).await?;
377 let model_data = model.before_soft_delete().await?;
378
379 let query = model.current_version_query();
380 let mut mutation = model.soft_delete_mutation();
381 let ctx = Self::update_one(&query, &mut mutation).await?;
382 Self::after_soft_delete(&ctx, model_data).await?;
383 Ok(())
384 }
385
386 async fn lock_by_id(id: &K) -> Result<(), Error> {
388 let mut model = Self::try_get_model(id).await?;
389 let model_data = model.before_lock().await?;
390
391 let query = model.current_version_query();
392 let mut mutation = model.lock_mutation();
393 let ctx = Self::update_one(&query, &mut mutation).await?;
394 Self::after_lock(&ctx, model_data).await?;
395 Ok(())
396 }
397
398 async fn archive_by_id(id: &K) -> Result<(), Error> {
400 let mut model = Self::try_get_model(id).await?;
401 let model_data = model.before_archive().await?;
402
403 let query = model.current_version_query();
404 let mut mutation = model.archive_mutation();
405 let ctx = Self::update_one(&query, &mut mutation).await?;
406 Self::after_archive(&ctx, model_data).await?;
407 Ok(())
408 }
409
410 async fn mutate_by_id(
412 id: &K,
413 data: &mut Map,
414 extension: Option<<Self as ModelHooks>::Extension>,
415 ) -> Result<(Validation, Self), Error> {
416 Self::before_extract().await?;
417
418 let mut model = Self::try_get_model(id).await?;
419 let version = model.version();
420 if data.get_u64("version").is_some_and(|v| version != v) {
421 bail!(
422 "409 Conflict: there is a version conflict for the model `{}`",
423 id
424 );
425 }
426 Self::before_validation(data, extension.as_ref()).await?;
427
428 let validation = model.read_map(data);
429 if !validation.is_success() {
430 return Ok((validation, model));
431 }
432 if let Some(extension) = extension {
433 model.after_extract(extension).await?;
434 }
435
436 let validation = model.check_constraints().await?;
437 if !validation.is_success() {
438 return Ok((validation, model));
439 }
440 if model.is_deleted() {
441 data.retain(|key, _value| key == "status");
442 } else if model.is_locked() {
443 data.retain(|key, _value| key == "visibility" || key == "status");
444 } else if model.is_archived() {
445 bail!("403 Forbidden: archived model `{}` can not be modified", id);
446 }
447 model.after_validation(data).await?;
448
449 let query = model.current_version_query();
450 let mut mutation = model.next_version_mutation(data);
451
452 let model_data = model.before_update().await?;
453 let ctx = Self::update_one(&query, &mut mutation).await?;
454 if ctx.rows_affected() != Some(1) {
455 bail!(
456 "404 Not Found: there is no version `{}` for the model `{}`",
457 version,
458 id,
459 );
460 }
461 Self::after_update(&ctx, model_data).await?;
462 Ok((validation, model))
463 }
464
465 async fn random_associations() -> Result<Map, Error> {
467 let mut associations = Map::new();
468 let table_name = Self::table_name();
469 for col in Self::columns() {
470 if col.reference().is_some_and(|r| r.name() == table_name) {
471 let col_name = col.name();
472 let size = col.random_size();
473 let values = Self::sample(size).await?;
474 if col.is_array_type() {
475 associations.upsert(col_name, values);
476 } else {
477 associations.upsert(col_name, values.first().cloned());
478 }
479 }
480 }
481 Ok(associations)
482 }
483
484 async fn mock() -> Result<(Validation, Self), Error> {
486 let mut data = Self::before_mock().await?;
487 let mut associations = Self::random_associations().await?;
488 data.append(&mut associations);
489 for col in Self::columns() {
490 if !col.has_attribute("constructor") {
491 let value = col.mock_value();
492 if !value.is_ignorable() {
493 data.upsert(col.name(), value);
494 }
495 }
496 }
497 Self::before_validation(&mut data, None).await?;
498
499 let mut model = Self::new();
500 let validation = model.read_map(&data);
501 if !validation.is_success() {
502 return Ok((validation, model));
503 }
504
505 let validation = model.check_constraints().await?;
506 if !validation.is_success() {
507 return Ok((validation, model));
508 }
509 model.after_validation(&mut data).await?;
510 model.after_mock().await?;
511 Ok((validation, model))
512 }
513}