use serde_json::Value as Json;
use toasty_core::stmt::{self, Value};
pub fn value_to_json(value: &Value) -> Json {
match value {
Value::Null => Json::Null,
Value::Bool(v) => Json::Bool(*v),
Value::I8(v) => Json::Number((*v).into()),
Value::I16(v) => Json::Number((*v).into()),
Value::I32(v) => Json::Number((*v).into()),
Value::I64(v) => Json::Number((*v).into()),
Value::U8(v) => Json::Number((*v).into()),
Value::U16(v) => Json::Number((*v).into()),
Value::U32(v) => Json::Number((*v).into()),
Value::U64(v) => Json::Number((*v).into()),
Value::F32(v) => serde_json::Number::from_f64((*v).into())
.map(Json::Number)
.unwrap_or(Json::Null),
Value::F64(v) => serde_json::Number::from_f64(*v)
.map(Json::Number)
.unwrap_or(Json::Null),
Value::String(v) => Json::String(v.clone()),
Value::Uuid(v) => Json::String(v.to_string()),
#[cfg(feature = "rust_decimal")]
Value::Decimal(v) => Json::String(v.to_string()),
#[cfg(feature = "bigdecimal")]
Value::BigDecimal(v) => Json::String(v.to_string()),
#[cfg(feature = "jiff")]
Value::Timestamp(v) => Json::String(v.to_string()),
#[cfg(feature = "jiff")]
Value::Zoned(v) => Json::String(v.to_string()),
#[cfg(feature = "jiff")]
Value::Date(v) => Json::String(v.to_string()),
#[cfg(feature = "jiff")]
Value::Time(v) => Json::String(v.to_string()),
#[cfg(feature = "jiff")]
Value::DateTime(v) => Json::String(v.to_string()),
_ => todo!("encode {value:?} as JSON"),
}
}
pub fn value_from_json(json: Json, ty: &stmt::Type) -> Value {
match (ty, json) {
(_, Json::Null) => Value::Null,
(stmt::Type::Bool, Json::Bool(v)) => Value::Bool(v),
(stmt::Type::String, Json::String(v)) => Value::String(v),
(stmt::Type::Uuid, Json::String(v)) => {
Value::Uuid(v.parse().expect("invalid UUID in JSON"))
}
(stmt::Type::I8, Json::Number(n)) => Value::I8(n.as_i64().unwrap() as i8),
(stmt::Type::I16, Json::Number(n)) => Value::I16(n.as_i64().unwrap() as i16),
(stmt::Type::I32, Json::Number(n)) => Value::I32(n.as_i64().unwrap() as i32),
(stmt::Type::I64, Json::Number(n)) => Value::I64(n.as_i64().unwrap()),
(stmt::Type::U8, Json::Number(n)) => Value::U8(n.as_u64().unwrap() as u8),
(stmt::Type::U16, Json::Number(n)) => Value::U16(n.as_u64().unwrap() as u16),
(stmt::Type::U32, Json::Number(n)) => Value::U32(n.as_u64().unwrap() as u32),
(stmt::Type::U64, Json::Number(n)) => Value::U64(n.as_u64().unwrap()),
(stmt::Type::F32, Json::Number(n)) => Value::F32(n.as_f64().unwrap() as f32),
(stmt::Type::F64, Json::Number(n)) => Value::F64(n.as_f64().unwrap()),
#[cfg(feature = "rust_decimal")]
(stmt::Type::Decimal, Json::String(v)) => {
Value::Decimal(v.parse().expect("invalid Decimal in JSON"))
}
#[cfg(feature = "bigdecimal")]
(stmt::Type::BigDecimal, Json::String(v)) => {
Value::BigDecimal(v.parse().expect("invalid BigDecimal in JSON"))
}
#[cfg(feature = "jiff")]
(stmt::Type::Timestamp, Json::String(v)) => {
Value::Timestamp(v.parse().expect("invalid Timestamp in JSON"))
}
#[cfg(feature = "jiff")]
(stmt::Type::Zoned, Json::String(v)) => {
Value::Zoned(v.parse().expect("invalid Zoned in JSON"))
}
#[cfg(feature = "jiff")]
(stmt::Type::Date, Json::String(v)) => {
Value::Date(v.parse().expect("invalid Date in JSON"))
}
#[cfg(feature = "jiff")]
(stmt::Type::Time, Json::String(v)) => {
Value::Time(v.parse().expect("invalid Time in JSON"))
}
#[cfg(feature = "jiff")]
(stmt::Type::DateTime, Json::String(v)) => {
Value::DateTime(v.parse().expect("invalid DateTime in JSON"))
}
(ty, json) => todo!("decode JSON value {json:?} as {ty:?}"),
}
}
pub fn value_list_to_json(value: &Value) -> Json {
let Value::List(items) = value else {
unreachable!("value_list_to_json called on {value:?}")
};
Json::Array(items.iter().map(value_to_json).collect())
}
pub fn value_list_from_json(json: Json, elem_ty: &stmt::Type) -> Value {
let Json::Array(items) = json else {
panic!("expected JSON array for Vec<scalar> column, got {json:?}")
};
Value::List(
items
.into_iter()
.map(|v| value_from_json(v, elem_ty))
.collect(),
)
}