odatav4_parser/renderers/
filter.rs1use crate::ast::{ArithmeticOp, ComparisonOp, FilterExpression, LambdaOp, LogicalOp};
2
3pub trait FilterRenderer {
5 fn quote_identifier(&mut self, ident: &str) -> String;
7
8 fn quote_string(&mut self, s: &str) -> String {
10 format!("'{}'", s.replace('\'', "''"))
11 }
12
13 fn render_filter(&mut self, expr: &FilterExpression) -> String {
15 println!("Trait default render_filter: {:?}", expr);
16 match expr {
17 FilterExpression::Comparison { left, op, right } => {
18 let left_sql = self.render_filter(left);
19 let right_sql = self.render_filter(right);
20 let op_sql = match op {
21 ComparisonOp::Eq => "=",
22 ComparisonOp::Ne => "<>",
23 ComparisonOp::Gt => ">",
24 ComparisonOp::Ge => ">=",
25 ComparisonOp::Lt => "<",
26 ComparisonOp::Le => "<=",
27 ComparisonOp::Has => {
28 return format!("({} & {}) = {}", left_sql, right_sql, right_sql);
30 }
31 };
32 format!("{} {} {}", left_sql, op_sql, right_sql)
33 }
34 FilterExpression::Logical { left, op, right } => {
35 let left_sql = self.render_filter(left);
36 let right_sql = self.render_filter(right);
37 let op_sql = match op {
38 LogicalOp::And => "AND",
39 LogicalOp::Or => "OR",
40 };
41 format!("({} {} {})", left_sql, op_sql, right_sql)
42 }
43 FilterExpression::Not(inner) => {
44 format!("NOT ({})", self.render_filter(inner))
45 }
46 FilterExpression::Arithmetic { left, op, right } => {
47 let left_sql = self.render_filter(left);
48 let right_sql = self.render_filter(right);
49 let op_sql = match op {
50 ArithmeticOp::Add => "+",
51 ArithmeticOp::Sub => "-",
52 ArithmeticOp::Mul => "*",
53 ArithmeticOp::Div => "/",
54 ArithmeticOp::Mod => "%",
55 };
56 format!("({} {} {})", left_sql, op_sql, right_sql)
57 }
58 FilterExpression::UnaryMinus(inner) => {
59 format!("-({})", self.render_filter(inner))
60 }
61 FilterExpression::FunctionCall { name, args } => {
62 self.render_function(name, args)
63 }
64 FilterExpression::In { field, values } => {
65 let field_sql = self.render_filter(field);
66 let values_sql = values
67 .iter()
68 .map(|v| self.render_filter(v))
69 .collect::<Vec<_>>()
70 .join(", ");
71 format!("{} IN ({})", field_sql, values_sql)
72 }
73 FilterExpression::Lambda { collection, operator, variable, predicate } => {
74 self.render_lambda(collection, operator, variable, predicate)
75 }
76 FilterExpression::Field(name) => self.quote_identifier(name),
77 FilterExpression::StringLiteral(s) => self.quote_string(s),
78 FilterExpression::NumberLiteral(n) => self.render_number_literal(*n),
79 FilterExpression::BooleanLiteral(b) => self.render_boolean_literal(*b),
80 FilterExpression::Null => "NULL".to_string(),
81 FilterExpression::GuidLiteral(guid) => self.quote_string(guid),
82 FilterExpression::DateLiteral(date) => self.quote_string(date),
83 }
84 }
85
86 fn render_number_literal(&mut self, n: f64) -> String {
88 if n.fract() == 0.0 {
89 format!("{:.0}", n)
90 } else {
91 n.to_string()
92 }
93 }
94
95 fn render_boolean_literal(&mut self, b: bool) -> String {
97 if b { "TRUE" } else { "FALSE" }.to_string()
98 }
99
100 fn render_function(&mut self, name: &str, args: &[FilterExpression]) -> String {
102 match name.to_lowercase().as_str() {
103 "contains" => self.render_contains(args),
105 "startswith" => self.render_startswith(args),
106 "endswith" => self.render_endswith(args),
107 "length" => self.render_length(args),
108 "indexof" => self.render_indexof(args),
109 "substring" => self.render_substring(args),
110 "tolower" => self.render_tolower(args),
111 "toupper" => self.render_toupper(args),
112 "trim" => self.render_trim(args),
113 "concat" => self.render_concat(args),
114
115 "year" => self.render_year(args),
117 "month" => self.render_month(args),
118 "day" => self.render_day(args),
119 "hour" => self.render_hour(args),
120 "minute" => self.render_minute(args),
121 "second" => self.render_second(args),
122 "now" => self.render_now(args),
123
124 "round" => self.render_round(args),
126 "floor" => self.render_floor(args),
127 "ceiling" => self.render_ceiling(args),
128
129 _ => format!("{}({})", name.to_uppercase(),
130 args.iter()
131 .map(|a| self.render_filter(a))
132 .collect::<Vec<_>>()
133 .join(", "))
134 }
135 }
136
137 fn render_contains(&mut self, args: &[FilterExpression]) -> String {
139 if args.len() != 2 {
140 return "1=0".to_string(); }
142 let field = self.render_filter(&args[0]);
143 let value = self.render_filter(&args[1]);
144 format!("{} LIKE CONCAT('%', {}, '%')", field, value.trim_matches('\''))
145 }
146
147 fn render_startswith(&mut self, args: &[FilterExpression]) -> String {
148 if args.len() != 2 {
149 return "1=0".to_string();
150 }
151 let field = self.render_filter(&args[0]);
152 let value = self.render_filter(&args[1]);
153 format!("{} LIKE CONCAT({}, '%')", field, value.trim_matches('\''))
154 }
155
156 fn render_endswith(&mut self, args: &[FilterExpression]) -> String {
157 if args.len() != 2 {
158 return "1=0".to_string();
159 }
160 let field = self.render_filter(&args[0]);
161 let value = self.render_filter(&args[1]);
162 format!("{} LIKE CONCAT('%', {})", field, value.trim_matches('\''))
163 }
164
165 fn render_length(&mut self, args: &[FilterExpression]) -> String {
166 if args.is_empty() {
167 return "0".to_string();
168 }
169 format!("LENGTH({})", self.render_filter(&args[0]))
170 }
171
172 fn render_indexof(&mut self, args: &[FilterExpression]) -> String {
173 if args.len() < 2 {
174 return "0".to_string();
175 }
176 let substr = self.render_filter(&args[1]);
178 let str_source = self.render_filter(&args[0]);
179 format!("POSITION({} IN {})", substr, str_source)
180 }
181
182 fn render_substring(&mut self, args: &[FilterExpression]) -> String {
183 if args.len() < 2 {
184 return "''".to_string();
185 }
186 let field = self.render_filter(&args[0]);
187 let start = self.render_filter(&args[1]);
188 if args.len() >= 3 {
189 let length = self.render_filter(&args[2]);
190 format!("SUBSTRING({}, {} + 1, {})", field, start, length)
191 } else {
192 format!("SUBSTRING({}, {} + 1)", field, start)
193 }
194 }
195
196 fn render_tolower(&mut self, args: &[FilterExpression]) -> String {
197 if args.is_empty() {
198 return "''".to_string();
199 }
200 format!("LOWER({})", self.render_filter(&args[0]))
201 }
202
203 fn render_toupper(&mut self, args: &[FilterExpression]) -> String {
204 if args.is_empty() {
205 return "''".to_string();
206 }
207 format!("UPPER({})", self.render_filter(&args[0]))
208 }
209
210 fn render_trim(&mut self, args: &[FilterExpression]) -> String {
211 if args.is_empty() {
212 return "''".to_string();
213 }
214 format!("TRIM({})", self.render_filter(&args[0]))
215 }
216
217 fn render_concat(&mut self, args: &[FilterExpression]) -> String {
218 if args.len() < 2 {
219 return "''".to_string();
220 }
221 let mut parts = Vec::new();
222 for a in args {
223 parts.push(self.render_filter(a));
224 }
225 format!("CONCAT({})", parts.join(", "))
226 }
227
228 fn render_year(&mut self, args: &[FilterExpression]) -> String {
230 if args.is_empty() {
231 return "0".to_string();
232 }
233 format!("YEAR({})", self.render_filter(&args[0]))
234 }
235
236 fn render_month(&mut self, args: &[FilterExpression]) -> String {
237 if args.is_empty() {
238 return "0".to_string();
239 }
240 format!("MONTH({})", self.render_filter(&args[0]))
241 }
242
243 fn render_day(&mut self, args: &[FilterExpression]) -> String {
244 if args.is_empty() {
245 return "0".to_string();
246 }
247 format!("DAY({})", self.render_filter(&args[0]))
248 }
249
250 fn render_hour(&mut self, args: &[FilterExpression]) -> String {
251 if args.is_empty() {
252 return "0".to_string();
253 }
254 format!("HOUR({})", self.render_filter(&args[0]))
255 }
256
257 fn render_minute(&mut self, args: &[FilterExpression]) -> String {
258 if args.is_empty() {
259 return "0".to_string();
260 }
261 format!("MINUTE({})", self.render_filter(&args[0]))
262 }
263
264 fn render_second(&mut self, args: &[FilterExpression]) -> String {
265 if args.is_empty() {
266 return "0".to_string();
267 }
268 format!("SECOND({})", self.render_filter(&args[0]))
269 }
270
271 fn render_now(&mut self, _args: &[FilterExpression]) -> String {
272 "NOW()".to_string()
273 }
274
275 fn render_round(&mut self, args: &[FilterExpression]) -> String {
277 if args.is_empty() {
278 return "0".to_string();
279 }
280 format!("ROUND({}, 0)", self.render_filter(&args[0]))
281 }
282
283 fn render_floor(&mut self, args: &[FilterExpression]) -> String {
284 if args.is_empty() {
285 return "0".to_string();
286 }
287 format!("FLOOR({})", self.render_filter(&args[0]))
288 }
289
290 fn render_ceiling(&mut self, args: &[FilterExpression]) -> String {
291 if args.is_empty() {
292 return "0".to_string();
293 }
294 format!("CEILING({})", self.render_filter(&args[0]))
295 }
296
297 fn render_lambda(&mut self, collection: &str, operator: &LambdaOp, variable: &str, _predicate: &FilterExpression) -> String {
299 let op_str = match operator {
300 LambdaOp::Any => "ANY",
301 LambdaOp::All => "ALL",
302 };
303 format!("/* TODO: {} lambda on {} with {} */", op_str, collection, variable)
304 }
305}