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