Skip to main content

wp_data_fmt/
raw.rs

1#[allow(deprecated)]
2use crate::formatter::DataFormat;
3use crate::formatter::{RecordFormatter, ValueFormatter};
4use wp_model_core::model::types::value::ObjectValue;
5use wp_model_core::model::{DataRecord, DataType, FieldStorage, Value};
6
7#[derive(Debug, Default)]
8pub struct Raw;
9
10impl Raw {
11    pub fn new() -> Self {
12        Self
13    }
14}
15
16#[allow(deprecated)]
17impl DataFormat for Raw {
18    type Output = String;
19    fn format_null(&self) -> String {
20        String::new()
21    }
22    fn format_bool(&self, v: &bool) -> String {
23        v.to_string()
24    }
25    fn format_string(&self, v: &str) -> String {
26        v.to_string()
27    }
28    fn format_i64(&self, v: &i64) -> String {
29        v.to_string()
30    }
31    fn format_f64(&self, v: &f64) -> String {
32        v.to_string()
33    }
34    fn format_ip(&self, v: &std::net::IpAddr) -> String {
35        v.to_string()
36    }
37    fn format_datetime(&self, v: &chrono::NaiveDateTime) -> String {
38        v.to_string()
39    }
40    fn format_object(&self, value: &ObjectValue) -> String {
41        if value.is_empty() {
42            return "{}".to_string();
43        }
44        let segments: Vec<String> = value
45            .iter()
46            .map(|(k, v)| format!("{}={}", k, self.fmt_value(v.get_value())))
47            .collect();
48        format!("{{{}}}", segments.join(", "))
49    }
50    fn format_array(&self, value: &[FieldStorage]) -> String {
51        if value.is_empty() {
52            return "[]".to_string();
53        }
54        let content: Vec<String> = value
55            .iter()
56            .map(|field| self.fmt_value(field.get_value()))
57            .collect();
58        format!("[{}]", content.join(", "))
59    }
60    fn format_field(&self, field: &FieldStorage) -> String {
61        match field.get_value() {
62            Value::Chars(s) => s.to_string(),
63            _ => self.fmt_value(field.get_value()),
64        }
65    }
66    fn format_record(&self, record: &DataRecord) -> String {
67        record
68            .items
69            .iter()
70            .filter(|f| *f.get_meta() != DataType::Ignore)
71            .map(|f| self.format_field(f))
72            .collect::<Vec<_>>()
73            .join(" ")
74    }
75}
76
77#[cfg(test)]
78#[allow(deprecated)]
79mod tests {
80    use super::*;
81    use std::net::IpAddr;
82    use std::str::FromStr;
83    use wp_model_core::model::DataField;
84
85    #[test]
86    fn test_raw_new() {
87        let raw = Raw::new();
88        assert_eq!(raw.format_null(), "");
89    }
90
91    #[test]
92    fn test_raw_default() {
93        let raw = Raw;
94        assert_eq!(raw.format_null(), "");
95    }
96
97    #[test]
98    fn test_format_null() {
99        let raw = Raw;
100        assert_eq!(raw.format_null(), "");
101    }
102
103    #[test]
104    fn test_format_bool() {
105        let raw = Raw;
106        assert_eq!(raw.format_bool(&true), "true");
107        assert_eq!(raw.format_bool(&false), "false");
108    }
109
110    #[test]
111    fn test_format_string() {
112        let raw = Raw;
113        assert_eq!(raw.format_string("hello"), "hello");
114        assert_eq!(raw.format_string("world"), "world");
115        assert_eq!(raw.format_string(""), "");
116    }
117
118    #[test]
119    fn test_format_i64() {
120        let raw = Raw;
121        assert_eq!(raw.format_i64(&0), "0");
122        assert_eq!(raw.format_i64(&42), "42");
123        assert_eq!(raw.format_i64(&-100), "-100");
124        assert_eq!(raw.format_i64(&i64::MAX), i64::MAX.to_string());
125    }
126
127    #[test]
128    fn test_format_f64() {
129        let raw = Raw;
130        assert_eq!(raw.format_f64(&3.24), "3.24");
131        assert_eq!(raw.format_f64(&0.0), "0");
132        assert_eq!(raw.format_f64(&-2.5), "-2.5");
133    }
134
135    #[test]
136    fn test_format_ip() {
137        let raw = Raw;
138        let ipv4 = IpAddr::from_str("192.168.1.1").unwrap();
139        assert_eq!(raw.format_ip(&ipv4), "192.168.1.1");
140
141        let ipv6 = IpAddr::from_str("::1").unwrap();
142        assert_eq!(raw.format_ip(&ipv6), "::1");
143    }
144
145    #[test]
146    fn test_format_datetime() {
147        let raw = Raw;
148        let dt = chrono::NaiveDateTime::parse_from_str("2024-01-15 10:30:45", "%Y-%m-%d %H:%M:%S")
149            .unwrap();
150        let result = raw.format_datetime(&dt);
151        assert!(result.contains("2024"));
152        assert!(result.contains("01"));
153        assert!(result.contains("15"));
154    }
155
156    #[test]
157    fn test_format_field_chars() {
158        let raw = Raw;
159        let field = FieldStorage::from_owned(DataField::from_chars("name", "Alice"));
160        let result = raw.format_field(&field);
161        assert_eq!(result, "Alice");
162    }
163
164    #[test]
165    fn test_format_field_digit() {
166        let raw = Raw;
167        let field = FieldStorage::from_owned(DataField::from_digit("age", 30));
168        let result = raw.format_field(&field);
169        assert_eq!(result, "30");
170    }
171
172    #[test]
173    fn test_format_record() {
174        let raw = Raw;
175        let record = DataRecord {
176            id: Default::default(),
177            items: vec![
178                FieldStorage::from_owned(DataField::from_chars("name", "Alice")),
179                FieldStorage::from_owned(DataField::from_digit("age", 30)),
180            ],
181        };
182        let result = raw.format_record(&record);
183        assert_eq!(result, "Alice 30");
184    }
185
186    #[test]
187    fn test_format_array_empty() {
188        let raw = Raw;
189        let arr: Vec<FieldStorage> = vec![];
190        assert_eq!(raw.format_array(&arr), "[]");
191    }
192
193    #[test]
194    fn test_format_array_with_values() {
195        let raw = Raw;
196        let arr = vec![
197            FieldStorage::from_owned(DataField::from_digit("", 1)),
198            FieldStorage::from_owned(DataField::from_digit("", 2)),
199            FieldStorage::from_owned(DataField::from_digit("", 3)),
200        ];
201        let result = raw.format_array(&arr);
202        assert_eq!(result, "[1, 2, 3]");
203    }
204
205    #[test]
206    fn test_format_object_empty() {
207        let raw = Raw;
208        let obj = ObjectValue::new();
209        assert_eq!(raw.format_object(&obj), "{}");
210    }
211
212    fn make_record_with_obj() -> DataRecord {
213        let mut obj = ObjectValue::new();
214        obj.insert(
215            "ssl_cipher".to_string(),
216            FieldStorage::from_owned(DataField::from_chars("ssl_cipher", "ECDHE")),
217        );
218        DataRecord {
219            id: Default::default(),
220            items: vec![
221                FieldStorage::from_owned(DataField::from_digit("status", 200)),
222                FieldStorage::from_owned(DataField::from_obj("extends", obj)),
223                FieldStorage::from_owned(DataField::from_digit("length", 50)),
224            ],
225        }
226    }
227
228    #[test]
229    fn test_format_record_with_obj_no_newlines() {
230        let raw = Raw;
231        let record = make_record_with_obj();
232        let result = raw.format_record(&record);
233        assert!(
234            !result.contains('\n'),
235            "record output should not contain newlines: {}",
236            result
237        );
238        assert!(result.contains("ECDHE"));
239    }
240
241    #[test]
242    fn test_fmt_record_with_obj_no_newlines() {
243        let raw = Raw;
244        let record = make_record_with_obj();
245        let result = raw.fmt_record(&record);
246        assert!(
247            !result.contains('\n'),
248            "record output should not contain newlines: {}",
249            result
250        );
251    }
252
253    #[test]
254    fn test_old_new_api_consistency_nested() {
255        let raw = Raw;
256        let record = make_record_with_obj();
257        assert_eq!(raw.format_record(&record), raw.fmt_record(&record));
258    }
259}
260
261// ============================================================================
262// 新 trait 实现:ValueFormatter + RecordFormatter
263// ============================================================================
264
265#[allow(clippy::items_after_test_module)]
266impl ValueFormatter for Raw {
267    type Output = String;
268
269    fn format_value(&self, value: &Value) -> String {
270        match value {
271            Value::Null => String::new(),
272            Value::Bool(v) => v.to_string(),
273            Value::Chars(v) => v.to_string(),
274            Value::Digit(v) => v.to_string(),
275            Value::Float(v) => v.to_string(),
276            Value::IpAddr(v) => v.to_string(),
277            Value::Time(v) => v.to_string(),
278            Value::Obj(obj) => {
279                if obj.is_empty() {
280                    "{}".to_string()
281                } else {
282                    let segments: Vec<String> = obj
283                        .iter()
284                        .map(|(k, field)| format!("{}={}", k, self.format_value(field.get_value())))
285                        .collect();
286                    format!("{{{}}}", segments.join(", "))
287                }
288            }
289            Value::Array(arr) => {
290                if arr.is_empty() {
291                    "[]".to_string()
292                } else {
293                    let content: Vec<String> = arr
294                        .iter()
295                        .map(|field| self.format_value(field.get_value()))
296                        .collect();
297                    format!("[{}]", content.join(", "))
298                }
299            }
300            _ => value.to_string(),
301        }
302    }
303}
304
305impl RecordFormatter for Raw {
306    fn fmt_field(&self, field: &FieldStorage) -> String {
307        match field.get_value() {
308            Value::Chars(s) => s.to_string(),
309            _ => self.format_value(field.get_value()),
310        }
311    }
312
313    fn fmt_record(&self, record: &DataRecord) -> String {
314        record
315            .items
316            .iter()
317            .filter(|f| *f.get_meta() != DataType::Ignore)
318            .map(|f| self.fmt_field(f))
319            .collect::<Vec<_>>()
320            .join(" ")
321    }
322}