green_barrel/
models.rs

1//! Adapts the Structure for database queries using a programmatic or web interface.
2
3pub mod addition;
4pub mod caching;
5pub mod control;
6pub mod converters;
7pub mod db_query_api;
8pub mod fixtures;
9pub mod helpers;
10pub mod hooks;
11pub mod output_data;
12pub mod validation;
13
14use async_trait::async_trait;
15
16use mongodb::{
17    bson::{doc, document::Document, oid::ObjectId},
18    Client,
19};
20use serde_json::{json, value::Value};
21use std::error::Error;
22
23use crate::models::helpers::Meta;
24
25/// Model options and field type map for Form.
26// *************************************************************************************************
27#[async_trait(?Send)]
28pub trait Main {
29    /// Get model key
30    /// ( to access model metadata in cache ).
31    // ---------------------------------------------------------------------------------------------
32    fn key() -> Result<String, Box<dyn Error>>;
33
34    /// Model instance from `create` method, convert to intermediate state `serde_json::value::Value`,
35    /// with the addition of Html-ID and data validation.
36    // ---------------------------------------------------------------------------------------------
37    fn custom_to_json_val() -> Result<Value, Box<dyn Error>>
38    where
39        Self: serde::de::DeserializeOwned + Sized;
40
41    /// Generate metadata of Model.
42    // ---------------------------------------------------------------------------------------------
43    fn generate_metadata() -> Result<Meta, Box<dyn Error>>
44    where
45        Self: serde::de::DeserializeOwned + Sized;
46
47    /// Getter and Setter for field `hash`.
48    // ---------------------------------------------------------------------------------------------
49    fn hash(&self) -> String;
50    fn set_hash(&mut self, value: String);
51
52    /// ObjectId from hash field.
53    // ---------------------------------------------------------------------------------------------
54    fn obj_id(&self) -> Result<Option<ObjectId>, Box<dyn Error>>;
55
56    /// ObjectId to hash field.
57    // ---------------------------------------------------------------------------------------------
58    fn set_obj_id(&mut self, object_id: ObjectId);
59
60    /// Getter and Setter for field `created_at`.
61    // ---------------------------------------------------------------------------------------------
62    fn created_at(&self) -> String;
63    fn set_created_at(&mut self, value: String);
64
65    /// Getter and Setter for field `updated_at`.
66    // ---------------------------------------------------------------------------------------------
67    fn updated_at(&self) -> String;
68    fn set_updated_at(&mut self, value: String);
69
70    /// Serializing the model instance to serde_json::Value format.
71    // ---------------------------------------------------------------------------------------------
72    fn self_to_json_val(&self) -> Result<Value, Box<dyn Error>>;
73
74    /// Enrich field type map with values for dynamic fields type.
75    // ---------------------------------------------------------------------------------------------
76    async fn injection(
77        client: &Client,
78        app_name: &str,
79        unique_app_key: &str,
80        collection_name: &str,
81        model_json: &mut Value,
82        fields_name: &Vec<String>,
83    ) -> Result<(), Box<dyn Error>>
84    where
85        Self: serde::de::DeserializeOwned + Sized,
86    {
87        // Init the name of the project's technical database.
88        let db_green_tech: String = format!("green_tech__{app_name}__{unique_app_key}");
89        // Access to the collection with values for dynamic fields type.
90        let collection = client
91            .database(&db_green_tech)
92            .collection::<Document>("dynamic_fields");
93        // Filter for searching a document.
94        let filter = doc! {
95            "collection": collection_name
96        };
97        // Get a document with values for dynamic fields type.
98        if let Some(doc) = collection.find_one(filter, None).await? {
99            let dyn_values_doc = doc.get_document("fields")?;
100            // Updating the `choices` parameter for fields with a dynamic field type.
101            for field_name in fields_name {
102                let field_type = model_json
103                    .get(field_name)
104                    .unwrap()
105                    .get("field_type")
106                    .unwrap()
107                    .as_str()
108                    .unwrap();
109                //
110                if field_type.contains("Dyn") {
111                    let arr = dyn_values_doc.get_array(field_name)?;
112                    if field_type.contains("Text") {
113                        let choices = arr
114                            .iter()
115                            .map(|item| {
116                                let arr = item.as_array().unwrap();
117                                (
118                                    arr[0].as_str().unwrap().to_string(),
119                                    arr[1].as_str().unwrap().to_string(),
120                                )
121                            })
122                            .collect::<Vec<(String, String)>>();
123                        *model_json
124                            .get_mut(field_name)
125                            .unwrap()
126                            .get_mut("choices")
127                            .unwrap() = json!(choices);
128                    } else if field_type.contains("I32") {
129                        let choices = arr
130                            .iter()
131                            .map(|item| {
132                                let arr = item.as_array().unwrap();
133                                (
134                                    arr[0].as_i32().unwrap(),
135                                    arr[1].as_str().unwrap().to_string(),
136                                )
137                            })
138                            .collect::<Vec<(i32, String)>>();
139                        *model_json
140                            .get_mut(field_name)
141                            .unwrap()
142                            .get_mut("choices")
143                            .unwrap() = json!(choices);
144                    } else if field_type.contains("U32") || field_type.contains("I64") {
145                        let choices = arr
146                            .iter()
147                            .map(|item| {
148                                let arr = item.as_array().unwrap();
149                                (
150                                    arr[0].as_i64().unwrap(),
151                                    arr[1].as_str().unwrap().to_string(),
152                                )
153                            })
154                            .collect::<Vec<(i64, String)>>();
155                        *model_json
156                            .get_mut(field_name)
157                            .unwrap()
158                            .get_mut("choices")
159                            .unwrap() = json!(choices);
160                    } else if field_type.contains("F64") {
161                        let choices = arr
162                            .iter()
163                            .map(|item| {
164                                let arr = item.as_array().unwrap();
165                                (
166                                    arr[0].as_f64().unwrap(),
167                                    arr[1].as_str().unwrap().to_string(),
168                                )
169                            })
170                            .collect::<Vec<(f64, String)>>();
171                        *model_json
172                            .get_mut(field_name)
173                            .unwrap()
174                            .get_mut("choices")
175                            .unwrap() = json!(choices);
176                    } else {
177                        Err(format!(
178                            "Model: {} > Method: `injection()` => \
179                                Invalid data type.",
180                            Self::generate_metadata()?.model_name,
181                        ))?
182                    }
183                }
184            }
185        }
186
187        Ok(())
188    }
189}