Skip to main content

wp_data_fmt/
json.rs

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        // Special chars should be escaped
185        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// ============================================================================
303// 新 trait 实现:ValueFormatter + RecordFormatter
304// ============================================================================
305
306#[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}