lemma/serialization/
json.rs1use crate::planning::semantics::{FactData, FactPath};
2use crate::planning::ExecutionPlan;
3use crate::LemmaError;
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5use serde_json::Value;
6use std::collections::{HashMap, HashSet};
7
8pub fn from_json(
13 json: &[u8],
14 _plan: &ExecutionPlan,
15) -> Result<HashMap<String, String>, LemmaError> {
16 let map: HashMap<String, Value> = serde_json::from_slice(json).map_err(|e| {
17 LemmaError::engine(format!("JSON parse error: {}", e), None, None::<String>)
18 })?;
19
20 Ok(map
21 .into_iter()
22 .filter(|(_, v)| !v.is_null())
23 .map(|(k, v)| (k, json_value_to_string(&v)))
24 .collect())
25}
26
27fn json_value_to_string(value: &Value) -> String {
28 match value {
29 Value::String(s) => s.clone(),
30 Value::Number(n) => n.to_string(),
31 Value::Bool(b) => b.to_string(),
32 Value::Array(_) | Value::Object(_) => serde_json::to_string(value).unwrap_or_default(),
33 Value::Null => String::new(),
34 }
35}
36
37pub fn serialize_resolved_fact_value_map<S>(
39 map: &HashMap<FactPath, FactData>,
40 serializer: S,
41) -> Result<S::Ok, S::Error>
42where
43 S: Serializer,
44{
45 let entries: Vec<(&FactPath, &FactData)> = map.iter().collect();
46 entries.serialize(serializer)
47}
48
49pub fn deserialize_resolved_fact_value_map<'de, D>(
51 deserializer: D,
52) -> Result<HashMap<FactPath, FactData>, D::Error>
53where
54 D: Deserializer<'de>,
55{
56 let entries: Vec<(FactPath, FactData)> = Vec::deserialize(deserializer)?;
57 Ok(entries.into_iter().collect())
58}
59
60pub fn serialize_fact_path_set<S>(set: &HashSet<FactPath>, serializer: S) -> Result<S::Ok, S::Error>
62where
63 S: Serializer,
64{
65 let items: Vec<&FactPath> = set.iter().collect();
66 items.serialize(serializer)
67}
68
69pub fn deserialize_fact_path_set<'de, D>(deserializer: D) -> Result<HashSet<FactPath>, D::Error>
71where
72 D: Deserializer<'de>,
73{
74 let items: Vec<FactPath> = Vec::deserialize(deserializer)?;
75 Ok(items.into_iter().collect())
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81 fn create_test_plan() -> ExecutionPlan {
82 ExecutionPlan {
83 doc_name: "test".to_string(),
84 facts: HashMap::new(),
85 rules: vec![],
86 sources: HashMap::from([("<test>".to_string(), "".to_string())]),
87 }
88 }
89
90 #[test]
91 fn test_json_string_to_string() {
92 let plan = create_test_plan();
93 let json = br#"{"name": "Alice"}"#;
94 let result = from_json(json, &plan).unwrap();
95 assert_eq!(result.get("name"), Some(&"Alice".to_string()));
96 }
97
98 #[test]
99 fn test_json_number_to_string() {
100 let plan = create_test_plan();
101 let json = br#"{"name": 42}"#;
102 let result = from_json(json, &plan).unwrap();
103 assert_eq!(result.get("name"), Some(&"42".to_string()));
104 }
105
106 #[test]
107 fn test_json_boolean_to_string() {
108 let plan = create_test_plan();
109 let json = br#"{"name": true}"#;
110 let result = from_json(json, &plan).unwrap();
111 assert_eq!(result.get("name"), Some(&"true".to_string()));
112 }
113
114 #[test]
115 fn test_json_array_to_string() {
116 let plan = create_test_plan();
117 let json = br#"{"data": [1, 2, 3]}"#;
118 let result = from_json(json, &plan).unwrap();
119 assert_eq!(result.get("data"), Some(&"[1,2,3]".to_string()));
120 }
121
122 #[test]
123 fn test_json_object_to_string() {
124 let plan = create_test_plan();
125 let json = br#"{"config": {"key": "value"}}"#;
126 let result = from_json(json, &plan).unwrap();
127 assert_eq!(
128 result.get("config"),
129 Some(&"{\"key\":\"value\"}".to_string())
130 );
131 }
132
133 #[test]
134 fn test_null_value_skipped() {
135 let plan = create_test_plan();
136 let json = br#"{"name": null, "age": 30}"#;
137 let result = from_json(json, &plan).unwrap();
138 assert_eq!(result.len(), 1);
139 assert!(!result.contains_key("name"));
140 assert_eq!(result.get("age"), Some(&"30".to_string()));
141 }
142
143 #[test]
144 fn test_all_null_values() {
145 let plan = create_test_plan();
146 let json = br#"{"name": null}"#;
147 let result = from_json(json, &plan).unwrap();
148 assert!(result.is_empty());
149 }
150
151 #[test]
152 fn test_mixed_valid_types() {
153 let plan = create_test_plan();
154 let json = br#"{"name": "Test", "count": 5, "active": true, "discount": 21}"#;
155 let result = from_json(json, &plan).unwrap();
156 assert_eq!(result.len(), 4);
157 assert_eq!(result.get("name"), Some(&"Test".to_string()));
158 assert_eq!(result.get("count"), Some(&"5".to_string()));
159 assert_eq!(result.get("active"), Some(&"true".to_string()));
160 assert_eq!(result.get("discount"), Some(&"21".to_string()));
161 }
162
163 #[test]
164 fn test_invalid_json_syntax() {
165 let plan = create_test_plan();
166 let json = br#"{"name": }"#;
167 let result = from_json(json, &plan);
168 assert!(result.is_err());
169 let error_message = result.unwrap_err().to_string();
170 assert!(error_message.contains("JSON parse error"));
171 }
172}