Closed plippe closed 3 years ago
I have written some helpers for my own application. Beware, my solution doesn't handle all cases. I have mapped some types to Null
instead of properly handling the issue.
fn recursive_into_value_with_serialize(value: serde_json::value::Value) -> Value {
match value {
serde_json::value::Value::Null => Value::EntityValue(HashMap::new()),
serde_json::value::Value::Bool(b) => Value::BooleanValue(b),
serde_json::value::Value::String(s) => Value::StringValue(s),
serde_json::value::Value::Number(n) => n
.as_i64()
.map(Value::IntegerValue)
.or_else(|| n.as_f64().map(Value::DoubleValue))
.unwrap(),
serde_json::value::Value::Array(vec) => {
let vec = vec
.into_iter()
.map(recursive_into_value_with_serialize)
.collect::<Vec<Value>>();
Value::ArrayValue(vec)
}
serde_json::value::Value::Object(map) => {
let map = map
.into_iter()
.map(|(k, v)| (k, recursive_into_value_with_serialize(v)))
.collect::<HashMap<String, Value>>();
Value::EntityValue(map)
}
}
}
pub fn into_value_with_serialize<A>(value: A) -> Value
where
A: serde::Serialize,
{
let value = serde_json::to_value(value).unwrap();
recursive_into_value_with_serialize(value)
}
fn recursive_from_value_with_deserialize(value: Value) -> serde_json::value::Value {
match value {
Value::BooleanValue(b) => serde_json::value::Value::Bool(b),
Value::IntegerValue(i) => serde_json::value::Value::Number(i.into()),
Value::DoubleValue(f) => {
serde_json::value::Value::Number(serde_json::Number::from_f64(f).unwrap())
}
Value::StringValue(s) => serde_json::value::Value::String(s),
Value::EntityValue(map) if map.is_empty() => serde_json::value::Value::Null,
Value::EntityValue(map) => {
let map = map
.into_iter()
.map(|(k, v)| (k, recursive_from_value_with_deserialize(v)))
.collect::<serde_json::map::Map<String, serde_json::value::Value>>();
serde_json::value::Value::Object(map)
}
Value::ArrayValue(vec) => {
let vec = vec
.into_iter()
.map(recursive_from_value_with_deserialize)
.collect::<Vec<serde_json::value::Value>>();
serde_json::value::Value::Array(vec)
}
Value::KeyValue(_) => serde_json::value::Value::Null,
Value::TimestampValue(_) => serde_json::value::Value::Null,
Value::BlobValue(_) => serde_json::value::Value::Null,
Value::GeoPointValue(_, _) => serde_json::value::Value::Null,
}
}
pub fn from_value_with_deserialize<A>(
value: google_cloud::datastore::Value,
) -> std::result::Result<A, ConvertError>
where
A: for<'de> serde::Deserialize<'de>,
{
let value = recursive_from_value_with_deserialize(value);
serde_json::from_value::<A>(value).map_err(|_| ConvertError::MissingProperty("".to_owned()))
}
Lastly, those helpers are used in the IntoValue
and FromValue
implementations.
impl FromValue for MyType {
fn from_value(value: Value) -> std::result::Result<Self, ConvertError> {
datastore::from_value_with_deserialize::<Self>(value)
}
}
impl IntoValue for MyType {
fn into_value(self) -> Value {
datastore::into_value_with_serialize::<Self>(self)
}
}
Hope this helps others and possibly makes it into the next version of the crate.
Hi,
Serde is a create library to encode and decode values. The list of supported data formats is quite large and contains json.
Are there any reasons Serde wasn't used for Google's Datastore?