1use crate::hit_mod::{Hit, HitKernel, IndexModelImporter};
2use crate::index::IndexEntryProperty;
3use crate::json::utils::*;
4use crate::json::JSONImportError;
5use crate::object_data::{DateTimeUtc, ObjectValue, ObjectValues};
6use chrono::{DateTime, Utc};
7use linked_hash_map::LinkedHashMap;
8use serde_json::Value;
9
10use std::rc::Rc;
11
12use crate::import::generic_import::{finish_import, import_data_object_values};
13
14fn json_to_object_value(value: &Value) -> Result<ObjectValue, JSONImportError> {
15 match value {
16 Value::Null => Ok(ObjectValue::Null),
17 Value::Number(value) => match value.as_f64() {
18 Some(value) => Ok(ObjectValue::F32(value as f32)),
19 None => Err(JSONImportError::InvalidTypeShouldBeANumber()),
20 },
21 Value::String(value) => Ok(ObjectValue::String(String::from(value))),
22 Value::Bool(value) => Ok(ObjectValue::Bool(*value)),
23 Value::Object(value) => {
24 let _type = get_object_property_as_string(value, String::from("type"))?;
25 let sub_value = get_object_property(value, String::from("value"))?;
26 if _type == String::from(JSON_FIELD_TYPE_REFERENCE) {
27 let reference = get_reference(sub_value)?;
28 return Ok(ObjectValue::Reference(reference));
29 } else if _type == String::from(JSON_FIELD_TYPE_REFERENCE_ARRAY) {
30 let array_of_ids = get_array_of_ids(sub_value)?;
31 return Ok(ObjectValue::VecReference(array_of_ids));
32 } else if _type == String::from(JSON_FIELD_TYPE_SUBOBJECT) {
33 let reference = get_reference(sub_value)?;
34 return Ok(ObjectValue::SubObject(reference));
35 } else if _type == String::from(JSON_FIELD_TYPE_SUBOBJECT_ARRAY) {
36 let array_of_ids = get_array_of_ids(sub_value)?;
37 return Ok(ObjectValue::VecSubObjects(array_of_ids));
38 } else if _type == String::from(JSON_FIELD_TYPE_DATE) {
39 let sub_value = get_value_as_string(sub_value)?;
40 let sub_value = DateTime::parse_from_rfc2822(&sub_value);
41 match sub_value {
42 Ok(sub_value) => Ok(ObjectValue::Date(DateTimeUtc::new(
43 sub_value.with_timezone(&Utc),
44 ))),
45 Err(_error) => Err(JSONImportError::InvalidDateFormat()),
46 }
47 } else {
48 return Err(JSONImportError::InvalidSubObjectType());
49 }
50 }
51 Value::Array(_value) => Err(JSONImportError::ShouldNotBeAnArray()),
52 }
53}
54
55fn get_parent(value: &JSONObject) -> Result<Option<IndexEntryProperty>, JSONImportError> {
56 let parent = get_object_property(value, String::from("parent"))?;
57 match parent {
58 Value::Null => {
59 return Ok(None);
60 }
61 Value::Object(parent) => {
62 let id = get_object_property_as_string(&parent, String::from("id"))?;
63 let property = get_object_property_as_string(&parent, String::from("property"))?;
64 return Ok(Some(IndexEntryProperty {
65 id: id,
66 property: property,
67 }));
68 }
69 _ => return Err(JSONImportError::InvalidTypeShouldBeAnObject()),
70 }
71}
72
73fn import_data<'index>(
74 data: &JSONObject,
75 kernel: Rc<HitKernel>,
76 new_index: &'index mut IndexModelImporter,
77) -> Result<(), JSONImportError> {
78 let id = get_object_property_as_string(data, String::from("id"))?;
79 let model = get_model(kernel, data)?;
80 let parent = get_parent(data)?;
81 let sub_data = get_object_property(data, String::from("data"))?;
82 let sub_data = get_value_as_object(sub_data)?;
83 let mut new_data: ObjectValues = LinkedHashMap::new();
84 for d in sub_data.iter() {
85 new_data.insert(String::from(d.0), json_to_object_value(d.1)?);
86 }
87
88 import_data_object_values(model, id, parent, new_index, new_data)
89 .map_err(JSONImportError::HitError)?;
90
91 return Ok(());
92}
93
94fn get_json_value(value: &String) -> Result<Value, JSONImportError> {
95 match serde_json::from_str(value) {
96 Err(_err) => Err(JSONImportError::InvalidJSON()),
97 Ok(value) => Ok(value),
98 }
99}
100pub fn import_from_string<'a>(
101 value: &String,
102 kernel: Rc<HitKernel>,
103) -> Result<Hit, JSONImportError> {
104 let value = get_json_value(value)?;
105 import(&value, kernel)
106}
107
108pub fn import<'a>(value: &Value, kernel: Rc<HitKernel>) -> Result<Hit, JSONImportError> {
109 let value = get_value_as_object(&value)?;
110 let id = get_object_property_as_string(value, String::from("id"))?;
111 let mut new_index = IndexModelImporter::new(&id, kernel.clone());
112 let data = get_object_property(value, String::from("data"))?;
113 let data = get_value_as_array(data)?;
114 for entry in data.iter() {
115 let clone = kernel.clone();
116 let entry = get_value_as_object(entry)?;
117 import_data(entry, clone, &mut new_index)?;
118 }
119 let new_index = finish_import(new_index, kernel).map_err(JSONImportError::HitError)?;
120 Ok(new_index)
121}