dm_database_parser_sqllog/
sqllog.rs

1//! SQL 日志数据结构定义
2//!
3//! 定义了解析后的 SQL 日志记录的数据结构。
4
5#[cfg(feature = "serde")]
6use serde::{Deserialize, Serialize};
7
8/// SQL 日志记录
9///
10/// 表示一条完整的 SQL 日志记录,包含时间戳、元数据、SQL 语句体和可选的性能指标。
11///
12
13#[derive(Debug, Clone, PartialEq, Default)]
14#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
15pub struct Sqllog {
16    /// 时间戳,格式为 "YYYY-MM-DD HH:MM:SS.mmm"
17    pub ts: String,
18
19    /// 元数据部分,包含会话信息、用户信息等
20    pub meta: MetaParts,
21
22    /// SQL 语句体
23    pub body: String,
24
25    /// 可选的性能指标信息
26    pub indicators: Option<IndicatorsParts>,
27}
28
29/// 元数据部分
30///
31/// 包含日志记录的所有元数据字段,如会话 ID、用户名等。
32#[derive(Debug, Clone, PartialEq, Default)]
33#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
34pub struct MetaParts {
35    /// EP(Execution Point)编号,范围 0-255
36    pub ep: u8,
37
38    /// 会话 ID
39    pub sess_id: String,
40
41    /// 线程 ID
42    pub thrd_id: String,
43
44    /// 用户名
45    pub username: String,
46
47    /// 事务 ID
48    pub trxid: String,
49
50    /// 语句 ID
51    pub statement: String,
52
53    /// 应用程序名称
54    pub appname: String,
55
56    /// 客户端 IP 地址(可选)
57    pub client_ip: String,
58}
59
60/// 性能指标部分
61///
62/// 包含 SQL 执行的性能指标,如执行时间、影响行数等。
63///
64
65#[derive(Debug, Clone, Copy, PartialEq, Default)]
66#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
67pub struct IndicatorsParts {
68    /// 执行时间(毫秒)
69    pub execute_time: f32,
70
71    /// 影响的行数
72    pub row_count: u32,
73
74    /// 执行 ID
75    pub execute_id: i64,
76}
77
78impl Sqllog {
79    /// 判断是否有性能指标信息
80    ///
81    /// # 返回
82    ///
83    /// 如果存在性能指标返回 `true`,否则返回 `false`
84    #[inline]
85    pub fn has_indicators(&self) -> bool {
86        self.indicators.is_some()
87    }
88
89    /// 获取执行时间(毫秒)
90    ///
91    /// # 返回
92    ///
93    /// 如果存在性能指标返回执行时间,否则返回 `None`
94    #[inline]
95    pub fn execute_time(&self) -> Option<f32> {
96        self.indicators.map(|i| i.execute_time)
97    }
98
99    /// 获取影响行数
100    ///
101    /// # 返回
102    ///
103    /// 如果存在性能指标返回影响行数,否则返回 `None`
104    #[inline]
105    pub fn row_count(&self) -> Option<u32> {
106        self.indicators.map(|i| i.row_count)
107    }
108
109    /// 获取执行 ID
110    ///
111    /// # 返回
112    ///
113    /// 如果存在性能指标返回执行 ID,否则返回 `None`
114    #[inline]
115    pub fn execute_id(&self) -> Option<i64> {
116        self.indicators.map(|i| i.execute_id)
117    }
118}
119
120impl MetaParts {
121    /// 判断是否有客户端 IP 信息
122    ///
123    /// # 返回
124    ///
125    /// 如果存在客户端 IP 返回 `true`,否则返回 `false`
126    #[inline]
127    pub fn has_client_ip(&self) -> bool {
128        !self.client_ip.is_empty()
129    }
130}
131
132#[cfg(test)]
133mod tests {
134    use super::*;
135
136    #[test]
137    fn test_sqllog_has_indicators() {
138        // 测试有指标的情况
139        let sqllog = Sqllog {
140            ts: "2025-08-12 10:57:09.548".to_string(),
141            meta: MetaParts::default(),
142            body: "SELECT 1".to_string(),
143            indicators: Some(IndicatorsParts {
144                execute_time: 10.5,
145                row_count: 100,
146                execute_id: 12345,
147            }),
148        };
149        assert!(sqllog.has_indicators());
150
151        // 测试没有指标的情况
152        let sqllog_no_indicators = Sqllog {
153            ts: "2025-08-12 10:57:09.548".to_string(),
154            meta: MetaParts::default(),
155            body: "SELECT 1".to_string(),
156            indicators: None,
157        };
158        assert!(!sqllog_no_indicators.has_indicators());
159    }
160
161    #[test]
162    fn test_sqllog_execute_time() {
163        // 测试有指标的情况
164        let sqllog = Sqllog {
165            ts: "2025-08-12 10:57:09.548".to_string(),
166            meta: MetaParts::default(),
167            body: "SELECT 1".to_string(),
168            indicators: Some(IndicatorsParts {
169                execute_time: 10.5,
170                row_count: 100,
171                execute_id: 12345,
172            }),
173        };
174        assert_eq!(sqllog.execute_time(), Some(10.5));
175
176        // 测试没有指标的情况
177        let sqllog_no_indicators = Sqllog {
178            ts: "2025-08-12 10:57:09.548".to_string(),
179            meta: MetaParts::default(),
180            body: "SELECT 1".to_string(),
181            indicators: None,
182        };
183        assert_eq!(sqllog_no_indicators.execute_time(), None);
184    }
185
186    #[test]
187    fn test_sqllog_row_count() {
188        // 测试有指标的情况
189        let sqllog = Sqllog {
190            ts: "2025-08-12 10:57:09.548".to_string(),
191            meta: MetaParts::default(),
192            body: "SELECT 1".to_string(),
193            indicators: Some(IndicatorsParts {
194                execute_time: 10.5,
195                row_count: 100,
196                execute_id: 12345,
197            }),
198        };
199        assert_eq!(sqllog.row_count(), Some(100));
200
201        // 测试没有指标的情况
202        let sqllog_no_indicators = Sqllog {
203            ts: "2025-08-12 10:57:09.548".to_string(),
204            meta: MetaParts::default(),
205            body: "SELECT 1".to_string(),
206            indicators: None,
207        };
208        assert_eq!(sqllog_no_indicators.row_count(), None);
209    }
210
211    #[test]
212    fn test_sqllog_execute_id() {
213        // 测试有指标的情况
214        let sqllog = Sqllog {
215            ts: "2025-08-12 10:57:09.548".to_string(),
216            meta: MetaParts::default(),
217            body: "SELECT 1".to_string(),
218            indicators: Some(IndicatorsParts {
219                execute_time: 10.5,
220                row_count: 100,
221                execute_id: 12345,
222            }),
223        };
224        assert_eq!(sqllog.execute_id(), Some(12345));
225
226        // 测试没有指标的情况
227        let sqllog_no_indicators = Sqllog {
228            ts: "2025-08-12 10:57:09.548".to_string(),
229            meta: MetaParts::default(),
230            body: "SELECT 1".to_string(),
231            indicators: None,
232        };
233        assert_eq!(sqllog_no_indicators.execute_id(), None);
234    }
235
236    #[test]
237    fn test_meta_has_client_ip() {
238        // 测试有 IP 的情况
239        let meta_with_ip = MetaParts {
240            ep: 0,
241            sess_id: "123".to_string(),
242            thrd_id: "456".to_string(),
243            username: "alice".to_string(),
244            trxid: "789".to_string(),
245            statement: "999".to_string(),
246            appname: "app".to_string(),
247            client_ip: "192.168.1.1".to_string(),
248        };
249        assert!(meta_with_ip.has_client_ip());
250
251        // 测试没有 IP 的情况
252        let meta_no_ip = MetaParts {
253            ep: 0,
254            sess_id: "123".to_string(),
255            thrd_id: "456".to_string(),
256            username: "alice".to_string(),
257            trxid: "789".to_string(),
258            statement: "999".to_string(),
259            appname: "app".to_string(),
260            client_ip: "".to_string(),
261        };
262        assert!(!meta_no_ip.has_client_ip());
263    }
264
265    #[test]
266    fn test_indicators_copy_trait() {
267        let indicators = IndicatorsParts {
268            execute_time: 10.5,
269            row_count: 100,
270            execute_id: 12345,
271        };
272        let copied = indicators;
273        assert_eq!(indicators.execute_time, copied.execute_time);
274        assert_eq!(indicators.row_count, copied.row_count);
275        assert_eq!(indicators.execute_id, copied.execute_id);
276    }
277
278    #[test]
279    fn test_sqllog_default() {
280        let sqllog = Sqllog::default();
281        assert_eq!(sqllog.ts, "");
282        assert_eq!(sqllog.body, "");
283        assert!(sqllog.indicators.is_none());
284    }
285
286    #[test]
287    fn test_meta_default() {
288        let meta = MetaParts::default();
289        assert_eq!(meta.ep, 0);
290        assert_eq!(meta.sess_id, "");
291        assert_eq!(meta.username, "");
292        assert!(!meta.has_client_ip());
293    }
294
295    #[test]
296    fn test_indicators_default() {
297        let indicators = IndicatorsParts::default();
298        assert_eq!(indicators.execute_time, 0.0);
299        assert_eq!(indicators.row_count, 0);
300        assert_eq!(indicators.execute_id, 0);
301    }
302}