dm_database_parser_sqllog/parser/
sqllog_parser.rs

1//! SqllogParser - 将 RecordParser 转换为 Sqllog 迭代器
2//!
3//! 提供了一个适配器,将原始的 `Record` 流转换为解析后的 `Sqllog` 流。
4
5use crate::error::ParseError;
6use crate::parser::record_parser::RecordParser;
7use crate::sqllog::Sqllog;
8use std::io::Read;
9
10/// 将 RecordParser 转换为 Sqllog 迭代器的适配器
11///
12/// `SqllogParser` 在 `RecordParser` 的基础上,自动将每个 `Record` 解析为 `Sqllog`。
13///
14/// # 类型参数
15///
16/// * `R` - 实现了 `Read` trait 的类型
17///
18/// # 示例
19///
20/// ```no_run
21/// use dm_database_parser_sqllog::SqllogParser;
22/// use std::fs::File;
23///
24/// let file = File::open("sqllog.txt").unwrap();
25/// let parser = SqllogParser::new(file);
26///
27/// for result in parser {
28///     match result {
29///         Ok(sqllog) => println!("SQL: {}", sqllog.body),
30///         Err(e) => eprintln!("解析错误: {}", e),
31///     }
32/// }
33/// ```
34pub struct SqllogParser<R: Read> {
35    record_parser: RecordParser<R>,
36}
37
38impl<R: Read> SqllogParser<R> {
39    /// 创建新的 SqllogParser
40    ///
41    /// # 参数
42    ///
43    /// * `reader` - 任何实现了 `Read` trait 的类型
44    ///
45    /// # 返回
46    ///
47    /// 返回一个新的 `SqllogParser` 实例
48    pub fn new(reader: R) -> Self {
49        Self {
50            record_parser: RecordParser::new(reader),
51        }
52    }
53}
54
55impl<R: Read> Iterator for SqllogParser<R> {
56    type Item = Result<Sqllog, ParseError>;
57
58    fn next(&mut self) -> Option<Self::Item> {
59        match self.record_parser.next()? {
60            Ok(record) => Some(record.parse_to_sqllog()),
61            Err(e) => Some(Err(ParseError::FileNotFound {
62                path: e.to_string(),
63            })),
64        }
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use super::*;
71    use std::io::Cursor;
72
73    #[test]
74    fn test_sqllog_parser_basic() {
75        let input = "2025-08-12 10:57:09.548 (EP[0] sess:123 thrd:456 user:alice trxid:789 stmt:999 appname:app) SELECT 1\n";
76        let cursor = Cursor::new(input);
77        let parser = SqllogParser::new(cursor);
78
79        let results: Vec<_> = parser.collect();
80        assert_eq!(results.len(), 1);
81        assert!(results[0].is_ok());
82
83        let sqllog = results[0].as_ref().unwrap();
84        assert_eq!(sqllog.ts, "2025-08-12 10:57:09.548");
85        assert_eq!(sqllog.meta.username, "alice");
86        assert_eq!(sqllog.body, "SELECT 1");
87    }
88
89    #[test]
90    fn test_sqllog_parser_with_indicators() {
91        let input = "2025-08-12 10:57:09.548 (EP[0] sess:123 thrd:456 user:alice trxid:789 stmt:999 appname:app) SELECT 1 EXECTIME: 10.5(ms) ROWCOUNT: 100(rows) EXEC_ID: 12345.\n";
92        let cursor = Cursor::new(input);
93        let parser = SqllogParser::new(cursor);
94
95        let results: Vec<_> = parser.collect();
96        assert_eq!(results.len(), 1);
97        assert!(results[0].is_ok());
98
99        let sqllog = results[0].as_ref().unwrap();
100        assert!(sqllog.has_indicators());
101        assert_eq!(sqllog.execute_time(), Some(10.5));
102        assert_eq!(sqllog.row_count(), Some(100));
103        assert_eq!(sqllog.execute_id(), Some(12345));
104    }
105
106    #[test]
107    fn test_sqllog_parser_multiline() {
108        let input = r#"2025-08-12 10:57:09.548 (EP[0] sess:123 thrd:456 user:alice trxid:789 stmt:999 appname:app) SELECT *
109FROM users
110WHERE id = 1
111"#;
112        let cursor = Cursor::new(input);
113        let parser = SqllogParser::new(cursor);
114
115        let results: Vec<_> = parser.collect();
116        assert_eq!(results.len(), 1);
117        assert!(results[0].is_ok());
118
119        let sqllog = results[0].as_ref().unwrap();
120        assert!(sqllog.body.contains("SELECT *"));
121        assert!(sqllog.body.contains("FROM users"));
122        assert!(sqllog.body.contains("WHERE id = 1"));
123    }
124
125    #[test]
126    fn test_sqllog_parser_empty() {
127        let input = "";
128        let cursor = Cursor::new(input);
129        let parser = SqllogParser::new(cursor);
130
131        let results: Vec<_> = parser.collect();
132        assert_eq!(results.len(), 0);
133    }
134
135    #[test]
136    fn test_sqllog_parser_multiple_records() {
137        let input = r#"2025-08-12 10:57:09.548 (EP[0] sess:123 thrd:456 user:alice trxid:789 stmt:999 appname:app) SELECT 1
1382025-08-12 10:57:10.548 (EP[0] sess:124 thrd:457 user:bob trxid:790 stmt:1000 appname:app) SELECT 2
139"#;
140        let cursor = Cursor::new(input);
141        let parser = SqllogParser::new(cursor);
142
143        let results: Vec<_> = parser.collect();
144        assert_eq!(results.len(), 2);
145        assert!(results[0].is_ok());
146        assert!(results[1].is_ok());
147
148        assert_eq!(results[0].as_ref().unwrap().meta.username, "alice");
149        assert_eq!(results[1].as_ref().unwrap().meta.username, "bob");
150    }
151}