Skip to main content

sz_orm_explain/
dialect.rs

1//! 方言分派辅助
2//!
3//! 提供 [`ExplainDialect`] → 解析器的映射与便捷入口,
4//! 核心分派逻辑在 [`crate::parser_for`]。
5
6use crate::{ExplainDialect, ExplainError, ExplainParser, ExplainPlan};
7
8/// 便捷入口:按 [`ExplainDialect`] 解析 EXPLAIN 输出
9///
10/// ```rust
11/// use sz_orm_explain::dialect::parse_explain;
12/// use sz_orm_explain::ExplainDialect;
13///
14/// let raw = "Seq Scan on users  (cost=0.00..21.50 rows=1150 width=36)";
15/// let plan = parse_explain(ExplainDialect::Postgres, raw).unwrap();
16/// assert_eq!(plan.scan_type, sz_orm_explain::ScanType::FullTable);
17/// ```
18pub fn parse_explain(dialect: ExplainDialect, raw: &str) -> Result<ExplainPlan, ExplainError> {
19    crate::parser_for(dialect)?.parse(raw)
20}
21
22/// 获取解析器并返回 trait 对象(供宏/CI 复用)
23pub fn get_parser(dialect: ExplainDialect) -> Result<Box<dyn ExplainParser>, ExplainError> {
24    crate::parser_for(dialect)
25}
26
27#[cfg(test)]
28mod tests {
29    use super::*;
30    use crate::{ExplainDialect, ScanType};
31
32    #[test]
33    fn mysql_parses() {
34        let plan = parse_explain(
35            ExplainDialect::MySql,
36            "| 1 | SIMPLE | users | ALL | NULL | NULL | NULL | NULL | 1150 | Using where |",
37        )
38        .unwrap();
39        assert_eq!(plan.scan_type, ScanType::FullTable);
40        assert_eq!(plan.table, "users");
41    }
42
43    #[test]
44    fn postgres_parses() {
45        let plan = parse_explain(
46            ExplainDialect::Postgres,
47            "Index Scan using t_pkey on t  (cost=0.29..8.31 rows=1 width=36)",
48        )
49        .unwrap();
50        assert_eq!(plan.scan_type, ScanType::IndexRange);
51        assert_eq!(plan.index.as_deref(), Some("t_pkey"));
52    }
53
54    #[test]
55    fn sqlite_parses() {
56        let plan = parse_explain(ExplainDialect::Sqlite, "QUERY PLAN\n|--SCAN users").unwrap();
57        assert_eq!(plan.scan_type, ScanType::FullTable);
58    }
59
60    #[test]
61    fn oracle_parses() {
62        let plan = parse_explain(
63            ExplainDialect::Oracle,
64            "| 1 |  TABLE ACCESS FULL | USERS | 1150 | 40250 | 21 |",
65        )
66        .unwrap();
67        assert_eq!(plan.scan_type, ScanType::FullTable);
68    }
69
70    #[test]
71    fn mssql_parses() {
72        let plan = parse_explain(
73            ExplainDialect::Mssql,
74            "|--Table Scan(OBJECT:([db].[dbo].[users]))",
75        )
76        .unwrap();
77        assert_eq!(plan.scan_type, ScanType::FullTable);
78    }
79
80    #[test]
81    fn all_dialects_have_parser() {
82        for d in [
83            ExplainDialect::MySql,
84            ExplainDialect::Postgres,
85            ExplainDialect::Sqlite,
86            ExplainDialect::Oracle,
87            ExplainDialect::Mssql,
88        ] {
89            assert!(crate::parser_for(d).is_ok(), "missing parser for {d:?}");
90        }
91    }
92}