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 inferred_type: None,
47 }))),
48
49 Expression::Nvl(f) => Ok(Expression::Coalesce(Box::new(VarArgFunc {
51 original_name: None,
52 expressions: vec![f.this, f.expression],
53 inferred_type: None,
54 }))),
55
56 Expression::Coalesce(mut f) => {
58 f.original_name = None;
59 Ok(Expression::Coalesce(f))
60 }
61
62 Expression::TryCast(c) => Ok(Expression::Cast(c)),
64
65 Expression::SafeCast(c) => Ok(Expression::Cast(c)),
67
68 Expression::ILike(op) => Ok(Expression::ILike(op)),
70
71 Expression::CountIf(f) => {
73 let case_expr = Expression::Case(Box::new(Case {
74 operand: None,
75 whens: vec![(f.this.clone(), Expression::number(1))],
76 else_: Some(Expression::number(0)),
77 comments: Vec::new(),
78 inferred_type: None,
79 }));
80 Ok(Expression::Sum(Box::new(AggFunc {
81 ignore_nulls: None,
82 having_max: None,
83 this: case_expr,
84 distinct: f.distinct,
85 filter: f.filter,
86 order_by: Vec::new(),
87 name: None,
88 limit: None,
89 inferred_type: None,
90 })))
91 }
92
93 Expression::Rand(r) => {
95 let _ = r.seed;
96 Ok(Expression::Random(crate::expressions::Random))
97 }
98
99 Expression::Function(f) => self.transform_function(*f),
101
102 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
104
105 Expression::Cast(c) => self.transform_cast(*c),
107
108 _ => Ok(expr),
110 }
111 }
112}
113
114impl MaterializeDialect {
115 fn transform_function(&self, f: Function) -> Result<Expression> {
116 let name_upper = f.name.to_uppercase();
117 match name_upper.as_str() {
118 "IFNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
120 original_name: None,
121 expressions: f.args,
122 inferred_type: None,
123 }))),
124
125 "NVL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
127 original_name: None,
128 expressions: f.args,
129 inferred_type: None,
130 }))),
131
132 "ISNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
134 original_name: None,
135 expressions: f.args,
136 inferred_type: None,
137 }))),
138
139 "NOW" => Ok(Expression::CurrentTimestamp(
141 crate::expressions::CurrentTimestamp {
142 precision: None,
143 sysdate: false,
144 },
145 )),
146
147 "GETDATE" => Ok(Expression::CurrentTimestamp(
149 crate::expressions::CurrentTimestamp {
150 precision: None,
151 sysdate: false,
152 },
153 )),
154
155 "RAND" => Ok(Expression::Random(crate::expressions::Random)),
157
158 "STRING_AGG" => Ok(Expression::Function(Box::new(f))),
160
161 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
163 Function::new("STRING_AGG".to_string(), f.args),
164 ))),
165
166 "LISTAGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
168 "STRING_AGG".to_string(),
169 f.args,
170 )))),
171
172 "SUBSTR" => Ok(Expression::Function(Box::new(Function::new(
174 "SUBSTRING".to_string(),
175 f.args,
176 )))),
177
178 "LENGTH" => Ok(Expression::Function(Box::new(f))),
180
181 "LEN" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
183 "LENGTH".to_string(),
184 f.args,
185 )))),
186
187 "CHARINDEX" if f.args.len() >= 2 => {
189 let mut args = f.args;
190 let substring = args.remove(0);
191 let string = args.remove(0);
192 Ok(Expression::Function(Box::new(Function::new(
193 "STRPOS".to_string(),
194 vec![string, substring],
195 ))))
196 }
197
198 "INSTR" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
200 "STRPOS".to_string(),
201 f.args,
202 )))),
203
204 "LOCATE" if f.args.len() >= 2 => {
206 let mut args = f.args;
207 let substring = args.remove(0);
208 let string = args.remove(0);
209 Ok(Expression::Function(Box::new(Function::new(
210 "STRPOS".to_string(),
211 vec![string, substring],
212 ))))
213 }
214
215 "STRPOS" => Ok(Expression::Function(Box::new(f))),
217
218 "ARRAY_LENGTH" => Ok(Expression::Function(Box::new(f))),
220
221 "SIZE" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
223 "ARRAY_LENGTH".to_string(),
224 f.args,
225 )))),
226
227 "CARDINALITY" => Ok(Expression::Function(Box::new(f))),
229
230 "TO_CHAR" => Ok(Expression::Function(Box::new(f))),
232
233 "DATE_FORMAT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
235 Function::new("TO_CHAR".to_string(), f.args),
236 ))),
237
238 "STRFTIME" if f.args.len() >= 2 => {
240 let mut args = f.args;
241 let format = args.remove(0);
242 let date = args.remove(0);
243 Ok(Expression::Function(Box::new(Function::new(
244 "TO_CHAR".to_string(),
245 vec![date, format],
246 ))))
247 }
248
249 "JSON_EXTRACT_PATH_TEXT" => Ok(Expression::Function(Box::new(f))),
251
252 "GET_JSON_OBJECT" if f.args.len() == 2 => Ok(Expression::Function(Box::new(
254 Function::new("JSON_EXTRACT_PATH_TEXT".to_string(), f.args),
255 ))),
256
257 "JSON_EXTRACT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
259 Function::new("JSON_EXTRACT_PATH_TEXT".to_string(), f.args),
260 ))),
261
262 _ => Ok(Expression::Function(Box::new(f))),
264 }
265 }
266
267 fn transform_aggregate_function(
268 &self,
269 f: Box<crate::expressions::AggregateFunction>,
270 ) -> Result<Expression> {
271 let name_upper = f.name.to_uppercase();
272 match name_upper.as_str() {
273 "COUNT_IF" if !f.args.is_empty() => {
275 let condition = f.args.into_iter().next().unwrap();
276 let case_expr = Expression::Case(Box::new(Case {
277 operand: None,
278 whens: vec![(condition, Expression::number(1))],
279 else_: Some(Expression::number(0)),
280 comments: Vec::new(),
281 inferred_type: None,
282 }));
283 Ok(Expression::Sum(Box::new(AggFunc {
284 ignore_nulls: None,
285 having_max: None,
286 this: case_expr,
287 distinct: f.distinct,
288 filter: f.filter,
289 order_by: Vec::new(),
290 name: None,
291 limit: None,
292 inferred_type: None,
293 })))
294 }
295
296 _ => Ok(Expression::AggregateFunction(f)),
298 }
299 }
300
301 fn transform_cast(&self, c: Cast) -> Result<Expression> {
302 Ok(Expression::Cast(Box::new(c)))
304 }
305}