Skip to main content

dm_database_parser_sqllog/parser/
builder.rs

1use std::fs;
2use std::path::{Path, PathBuf};
3use std::str;
4
5use crate::error::ParseError;
6use crate::parser::LogParser;
7use crate::parser::encoding::FileEncodingHint;
8
9/// 配置并构建 [`LogParser`] 的构建器模式 API。
10pub struct LogParserBuilder {
11    path: PathBuf,
12    encoding_hint: Option<FileEncodingHint>,
13}
14
15impl LogParserBuilder {
16    /// 创建一个新的 `LogParserBuilder`。
17    pub fn new<P: AsRef<Path>>(path: P) -> Self {
18        Self {
19            path: path.as_ref().to_path_buf(),
20            encoding_hint: None,
21        }
22    }
23
24    /// 设置文件编码提示。
25    pub fn encoding_hint(mut self, hint: FileEncodingHint) -> Self {
26        self.encoding_hint = Some(hint);
27        self
28    }
29
30    /// 构建并返回 [`LogParser`] 实例。
31    pub fn build(self) -> Result<LogParser, ParseError> {
32        let data = fs::read(&self.path).map_err(|e| ParseError::IoError(e.to_string()))?;
33
34        let encoding = match self.encoding_hint {
35            Some(hint) => hint,
36            None => {
37                // 自动编码探测:采样头部 64KB 和尾部 4KB
38                let head_size = data.len().min(64 * 1024);
39                let head_ok = str::from_utf8(&data[..head_size]).is_ok();
40                let tail_start = data.len().saturating_sub(4 * 1024).max(head_size);
41                let tail_ok =
42                    tail_start >= data.len() || str::from_utf8(&data[tail_start..]).is_ok();
43                if head_ok && tail_ok {
44                    FileEncodingHint::Utf8
45                } else {
46                    FileEncodingHint::Gb18030
47                }
48            }
49        };
50
51        Ok(LogParser { data, encoding })
52    }
53}