Skip to main content

spreadsheet_kit/
response_prune.rs

1use anyhow::Result;
2use schemars::{JsonSchema, Schema, SchemaGenerator};
3use serde::Serialize;
4use serde::ser::Error as _;
5use serde_json::Value;
6use std::borrow::Cow;
7
8pub fn to_pruned_value<T: Serialize>(value: &T) -> Result<Value> {
9    let mut json = serde_json::to_value(value)?;
10    prune_non_structural_empties(&mut json);
11    Ok(json)
12}
13
14#[derive(Debug, Clone)]
15pub struct Pruned<T>(pub T);
16
17impl<T: Serialize> Serialize for Pruned<T> {
18    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
19    where
20        S: serde::Serializer,
21    {
22        let mut value = serde_json::to_value(&self.0).map_err(S::Error::custom)?;
23        prune_non_structural_empties(&mut value);
24        value.serialize(serializer)
25    }
26}
27
28impl<T: JsonSchema> JsonSchema for Pruned<T> {
29    fn schema_name() -> Cow<'static, str> {
30        T::schema_name()
31    }
32
33    fn json_schema(generator: &mut SchemaGenerator) -> Schema {
34        T::json_schema(generator)
35    }
36}
37
38fn preserve_empty_array_for_key(key: &str) -> bool {
39    matches!(
40        key,
41        "warnings"
42            | "matches"
43            | "target_deltas"
44            | "changed_targets"
45            | "new_errors"
46            | "resolved_errors"
47            | "preexisting_errors"
48            | "named_range_deltas"
49            | "formula_targets"
50            | "likely_patch_targets"
51            | "adjacent_sum_targets"
52            | "merged_ranges_fully_contained"
53            | "merged_ranges_crossing_boundary"
54    )
55}
56
57pub fn prune_non_structural_empties(value: &mut Value) {
58    match value {
59        Value::Object(map) => {
60            let mut remove_keys = Vec::new();
61            for (key, child) in map.iter_mut() {
62                prune_non_structural_empties(child);
63                if child.is_null() {
64                    remove_keys.push(key.clone());
65                    continue;
66                }
67                if let Value::Object(obj) = child
68                    && obj.is_empty()
69                {
70                    remove_keys.push(key.clone());
71                    continue;
72                }
73                if let Value::Array(arr) = child
74                    && arr.is_empty()
75                    && !preserve_empty_array_for_key(key)
76                {
77                    remove_keys.push(key.clone());
78                }
79            }
80            for key in remove_keys {
81                map.remove(&key);
82            }
83        }
84        Value::Array(items) => {
85            for child in items.iter_mut() {
86                prune_non_structural_empties(child);
87            }
88        }
89        _ => {}
90    }
91}