use core::fmt::Debug;
use serde::{Deserialize, Serialize};
use std::any::{Any, TypeId};
use strum::{EnumMessage, IntoEnumIterator};
#[derive(
Debug,
PartialEq,
Eq,
Clone,
Copy,
Serialize,
Deserialize,
strum::Display,
strum::EnumIter,
strum::EnumMessage,
strum::EnumString,
)]
pub enum Dialect {
#[strum(serialize = "ansi")]
Ansi,
#[strum(serialize = "bigquery")]
BigQuery,
#[strum(serialize = "clickhouse")]
ClickHouse,
#[strum(serialize = "duckdb")]
DuckDb,
#[strum(serialize = "generic")]
Generic,
#[strum(serialize = "hive")]
Hive,
#[strum(serialize = "mssql")]
MsSql,
#[strum(serialize = "mysql")]
MySql,
#[strum(serialize = "postgres")]
PostgreSql,
#[strum(serialize = "sqlite")]
SQLite,
#[strum(serialize = "snowflake")]
Snowflake,
}
impl Dialect {
pub(super) fn handler(&self) -> Box<dyn DialectHandler> {
match self {
Dialect::MsSql => Box::new(MsSqlDialect),
Dialect::MySql => Box::new(MySqlDialect),
Dialect::BigQuery => Box::new(BigQueryDialect),
Dialect::SQLite => Box::new(SQLiteDialect),
Dialect::ClickHouse => Box::new(ClickHouseDialect),
Dialect::Snowflake => Box::new(SnowflakeDialect),
Dialect::DuckDb => Box::new(DuckDbDialect),
Dialect::PostgreSql => Box::new(PostgresDialect),
Dialect::Ansi | Dialect::Generic | Dialect::Hive => Box::new(GenericDialect),
}
}
pub fn names() -> Vec<&'static str> {
Dialect::iter()
.flat_map(|d| d.get_serializations().to_vec())
.collect::<Vec<&'static str>>()
}
}
impl Default for Dialect {
fn default() -> Self {
Dialect::Generic
}
}
#[derive(Debug)]
pub struct GenericDialect;
#[derive(Debug)]
pub struct SQLiteDialect;
#[derive(Debug)]
pub struct MySqlDialect;
#[derive(Debug)]
pub struct MsSqlDialect;
#[derive(Debug)]
pub struct BigQueryDialect;
#[derive(Debug)]
pub struct ClickHouseDialect;
#[derive(Debug)]
pub struct SnowflakeDialect;
#[derive(Debug)]
pub struct DuckDbDialect;
#[derive(Debug)]
pub struct PostgresDialect;
pub(super) enum ColumnExclude {
Exclude,
Except,
}
pub(super) trait DialectHandler: Any + Debug {
fn use_top(&self) -> bool {
false
}
fn ident_quote(&self) -> char {
'"'
}
fn big_query_quoting(&self) -> bool {
false
}
fn column_exclude(&self) -> Option<ColumnExclude> {
None
}
fn set_ops_distinct(&self) -> bool {
true
}
fn except_all(&self) -> bool {
true
}
fn intersect_all(&self) -> bool {
self.except_all()
}
fn has_concat_function(&self) -> bool {
true
}
fn requires_quotes_intervals(&self) -> bool {
false
}
fn stars_in_group(&self) -> bool {
true
}
}
impl dyn DialectHandler {
#[inline]
pub fn is<T: DialectHandler + 'static>(&self) -> bool {
TypeId::of::<T>() == self.type_id()
}
}
impl DialectHandler for GenericDialect {}
impl DialectHandler for PostgresDialect {
fn requires_quotes_intervals(&self) -> bool {
true
}
}
impl DialectHandler for SQLiteDialect {
fn set_ops_distinct(&self) -> bool {
false
}
fn except_all(&self) -> bool {
false
}
fn has_concat_function(&self) -> bool {
false
}
fn stars_in_group(&self) -> bool {
false
}
}
impl DialectHandler for MsSqlDialect {
fn use_top(&self) -> bool {
true
}
}
impl DialectHandler for MySqlDialect {
fn ident_quote(&self) -> char {
'`'
}
fn set_ops_distinct(&self) -> bool {
true
}
}
impl DialectHandler for ClickHouseDialect {
fn ident_quote(&self) -> char {
'`'
}
}
impl DialectHandler for BigQueryDialect {
fn ident_quote(&self) -> char {
'`'
}
fn big_query_quoting(&self) -> bool {
true
}
fn column_exclude(&self) -> Option<ColumnExclude> {
Some(ColumnExclude::Except)
}
fn set_ops_distinct(&self) -> bool {
true
}
}
impl DialectHandler for SnowflakeDialect {
fn column_exclude(&self) -> Option<ColumnExclude> {
Some(ColumnExclude::Exclude)
}
fn set_ops_distinct(&self) -> bool {
false
}
}
impl DialectHandler for DuckDbDialect {
fn column_exclude(&self) -> Option<ColumnExclude> {
Some(ColumnExclude::Exclude)
}
fn except_all(&self) -> bool {
false
}
}
#[cfg(test)]
mod tests {
use super::Dialect;
use insta::assert_debug_snapshot;
use std::str::FromStr;
#[test]
fn test_dialect_from_str() {
assert_debug_snapshot!(Dialect::from_str("postgres"), @r###"
Ok(
PostgreSql,
)
"###);
assert_debug_snapshot!(Dialect::from_str("foo"), @r###"
Err(
VariantNotFound,
)
"###);
}
}