use rust_decimal::Decimal;
use rust_decimal::prelude::ToPrimitive;
use schema_core::GenericValue;
use serde_json::{Number, Value};
pub fn to_json(value: &GenericValue) -> Value {
match value {
GenericValue::Null => Value::Null,
GenericValue::Bool(b) => Value::Bool(*b),
GenericValue::Int(i) => Value::Number((*i).into()),
GenericValue::Decimal(d) => decimal_to_json(d),
GenericValue::String(s) => Value::String(s.clone()),
GenericValue::Array(items) => Value::Array(items.iter().map(to_json).collect()),
GenericValue::Map(fields) => Value::Object(
fields
.iter()
.map(|(k, v)| (k.clone(), to_json(v)))
.collect(),
),
}
}
fn decimal_to_json(value: &Decimal) -> Value {
match value.to_f64().and_then(Number::from_f64) {
Some(number) => Value::Number(number),
None => Value::String(value.to_string()),
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::BTreeMap;
#[test]
fn maps_to_plain_json() {
let value = GenericValue::Map(BTreeMap::from([
("name".to_owned(), GenericValue::String("ada".to_owned())),
("age".to_owned(), GenericValue::Int(36)),
("admin".to_owned(), GenericValue::Bool(true)),
(
"tags".to_owned(),
GenericValue::Array(vec![GenericValue::String("a".to_owned())]),
),
("missing".to_owned(), GenericValue::Null),
]));
assert_eq!(
to_json(&value),
serde_json::json!({
"name": "ada",
"age": 36,
"admin": true,
"tags": ["a"],
"missing": null,
})
);
}
#[test]
fn decimal_becomes_a_number() {
let value = GenericValue::Decimal(Decimal::new(1234, 2)); assert_eq!(to_json(&value), serde_json::json!(12.34));
}
}