(expr: &ast::Expr)
| 26 | } |
| 27 | |
| 28 | pub(super) fn expr_to_sql_value(expr: &ast::Expr) -> Result<SqlValue> { |
| 29 | match expr { |
| 30 | ast::Expr::Value(v) => convert_value(&v.value), |
| 31 | // Array literals lower element-wise into `SqlValue::Array`; there is |
| 32 | // no array-literal `SqlValue` the constant folder could produce. |
| 33 | ast::Expr::Array(ast::Array { elem, .. }) => { |
| 34 | let vals = elem.iter().map(expr_to_sql_value).collect::<Result<_>>()?; |
| 35 | Ok(SqlValue::Array(vals)) |
| 36 | } |
| 37 | // `ST_Point(...)` / `ST_GeomFromGeoJSON(...)` synthesise a GeoJSON |
| 38 | // string in place rather than resolving as registered scalar |
| 39 | // functions, so they keep their bespoke handling. |
| 40 | ast::Expr::Function(func) => match SpatialConstructor::from_function(func) { |
| 41 | Some(ctor) => spatial_constructor_to_value(ctor, func), |
| 42 | // Non-spatial functions (`now()`, `date_add(...)`, registered |
| 43 | // scalars) fold through the shared pipeline below. |
| 44 | None => fold_constant_value(expr), |
| 45 | }, |
| 46 | // Everything else — `::TYPE` / `CAST(... AS TYPE)` casts, arithmetic, |
| 47 | // string concatenation, parenthesised literals — goes through the |
| 48 | // same resolver and constant folder the `SELECT` projection path |
| 49 | // uses, so the two surfaces never drift. Only genuinely row- or |
| 50 | // runtime-dependent expressions (column refs, subqueries, unknown |
| 51 | // functions) fail here. |
| 52 | _ => fold_constant_value(expr), |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | fn fold_constant_value(expr: &ast::Expr) -> Result<SqlValue> { |
| 57 | let sql_expr = crate::resolver::expr::convert_expr(expr)?; |
no test coverage detected