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

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