Skip to main content

nodedb_sql/resolver/expr/convert/
predicates.rs

1// SPDX-License-Identifier: Apache-2.0
2
3//! Predicate and conditional expression conversion.
4
5use sqlparser::ast::{CaseWhen, Expr};
6
7use crate::error::Result;
8use crate::resolver::ColumnScope;
9use crate::types::*;
10
11use super::entry::convert_expr_depth;
12
13pub(super) fn convert_is_null(
14    inner: &Expr,
15    negated: bool,
16    depth: &mut usize,
17    scope: &ColumnScope<'_>,
18) -> Result<SqlExpr> {
19    Ok(SqlExpr::IsNull {
20        expr: Box::new(convert_expr_depth(inner, depth, scope)?),
21        negated,
22    })
23}
24
25pub(super) fn convert_in_list(
26    expr: &Expr,
27    list: &[Expr],
28    negated: bool,
29    depth: &mut usize,
30    scope: &ColumnScope<'_>,
31) -> Result<SqlExpr> {
32    Ok(SqlExpr::InList {
33        expr: Box::new(convert_expr_depth(expr, depth, scope)?),
34        list: list
35            .iter()
36            .map(|e| convert_expr_depth(e, depth, scope))
37            .collect::<Result<_>>()?,
38        negated,
39    })
40}
41
42pub(super) fn convert_between(
43    expr: &Expr,
44    low: &Expr,
45    high: &Expr,
46    negated: bool,
47    depth: &mut usize,
48    scope: &ColumnScope<'_>,
49) -> Result<SqlExpr> {
50    Ok(SqlExpr::Between {
51        expr: Box::new(convert_expr_depth(expr, depth, scope)?),
52        low: Box::new(convert_expr_depth(low, depth, scope)?),
53        high: Box::new(convert_expr_depth(high, depth, scope)?),
54        negated,
55    })
56}
57
58pub(super) fn convert_like(
59    expr: &Expr,
60    pattern: &Expr,
61    negated: bool,
62    case_insensitive: bool,
63    depth: &mut usize,
64    scope: &ColumnScope<'_>,
65) -> Result<SqlExpr> {
66    Ok(SqlExpr::Like {
67        expr: Box::new(convert_expr_depth(expr, depth, scope)?),
68        pattern: Box::new(convert_expr_depth(pattern, depth, scope)?),
69        negated,
70        case_insensitive,
71    })
72}
73
74pub(super) fn convert_case(
75    operand: Option<&Expr>,
76    conditions: &[CaseWhen],
77    else_result: Option<&Expr>,
78    depth: &mut usize,
79    scope: &ColumnScope<'_>,
80) -> Result<SqlExpr> {
81    let when_then = conditions
82        .iter()
83        .map(|cw| {
84            Ok((
85                convert_expr_depth(&cw.condition, depth, scope)?,
86                convert_expr_depth(&cw.result, depth, scope)?,
87            ))
88        })
89        .collect::<Result<Vec<_>>>()?;
90    Ok(SqlExpr::Case {
91        operand: operand
92            .map(|e| convert_expr_depth(e, depth, scope).map(Box::new))
93            .transpose()?,
94        when_then,
95        else_expr: else_result
96            .map(|e| convert_expr_depth(e, depth, scope).map(Box::new))
97            .transpose()?,
98    })
99}
100
101#[cfg(test)]
102mod tests {
103    use crate::resolver::expr::convert::entry::tests::where_sql_expr;
104    use crate::types::*;
105
106    #[test]
107    fn like_is_case_sensitive() {
108        let expr = where_sql_expr("SELECT * FROM t WHERE name LIKE 'foo%'");
109        match expr {
110            SqlExpr::Like {
111                negated,
112                case_insensitive,
113                ..
114            } => {
115                assert!(!negated, "LIKE should not be negated");
116                assert!(!case_insensitive, "LIKE should be case-sensitive");
117            }
118            other => panic!("expected SqlExpr::Like, got {other:?}"),
119        }
120    }
121
122    #[test]
123    fn ilike_is_case_insensitive() {
124        let expr = where_sql_expr("SELECT * FROM t WHERE name ILIKE 'foo%'");
125        match expr {
126            SqlExpr::Like {
127                negated,
128                case_insensitive,
129                ..
130            } => {
131                assert!(!negated, "ILIKE should not be negated");
132                assert!(case_insensitive, "ILIKE should be case-insensitive");
133            }
134            other => panic!("expected SqlExpr::Like, got {other:?}"),
135        }
136    }
137
138    #[test]
139    fn not_like_is_negated_case_sensitive() {
140        let expr = where_sql_expr("SELECT * FROM t WHERE name NOT LIKE 'foo%'");
141        match expr {
142            SqlExpr::Like {
143                negated,
144                case_insensitive,
145                ..
146            } => {
147                assert!(negated, "NOT LIKE should be negated");
148                assert!(!case_insensitive, "NOT LIKE should be case-sensitive");
149            }
150            other => panic!("expected SqlExpr::Like, got {other:?}"),
151        }
152    }
153
154    #[test]
155    fn not_ilike_is_negated_case_insensitive() {
156        let expr = where_sql_expr("SELECT * FROM t WHERE name NOT ILIKE 'foo%'");
157        match expr {
158            SqlExpr::Like {
159                negated,
160                case_insensitive,
161                ..
162            } => {
163                assert!(negated, "NOT ILIKE should be negated");
164                assert!(case_insensitive, "NOT ILIKE should be case-insensitive");
165            }
166            other => panic!("expected SqlExpr::Like, got {other:?}"),
167        }
168    }
169}