Skip to main content

sqruff_lib_core/dialects/
init.rs

1use strum::IntoEnumIterator;
2use strum_macros::AsRefStr;
3
4use crate::value::Value;
5
6/// Trait for dialect-specific configuration.
7/// Each dialect implements this to parse and validate its configuration from raw config values.
8pub trait DialectConfig: Default + Clone + std::fmt::Debug {
9    /// Parse configuration from a Value (typically a Map from the config file's dialect section).
10    /// Returns the default configuration if parsing fails or if the input is None.
11    fn from_value(value: &Value) -> Self {
12        let _ = value;
13        Self::default()
14    }
15}
16
17/// A null/empty configuration for dialects that don't have any configuration options.
18#[derive(Debug, Clone, Default)]
19pub struct NullDialectConfig;
20
21impl DialectConfig for NullDialectConfig {}
22
23#[derive(
24    strum_macros::EnumString,
25    strum_macros::EnumIter,
26    AsRefStr,
27    Debug,
28    Clone,
29    Copy,
30    Default,
31    Ord,
32    PartialOrd,
33    Eq,
34    PartialEq,
35    Hash,
36)]
37#[strum(serialize_all = "snake_case")]
38pub enum DialectKind {
39    #[default]
40    Ansi,
41    Athena,
42    Bigquery,
43    Clickhouse,
44    Databricks,
45    Duckdb,
46    Mysql,
47    Postgres,
48    Redshift,
49    Snowflake,
50    Sparksql,
51    Sqlite,
52    Trino,
53    Tsql,
54}
55
56impl DialectKind {
57    /// Returns the human-readable name of the dialect.
58    pub fn name(&self) -> &'static str {
59        match self {
60            DialectKind::Ansi => "ansi",
61            DialectKind::Athena => "athena",
62            DialectKind::Bigquery => "bigquery",
63            DialectKind::Clickhouse => "clickhouse",
64            DialectKind::Databricks => "databricks",
65            DialectKind::Duckdb => "duckdb",
66            DialectKind::Mysql => "mysql",
67            DialectKind::Postgres => "postgres",
68            DialectKind::Redshift => "redshift",
69            DialectKind::Snowflake => "snowflake",
70            DialectKind::Sparksql => "sparksql",
71            DialectKind::Sqlite => "sqlite",
72            DialectKind::Trino => "trino",
73            DialectKind::Tsql => "tsql",
74        }
75    }
76
77    /// Returns a human-readable description of the dialect.
78    pub fn description(&self) -> &'static str {
79        match self {
80            DialectKind::Ansi => {
81                "Standard SQL syntax. The default dialect and base for all others."
82            }
83            DialectKind::Athena => "Amazon Athena SQL dialect for querying data in S3.",
84            DialectKind::Bigquery => {
85                "Google BigQuery SQL dialect for analytics and data warehousing."
86            }
87            DialectKind::Clickhouse => "ClickHouse SQL dialect for real-time analytics.",
88            DialectKind::Databricks => "Databricks SQL dialect for lakehouse analytics.",
89            DialectKind::Duckdb => "DuckDB SQL dialect for in-process analytical database.",
90            DialectKind::Mysql => "MySQL SQL dialect for the popular open-source database.",
91            DialectKind::Postgres => {
92                "PostgreSQL SQL dialect for the advanced open-source database."
93            }
94            DialectKind::Redshift => "Amazon Redshift SQL dialect for cloud data warehousing.",
95            DialectKind::Snowflake => "Snowflake SQL dialect for cloud data platform.",
96            DialectKind::Sparksql => "Apache Spark SQL dialect for big data processing.",
97            DialectKind::Sqlite => "SQLite SQL dialect for embedded database.",
98            DialectKind::Trino => "Trino (formerly PrestoSQL) dialect for distributed SQL queries.",
99            DialectKind::Tsql => "T-SQL dialect for Microsoft SQL Server and Azure SQL.",
100        }
101    }
102
103    /// Returns the configuration section header for this dialect.
104    /// Format: `[sqruff:dialect:{dialect_name}]`
105    pub fn config_section(&self) -> String {
106        format!("[sqruff:dialect:{}]", self.name())
107    }
108
109    /// Returns an optional URL to the official documentation for the dialect.
110    pub fn doc_url(&self) -> Option<&'static str> {
111        match self {
112            DialectKind::Ansi => None,
113            DialectKind::Athena => {
114                Some("https://docs.aws.amazon.com/athena/latest/ug/ddl-sql-reference.html")
115            }
116            DialectKind::Bigquery => {
117                Some("https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax")
118            }
119            DialectKind::Clickhouse => Some("https://clickhouse.com/docs/en/sql-reference/"),
120            DialectKind::Databricks => {
121                Some("https://docs.databricks.com/en/sql/language-manual/index.html")
122            }
123            DialectKind::Duckdb => Some("https://duckdb.org/docs/sql/introduction"),
124            DialectKind::Mysql => Some("https://dev.mysql.com/doc/"),
125            DialectKind::Postgres => Some("https://www.postgresql.org/docs/current/sql.html"),
126            DialectKind::Redshift => {
127                Some("https://docs.aws.amazon.com/redshift/latest/dg/cm_chap_SQLCommandRef.html")
128            }
129            DialectKind::Snowflake => Some("https://docs.snowflake.com/en/sql-reference.html"),
130            DialectKind::Sparksql => Some("https://spark.apache.org/sql/"),
131            DialectKind::Sqlite => Some("https://www.sqlite.org/lang.html"),
132            DialectKind::Trino => Some("https://trino.io/docs/current/sql.html"),
133            DialectKind::Tsql => {
134                Some("https://learn.microsoft.com/en-us/sql/t-sql/language-reference")
135            }
136        }
137    }
138}
139
140/// Generate a readout of available dialects.
141pub fn dialect_readout() -> Vec<String> {
142    DialectKind::iter()
143        .map(|x| x.as_ref().to_string())
144        .collect()
145}
146
147#[cfg(test)]
148mod tests {
149    use super::DialectKind;
150
151    #[test]
152    fn dialect_readout_is_alphabetically_sorted() {
153        let readout = super::dialect_readout();
154
155        let mut sorted = readout.clone();
156        sorted.sort();
157
158        assert_eq!(readout, sorted);
159    }
160
161    #[test]
162    fn config_section_format() {
163        assert_eq!(
164            DialectKind::Snowflake.config_section(),
165            "[sqruff:dialect:snowflake]"
166        );
167        assert_eq!(
168            DialectKind::Bigquery.config_section(),
169            "[sqruff:dialect:bigquery]"
170        );
171        assert_eq!(DialectKind::Ansi.config_section(), "[sqruff:dialect:ansi]");
172    }
173}