base_d/encoders/algorithms/schema/serializers/
json.rs

1use crate::encoders::algorithms::schema::serializers::OutputSerializer;
2use crate::encoders::algorithms::schema::types::*;
3use serde_json::{Map, Value, json};
4use std::collections::HashMap;
5
6pub struct JsonSerializer;
7
8impl OutputSerializer for JsonSerializer {
9    type Error = SchemaError;
10
11    fn serialize(ir: &IntermediateRepresentation, pretty: bool) -> Result<String, Self::Error> {
12        if ir.header.row_count == 0 {
13            return Err(SchemaError::InvalidInput(
14                "No rows to serialize".to_string(),
15            ));
16        }
17
18        // Build rows
19        let mut rows = Vec::new();
20        for row_idx in 0..ir.header.row_count {
21            let mut row_map = HashMap::new();
22
23            for (field_idx, field) in ir.header.fields.iter().enumerate() {
24                let value = ir
25                    .get_value(row_idx, field_idx)
26                    .ok_or_else(|| SchemaError::InvalidInput("Missing value".to_string()))?;
27
28                let json_value = if ir.is_null(row_idx, field_idx) {
29                    Value::Null
30                } else {
31                    schema_value_to_json(value)?
32                };
33
34                row_map.insert(field.name.clone(), json_value);
35            }
36
37            rows.push(row_map);
38        }
39
40        // Unflatten each row
41        let mut unflattened_rows = Vec::new();
42        for row_map in rows {
43            let unflattened = unflatten_object(row_map);
44            unflattened_rows.push(unflattened);
45        }
46
47        // Determine output format
48        let result = if ir.header.row_count == 1 {
49            // Single row - output as object
50            unflattened_rows.into_iter().next().unwrap()
51        } else {
52            // Multiple rows - output as array
53            Value::Array(unflattened_rows)
54        };
55
56        // Apply root key if present
57        let final_result = if let Some(root_key) = &ir.header.root_key {
58            let mut obj = Map::new();
59            obj.insert(root_key.clone(), result);
60            Value::Object(obj)
61        } else {
62            result
63        };
64
65        // Serialize to JSON string
66        if pretty {
67            serde_json::to_string_pretty(&final_result)
68                .map_err(|e| SchemaError::InvalidInput(format!("JSON serialization failed: {}", e)))
69        } else {
70            serde_json::to_string(&final_result)
71                .map_err(|e| SchemaError::InvalidInput(format!("JSON serialization failed: {}", e)))
72        }
73    }
74}
75
76/// Convert SchemaValue to JSON Value
77fn schema_value_to_json(value: &SchemaValue) -> Result<Value, SchemaError> {
78    match value {
79        SchemaValue::U64(n) => Ok(json!(*n)),
80        SchemaValue::I64(n) => Ok(json!(*n)),
81        SchemaValue::F64(n) => Ok(json!(*n)),
82        SchemaValue::String(s) => Ok(json!(s)),
83        SchemaValue::Bool(b) => Ok(json!(*b)),
84        SchemaValue::Null => Ok(Value::Null),
85        SchemaValue::Array(arr) => {
86            let mut json_arr = Vec::new();
87            for item in arr {
88                json_arr.push(schema_value_to_json(item)?);
89            }
90            Ok(Value::Array(json_arr))
91        }
92    }
93}
94
95/// Unflatten dotted keys back to nested objects
96fn unflatten_object(flat: HashMap<String, Value>) -> Value {
97    let mut result = Map::new();
98
99    for (key, value) in flat {
100        let parts: Vec<&str> = key.split('.').collect();
101        insert_nested(&mut result, &parts, value);
102    }
103
104    Value::Object(result)
105}
106
107/// Insert a value into nested structure
108fn insert_nested(obj: &mut Map<String, Value>, parts: &[&str], value: Value) {
109    if parts.is_empty() {
110        return;
111    }
112
113    if parts.len() == 1 {
114        obj.insert(parts[0].to_string(), value);
115        return;
116    }
117
118    let key = parts[0];
119    let remaining = &parts[1..];
120
121    let nested = obj
122        .entry(key.to_string())
123        .or_insert_with(|| Value::Object(Map::new()));
124
125    if let Value::Object(nested_obj) = nested {
126        insert_nested(nested_obj, remaining, value);
127    }
128}
129
130#[cfg(test)]
131mod tests {
132    use super::*;
133
134    #[test]
135    fn test_simple_object() {
136        let fields = vec![
137            FieldDef::new("id", FieldType::U64),
138            FieldDef::new("name", FieldType::String),
139        ];
140        let header = SchemaHeader::new(1, fields);
141        let values = vec![
142            SchemaValue::U64(1),
143            SchemaValue::String("alice".to_string()),
144        ];
145        let ir = IntermediateRepresentation::new(header, values).unwrap();
146
147        let output = JsonSerializer::serialize(&ir, false).unwrap();
148        let parsed: Value = serde_json::from_str(&output).unwrap();
149
150        assert_eq!(parsed["id"], json!(1));
151        assert_eq!(parsed["name"], json!("alice"));
152    }
153
154    #[test]
155    fn test_array_of_objects() {
156        let fields = vec![FieldDef::new("id", FieldType::U64)];
157        let header = SchemaHeader::new(2, fields);
158        let values = vec![SchemaValue::U64(1), SchemaValue::U64(2)];
159        let ir = IntermediateRepresentation::new(header, values).unwrap();
160
161        let output = JsonSerializer::serialize(&ir, false).unwrap();
162        let parsed: Value = serde_json::from_str(&output).unwrap();
163
164        assert!(parsed.is_array());
165        assert_eq!(parsed[0]["id"], json!(1));
166        assert_eq!(parsed[1]["id"], json!(2));
167    }
168
169    #[test]
170    fn test_nested_object() {
171        let fields = vec![FieldDef::new("user.profile.name", FieldType::String)];
172        let header = SchemaHeader::new(1, fields);
173        let values = vec![SchemaValue::String("alice".to_string())];
174        let ir = IntermediateRepresentation::new(header, values).unwrap();
175
176        let output = JsonSerializer::serialize(&ir, false).unwrap();
177        let parsed: Value = serde_json::from_str(&output).unwrap();
178
179        assert_eq!(parsed["user"]["profile"]["name"], json!("alice"));
180    }
181
182    #[test]
183    fn test_root_key() {
184        let mut header = SchemaHeader::new(1, vec![FieldDef::new("id", FieldType::U64)]);
185        header.root_key = Some("users".to_string());
186        header.set_flag(FLAG_HAS_ROOT_KEY);
187
188        let values = vec![SchemaValue::U64(1)];
189        let ir = IntermediateRepresentation::new(header, values).unwrap();
190
191        let output = JsonSerializer::serialize(&ir, false).unwrap();
192        let parsed: Value = serde_json::from_str(&output).unwrap();
193
194        assert!(parsed["users"].is_object());
195        assert_eq!(parsed["users"]["id"], json!(1));
196    }
197
198    #[test]
199    fn test_null_handling() {
200        let mut header = SchemaHeader::new(
201            1,
202            vec![
203                FieldDef::new("name", FieldType::String),
204                FieldDef::new("age", FieldType::U64),
205            ],
206        );
207
208        // Mark age as null
209        let mut null_bitmap = vec![0u8; 1];
210        null_bitmap[0] |= 1 << 1; // Set bit 1
211        header.null_bitmap = Some(null_bitmap);
212        header.set_flag(FLAG_HAS_NULLS);
213
214        let values = vec![SchemaValue::String("alice".to_string()), SchemaValue::Null];
215        let ir = IntermediateRepresentation::new(header, values).unwrap();
216
217        let output = JsonSerializer::serialize(&ir, false).unwrap();
218        let parsed: Value = serde_json::from_str(&output).unwrap();
219
220        assert_eq!(parsed["name"], json!("alice"));
221        assert_eq!(parsed["age"], Value::Null);
222    }
223
224    #[test]
225    fn test_homogeneous_array() {
226        let fields = vec![FieldDef::new(
227            "scores",
228            FieldType::Array(Box::new(FieldType::U64)),
229        )];
230        let header = SchemaHeader::new(1, fields);
231        let values = vec![SchemaValue::Array(vec![
232            SchemaValue::U64(1),
233            SchemaValue::U64(2),
234            SchemaValue::U64(3),
235        ])];
236        let ir = IntermediateRepresentation::new(header, values).unwrap();
237
238        let output = JsonSerializer::serialize(&ir, false).unwrap();
239        let parsed: Value = serde_json::from_str(&output).unwrap();
240
241        assert_eq!(parsed["scores"], json!([1, 2, 3]));
242    }
243
244    #[test]
245    fn test_empty_array() {
246        let fields = vec![FieldDef::new(
247            "items",
248            FieldType::Array(Box::new(FieldType::Null)),
249        )];
250        let header = SchemaHeader::new(1, fields);
251        let values = vec![SchemaValue::Array(vec![])];
252        let ir = IntermediateRepresentation::new(header, values).unwrap();
253
254        let output = JsonSerializer::serialize(&ir, false).unwrap();
255        let parsed: Value = serde_json::from_str(&output).unwrap();
256
257        assert_eq!(parsed["items"], json!([]));
258    }
259
260    #[test]
261    fn test_deep_nesting() {
262        let fields = vec![FieldDef::new("a.b.c.d", FieldType::U64)];
263        let header = SchemaHeader::new(1, fields);
264        let values = vec![SchemaValue::U64(1)];
265        let ir = IntermediateRepresentation::new(header, values).unwrap();
266
267        let output = JsonSerializer::serialize(&ir, false).unwrap();
268        let parsed: Value = serde_json::from_str(&output).unwrap();
269
270        assert_eq!(parsed["a"]["b"]["c"]["d"], json!(1));
271    }
272
273    #[test]
274    fn test_unflatten_object() {
275        let mut flat = HashMap::new();
276        flat.insert("a.b".to_string(), json!(1));
277
278        let unflattened = unflatten_object(flat);
279
280        assert_eq!(unflattened["a"]["b"], json!(1));
281    }
282
283    #[test]
284    fn test_pretty_output() {
285        let fields = vec![
286            FieldDef::new("id", FieldType::U64),
287            FieldDef::new("name", FieldType::String),
288        ];
289        let header = SchemaHeader::new(1, fields);
290        let values = vec![
291            SchemaValue::U64(1),
292            SchemaValue::String("alice".to_string()),
293        ];
294        let ir = IntermediateRepresentation::new(header, values).unwrap();
295
296        // Test compact output
297        let compact = JsonSerializer::serialize(&ir, false).unwrap();
298        assert!(!compact.contains('\n'));
299        assert_eq!(compact, r#"{"id":1,"name":"alice"}"#);
300
301        // Test pretty output
302        let pretty = JsonSerializer::serialize(&ir, true).unwrap();
303        assert!(pretty.contains('\n'));
304        assert!(pretty.contains("  ")); // Indentation
305
306        // Both should parse to same JSON value
307        let compact_value: Value = serde_json::from_str(&compact).unwrap();
308        let pretty_value: Value = serde_json::from_str(&pretty).unwrap();
309        assert_eq!(compact_value, pretty_value);
310    }
311}