use crate::datatypes::values::Value;
use std::collections::HashMap;
pub fn json_object_to_value_map(
map: &serde_json::Map<String, serde_json::Value>,
) -> HashMap<String, Value> {
map.iter()
.map(|(k, v)| (k.clone(), json_value_to_kglite_value(v)))
.collect()
}
pub fn json_value_to_kglite_value(v: &serde_json::Value) -> Value {
match v {
serde_json::Value::Null => Value::Null,
serde_json::Value::Bool(b) => Value::Boolean(*b),
serde_json::Value::Number(n) => {
if let Some(i) = n.as_i64() {
Value::Int64(i)
} else if let Some(f) = n.as_f64() {
Value::Float64(f)
} else {
Value::Null
}
}
serde_json::Value::String(s) => Value::String(s.clone()),
serde_json::Value::Array(items) => {
Value::List(items.iter().map(json_value_to_kglite_value).collect())
}
serde_json::Value::Object(map) => Value::Map(
map.iter()
.map(|(k, v)| (k.clone(), json_value_to_kglite_value(v)))
.collect(),
),
}
}
pub fn kglite_value_to_json(v: &Value) -> serde_json::Value {
use serde_json::Value as J;
match v {
Value::Null => J::Null,
Value::Boolean(b) => J::Bool(*b),
Value::Int64(i) => J::Number((*i).into()),
Value::Float64(f) => serde_json::Number::from_f64(*f)
.map(J::Number)
.unwrap_or(J::Null),
Value::String(s) => J::String(s.clone()),
Value::List(items) => J::Array(items.iter().map(kglite_value_to_json).collect()),
Value::Map(m) => J::Object(
m.iter()
.map(|(k, v)| (k.clone(), kglite_value_to_json(v)))
.collect(),
),
other => J::String(format!("{other:?}")),
}
}
#[cfg(test)]
#[allow(clippy::approx_constant)]
mod tests {
use super::*;
#[test]
fn null_roundtrip() {
assert_eq!(
json_value_to_kglite_value(&serde_json::json!(null)),
Value::Null
);
}
#[test]
fn bool_roundtrip() {
assert_eq!(
json_value_to_kglite_value(&serde_json::json!(true)),
Value::Boolean(true)
);
assert_eq!(
json_value_to_kglite_value(&serde_json::json!(false)),
Value::Boolean(false)
);
}
#[test]
fn integer_number() {
assert_eq!(
json_value_to_kglite_value(&serde_json::json!(42)),
Value::Int64(42)
);
assert_eq!(
json_value_to_kglite_value(&serde_json::json!(-7)),
Value::Int64(-7)
);
}
#[test]
fn float_number() {
match json_value_to_kglite_value(&serde_json::json!(3.14)) {
Value::Float64(f) => assert!((f - 3.14).abs() < 1e-9),
other => panic!("expected Float64, got {other:?}"),
}
}
#[test]
fn string_roundtrip() {
assert_eq!(
json_value_to_kglite_value(&serde_json::json!("hello")),
Value::String("hello".to_string())
);
}
#[test]
fn array_maps_to_list() {
let v = serde_json::json!([1, "two", null, true]);
assert_eq!(
json_value_to_kglite_value(&v),
Value::List(vec![
Value::Int64(1),
Value::String("two".to_string()),
Value::Null,
Value::Boolean(true),
])
);
}
#[test]
fn object_maps_to_map() {
let v = serde_json::json!({"a": 1, "b": "x"});
let mut expected = std::collections::BTreeMap::new();
expected.insert("a".to_string(), Value::Int64(1));
expected.insert("b".to_string(), Value::String("x".to_string()));
assert_eq!(json_value_to_kglite_value(&v), Value::Map(expected));
}
#[test]
fn nested_array_of_objects() {
let v = serde_json::json!([{"id": 1}, {"id": 2}]);
match json_value_to_kglite_value(&v) {
Value::List(items) => {
assert_eq!(items.len(), 2);
match &items[0] {
Value::Map(m) => assert_eq!(m.get("id"), Some(&Value::Int64(1))),
other => panic!("expected Map, got {other:?}"),
}
}
other => panic!("expected List, got {other:?}"),
}
}
#[test]
fn value_to_json_natural_scalars() {
assert_eq!(kglite_value_to_json(&Value::Int64(2)), serde_json::json!(2));
assert_eq!(
kglite_value_to_json(&Value::String("x".into())),
serde_json::json!("x")
);
assert_eq!(
kglite_value_to_json(&Value::Boolean(true)),
serde_json::json!(true)
);
assert_eq!(kglite_value_to_json(&Value::Null), serde_json::Value::Null);
}
#[test]
fn value_to_json_natural_nested_is_untagged() {
let mut m = std::collections::BTreeMap::new();
m.insert("id".to_string(), Value::Int64(7));
let v = Value::List(vec![Value::Int64(1), Value::Map(m)]);
assert_eq!(kglite_value_to_json(&v), serde_json::json!([1, {"id": 7}]));
}
#[test]
fn value_to_json_is_inverse_of_inbound() {
let j = serde_json::json!({"rows": [{"id": 1}, {"id": 2}]});
let back = kglite_value_to_json(&json_value_to_kglite_value(&j));
assert_eq!(back, j);
}
}