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