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}