Skip to main content

scythe_core/
dialect.rs

1/// Supported SQL dialects for parsing and type resolution.
2#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
3pub enum SqlDialect {
4    #[default]
5    PostgreSQL,
6    MySQL,
7    SQLite,
8    MsSql,
9    Oracle,
10    Snowflake,
11}
12
13impl SqlDialect {
14    /// Convert to a boxed sqlparser dialect for use with the parser.
15    pub fn to_sqlparser_dialect(&self) -> Box<dyn sqlparser::dialect::Dialect> {
16        match self {
17            SqlDialect::PostgreSQL => Box::new(sqlparser::dialect::PostgreSqlDialect {}),
18            SqlDialect::MySQL => Box::new(sqlparser::dialect::MySqlDialect {}),
19            SqlDialect::SQLite => Box::new(sqlparser::dialect::SQLiteDialect {}),
20            SqlDialect::MsSql => Box::new(sqlparser::dialect::MsSqlDialect {}),
21            SqlDialect::Oracle => Box::new(sqlparser::dialect::OracleDialect {}),
22            SqlDialect::Snowflake => Box::new(sqlparser::dialect::SnowflakeDialect {}),
23        }
24    }
25
26    /// Parse a dialect name from a string (case-insensitive).
27    /// Returns `Option<Self>` instead of `Result` since unknown dialects are not errors.
28    #[allow(clippy::should_implement_trait)]
29    pub fn from_str(s: &str) -> Option<Self> {
30        match s.to_lowercase().as_str() {
31            "postgresql" | "postgres" | "pg" | "cockroachdb" | "crdb" => Some(Self::PostgreSQL),
32            "mysql" | "mariadb" => Some(Self::MySQL),
33            "sqlite" | "sqlite3" => Some(Self::SQLite),
34            "duckdb" | "redshift" => Some(Self::PostgreSQL),
35            "mssql" | "sqlserver" | "tsql" => Some(Self::MsSql),
36            "oracle" => Some(Self::Oracle),
37            "snowflake" => Some(Self::Snowflake),
38            _ => None,
39        }
40    }
41}
42
43#[cfg(test)]
44mod tests {
45    use super::*;
46
47    #[test]
48    fn test_from_str_postgresql() {
49        assert_eq!(
50            SqlDialect::from_str("postgresql"),
51            Some(SqlDialect::PostgreSQL)
52        );
53        assert_eq!(
54            SqlDialect::from_str("postgres"),
55            Some(SqlDialect::PostgreSQL)
56        );
57        assert_eq!(SqlDialect::from_str("pg"), Some(SqlDialect::PostgreSQL));
58        assert_eq!(
59            SqlDialect::from_str("PostgreSQL"),
60            Some(SqlDialect::PostgreSQL)
61        );
62    }
63
64    #[test]
65    fn test_from_str_mysql() {
66        assert_eq!(SqlDialect::from_str("mysql"), Some(SqlDialect::MySQL));
67        assert_eq!(SqlDialect::from_str("mariadb"), Some(SqlDialect::MySQL));
68        assert_eq!(SqlDialect::from_str("MySQL"), Some(SqlDialect::MySQL));
69    }
70
71    #[test]
72    fn test_from_str_sqlite() {
73        assert_eq!(SqlDialect::from_str("sqlite"), Some(SqlDialect::SQLite));
74        assert_eq!(SqlDialect::from_str("sqlite3"), Some(SqlDialect::SQLite));
75    }
76
77    #[test]
78    fn test_from_str_cockroachdb() {
79        assert_eq!(
80            SqlDialect::from_str("cockroachdb"),
81            Some(SqlDialect::PostgreSQL)
82        );
83        assert_eq!(SqlDialect::from_str("crdb"), Some(SqlDialect::PostgreSQL));
84        assert_eq!(
85            SqlDialect::from_str("CockroachDB"),
86            Some(SqlDialect::PostgreSQL)
87        );
88    }
89
90    #[test]
91    fn test_from_str_duckdb() {
92        assert_eq!(SqlDialect::from_str("duckdb"), Some(SqlDialect::PostgreSQL));
93        assert_eq!(SqlDialect::from_str("DuckDB"), Some(SqlDialect::PostgreSQL));
94    }
95
96    #[test]
97    fn test_from_str_mssql() {
98        assert_eq!(SqlDialect::from_str("mssql"), Some(SqlDialect::MsSql));
99        assert_eq!(SqlDialect::from_str("sqlserver"), Some(SqlDialect::MsSql));
100        assert_eq!(SqlDialect::from_str("tsql"), Some(SqlDialect::MsSql));
101        assert_eq!(SqlDialect::from_str("MSSQL"), Some(SqlDialect::MsSql));
102    }
103
104    #[test]
105    fn test_from_str_oracle() {
106        assert_eq!(SqlDialect::from_str("oracle"), Some(SqlDialect::Oracle));
107        assert_eq!(SqlDialect::from_str("Oracle"), Some(SqlDialect::Oracle));
108    }
109
110    #[test]
111    fn test_from_str_snowflake() {
112        assert_eq!(
113            SqlDialect::from_str("snowflake"),
114            Some(SqlDialect::Snowflake)
115        );
116        assert_eq!(
117            SqlDialect::from_str("Snowflake"),
118            Some(SqlDialect::Snowflake)
119        );
120    }
121
122    #[test]
123    fn test_from_str_redshift() {
124        assert_eq!(
125            SqlDialect::from_str("redshift"),
126            Some(SqlDialect::PostgreSQL)
127        );
128        assert_eq!(
129            SqlDialect::from_str("Redshift"),
130            Some(SqlDialect::PostgreSQL)
131        );
132    }
133
134    #[test]
135    fn test_from_str_mariadb() {
136        assert_eq!(SqlDialect::from_str("mariadb"), Some(SqlDialect::MySQL));
137        assert_eq!(SqlDialect::from_str("MariaDB"), Some(SqlDialect::MySQL));
138    }
139
140    #[test]
141    fn test_from_str_unknown() {
142        assert_eq!(SqlDialect::from_str("nosuchdb"), None);
143        assert_eq!(SqlDialect::from_str(""), None);
144    }
145
146    #[test]
147    fn test_default_is_postgresql() {
148        assert_eq!(SqlDialect::default(), SqlDialect::PostgreSQL);
149    }
150
151    #[test]
152    fn test_to_sqlparser_dialect() {
153        // Just verify they don't panic
154        let _ = SqlDialect::PostgreSQL.to_sqlparser_dialect();
155        let _ = SqlDialect::MySQL.to_sqlparser_dialect();
156        let _ = SqlDialect::SQLite.to_sqlparser_dialect();
157        let _ = SqlDialect::MsSql.to_sqlparser_dialect();
158        let _ = SqlDialect::Oracle.to_sqlparser_dialect();
159        let _ = SqlDialect::Snowflake.to_sqlparser_dialect();
160    }
161}