1use super::{DialectImpl, DialectType};
7use crate::error::Result;
8use crate::expressions::{AggFunc, Case, Cast, Expression, Function, VarArgFunc};
9use crate::generator::GeneratorConfig;
10use crate::tokens::TokenizerConfig;
11
12pub struct MaterializeDialect;
14
15impl DialectImpl for MaterializeDialect {
16 fn dialect_type(&self) -> DialectType {
17 DialectType::Materialize
18 }
19
20 fn tokenizer_config(&self) -> TokenizerConfig {
21 let mut config = TokenizerConfig::default();
22 config.identifiers.insert('"', '"');
24 config.nested_comments = true;
26 config
27 }
28
29 fn generator_config(&self) -> GeneratorConfig {
30 use crate::generator::IdentifierQuoteStyle;
31 GeneratorConfig {
32 identifier_quote: '"',
33 identifier_quote_style: IdentifierQuoteStyle::DOUBLE_QUOTE,
34 dialect: Some(DialectType::Materialize),
35 ..Default::default()
36 }
37 }
38
39 fn transform_expr(&self, expr: Expression) -> Result<Expression> {
40 match expr {
41 Expression::IfNull(f) => Ok(Expression::Coalesce(Box::new(VarArgFunc { original_name: None,
43 expressions: vec![f.this, f.expression],
44 }))),
45
46 Expression::Nvl(f) => Ok(Expression::Coalesce(Box::new(VarArgFunc { original_name: None,
48 expressions: vec![f.this, f.expression],
49 }))),
50
51 Expression::Coalesce(mut f) => {
53 f.original_name = None;
54 Ok(Expression::Coalesce(f))
55 }
56
57 Expression::TryCast(c) => Ok(Expression::Cast(c)),
59
60 Expression::SafeCast(c) => Ok(Expression::Cast(c)),
62
63 Expression::ILike(op) => Ok(Expression::ILike(op)),
65
66 Expression::CountIf(f) => {
68 let case_expr = Expression::Case(Box::new(Case {
69 operand: None,
70 whens: vec![(f.this.clone(), Expression::number(1))],
71 else_: Some(Expression::number(0)),
72 }));
73 Ok(Expression::Sum(Box::new(AggFunc { ignore_nulls: None, having_max: None,
74 this: case_expr,
75 distinct: f.distinct,
76 filter: f.filter,
77 order_by: Vec::new(),
78 name: None,
79 limit: None,
80 })))
81 }
82
83 Expression::Rand(r) => {
85 let _ = r.seed;
86 Ok(Expression::Random(crate::expressions::Random))
87 }
88
89 Expression::Function(f) => self.transform_function(*f),
91
92 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
94
95 Expression::Cast(c) => self.transform_cast(*c),
97
98 _ => Ok(expr),
100 }
101 }
102}
103
104impl MaterializeDialect {
105 fn transform_function(&self, f: Function) -> Result<Expression> {
106 let name_upper = f.name.to_uppercase();
107 match name_upper.as_str() {
108 "IFNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc { original_name: None,
110 expressions: f.args,
111 }))),
112
113 "NVL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc { original_name: None,
115 expressions: f.args,
116 }))),
117
118 "ISNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc { original_name: None,
120 expressions: f.args,
121 }))),
122
123 "NOW" => Ok(Expression::CurrentTimestamp(
125 crate::expressions::CurrentTimestamp { precision: None, sysdate: false },
126 )),
127
128 "GETDATE" => Ok(Expression::CurrentTimestamp(
130 crate::expressions::CurrentTimestamp { precision: None, sysdate: false },
131 )),
132
133 "RAND" => Ok(Expression::Random(crate::expressions::Random)),
135
136 "STRING_AGG" => Ok(Expression::Function(Box::new(f))),
138
139 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
141 Function::new("STRING_AGG".to_string(), f.args),
142 ))),
143
144 "LISTAGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
146 "STRING_AGG".to_string(),
147 f.args,
148 )))),
149
150 "SUBSTR" => Ok(Expression::Function(Box::new(Function::new(
152 "SUBSTRING".to_string(),
153 f.args,
154 )))),
155
156 "LENGTH" => Ok(Expression::Function(Box::new(f))),
158
159 "LEN" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
161 "LENGTH".to_string(),
162 f.args,
163 )))),
164
165 "CHARINDEX" if f.args.len() >= 2 => {
167 let mut args = f.args;
168 let substring = args.remove(0);
169 let string = args.remove(0);
170 Ok(Expression::Function(Box::new(Function::new(
171 "STRPOS".to_string(),
172 vec![string, substring],
173 ))))
174 }
175
176 "INSTR" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
178 "STRPOS".to_string(),
179 f.args,
180 )))),
181
182 "LOCATE" if f.args.len() >= 2 => {
184 let mut args = f.args;
185 let substring = args.remove(0);
186 let string = args.remove(0);
187 Ok(Expression::Function(Box::new(Function::new(
188 "STRPOS".to_string(),
189 vec![string, substring],
190 ))))
191 }
192
193 "STRPOS" => Ok(Expression::Function(Box::new(f))),
195
196 "ARRAY_LENGTH" => Ok(Expression::Function(Box::new(f))),
198
199 "SIZE" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
201 "ARRAY_LENGTH".to_string(),
202 f.args,
203 )))),
204
205 "CARDINALITY" => Ok(Expression::Function(Box::new(f))),
207
208 "TO_CHAR" => Ok(Expression::Function(Box::new(f))),
210
211 "DATE_FORMAT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
213 "TO_CHAR".to_string(),
214 f.args,
215 )))),
216
217 "STRFTIME" if f.args.len() >= 2 => {
219 let mut args = f.args;
220 let format = args.remove(0);
221 let date = args.remove(0);
222 Ok(Expression::Function(Box::new(Function::new(
223 "TO_CHAR".to_string(),
224 vec![date, format],
225 ))))
226 }
227
228 "JSON_EXTRACT_PATH_TEXT" => Ok(Expression::Function(Box::new(f))),
230
231 "GET_JSON_OBJECT" if f.args.len() == 2 => Ok(Expression::Function(Box::new(
233 Function::new("JSON_EXTRACT_PATH_TEXT".to_string(), f.args),
234 ))),
235
236 "JSON_EXTRACT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
238 Function::new("JSON_EXTRACT_PATH_TEXT".to_string(), f.args),
239 ))),
240
241 _ => Ok(Expression::Function(Box::new(f))),
243 }
244 }
245
246 fn transform_aggregate_function(
247 &self,
248 f: Box<crate::expressions::AggregateFunction>,
249 ) -> Result<Expression> {
250 let name_upper = f.name.to_uppercase();
251 match name_upper.as_str() {
252 "COUNT_IF" if !f.args.is_empty() => {
254 let condition = f.args.into_iter().next().unwrap();
255 let case_expr = Expression::Case(Box::new(Case {
256 operand: None,
257 whens: vec![(condition, Expression::number(1))],
258 else_: Some(Expression::number(0)),
259 }));
260 Ok(Expression::Sum(Box::new(AggFunc { ignore_nulls: None, having_max: None,
261 this: case_expr,
262 distinct: f.distinct,
263 filter: f.filter,
264 order_by: Vec::new(),
265 name: None,
266 limit: None,
267 })))
268 }
269
270 _ => Ok(Expression::AggregateFunction(f)),
272 }
273 }
274
275 fn transform_cast(&self, c: Cast) -> Result<Expression> {
276 Ok(Expression::Cast(Box::new(c)))
278 }
279}