zino_core/model/
mod.rs

1//! Domain specific models.
2use crate::{AvroValue, JsonValue, Map, Record, validation::Validation};
3use serde::{Serialize, de::DeserializeOwned};
4
5mod column;
6mod context;
7mod hook;
8mod mutation;
9mod order;
10mod query;
11mod reference;
12mod translation;
13
14#[doc(no_inline)]
15pub use apache_avro::schema;
16
17pub use column::Column;
18pub use context::QueryContext;
19pub use hook::ModelHooks;
20pub use mutation::Mutation;
21pub use order::QueryOrder;
22pub use query::Query;
23pub use reference::Reference;
24pub use translation::Translation;
25
26/// General data model.
27///
28/// This trait can be derived by `zino_derive::Model`.
29pub trait Model: Default + Serialize + DeserializeOwned {
30    /// Model name.
31    const MODEL_NAME: &'static str;
32    /// Data item name.
33    const ITEM_NAME: (&'static str, &'static str) = ("entry", "entries");
34
35    /// Creates a new instance.
36    #[inline]
37    fn new() -> Self {
38        Self::default()
39    }
40
41    /// Returns the model name.
42    #[inline]
43    fn model_name() -> &'static str {
44        Self::MODEL_NAME
45    }
46
47    /// Updates the model using the json object and returns the validation result.
48    #[must_use]
49    fn read_map(&mut self, data: &Map) -> Validation {
50        let mut validation = Validation::new();
51        if data.is_empty() {
52            let message = format!("`{}` model data should be nonempty", Self::MODEL_NAME);
53            validation.record("data", message);
54        }
55        validation
56    }
57
58    /// Attempts to construct a model from a json object.
59    #[inline]
60    fn try_from_map(data: Map) -> Result<Self, serde_json::Error> {
61        serde_json::from_value(JsonValue::from(data))
62    }
63
64    /// Attempts to construct a model from an Avro record.
65    #[inline]
66    fn try_from_avro_record(data: Record) -> Result<Self, apache_avro::Error> {
67        apache_avro::from_value(&AvroValue::Record(data))
68    }
69
70    /// Consumes the model and returns as a json object.
71    ///
72    /// # Panics
73    ///
74    /// It will panic if the model cann't be converted to a json object.
75    #[must_use]
76    fn into_map(self) -> Map {
77        match serde_json::to_value(self) {
78            Ok(JsonValue::Object(map)) => map,
79            _ => panic!(
80                "`{}` model cann't be converted to a json object",
81                Self::MODEL_NAME
82            ),
83        }
84    }
85
86    /// Consumes the model and returns as an Avro record.
87    ///
88    /// # Panics
89    ///
90    /// It will panic if the model cann't be converted to an Avro record.
91    #[must_use]
92    fn into_avro_record(self) -> Record {
93        match apache_avro::to_value(self) {
94            Ok(AvroValue::Record(record)) => record,
95            _ => panic!(
96                "`{}` model cann't be converted to an Avro record",
97                Self::MODEL_NAME
98            ),
99        }
100    }
101
102    /// Constructs an instance of `Map` for the data item.
103    #[inline]
104    fn data_item(value: impl Into<JsonValue>) -> Map {
105        let item_name = Self::ITEM_NAME.0;
106        let mut map = Map::new();
107        map.insert(item_name.to_owned(), value.into());
108        map
109    }
110
111    /// Constructs an instance of `Map` for the data items.
112    #[inline]
113    fn data_items<T: Into<JsonValue>>(values: Vec<T>) -> Map {
114        let item_name = Self::ITEM_NAME.1;
115        let mut map = Map::new();
116        map.insert(["num", item_name].join("_"), values.len().into());
117        map.insert(item_name.to_owned(), values.into());
118        map
119    }
120}