Recursively evaluate a sqlparser AST expression with column reference support.
(
expr: &sqlparser::ast::Expr,
ctx: &HashMap<String, nodedb_types::Value>,
)
| 208 | |
| 209 | /// Recursively evaluate a sqlparser AST expression with column reference support. |
| 210 | fn eval_ast_expr( |
| 211 | expr: &sqlparser::ast::Expr, |
| 212 | ctx: &HashMap<String, nodedb_types::Value>, |
| 213 | ) -> Option<nodedb_types::Value> { |
| 214 | use nodedb_types::Value; |
| 215 | use sqlparser::ast::{Expr, UnaryOperator}; |
| 216 | |
| 217 | match expr { |
| 218 | Expr::Value(v) => eval_ast_literal(&v.value), |
| 219 | |
| 220 | // Unqualified column: `n` |
| 221 | Expr::Identifier(ident) => { |
| 222 | let name = ident.value.to_lowercase(); |
| 223 | ctx.get(&name).cloned() |
| 224 | } |
| 225 | |
| 226 | // Qualified: `c.n` — strip qualifier |
| 227 | Expr::CompoundIdentifier(parts) if parts.len() == 2 => { |
| 228 | let col = parts[1].value.to_lowercase(); |
| 229 | ctx.get(&col).cloned() |
| 230 | } |
| 231 | |
| 232 | Expr::UnaryOp { |
| 233 | op: UnaryOperator::Minus, |
| 234 | expr: inner, |
| 235 | } => match eval_ast_expr(inner, ctx)? { |
| 236 | Value::Integer(i) => Some(Value::Integer(-i)), |
| 237 | Value::Float(f) => Some(Value::Float(-f)), |
| 238 | _ => None, |
| 239 | }, |
| 240 | |
| 241 | Expr::UnaryOp { |
| 242 | op: UnaryOperator::Not, |
| 243 | expr: inner, |
| 244 | } => match eval_ast_expr(inner, ctx)? { |
| 245 | Value::Bool(b) => Some(Value::Bool(!b)), |
| 246 | _ => None, |
| 247 | }, |
| 248 | |
| 249 | Expr::BinaryOp { left, op, right } => { |
| 250 | let l = eval_ast_expr(left, ctx)?; |
| 251 | let r = eval_ast_expr(right, ctx)?; |
| 252 | eval_binary_op(&l, op, &r) |
| 253 | } |
| 254 | |
| 255 | Expr::Nested(inner) => eval_ast_expr(inner, ctx), |
| 256 | |
| 257 | _ => None, |
| 258 | } |
| 259 | } |
| 260 | |
| 261 | fn eval_ast_literal(v: &sqlparser::ast::Value) -> Option<nodedb_types::Value> { |
| 262 | use sqlparser::ast::Value; |
no test coverage detected