use nautilus_core::Value;
pub(crate) fn value_to_json(v: &Value) -> serde_json::Value {
match v {
Value::Null => serde_json::Value::Null,
Value::Bool(b) => serde_json::Value::Bool(*b),
Value::I32(i) => serde_json::Value::Number((*i).into()),
Value::I64(i) => serde_json::Value::Number((*i).into()),
Value::F64(f) => serde_json::Value::Number(
serde_json::Number::from_f64(*f).unwrap_or(serde_json::Number::from(0)),
),
Value::Decimal(d) => serde_json::Value::String(d.to_string()),
Value::DateTime(dt) => serde_json::Value::String(dt.to_string()),
Value::Uuid(u) => serde_json::Value::String(u.to_string()),
Value::Json(j) => j.clone(),
Value::Hstore(map) => serde_json::Value::Object(
map.iter()
.map(|(key, value)| {
(
key.clone(),
value
.as_ref()
.map(|item| serde_json::Value::String(item.clone()))
.unwrap_or(serde_json::Value::Null),
)
})
.collect(),
),
Value::Geometry(raw) | Value::Geography(raw) => serde_json::Value::String(raw.clone()),
Value::Vector(values) => serde_json::Value::Array(
values
.iter()
.map(|value| {
serde_json::Number::from_f64(*value as f64)
.map(serde_json::Value::Number)
.unwrap_or(serde_json::Value::Null)
})
.collect(),
),
Value::String(s) => serde_json::Value::String(s.clone()),
Value::Bytes(b) => {
serde_json::Value::String(b.iter().map(|byte| format!("{:02x}", byte)).collect())
}
Value::Array(items) => serde_json::Value::Array(items.iter().map(value_to_json).collect()),
Value::Array2D(rows) => serde_json::Value::Array(
rows.iter()
.map(|row| serde_json::Value::Array(row.iter().map(value_to_json).collect()))
.collect(),
),
Value::Enum { value, .. } => serde_json::Value::String(value.clone()),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_value_to_json_primitives() {
assert_eq!(value_to_json(&Value::Null), serde_json::Value::Null);
assert_eq!(
value_to_json(&Value::Bool(true)),
serde_json::Value::Bool(true)
);
assert_eq!(value_to_json(&Value::I32(42)), serde_json::json!(42));
assert_eq!(value_to_json(&Value::I64(99)), serde_json::json!(99));
assert_eq!(value_to_json(&Value::F64(1.5)), serde_json::json!(1.5));
assert_eq!(
value_to_json(&Value::String("hi".to_string())),
serde_json::Value::String("hi".to_string()),
);
}
#[test]
fn test_value_to_json_array() {
let arr = Value::Array(vec![Value::I64(1), Value::I64(2)]);
assert_eq!(value_to_json(&arr), serde_json::json!([1, 2]));
}
#[test]
fn test_value_to_json_array2d() {
let arr2d = Value::Array2D(vec![
vec![Value::I64(1), Value::I64(2)],
vec![Value::I64(3), Value::I64(4)],
]);
assert_eq!(value_to_json(&arr2d), serde_json::json!([[1, 2], [3, 4]]));
}
#[test]
fn test_value_to_json_nested_json() {
let inner = serde_json::json!({"a": 1});
let v = Value::Json(inner.clone());
assert_eq!(value_to_json(&v), inner);
}
#[test]
fn test_value_to_json_hstore() {
let value = Value::Hstore(std::collections::BTreeMap::from([
("display_name".to_string(), Some("Bob".to_string())),
("nickname".to_string(), None),
]));
assert_eq!(
value_to_json(&value),
serde_json::json!({
"display_name": "Bob",
"nickname": null
})
);
}
}