1use super::{DialectImpl, DialectType};
7use crate::error::Result;
8use crate::expressions::{AggFunc, Case, Cast, Expression, Function, VarArgFunc};
9#[cfg(feature = "generate")]
10use crate::generator::GeneratorConfig;
11use crate::tokens::TokenizerConfig;
12
13pub struct MaterializeDialect;
15
16impl DialectImpl for MaterializeDialect {
17 fn dialect_type(&self) -> DialectType {
18 DialectType::Materialize
19 }
20
21 fn tokenizer_config(&self) -> TokenizerConfig {
22 let mut config = TokenizerConfig::default();
23 config.identifiers.insert('"', '"');
25 config.nested_comments = true;
27 config
28 }
29
30 #[cfg(feature = "generate")]
31
32 fn generator_config(&self) -> GeneratorConfig {
33 use crate::generator::IdentifierQuoteStyle;
34 GeneratorConfig {
35 identifier_quote: '"',
36 identifier_quote_style: IdentifierQuoteStyle::DOUBLE_QUOTE,
37 dialect: Some(DialectType::Materialize),
38 single_string_interval: true,
39 ..Default::default()
40 }
41 }
42
43 #[cfg(feature = "transpile")]
44
45 fn transform_expr(&self, expr: Expression) -> Result<Expression> {
46 match expr {
47 Expression::IfNull(f) => Ok(Expression::Coalesce(Box::new(VarArgFunc {
49 original_name: None,
50 expressions: vec![f.this, f.expression],
51 inferred_type: None,
52 }))),
53
54 Expression::Nvl(f) => Ok(Expression::Coalesce(Box::new(VarArgFunc {
56 original_name: None,
57 expressions: vec![f.this, f.expression],
58 inferred_type: None,
59 }))),
60
61 Expression::Coalesce(mut f) => {
63 f.original_name = None;
64 Ok(Expression::Coalesce(f))
65 }
66
67 Expression::TryCast(c) => Ok(Expression::Cast(c)),
69
70 Expression::SafeCast(c) => Ok(Expression::Cast(c)),
72
73 Expression::ILike(op) => Ok(Expression::ILike(op)),
75
76 Expression::CountIf(f) => {
78 let case_expr = Expression::Case(Box::new(Case {
79 operand: None,
80 whens: vec![(f.this.clone(), Expression::number(1))],
81 else_: Some(Expression::number(0)),
82 comments: Vec::new(),
83 inferred_type: None,
84 }));
85 Ok(Expression::Sum(Box::new(AggFunc {
86 ignore_nulls: None,
87 having_max: None,
88 this: case_expr,
89 distinct: f.distinct,
90 filter: f.filter,
91 order_by: Vec::new(),
92 name: None,
93 limit: None,
94 inferred_type: None,
95 })))
96 }
97
98 Expression::Rand(r) => {
100 let _ = r.seed;
101 Ok(Expression::Random(crate::expressions::Random))
102 }
103
104 Expression::Function(f) => self.transform_function(*f),
106
107 Expression::AggregateFunction(f) => self.transform_aggregate_function(f),
109
110 Expression::Cast(c) => self.transform_cast(*c),
112
113 _ => Ok(expr),
115 }
116 }
117}
118
119#[cfg(feature = "transpile")]
120impl MaterializeDialect {
121 fn transform_function(&self, f: Function) -> Result<Expression> {
122 let name_upper = f.name.to_uppercase();
123 match name_upper.as_str() {
124 "IFNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
126 original_name: None,
127 expressions: f.args,
128 inferred_type: None,
129 }))),
130
131 "NVL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
133 original_name: None,
134 expressions: f.args,
135 inferred_type: None,
136 }))),
137
138 "ISNULL" if f.args.len() == 2 => Ok(Expression::Coalesce(Box::new(VarArgFunc {
140 original_name: None,
141 expressions: f.args,
142 inferred_type: None,
143 }))),
144
145 "NOW" => Ok(Expression::CurrentTimestamp(
147 crate::expressions::CurrentTimestamp {
148 precision: None,
149 sysdate: false,
150 },
151 )),
152
153 "GETDATE" => Ok(Expression::CurrentTimestamp(
155 crate::expressions::CurrentTimestamp {
156 precision: None,
157 sysdate: false,
158 },
159 )),
160
161 "RAND" => Ok(Expression::Random(crate::expressions::Random)),
163
164 "STRING_AGG" => Ok(Expression::Function(Box::new(f))),
166
167 "GROUP_CONCAT" if !f.args.is_empty() => Ok(Expression::Function(Box::new(
169 Function::new("STRING_AGG".to_string(), f.args),
170 ))),
171
172 "LISTAGG" if !f.args.is_empty() => Ok(Expression::Function(Box::new(Function::new(
174 "STRING_AGG".to_string(),
175 f.args,
176 )))),
177
178 "SUBSTR" => Ok(Expression::Function(Box::new(Function::new(
180 "SUBSTRING".to_string(),
181 f.args,
182 )))),
183
184 "LENGTH" => Ok(Expression::Function(Box::new(f))),
186
187 "LEN" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
189 "LENGTH".to_string(),
190 f.args,
191 )))),
192
193 "CHARINDEX" if f.args.len() >= 2 => {
195 let mut args = f.args;
196 let substring = args.remove(0);
197 let string = args.remove(0);
198 Ok(Expression::Function(Box::new(Function::new(
199 "STRPOS".to_string(),
200 vec![string, substring],
201 ))))
202 }
203
204 "INSTR" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(Function::new(
206 "STRPOS".to_string(),
207 f.args,
208 )))),
209
210 "LOCATE" if f.args.len() >= 2 => {
212 let mut args = f.args;
213 let substring = args.remove(0);
214 let string = args.remove(0);
215 Ok(Expression::Function(Box::new(Function::new(
216 "STRPOS".to_string(),
217 vec![string, substring],
218 ))))
219 }
220
221 "STRPOS" => Ok(Expression::Function(Box::new(f))),
223
224 "ARRAY_LENGTH" => Ok(Expression::Function(Box::new(f))),
226
227 "SIZE" if f.args.len() == 1 => Ok(Expression::Function(Box::new(Function::new(
229 "ARRAY_LENGTH".to_string(),
230 f.args,
231 )))),
232
233 "CARDINALITY" => Ok(Expression::Function(Box::new(f))),
235
236 "TO_CHAR" => Ok(Expression::Function(Box::new(f))),
238
239 "DATE_FORMAT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
241 Function::new("TO_CHAR".to_string(), f.args),
242 ))),
243
244 "STRFTIME" if f.args.len() >= 2 => {
246 let mut args = f.args;
247 let format = args.remove(0);
248 let date = args.remove(0);
249 Ok(Expression::Function(Box::new(Function::new(
250 "TO_CHAR".to_string(),
251 vec![date, format],
252 ))))
253 }
254
255 "JSON_EXTRACT_PATH_TEXT" => Ok(Expression::Function(Box::new(f))),
257
258 "GET_JSON_OBJECT" if f.args.len() == 2 => Ok(Expression::Function(Box::new(
260 Function::new("JSON_EXTRACT_PATH_TEXT".to_string(), f.args),
261 ))),
262
263 "JSON_EXTRACT" if f.args.len() >= 2 => Ok(Expression::Function(Box::new(
265 Function::new("JSON_EXTRACT_PATH_TEXT".to_string(), f.args),
266 ))),
267
268 _ => Ok(Expression::Function(Box::new(f))),
270 }
271 }
272
273 fn transform_aggregate_function(
274 &self,
275 f: Box<crate::expressions::AggregateFunction>,
276 ) -> Result<Expression> {
277 let name_upper = f.name.to_uppercase();
278 match name_upper.as_str() {
279 "COUNT_IF" if !f.args.is_empty() => {
281 let condition = f.args.into_iter().next().unwrap();
282 let case_expr = Expression::Case(Box::new(Case {
283 operand: None,
284 whens: vec![(condition, Expression::number(1))],
285 else_: Some(Expression::number(0)),
286 comments: Vec::new(),
287 inferred_type: None,
288 }));
289 Ok(Expression::Sum(Box::new(AggFunc {
290 ignore_nulls: None,
291 having_max: None,
292 this: case_expr,
293 distinct: f.distinct,
294 filter: f.filter,
295 order_by: Vec::new(),
296 name: None,
297 limit: None,
298 inferred_type: None,
299 })))
300 }
301
302 _ => Ok(Expression::AggregateFunction(f)),
304 }
305 }
306
307 fn transform_cast(&self, c: Cast) -> Result<Expression> {
308 Ok(Expression::Cast(Box::new(c)))
310 }
311}