hit_data/json/
export.rs

1use crate::hit_mod::{Hit, HitEntry};
2use crate::index::IndexEntryProperty;
3use crate::json::utils::*;
4use crate::object_data::{ObjectValue, Reference};
5use serde_json::{json, Map, Value};
6use std::collections::HashMap;
7
8fn reference_to_data(reference: &Reference) -> JSONObject {
9    let mut ref_object = Map::new();
10    ref_object.insert(
11        String::from("id"),
12        Value::String(String::from(&reference.id)),
13    );
14    return ref_object;
15}
16fn reference_to_json_object(reference: &Reference, _type: String) -> JSONObject {
17    let mut new_value = Map::new();
18    new_value.insert(String::from("type"), Value::String(_type));
19    let ref_object = reference_to_data(reference);
20    new_value.insert(String::from("value"), Value::Object(ref_object));
21    return new_value;
22}
23fn vecreference_to_json_object(references: &Vec<Reference>, _type: String) -> JSONObject {
24    let mut new_value = Map::new();
25    new_value.insert(String::from("type"), Value::String(_type));
26    let mut array_of_refs: Vec<Value> = vec![];
27    for reference in references {
28        array_of_refs.push(Value::Object(reference_to_data(reference)));
29    }
30    new_value.insert(String::from("value"), Value::Array(array_of_refs));
31    return new_value;
32}
33fn vecstring_to_json_object(strings: &Vec<String>) -> JSONObject {
34    let mut new_value = Map::new();
35    new_value.insert(
36        String::from("type"),
37        Value::String(JSON_FIELD_TYPE_STRING_ARRAY.to_string()),
38    );
39    let mut array_of_strings: Vec<Value> = vec![];
40    for string in strings {
41        array_of_strings.push(Value::String(string.to_string()));
42    }
43    new_value.insert(String::from("value"), Value::Array(array_of_strings));
44    return new_value;
45}
46
47fn object_value_to_json(value: &ObjectValue) -> Result<Value, String> {
48    match value {
49        ObjectValue::Bool(value) => Ok(Value::Bool(*value)),
50        ObjectValue::Date(value) => {
51            let mut new_value = Map::new();
52            new_value.insert(
53                String::from("type"),
54                Value::String(String::from(JSON_FIELD_TYPE_DATE)),
55            );
56            new_value.insert(
57                String::from("value"),
58                Value::String(value.get_date_as_string()),
59            );
60            return Ok(Value::Object(new_value));
61        }
62        ObjectValue::F32(value) => {
63            let number = serde_json::Number::from_f64(*value as f64)
64                .ok_or(String::from("Invalid number"))?;
65            return Ok(Value::Number(number));
66        }
67        ObjectValue::I32(value) => {
68            let number = serde_json::Number::from_f64(*value as f64)
69                .ok_or(String::from("Invalid number"))?;
70            return Ok(Value::Number(number));
71        }
72        ObjectValue::Null => Ok(Value::Null),
73        ObjectValue::String(value) => Ok(Value::String(String::from(value))),
74        ObjectValue::Reference(value) => {
75            return Ok(Value::Object(reference_to_json_object(
76                value,
77                String::from(JSON_FIELD_TYPE_REFERENCE),
78            )));
79        }
80        ObjectValue::SubObject(value) => {
81            return Ok(Value::Object(reference_to_json_object(
82                value,
83                String::from(JSON_FIELD_TYPE_SUBOBJECT),
84            )));
85        }
86        ObjectValue::VecString(value) => {
87            return Ok(Value::Object(vecstring_to_json_object(value)));
88        }
89        ObjectValue::VecReference(value) => {
90            return Ok(Value::Object(vecreference_to_json_object(
91                value,
92                String::from(JSON_FIELD_TYPE_REFERENCE_ARRAY),
93            )));
94        }
95        ObjectValue::VecSubObjects(value) => {
96            return Ok(Value::Object(vecreference_to_json_object(
97                value,
98                String::from(JSON_FIELD_TYPE_SUBOBJECT_ARRAY),
99            )));
100        }
101    }
102}
103fn export_parent(parent: Option<IndexEntryProperty>) -> Value {
104    match parent {
105        None => Value::Null,
106        Some(parent) => json!({
107            "id": parent.id,
108            "property": parent.property
109        }),
110    }
111}
112
113fn export_object(object: HitEntry) -> Result<Value, String> {
114    let model = &object.get_model();
115    let mut data = HashMap::new();
116    for (key, _field) in model.fields.iter() {
117        let entry = object.entry.borrow();
118        let entry = entry.get(key);
119        match entry {
120            ObjectValue::Null => {}
121            _ => {
122                let json_entry = object_value_to_json(entry)?;
123                data.insert(key, json_entry);
124            }
125        };
126    }
127    return Ok(json!({
128        "model": model.get_name(),
129        "id": object.entry.borrow().get_id(),
130        "data": data,
131        "parent": export_parent(object.entry.borrow().get_parent()),
132    }));
133}
134
135pub fn export(index: &Hit) -> Result<Value, String> {
136    let mut data = vec![];
137    for (id, entry) in index.index.iter() {
138        let model = { index.get_model(id).ok_or("Model not found")? };
139        let exported_object = export_object(HitEntry {
140            entry: entry.clone(),
141            model: model.clone(),
142        })?;
143        data.push(exported_object);
144    }
145    return Ok(json!({
146        "id": index.get_main_object_id(),
147        "data": data
148    }));
149}
150
151#[cfg(test)]
152mod tests {
153    use crate::json::export::export;
154    use crate::json::import::import_from_string;
155    use crate::test_kernel::create_test_kernel;
156    use serde_json::json;
157    use std::rc::Rc;
158
159    #[test]
160    pub fn test_json_import() {
161        let json_data = json!({
162           "data": [
163              {
164                 "data": {
165                    "age": 12.0,
166                    "name": "Hello",
167                    "sub_items": {
168                       "type": "subobject_array",
169                       "value": [
170                          {
171                             "id": "id2"
172                          }
173                       ]
174                    }
175                 },
176                 "id": "id1",
177                 "model": "test/test",
178                 "parent": null
179              },
180              {
181                 "data": {
182                    "age": 123.0,
183                    "name": "Hello2",
184                    "sub_items": {
185                       "type": "subobject_array",
186                       "value": [
187                          {
188                             "id": "id3"
189                          }
190                       ]
191                    }
192                 },
193                 "id": "id2",
194                 "model": "test/test",
195                 "parent": {
196                    "id": "id1",
197                    "property": "sub_items"
198                 }
199              },
200              {
201                 "data": {
202                    "age": 123.0,
203                    "name": "Hello3"
204                 },
205                 "id": "id3",
206                 "model": "test/test",
207                 "parent": {
208                    "id": "id2",
209                    "property": "sub_items"
210                 }
211              }
212           ],
213           "id": "id1"
214        });
215        let (dump, json_data) = import(json_data);
216        let (dump2, json_data) = import(json_data);
217        let (dump3, _) = import(json_data);
218        assert_eq!(dump, dump2, "Test 1");
219        assert_eq!(dump2, dump3, "Test 2");
220    }
221
222    fn import(json_data: serde_json::Value) -> (String, serde_json::Value) {
223        let dump = format!("{}", json_data);
224        let kernel = Rc::new(create_test_kernel());
225        let index = import_from_string(&dump, kernel.clone()).expect("Import failed");
226        let exported = export(&index).expect("Export failed");
227        (dump, exported)
228    }
229}