use crate::hit_mod::{Hit, HitEntry};
use crate::index::IndexEntryProperty;
use crate::json::utils::*;
use crate::object_data::{ObjectValue, Reference};
use serde_json::{json, Map, Value};
use std::collections::HashMap;
fn reference_to_data(reference: &Reference) -> JSONObject {
let mut ref_object = Map::new();
ref_object.insert(
String::from("id"),
Value::String(String::from(&reference.id)),
);
return ref_object;
}
fn reference_to_json_object(reference: &Reference, _type: String) -> JSONObject {
let mut new_value = Map::new();
new_value.insert(String::from("type"), Value::String(_type));
let ref_object = reference_to_data(reference);
new_value.insert(String::from("value"), Value::Object(ref_object));
return new_value;
}
fn vecreference_to_json_object(references: &Vec<Reference>, _type: String) -> JSONObject {
let mut new_value = Map::new();
new_value.insert(String::from("type"), Value::String(_type));
let mut array_of_refs: Vec<Value> = vec![];
for reference in references {
array_of_refs.push(Value::Object(reference_to_data(reference)));
}
new_value.insert(String::from("value"), Value::Array(array_of_refs));
return new_value;
}
fn vecstring_to_json_object(strings: &Vec<String>) -> JSONObject {
let mut new_value = Map::new();
new_value.insert(
String::from("type"),
Value::String(JSON_FIELD_TYPE_STRING_ARRAY.to_string()),
);
let mut array_of_strings: Vec<Value> = vec![];
for string in strings {
array_of_strings.push(Value::String(string.to_string()));
}
new_value.insert(String::from("value"), Value::Array(array_of_strings));
return new_value;
}
fn object_value_to_json(value: &ObjectValue) -> Result<Value, String> {
match value {
ObjectValue::Bool(value) => Ok(Value::Bool(*value)),
ObjectValue::Date(value) => {
let mut new_value = Map::new();
new_value.insert(
String::from("type"),
Value::String(String::from(JSON_FIELD_TYPE_DATE)),
);
new_value.insert(
String::from("value"),
Value::String(value.get_date_as_string()),
);
return Ok(Value::Object(new_value));
}
ObjectValue::F32(value) => {
let number = serde_json::Number::from_f64(*value as f64)
.ok_or(String::from("Invalid number"))?;
return Ok(Value::Number(number));
}
ObjectValue::I32(value) => {
let number = serde_json::Number::from_f64(*value as f64)
.ok_or(String::from("Invalid number"))?;
return Ok(Value::Number(number));
}
ObjectValue::Null => Ok(Value::Null),
ObjectValue::String(value) => Ok(Value::String(String::from(value))),
ObjectValue::Reference(value) => {
return Ok(Value::Object(reference_to_json_object(
value,
String::from(JSON_FIELD_TYPE_REFERENCE),
)));
}
ObjectValue::SubObject(value) => {
return Ok(Value::Object(reference_to_json_object(
value,
String::from(JSON_FIELD_TYPE_SUBOBJECT),
)));
}
ObjectValue::VecString(value) => {
return Ok(Value::Object(vecstring_to_json_object(value)));
}
ObjectValue::VecReference(value) => {
return Ok(Value::Object(vecreference_to_json_object(
value,
String::from(JSON_FIELD_TYPE_REFERENCE_ARRAY),
)));
}
ObjectValue::VecSubObjects(value) => {
return Ok(Value::Object(vecreference_to_json_object(
value,
String::from(JSON_FIELD_TYPE_SUBOBJECT_ARRAY),
)));
}
}
}
fn export_parent(parent: Option<IndexEntryProperty>) -> Value {
match parent {
None => Value::Null,
Some(parent) => json!({
"id": parent.id,
"property": parent.property
}),
}
}
fn export_object(object: HitEntry) -> Result<Value, String> {
let model = &object.get_model();
let mut data = HashMap::new();
for (key, _field) in model.fields.iter() {
let entry = object.entry.borrow();
let entry = entry.get(key);
match entry {
ObjectValue::Null => {}
_ => {
let json_entry = object_value_to_json(entry)?;
data.insert(key, json_entry);
}
};
}
return Ok(json!({
"model": model.get_name(),
"id": object.entry.borrow().get_id(),
"data": data,
"parent": export_parent(object.entry.borrow().get_parent()),
}));
}
pub fn export(index: &Hit) -> Result<Value, String> {
let mut data = vec![];
for (id, entry) in index.index.iter() {
let model = { index.get_model(id).ok_or("Model not found")? };
let exported_object = export_object(HitEntry {
entry: entry.clone(),
model: model.clone(),
})?;
data.push(exported_object);
}
return Ok(json!({
"id": index.get_main_object_id(),
"data": data
}));
}
#[cfg(test)]
mod tests {
use crate::json::export::export;
use crate::json::import::import_from_string;
use crate::test_kernel::create_test_kernel;
use serde_json::json;
use std::rc::Rc;
#[test]
pub fn test_json_import() {
let json_data = json!({
"data": [
{
"data": {
"age": 12.0,
"name": "Hello",
"sub_items": {
"type": "subobject_array",
"value": [
{
"id": "id2"
}
]
}
},
"id": "id1",
"model": "test/test",
"parent": null
},
{
"data": {
"age": 123.0,
"name": "Hello2",
"sub_items": {
"type": "subobject_array",
"value": [
{
"id": "id3"
}
]
}
},
"id": "id2",
"model": "test/test",
"parent": {
"id": "id1",
"property": "sub_items"
}
},
{
"data": {
"age": 123.0,
"name": "Hello3"
},
"id": "id3",
"model": "test/test",
"parent": {
"id": "id2",
"property": "sub_items"
}
}
],
"id": "id1"
});
let (dump, json_data) = import(json_data);
let (dump2, json_data) = import(json_data);
let (dump3, _) = import(json_data);
assert_eq!(dump, dump2, "Test 1");
assert_eq!(dump2, dump3, "Test 2");
}
fn import(json_data: serde_json::Value) -> (String, serde_json::Value) {
let dump = format!("{}", json_data);
let kernel = Rc::new(create_test_kernel());
let index = import_from_string(&dump, kernel.clone()).expect("Import failed");
let exported = export(&index).expect("Export failed");
(dump, exported)
}
}