postrust_response/
json.rs

1//! JSON response formatting.
2
3use super::FormatError;
4use bytes::Bytes;
5
6/// Format rows as a JSON array.
7pub fn format_json_response(rows: &[serde_json::Value]) -> Result<Bytes, FormatError> {
8    let json = serde_json::to_vec(rows)?;
9    Ok(Bytes::from(json))
10}
11
12/// Format a single row as JSON object.
13pub fn format_json_object(row: &serde_json::Value) -> Result<Bytes, FormatError> {
14    let json = serde_json::to_vec(row)?;
15    Ok(Bytes::from(json))
16}
17
18/// Format rows with nulls stripped (for vnd.pgrst.array+json).
19pub fn format_json_strip_nulls(rows: &[serde_json::Value]) -> Result<Bytes, FormatError> {
20    let stripped: Vec<serde_json::Value> = rows
21        .iter()
22        .map(|row| strip_nulls(row.clone()))
23        .collect();
24    let json = serde_json::to_vec(&stripped)?;
25    Ok(Bytes::from(json))
26}
27
28/// Recursively strip null values from a JSON value.
29fn strip_nulls(value: serde_json::Value) -> serde_json::Value {
30    match value {
31        serde_json::Value::Object(map) => {
32            let filtered: serde_json::Map<String, serde_json::Value> = map
33                .into_iter()
34                .filter(|(_, v)| !v.is_null())
35                .map(|(k, v)| (k, strip_nulls(v)))
36                .collect();
37            serde_json::Value::Object(filtered)
38        }
39        serde_json::Value::Array(arr) => {
40            let filtered: Vec<serde_json::Value> = arr
41                .into_iter()
42                .map(strip_nulls)
43                .collect();
44            serde_json::Value::Array(filtered)
45        }
46        other => other,
47    }
48}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53    use serde_json::json;
54
55    #[test]
56    fn test_format_json_response() {
57        let rows = vec![
58            json!({"id": 1, "name": "Alice"}),
59            json!({"id": 2, "name": "Bob"}),
60        ];
61
62        let result = format_json_response(&rows).unwrap();
63        let parsed: Vec<serde_json::Value> = serde_json::from_slice(&result).unwrap();
64
65        assert_eq!(parsed.len(), 2);
66        assert_eq!(parsed[0]["name"], "Alice");
67    }
68
69    #[test]
70    fn test_format_json_object() {
71        let row = json!({"id": 1, "name": "Alice"});
72
73        let result = format_json_object(&row).unwrap();
74        let parsed: serde_json::Value = serde_json::from_slice(&result).unwrap();
75
76        assert_eq!(parsed["name"], "Alice");
77    }
78
79    #[test]
80    fn test_strip_nulls() {
81        let value = json!({
82            "id": 1,
83            "name": "Alice",
84            "email": null,
85            "nested": {
86                "a": 1,
87                "b": null
88            }
89        });
90
91        let stripped = strip_nulls(value);
92
93        assert!(stripped.get("id").is_some());
94        assert!(stripped.get("name").is_some());
95        assert!(stripped.get("email").is_none());
96        assert!(stripped["nested"].get("b").is_none());
97    }
98
99    #[test]
100    fn test_format_empty_array() {
101        let rows: Vec<serde_json::Value> = vec![];
102        let result = format_json_response(&rows).unwrap();
103        assert_eq!(&result[..], b"[]");
104    }
105}