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