Skip to main content

doido_model/
serialization.rs

1//! Model serialization helpers: `as_json` with `only`/`except` filtering (Rails
2//! `as_json(only:/except:)`) and serialized columns (store a struct as JSON text).
3
4use serde::de::DeserializeOwned;
5use serde::Serialize;
6use serde_json::Value;
7
8/// Serialize a value to a JSON [`Value`] (null on failure).
9pub fn as_json<T: Serialize>(value: &T) -> Value {
10    serde_json::to_value(value).unwrap_or(Value::Null)
11}
12
13/// Serialize keeping only the listed top-level keys (Rails `as_json(only:)`).
14pub fn as_json_only<T: Serialize>(value: &T, keys: &[&str]) -> Value {
15    filter_object(as_json(value), |k| keys.contains(&k))
16}
17
18/// Serialize dropping the listed top-level keys (Rails `as_json(except:)`).
19pub fn as_json_except<T: Serialize>(value: &T, keys: &[&str]) -> Value {
20    filter_object(as_json(value), |k| !keys.contains(&k))
21}
22
23fn filter_object(value: Value, keep: impl Fn(&str) -> bool) -> Value {
24    match value {
25        Value::Object(map) => Value::Object(map.into_iter().filter(|(k, _)| keep(k)).collect()),
26        other => other,
27    }
28}
29
30/// Serialize a value to a JSON string for storage in a text/JSON column.
31pub fn serialize_column<T: Serialize>(value: &T) -> doido_core::Result<String> {
32    serde_json::to_string(value)
33        .map_err(|e| doido_core::anyhow::anyhow!("serialize_column failed: {e}"))
34}
35
36/// Deserialize a value previously stored by [`serialize_column`].
37pub fn deserialize_column<T: DeserializeOwned>(raw: &str) -> doido_core::Result<T> {
38    serde_json::from_str(raw)
39        .map_err(|e| doido_core::anyhow::anyhow!("deserialize_column failed: {e}"))
40}