1mod binary_op;
2mod case;
3mod exists;
4mod is_null;
5mod like;
6mod nested;
7mod unary_op;
8
9pub mod aggregate;
10pub mod alias_as;
11pub mod between;
12pub mod function;
13pub mod in_list;
14pub mod numeric;
15
16use {
17 crate::{
18 ast::{Aggregate, AstLiteral, BinaryOperator, Expr, Function, Query, UnaryOperator},
19 ast_builder::QueryNode,
20 parse_sql::{parse_comma_separated_exprs, parse_expr, parse_query},
21 prelude::DataType,
22 result::{Error, Result},
23 translate::{translate_expr, translate_query},
24 },
25 aggregate::AggregateNode,
26 bigdecimal::BigDecimal,
27 function::FunctionNode,
28 in_list::InListNode,
29 numeric::NumericNode,
30 std::borrow::Cow,
31};
32pub use {
33 case::case,
34 exists::{exists, not_exists},
35 nested::nested,
36 unary_op::{bitwise_not, factorial, minus, not, plus},
37};
38
39#[derive(Clone, Debug)]
40pub enum ExprNode<'a> {
41 Expr(Cow<'a, Expr>),
42 SqlExpr(Cow<'a, str>),
43 Identifier(Cow<'a, str>),
44 Numeric(NumericNode<'a>),
45 QuotedString(Cow<'a, str>),
46 TypedString {
47 data_type: DataType,
48 value: Cow<'a, str>,
49 },
50 Between {
51 expr: Box<ExprNode<'a>>,
52 negated: bool,
53 low: Box<ExprNode<'a>>,
54 high: Box<ExprNode<'a>>,
55 },
56 Like {
57 expr: Box<ExprNode<'a>>,
58 negated: bool,
59 pattern: Box<ExprNode<'a>>,
60 },
61 ILike {
62 expr: Box<ExprNode<'a>>,
63 negated: bool,
64 pattern: Box<ExprNode<'a>>,
65 },
66 BinaryOp {
67 left: Box<ExprNode<'a>>,
68 op: BinaryOperator,
69 right: Box<ExprNode<'a>>,
70 },
71 UnaryOp {
72 op: UnaryOperator,
73 expr: Box<ExprNode<'a>>,
74 },
75 IsNull(Box<ExprNode<'a>>),
76 IsNotNull(Box<ExprNode<'a>>),
77 InList {
78 expr: Box<ExprNode<'a>>,
79 list: Box<InListNode<'a>>,
80 negated: bool,
81 },
82 Nested(Box<ExprNode<'a>>),
83 Function(Box<FunctionNode<'a>>),
84 Aggregate(Box<AggregateNode<'a>>),
85 Exists {
86 subquery: Box<QueryNode<'a>>,
87 negated: bool,
88 },
89 Subquery(Box<QueryNode<'a>>),
90 Case {
91 operand: Option<Box<ExprNode<'a>>>,
92 when_then: Vec<(ExprNode<'a>, ExprNode<'a>)>,
93 else_result: Option<Box<ExprNode<'a>>>,
94 },
95}
96
97impl<'a> TryFrom<ExprNode<'a>> for Expr {
98 type Error = Error;
99
100 fn try_from(expr_node: ExprNode<'a>) -> Result<Self> {
101 match expr_node {
102 ExprNode::Expr(expr) => Ok(expr.into_owned()),
103 ExprNode::SqlExpr(expr) => {
104 let expr = parse_expr(expr)?;
105
106 translate_expr(&expr)
107 }
108 ExprNode::Identifier(value) => {
109 let idents = value.as_ref().split('.').collect::<Vec<_>>();
110
111 Ok(match idents.as_slice() {
112 [alias, ident] => Expr::CompoundIdentifier {
113 alias: alias.to_string(),
114 ident: ident.to_string(),
115 },
116 _ => Expr::Identifier(value.into_owned()),
117 })
118 }
119 ExprNode::Numeric(node) => node.try_into().map(Expr::Literal),
120 ExprNode::QuotedString(value) => {
121 let value = value.into_owned();
122
123 Ok(Expr::Literal(AstLiteral::QuotedString(value)))
124 }
125 ExprNode::TypedString { data_type, value } => Ok(Expr::TypedString {
126 data_type,
127 value: value.into_owned(),
128 }),
129 ExprNode::Between {
130 expr,
131 negated,
132 low,
133 high,
134 } => {
135 let expr = Expr::try_from(*expr).map(Box::new)?;
136 let low = Expr::try_from(*low).map(Box::new)?;
137 let high = Expr::try_from(*high).map(Box::new)?;
138
139 Ok(Expr::Between {
140 expr,
141 negated,
142 low,
143 high,
144 })
145 }
146 ExprNode::Like {
147 expr,
148 negated,
149 pattern,
150 } => {
151 let expr = Expr::try_from(*expr).map(Box::new)?;
152 let pattern = Expr::try_from(*pattern).map(Box::new)?;
153
154 Ok(Expr::Like {
155 expr,
156 negated,
157 pattern,
158 })
159 }
160 ExprNode::ILike {
161 expr,
162 negated,
163 pattern,
164 } => {
165 let expr = Expr::try_from(*expr).map(Box::new)?;
166 let pattern = Expr::try_from(*pattern).map(Box::new)?;
167
168 Ok(Expr::ILike {
169 expr,
170 negated,
171 pattern,
172 })
173 }
174 ExprNode::BinaryOp { left, op, right } => {
175 let left = Expr::try_from(*left).map(Box::new)?;
176 let right = Expr::try_from(*right).map(Box::new)?;
177
178 Ok(Expr::BinaryOp { left, op, right })
179 }
180 ExprNode::UnaryOp { op, expr } => {
181 let expr = Expr::try_from(*expr).map(Box::new)?;
182 Ok(Expr::UnaryOp { op, expr })
183 }
184 ExprNode::IsNull(expr) => Expr::try_from(*expr).map(Box::new).map(Expr::IsNull),
185 ExprNode::IsNotNull(expr) => Expr::try_from(*expr).map(Box::new).map(Expr::IsNotNull),
186 ExprNode::InList {
187 expr,
188 list,
189 negated,
190 } => {
191 let expr = Expr::try_from(*expr).map(Box::new)?;
192
193 match *list {
194 InListNode::InList(list) => {
195 let list = list
196 .into_iter()
197 .map(Expr::try_from)
198 .collect::<Result<Vec<_>>>()?;
199 Ok(Expr::InList {
200 expr,
201 list,
202 negated,
203 })
204 }
205 InListNode::Query(subquery) => {
206 let subquery = Query::try_from(*subquery).map(Box::new)?;
207 Ok(Expr::InSubquery {
208 expr,
209 subquery,
210 negated,
211 })
212 }
213 InListNode::Text(value) => {
214 let subquery = parse_query(value.clone())
215 .and_then(|item| translate_query(&item))
216 .map(Box::new);
217
218 if let Ok(subquery) = subquery {
219 return Ok(Expr::InSubquery {
220 expr,
221 subquery,
222 negated,
223 });
224 }
225
226 parse_comma_separated_exprs(&*value)?
227 .iter()
228 .map(translate_expr)
229 .collect::<Result<Vec<_>>>()
230 .map(|list| Expr::InList {
231 expr,
232 list,
233 negated,
234 })
235 }
236 }
237 }
238 ExprNode::Nested(expr) => Expr::try_from(*expr).map(Box::new).map(Expr::Nested),
239 ExprNode::Function(func_expr) => Function::try_from(*func_expr)
240 .map(Box::new)
241 .map(Expr::Function),
242 ExprNode::Aggregate(aggr_expr) => Aggregate::try_from(*aggr_expr)
243 .map(Box::new)
244 .map(Expr::Aggregate),
245 ExprNode::Exists { subquery, negated } => Query::try_from(*subquery)
246 .map(Box::new)
247 .map(|subquery| Expr::Exists { subquery, negated }),
248 ExprNode::Subquery(subquery) => {
249 Query::try_from(*subquery).map(Box::new).map(Expr::Subquery)
250 }
251 ExprNode::Case {
252 operand,
253 when_then,
254 else_result,
255 } => {
256 let operand = operand
257 .map(|expr| Expr::try_from(*expr))
258 .transpose()?
259 .map(Box::new);
260 let when_then = when_then
261 .into_iter()
262 .map(|(when, then)| {
263 let when = Expr::try_from(when)?;
264 let then = Expr::try_from(then)?;
265 Ok((when, then))
266 })
267 .collect::<Result<Vec<_>>>()?;
268
269 let else_result = else_result
270 .map(|expr| Expr::try_from(*expr))
271 .transpose()?
272 .map(Box::new);
273 Ok(Expr::Case {
274 operand,
275 when_then,
276 else_result,
277 })
278 }
279 }
280 }
281}
282
283impl<'a> From<&'a str> for ExprNode<'a> {
284 fn from(expr: &'a str) -> Self {
285 ExprNode::SqlExpr(Cow::Borrowed(expr))
286 }
287}
288
289impl<'a> From<String> for ExprNode<'a> {
290 fn from(expr: String) -> Self {
291 ExprNode::SqlExpr(Cow::Owned(expr))
292 }
293}
294
295impl<'a> From<i64> for ExprNode<'a> {
296 fn from(n: i64) -> Self {
297 ExprNode::Expr(Cow::Owned(Expr::Literal(AstLiteral::Number(
298 BigDecimal::from(n),
299 ))))
300 }
301}
302
303impl<'a> From<bool> for ExprNode<'a> {
304 fn from(b: bool) -> Self {
305 ExprNode::Expr(Cow::Owned(Expr::Literal(AstLiteral::Boolean(b))))
306 }
307}
308
309impl<'a> From<QueryNode<'a>> for ExprNode<'a> {
310 fn from(node: QueryNode<'a>) -> Self {
311 ExprNode::Subquery(Box::new(node))
312 }
313}
314
315impl<'a> From<Expr> for ExprNode<'a> {
316 fn from(expr: Expr) -> Self {
317 ExprNode::Expr(Cow::Owned(expr))
318 }
319}
320
321impl<'a> From<&'a Expr> for ExprNode<'a> {
322 fn from(expr: &'a Expr) -> Self {
323 ExprNode::Expr(Cow::Borrowed(expr))
324 }
325}
326
327pub fn expr<'a, T: Into<Cow<'a, str>>>(value: T) -> ExprNode<'a> {
328 ExprNode::SqlExpr(value.into())
329}
330
331pub fn col<'a, T: Into<Cow<'a, str>>>(value: T) -> ExprNode<'a> {
332 ExprNode::Identifier(value.into())
333}
334
335pub fn num<'a, T: Into<NumericNode<'a>>>(value: T) -> ExprNode<'a> {
336 ExprNode::Numeric(value.into())
337}
338
339pub fn text<'a, T: Into<Cow<'a, str>>>(value: T) -> ExprNode<'a> {
340 ExprNode::QuotedString(value.into())
341}
342
343pub fn date<'a, T: Into<Cow<'a, str>>>(date: T) -> ExprNode<'a> {
344 ExprNode::TypedString {
345 data_type: DataType::Date,
346 value: date.into(),
347 }
348}
349
350pub fn timestamp<'a, T: Into<Cow<'a, str>>>(timestamp: T) -> ExprNode<'a> {
351 ExprNode::TypedString {
352 data_type: DataType::Timestamp,
353 value: timestamp.into(),
354 }
355}
356
357pub fn time<'a, T: Into<Cow<'a, str>>>(time: T) -> ExprNode<'a> {
358 ExprNode::TypedString {
359 data_type: DataType::Time,
360 value: time.into(),
361 }
362}
363
364pub fn uuid<'a, T: Into<Cow<'a, str>>>(uuid: T) -> ExprNode<'a> {
365 ExprNode::TypedString {
366 data_type: DataType::Uuid,
367 value: uuid.into(),
368 }
369}
370
371pub fn bytea<'a, T: AsRef<[u8]>>(bytea: T) -> ExprNode<'a> {
377 ExprNode::TypedString {
378 data_type: DataType::Bytea,
379 value: hex::encode(bytea).into(),
380 }
381}
382
383pub fn subquery<'a, T: Into<QueryNode<'a>>>(query_node: T) -> ExprNode<'a> {
384 ExprNode::Subquery(Box::new(query_node.into()))
385}
386
387pub fn null() -> ExprNode<'static> {
388 ExprNode::Expr(Cow::Owned(Expr::Literal(AstLiteral::Null)))
389}
390
391#[cfg(test)]
392mod tests {
393 use {
394 super::ExprNode,
395 crate::{
396 ast::Expr,
397 ast_builder::{
398 QueryNode, bytea, col, date, expr, null, num, subquery, table, test_expr, text,
399 time, timestamp, uuid,
400 },
401 },
402 };
403
404 #[test]
405 fn into_expr_node() {
406 let actual: ExprNode = "id IS NOT NULL".into();
407 let expected = "id IS NOT NULL";
408 test_expr(actual, expected);
409
410 let actual: ExprNode = String::from("1 + 10)").into();
411 let expected = "1 + 10";
412 test_expr(actual, expected);
413
414 let actual: ExprNode = 1024.into();
415 let expected = "1024";
416 test_expr(actual, expected);
417
418 let actual: ExprNode = true.into();
419 let expected = "True";
420 test_expr(actual, expected);
421
422 let actual: ExprNode = QueryNode::from(table("Foo").select().project("id")).into();
423 let expected = "(SELECT id FROM Foo)";
424 test_expr(actual, expected);
425
426 let expr = Expr::Identifier("id".to_owned());
427 let actual: ExprNode = (&expr).into();
428 let expected = "id";
429 test_expr(actual, expected);
430
431 let actual: ExprNode = expr.into();
432 test_expr(actual, expected);
433 }
434
435 #[test]
436 fn syntactic_sugar() {
437 let actual = expr("col1 > 10");
438 let expected = "col1 > 10";
439 test_expr(actual, expected);
440
441 let actual = col("id");
442 let expected = "id";
443 test_expr(actual, expected);
444
445 let actual = col("Foo.id");
446 let expected = "Foo.id";
447 test_expr(actual, expected);
448
449 let actual = num(2048);
450 let expected = "2048";
451 test_expr(actual, expected);
452
453 let actual = num(6.5);
454 let expected = "6.5";
455 test_expr(actual, expected);
456
457 let actual = num("123.456");
458 let expected = "123.456";
459 test_expr(actual, expected);
460
461 let actual = text("hello world");
462 let expected = "'hello world'";
463 test_expr(actual, expected);
464
465 let actual = date("2022-10-11");
466 let expected = "DATE '2022-10-11'";
467 test_expr(actual, expected);
468
469 let actual = timestamp("2022-10-11 13:34:49");
470 let expected = "TIMESTAMP '2022-10-11 13:34:49'";
471 test_expr(actual, expected);
472
473 let actual = time("15:00:07");
474 let expected = "TIME '15:00:07'";
475 test_expr(actual, expected);
476
477 let actual = uuid("936DA01F9ABD4d9d80C702AF85C822A8");
478 let expected = "UUID '936DA01F9ABD4d9d80C702AF85C822A8'";
479 test_expr(actual, expected);
480
481 let actual = bytea(b"hello world");
482 let expected = "BYTEA '68656c6c6f20776f726c64'";
483 test_expr(actual, expected);
484
485 let actual = subquery(table("Foo").select().filter("id IS NOT NULL"));
486 let expected = "(SELECT * FROM Foo WHERE id IS NOT NULL)";
487 test_expr(actual, expected);
488
489 let actual = null();
490 let expected = "NULL";
491 test_expr(actual, expected);
492 }
493}