Skip to main content

polyglot_sql/dialects/
druid.rs

1//! Apache Druid Dialect
2//!
3//! Druid-specific SQL dialect based on sqlglot patterns.
4//! Reference: https://druid.apache.org/docs/latest/querying/sql-data-types/
5//!
6//! Key characteristics:
7//! - Type mappings: NCHAR, NVARCHAR, TEXT, UUID → STRING
8//! - CURRENT_TIMESTAMP without parentheses
9//! - MOD function for modulo
10//! - ARRAY[...] syntax for arrays
11
12use super::{DialectImpl, DialectType};
13use crate::error::Result;
14use crate::expressions::{Expression, Function};
15#[cfg(feature = "generate")]
16use crate::generator::GeneratorConfig;
17use crate::tokens::TokenizerConfig;
18
19/// Apache Druid dialect
20pub struct DruidDialect;
21
22impl DialectImpl for DruidDialect {
23    fn dialect_type(&self) -> DialectType {
24        DialectType::Druid
25    }
26
27    fn tokenizer_config(&self) -> TokenizerConfig {
28        let mut config = TokenizerConfig::default();
29        // Druid uses double quotes for identifiers
30        config.identifiers.insert('"', '"');
31        config
32    }
33
34    #[cfg(feature = "generate")]
35
36    fn generator_config(&self) -> GeneratorConfig {
37        use crate::generator::IdentifierQuoteStyle;
38        GeneratorConfig {
39            identifier_quote: '"',
40            identifier_quote_style: IdentifierQuoteStyle::DOUBLE_QUOTE,
41            dialect: Some(DialectType::Druid),
42            ..Default::default()
43        }
44    }
45
46    #[cfg(feature = "transpile")]
47
48    fn transform_expr(&self, expr: Expression) -> Result<Expression> {
49        match expr {
50            // CurrentTimestamp without args in Druid
51            Expression::CurrentTimestamp(_) => Ok(Expression::CurrentTimestamp(
52                crate::expressions::CurrentTimestamp {
53                    precision: None,
54                    sysdate: false,
55                },
56            )),
57
58            // Modulo -> MOD function in Druid
59            Expression::Mod(op) => Ok(Expression::Function(Box::new(Function::new(
60                "MOD".to_string(),
61                vec![op.left, op.right],
62            )))),
63
64            // Generic function transformations
65            Expression::Function(f) => self.transform_function(*f),
66
67            // Pass through everything else
68            _ => Ok(expr),
69        }
70    }
71}
72
73#[cfg(feature = "transpile")]
74impl DruidDialect {
75    fn transform_function(&self, f: Function) -> Result<Expression> {
76        let name_upper = f.name.to_uppercase();
77        match name_upper.as_str() {
78            // CURRENT_TIMESTAMP without parentheses
79            "CURRENT_TIMESTAMP" => Ok(Expression::CurrentTimestamp(
80                crate::expressions::CurrentTimestamp {
81                    precision: None,
82                    sysdate: false,
83                },
84            )),
85
86            // Pass through everything else
87            _ => Ok(Expression::Function(Box::new(f))),
88        }
89    }
90}