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 single_string_interval: true,
36 ..Default::default()
37 }
38 }
39
40 fn transform_expr(&self, expr: Expression) -> Result<Expression> {
41 match expr {
42 Expression::IfNull(f) => Ok(Expression::Coalesce(Box::new(VarArgFunc {
44 original_name: None,
45 expressions: vec![f.this, f.expression],
46 }))),
47
48 Expression::Nvl(f) => Ok(Expression::Coalesce(Box::new(VarArgFunc {
50 original_name: None,
51 expressions: vec![f.this, f.expression],
52 }))),
53
54 Expression::Coalesce(mut f) => {
56 f.original_name = None;
57 Ok(Expression::Coalesce(f))
58 }
59
60 Expression::TryCast(c) => Ok(Expression::Cast(c)),
62
63 Expression::SafeCast(c) => Ok(Expression::Cast(c)),
65
66 Expression::ILike(op) => Ok(Expression::ILike(op)),
68
69 Expression::CountIf(f) => {
71 let case_expr = Expression::Case(Box::new(Case {
72 operand: None,
73 whens: vec![(f.this.clone(), Expression::number(1))],
74 else_: Some(Expression::number(0)),
75 comments: Vec::new(),
76 }));
77 Ok(Expression::Sum(Box::new(AggFunc {
78 ignore_nulls: None,
79 having_max: None,
80 this: case_expr,
81 distinct: f.distinct,
82 filter: f.filter,
83 order_by: Vec::new(),
84 name: None,
85 limit: None,
86 })))
87 }
88
89 Expression::Rand(r) => {
91 let _ = r.seed;
92 Ok(Expression::Random(crate::expressions::Random))
93 }
94
95 Expression::Function(f) => self.transform_function(*f),
97
98 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
100
101 Expression::Cast(c) => self.transform_cast(*c),
103
104 _ => Ok(expr),
106 }
107 }
108}
109
110impl MaterializeDialect {
111 fn transform_function(&self, f: Function) -> Result<Expression> {
112 let name_upper = f.name.to_uppercase();
113 match name_upper.as_str() {
114 "IFNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
116 original_name: None,
117 expressions: f.args,
118 }))),
119
120 "NVL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
122 original_name: None,
123 expressions: f.args,
124 }))),
125
126 "ISNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
128 original_name: None,
129 expressions: f.args,
130 }))),
131
132 "NOW" => Ok(Expression::CurrentTimestamp(
134 crate::expressions::CurrentTimestamp {
135 precision: None,
136 sysdate: false,
137 },
138 )),
139
140 "GETDATE" => Ok(Expression::CurrentTimestamp(
142 crate::expressions::CurrentTimestamp {
143 precision: None,
144 sysdate: false,
145 },
146 )),
147
148 "RAND" => Ok(Expression::Random(crate::expressions::Random)),
150
151 "STRING_AGG" => Ok(Expression::Function(Box::new(f))),
153
154 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
156 Function::new("STRING_AGG".to_string(), f.args),
157 ))),
158
159 "LISTAGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
161 "STRING_AGG".to_string(),
162 f.args,
163 )))),
164
165 "SUBSTR" => Ok(Expression::Function(Box::new(Function::new(
167 "SUBSTRING".to_string(),
168 f.args,
169 )))),
170
171 "LENGTH" => Ok(Expression::Function(Box::new(f))),
173
174 "LEN" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
176 "LENGTH".to_string(),
177 f.args,
178 )))),
179
180 "CHARINDEX" if f.args.len() >= 2 => {
182 let mut args = f.args;
183 let substring = args.remove(0);
184 let string = args.remove(0);
185 Ok(Expression::Function(Box::new(Function::new(
186 "STRPOS".to_string(),
187 vec![string, substring],
188 ))))
189 }
190
191 "INSTR" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
193 "STRPOS".to_string(),
194 f.args,
195 )))),
196
197 "LOCATE" if f.args.len() >= 2 => {
199 let mut args = f.args;
200 let substring = args.remove(0);
201 let string = args.remove(0);
202 Ok(Expression::Function(Box::new(Function::new(
203 "STRPOS".to_string(),
204 vec![string, substring],
205 ))))
206 }
207
208 "STRPOS" => Ok(Expression::Function(Box::new(f))),
210
211 "ARRAY_LENGTH" => Ok(Expression::Function(Box::new(f))),
213
214 "SIZE" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
216 "ARRAY_LENGTH".to_string(),
217 f.args,
218 )))),
219
220 "CARDINALITY" => Ok(Expression::Function(Box::new(f))),
222
223 "TO_CHAR" => Ok(Expression::Function(Box::new(f))),
225
226 "DATE_FORMAT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
228 Function::new("TO_CHAR".to_string(), f.args),
229 ))),
230
231 "STRFTIME" if f.args.len() >= 2 => {
233 let mut args = f.args;
234 let format = args.remove(0);
235 let date = args.remove(0);
236 Ok(Expression::Function(Box::new(Function::new(
237 "TO_CHAR".to_string(),
238 vec![date, format],
239 ))))
240 }
241
242 "JSON_EXTRACT_PATH_TEXT" => Ok(Expression::Function(Box::new(f))),
244
245 "GET_JSON_OBJECT" if f.args.len() == 2 => Ok(Expression::Function(Box::new(
247 Function::new("JSON_EXTRACT_PATH_TEXT".to_string(), f.args),
248 ))),
249
250 "JSON_EXTRACT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
252 Function::new("JSON_EXTRACT_PATH_TEXT".to_string(), f.args),
253 ))),
254
255 _ => Ok(Expression::Function(Box::new(f))),
257 }
258 }
259
260 fn transform_aggregate_function(
261 &self,
262 f: Box<crate::expressions::AggregateFunction>,
263 ) -> Result<Expression> {
264 let name_upper = f.name.to_uppercase();
265 match name_upper.as_str() {
266 "COUNT_IF" if !f.args.is_empty() => {
268 let condition = f.args.into_iter().next().unwrap();
269 let case_expr = Expression::Case(Box::new(Case {
270 operand: None,
271 whens: vec![(condition, Expression::number(1))],
272 else_: Some(Expression::number(0)),
273 comments: Vec::new(),
274 }));
275 Ok(Expression::Sum(Box::new(AggFunc {
276 ignore_nulls: None,
277 having_max: None,
278 this: case_expr,
279 distinct: f.distinct,
280 filter: f.filter,
281 order_by: Vec::new(),
282 name: None,
283 limit: None,
284 })))
285 }
286
287 _ => Ok(Expression::AggregateFunction(f)),
289 }
290 }
291
292 fn transform_cast(&self, c: Cast) -> Result<Expression> {
293 Ok(Expression::Cast(Box::new(c)))
295 }
296}