pjson_rs/infrastructure/adapters/
json_adapter.rs1use crate::domain::value_objects::JsonData;
7use serde_json::Value as SerdeValue;
8use std::collections::HashMap;
9
10pub struct JsonAdapter;
12
13impl JsonAdapter {
14 pub fn to_serde_value(data: &JsonData) -> SerdeValue {
16 match data {
17 JsonData::Null => SerdeValue::Null,
18 JsonData::Bool(b) => SerdeValue::Bool(*b),
19 JsonData::Integer(i) => SerdeValue::Number(serde_json::Number::from(*i)),
20 JsonData::Float(f) => SerdeValue::Number(
21 serde_json::Number::from_f64(*f).unwrap_or_else(|| serde_json::Number::from(0)),
22 ),
23 JsonData::String(s) => SerdeValue::String(s.clone()),
24 JsonData::Array(arr) => {
25 let values: Vec<SerdeValue> = arr.iter().map(Self::to_serde_value).collect();
26 SerdeValue::Array(values)
27 }
28 JsonData::Object(obj) => {
29 let mut map = serde_json::Map::new();
30 for (key, value) in obj {
31 map.insert(key.clone(), Self::to_serde_value(value));
32 }
33 SerdeValue::Object(map)
34 }
35 }
36 }
37
38 pub fn from_serde_value(value: &SerdeValue) -> JsonData {
40 match value {
41 SerdeValue::Null => JsonData::Null,
42 SerdeValue::Bool(b) => JsonData::Bool(*b),
43 SerdeValue::Number(n) => {
44 if let Some(i) = n.as_i64() {
45 JsonData::Integer(i)
46 } else if let Some(f) = n.as_f64() {
47 JsonData::Float(f)
48 } else {
49 JsonData::Integer(0) }
51 }
52 SerdeValue::String(s) => JsonData::String(s.clone()),
53 SerdeValue::Array(arr) => {
54 let values: Vec<JsonData> = arr.iter().map(Self::from_serde_value).collect();
55 JsonData::Array(values)
56 }
57 SerdeValue::Object(obj) => {
58 let mut map = HashMap::new();
59 for (key, value) in obj {
60 map.insert(key.clone(), Self::from_serde_value(value));
61 }
62 JsonData::Object(map)
63 }
64 }
65 }
66
67 pub fn parse_json_string(json_str: &str) -> Result<JsonData, serde_json::Error> {
69 let serde_value: SerdeValue = serde_json::from_str(json_str)?;
70 Ok(Self::from_serde_value(&serde_value))
71 }
72
73 pub fn to_json_string(data: &JsonData) -> Result<String, serde_json::Error> {
75 let serde_value = Self::to_serde_value(data);
76 serde_json::to_string(&serde_value)
77 }
78
79 pub fn to_json_string_pretty(data: &JsonData) -> Result<String, serde_json::Error> {
81 let serde_value = Self::to_serde_value(data);
82 serde_json::to_string_pretty(&serde_value)
83 }
84
85 pub fn merge(left: JsonData, right: JsonData) -> JsonData {
87 match (left, right) {
88 (JsonData::Object(mut left_obj), JsonData::Object(right_obj)) => {
89 for (key, value) in right_obj {
90 if let Some(existing) = left_obj.get(&key).cloned() {
91 left_obj.insert(key, Self::merge(existing, value));
92 } else {
93 left_obj.insert(key, value);
94 }
95 }
96 JsonData::Object(left_obj)
97 }
98 (_, right) => right, }
100 }
101
102 pub fn deep_clone(data: &JsonData) -> JsonData {
104 data.clone() }
106
107 pub fn validate_pjs_structure(data: &JsonData) -> Result<(), String> {
109 match data {
110 JsonData::Object(_) => Ok(()), JsonData::Array(_) => Ok(()), _ => Err("PJS root data must be object or array".to_string()),
113 }
114 }
115
116 pub fn extract_leaf_paths(data: &JsonData) -> Vec<String> {
118 let mut paths = Vec::new();
119 Self::extract_paths_recursive(data, String::new(), &mut paths);
120 paths
121 }
122
123 fn extract_paths_recursive(data: &JsonData, current_path: String, paths: &mut Vec<String>) {
124 match data {
125 JsonData::Object(obj) => {
126 if obj.is_empty() {
127 paths.push(current_path);
128 } else {
129 for (key, value) in obj {
130 let new_path = if current_path.is_empty() {
131 key.clone()
132 } else {
133 format!("{current_path}.{key}")
134 };
135 Self::extract_paths_recursive(value, new_path, paths);
136 }
137 }
138 }
139 JsonData::Array(arr) => {
140 if arr.is_empty() {
141 paths.push(current_path);
142 } else {
143 for (index, value) in arr.iter().enumerate() {
144 let new_path = if current_path.is_empty() {
145 format!("[{index}]")
146 } else {
147 format!("{current_path}[{index}]")
148 };
149 Self::extract_paths_recursive(value, new_path, paths);
150 }
151 }
152 }
153 _ => {
154 paths.push(current_path);
156 }
157 }
158 }
159}
160
161#[cfg(test)]
162mod tests {
163 use super::*;
164
165 #[test]
166 fn test_serde_conversion_primitives() {
167 let json_data = JsonData::string("hello");
168 let serde_value = JsonAdapter::to_serde_value(&json_data);
169 let converted_back = JsonAdapter::from_serde_value(&serde_value);
170
171 assert_eq!(json_data, converted_back);
172 }
173
174 #[test]
175 fn test_serde_conversion_complex() {
176 let mut obj = HashMap::new();
177 obj.insert("name".to_string(), JsonData::string("John"));
178 obj.insert("age".to_string(), JsonData::integer(30));
179 obj.insert("active".to_string(), JsonData::bool(true));
180
181 let json_data = JsonData::object(obj);
182 let serde_value = JsonAdapter::to_serde_value(&json_data);
183 let converted_back = JsonAdapter::from_serde_value(&serde_value);
184
185 assert_eq!(json_data, converted_back);
186 }
187
188 #[test]
189 fn test_json_string_parsing() {
190 let json_str = r#"{"name":"John","age":30,"active":true}"#;
191 let parsed = JsonAdapter::parse_json_string(json_str).unwrap();
192
193 assert_eq!(parsed.get_path("name").unwrap().as_str(), Some("John"));
194 assert_eq!(parsed.get_path("age").unwrap().as_f64(), Some(30.0));
195 assert_eq!(parsed.get_path("active").unwrap().as_bool(), Some(true));
196 }
197
198 #[test]
199 fn test_json_string_generation() {
200 let mut obj = HashMap::new();
201 obj.insert("name".to_string(), JsonData::string("John"));
202 obj.insert("age".to_string(), JsonData::integer(30));
203
204 let json_data = JsonData::object(obj);
205 let json_str = JsonAdapter::to_json_string(&json_data).unwrap();
206
207 assert!(json_str.contains("John"));
208 assert!(json_str.contains("30"));
209 }
210
211 #[test]
212 fn test_merge_objects() {
213 let mut left = HashMap::new();
214 left.insert("name".to_string(), JsonData::string("John"));
215 left.insert("age".to_string(), JsonData::integer(25));
216
217 let mut right = HashMap::new();
218 right.insert("age".to_string(), JsonData::integer(30));
219 right.insert("city".to_string(), JsonData::string("NYC"));
220
221 let merged = JsonAdapter::merge(JsonData::object(left), JsonData::object(right));
222
223 assert_eq!(merged.get_path("name").unwrap().as_str(), Some("John"));
224 assert_eq!(merged.get_path("age").unwrap().as_i64(), Some(30)); assert_eq!(merged.get_path("city").unwrap().as_str(), Some("NYC"));
226 }
227
228 #[test]
229 fn test_extract_leaf_paths() {
230 let mut user = HashMap::new();
231 user.insert("name".to_string(), JsonData::string("John"));
232 user.insert("age".to_string(), JsonData::integer(30));
233
234 let mut profile = HashMap::new();
235 profile.insert("bio".to_string(), JsonData::string("Developer"));
236 user.insert("profile".to_string(), JsonData::object(profile));
237
238 let root = JsonData::object(
239 [("user".to_string(), JsonData::object(user))]
240 .into_iter()
241 .collect(),
242 );
243
244 let paths = JsonAdapter::extract_leaf_paths(&root);
245
246 assert!(paths.contains(&"user.name".to_string()));
247 assert!(paths.contains(&"user.age".to_string()));
248 assert!(paths.contains(&"user.profile.bio".to_string()));
249 }
250
251 #[test]
252 fn test_validate_pjs_structure() {
253 assert!(JsonAdapter::validate_pjs_structure(&JsonData::object(HashMap::new())).is_ok());
255 assert!(JsonAdapter::validate_pjs_structure(&JsonData::array(vec![])).is_ok());
256
257 assert!(JsonAdapter::validate_pjs_structure(&JsonData::string("test")).is_err());
259 assert!(JsonAdapter::validate_pjs_structure(&JsonData::integer(42)).is_err());
260 }
261}