1#[allow(deprecated)]
2use crate::formatter::StaticDataFormatter;
3use crate::formatter::{RecordFormatter, ValueFormatter};
4use serde_json::{Value as JsonValue, json};
5use wp_model_core::model::{DataRecord, DataType, FieldStorage, Value, types::value::ObjectValue};
6
7#[derive(Debug, Default)]
8pub struct Json;
9
10#[allow(deprecated)]
11impl StaticDataFormatter for Json {
12 type Output = String;
13 fn stdfmt_null() -> String {
14 "null".to_string()
15 }
16 fn stdfmt_bool(value: &bool) -> String {
17 json!(value).to_string()
18 }
19 fn stdfmt_string(value: &str) -> String {
20 serde_json::to_string(value).unwrap_or_else(|_| "\"\"".to_string())
21 }
22 fn stdfmt_i64(value: &i64) -> String {
23 json!(value).to_string()
24 }
25 fn stdfmt_f64(value: &f64) -> String {
26 if value.is_nan() {
27 "null".to_string()
28 } else if value.is_infinite() {
29 if value.is_sign_positive() {
30 "\"Infinity\"".to_string()
31 } else {
32 "\"-Infinity\"".to_string()
33 }
34 } else {
35 json!(value).to_string()
36 }
37 }
38 fn stdfmt_ip_addr(value: &std::net::IpAddr) -> String {
39 json!(value.to_string()).to_string()
40 }
41 fn stdfmt_datetime(value: &chrono::NaiveDateTime) -> String {
42 json!(value.to_string()).to_string()
43 }
44 fn stdfmt_object(value: &ObjectValue) -> String {
45 let mut json_obj = serde_json::Map::new();
46 for (_k, v) in value.iter() {
47 json_obj.insert(v.get_name().to_string(), to_json_value(v.get_value()));
48 }
49 json!(json_obj).to_string()
50 }
51 fn stdfmt_array(value: &[FieldStorage]) -> String {
52 let items: Vec<String> = value
53 .iter()
54 .map(|field| match field.get_value() {
55 Value::Chars(s) => Self::stdfmt_string(s),
56 _ => Self::stdfmt_value(field.get_value()),
57 })
58 .collect();
59 format!("[{}]", items.join(","))
60 }
61 fn stdfmt_field(field: &FieldStorage) -> String {
62 if field.get_name().is_empty() {
63 Self::stdfmt_value(field.get_value())
64 } else {
65 format!(
66 "\"{}\":{}",
67 field.get_name(),
68 Self::stdfmt_value(field.get_value())
69 )
70 }
71 }
72 fn stdfmt_record(record: &DataRecord) -> String {
73 let mut items = Vec::new();
74 for field in record
75 .items
76 .iter()
77 .filter(|f| *f.get_meta() != DataType::Ignore)
78 {
79 items.push(Self::stdfmt_field(field));
80 }
81 format!("{{{}}}", items.join(","))
82 }
83}
84
85#[allow(deprecated)]
86impl crate::formatter::DataFormat for Json {
87 type Output = String;
88 fn format_null(&self) -> String {
89 Self::stdfmt_null()
90 }
91 fn format_bool(&self, v: &bool) -> String {
92 Self::stdfmt_bool(v)
93 }
94 fn format_string(&self, v: &str) -> String {
95 Self::stdfmt_string(v)
96 }
97 fn format_i64(&self, v: &i64) -> String {
98 Self::stdfmt_i64(v)
99 }
100 fn format_f64(&self, v: &f64) -> String {
101 Self::stdfmt_f64(v)
102 }
103 fn format_ip(&self, v: &std::net::IpAddr) -> String {
104 Self::stdfmt_ip_addr(v)
105 }
106 fn format_datetime(&self, v: &chrono::NaiveDateTime) -> String {
107 Self::stdfmt_datetime(v)
108 }
109 fn format_object(&self, v: &ObjectValue) -> String {
110 Self::stdfmt_object(v)
111 }
112 fn format_array(&self, v: &[FieldStorage]) -> String {
113 Self::stdfmt_array(v)
114 }
115 fn format_field(&self, f: &FieldStorage) -> String {
116 Self::stdfmt_field(f)
117 }
118 fn format_record(&self, r: &DataRecord) -> String {
119 Self::stdfmt_record(r)
120 }
121}
122
123fn to_json_value(value: &Value) -> JsonValue {
124 match value {
125 Value::Bool(v) => JsonValue::Bool(*v),
126 Value::Chars(v) => JsonValue::String(v.to_string()),
127 Value::Digit(v) => JsonValue::Number((*v).into()),
128 Value::Float(v) => {
129 if v.is_nan() {
130 JsonValue::Null
131 } else if v.is_infinite() {
132 if v.is_sign_positive() {
133 JsonValue::String("Infinity".to_string())
134 } else {
135 JsonValue::String("-Infinity".to_string())
136 }
137 } else {
138 JsonValue::Number(serde_json::Number::from_f64(*v).unwrap_or(0.into()))
139 }
140 }
141 Value::IpAddr(v) => JsonValue::String(v.to_string()),
142 Value::Time(v) => JsonValue::String(v.to_string()),
143 Value::Obj(v) => {
144 let mut map = serde_json::Map::new();
145 for (_k, field) in v.iter() {
146 map.insert(
147 field.get_name().to_string(),
148 to_json_value(field.get_value()),
149 );
150 }
151 JsonValue::Object(map)
152 }
153 Value::Array(v) => {
154 JsonValue::Array(v.iter().map(|f| to_json_value(f.get_value())).collect())
155 }
156 _ => JsonValue::Null,
157 }
158}
159
160#[cfg(test)]
161#[allow(deprecated)]
162mod tests {
163 use super::*;
164 use crate::formatter::DataFormat;
165 use std::net::IpAddr;
166 use std::str::FromStr;
167 use wp_model_core::model::DataField;
168
169 #[test]
170 fn test_json_stdfmt_null() {
171 assert_eq!(Json::stdfmt_null(), "null");
172 }
173
174 #[test]
175 fn test_json_stdfmt_bool() {
176 assert_eq!(Json::stdfmt_bool(&true), "true");
177 assert_eq!(Json::stdfmt_bool(&false), "false");
178 }
179
180 #[test]
181 fn test_json_stdfmt_string() {
182 assert_eq!(Json::stdfmt_string("hello"), "\"hello\"");
183 assert_eq!(Json::stdfmt_string(""), "\"\"");
184 assert_eq!(Json::stdfmt_string("say \"hi\""), "\"say \\\"hi\\\"\"");
186 }
187
188 #[test]
189 fn test_json_stdfmt_i64() {
190 assert_eq!(Json::stdfmt_i64(&0), "0");
191 assert_eq!(Json::stdfmt_i64(&42), "42");
192 assert_eq!(Json::stdfmt_i64(&-100), "-100");
193 }
194
195 #[test]
196 fn test_json_stdfmt_f64_normal() {
197 assert_eq!(Json::stdfmt_f64(&3.24), "3.24");
198 assert_eq!(Json::stdfmt_f64(&0.0), "0.0");
199 assert_eq!(Json::stdfmt_f64(&-2.5), "-2.5");
200 }
201
202 #[test]
203 fn test_json_stdfmt_f64_special() {
204 assert_eq!(Json::stdfmt_f64(&f64::NAN), "null");
205 assert_eq!(Json::stdfmt_f64(&f64::INFINITY), "\"Infinity\"");
206 assert_eq!(Json::stdfmt_f64(&f64::NEG_INFINITY), "\"-Infinity\"");
207 }
208
209 #[test]
210 fn test_json_stdfmt_ip_addr() {
211 let ipv4 = IpAddr::from_str("192.168.1.1").unwrap();
212 assert_eq!(Json::stdfmt_ip_addr(&ipv4), "\"192.168.1.1\"");
213
214 let ipv6 = IpAddr::from_str("::1").unwrap();
215 assert_eq!(Json::stdfmt_ip_addr(&ipv6), "\"::1\"");
216 }
217
218 #[test]
219 fn test_json_stdfmt_datetime() {
220 let dt = chrono::NaiveDateTime::parse_from_str("2024-01-15 10:30:45", "%Y-%m-%d %H:%M:%S")
221 .unwrap();
222 let result = Json::stdfmt_datetime(&dt);
223 assert!(result.starts_with('"'));
224 assert!(result.ends_with('"'));
225 assert!(result.contains("2024"));
226 }
227
228 #[test]
229 fn test_json_stdfmt_field_with_name() {
230 let field = FieldStorage::from_owned(DataField::from_chars("name", "Alice"));
231 let result = Json::stdfmt_field(&field);
232 assert_eq!(result, "\"name\":\"Alice\"");
233 }
234
235 #[test]
236 fn test_json_stdfmt_field_without_name() {
237 let field = FieldStorage::from_owned(DataField::from_chars("", "value"));
238 let result = Json::stdfmt_field(&field);
239 assert_eq!(result, "\"value\"");
240 }
241
242 #[test]
243 fn test_json_stdfmt_record() {
244 let record = DataRecord {
245 id: Default::default(),
246 items: vec![
247 FieldStorage::from_owned(DataField::from_chars("name", "Alice")),
248 FieldStorage::from_owned(DataField::from_digit("age", 30)),
249 ],
250 };
251 let result = Json::stdfmt_record(&record);
252 assert!(result.starts_with('{'));
253 assert!(result.ends_with('}'));
254 assert!(result.contains("\"name\":\"Alice\""));
255 assert!(result.contains("\"age\":30"));
256 }
257
258 #[test]
259 fn test_json_dataformat_impl() {
260 let json = Json;
261 assert_eq!(json.format_null(), "null");
262 assert_eq!(json.format_bool(&true), "true");
263 assert_eq!(json.format_string("test"), "\"test\"");
264 assert_eq!(json.format_i64(&42), "42");
265 assert_eq!(json.format_f64(&3.24), "3.24");
266 }
267
268 #[test]
269 fn test_to_json_value_basic() {
270 assert_eq!(to_json_value(&Value::Bool(true)), JsonValue::Bool(true));
271 assert_eq!(
272 to_json_value(&Value::Chars("hi".into())),
273 JsonValue::String("hi".into())
274 );
275 assert_eq!(
276 to_json_value(&Value::Digit(42)),
277 JsonValue::Number(42.into())
278 );
279 }
280
281 #[test]
282 fn test_to_json_value_float_special() {
283 assert_eq!(to_json_value(&Value::Float(f64::NAN)), JsonValue::Null);
284 assert_eq!(
285 to_json_value(&Value::Float(f64::INFINITY)),
286 JsonValue::String("Infinity".into())
287 );
288 }
289
290 #[test]
291 fn test_json_stdfmt_array() {
292 let arr = vec![
293 FieldStorage::from_owned(DataField::from_digit("", 1)),
294 FieldStorage::from_owned(DataField::from_digit("", 2)),
295 FieldStorage::from_owned(DataField::from_digit("", 3)),
296 ];
297 let result = Json::stdfmt_array(&arr);
298 assert_eq!(result, "[1,2,3]");
299 }
300}
301
302#[allow(clippy::items_after_test_module)]
307impl ValueFormatter for Json {
308 type Output = String;
309
310 fn format_value(&self, value: &Value) -> String {
311 match value {
312 Value::Null => "null".to_string(),
313 Value::Bool(v) => json!(v).to_string(),
314 Value::Chars(v) => serde_json::to_string(v).unwrap_or_else(|_| "\"\"".to_string()),
315 Value::Digit(v) => json!(v).to_string(),
316 Value::Float(v) => {
317 if v.is_nan() {
318 "null".to_string()
319 } else if v.is_infinite() {
320 if v.is_sign_positive() {
321 "\"Infinity\"".to_string()
322 } else {
323 "\"-Infinity\"".to_string()
324 }
325 } else {
326 json!(v).to_string()
327 }
328 }
329 Value::IpAddr(v) => json!(v.to_string()).to_string(),
330 Value::Time(v) => json!(v.to_string()).to_string(),
331 Value::Obj(v) => {
332 let mut json_obj = serde_json::Map::new();
333 for (_k, field) in v.iter() {
334 json_obj.insert(
335 field.get_name().to_string(),
336 to_json_value(field.get_value()),
337 );
338 }
339 json!(json_obj).to_string()
340 }
341 Value::Array(v) => {
342 let items: Vec<String> = v
343 .iter()
344 .map(|field| self.format_value(field.get_value()))
345 .collect();
346 format!("[{}]", items.join(","))
347 }
348 _ => json!(value.to_string()).to_string(),
349 }
350 }
351}
352
353impl RecordFormatter for Json {
354 fn fmt_field(&self, field: &FieldStorage) -> String {
355 if field.get_name().is_empty() {
356 self.format_value(field.get_value())
357 } else {
358 format!(
359 "\"{}\":{}",
360 field.get_name(),
361 self.format_value(field.get_value())
362 )
363 }
364 }
365
366 fn fmt_record(&self, record: &DataRecord) -> String {
367 let mut items = Vec::new();
368 for field in record
369 .items
370 .iter()
371 .filter(|f| *f.get_meta() != DataType::Ignore)
372 {
373 items.push(self.fmt_field(field));
374 }
375 format!("{{{}}}", items.join(","))
376 }
377}