Skip to main content

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