dm_database_parser_sqllog/
sqllog.rs

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