sql::ast

Function visit_expressions_mut

pub fn visit_expressions_mut<V, E, F>(v: &mut V, f: F) -> ControlFlow<E>
where V: VisitMut, F: FnMut(&mut Expr) -> ControlFlow<E>,
Expand description

Invokes the provided closure iteratively with a mutable reference to all expressions present in v.

This performs a depth-first search, so if the closure mutates the expression

§Example

§Remove all select limits in sub-queries

let sql = "SELECT (SELECT y FROM z LIMIT 9) FROM t LIMIT 3";
let mut statements = Parser::parse_sql(&GenericDialect{}, sql).unwrap();

// Remove all select limits in sub-queries
visit_expressions_mut(&mut statements, |expr| {
  if let Expr::Subquery(q) = expr {
     q.limit = None
  }
  ControlFlow::<()>::Continue(())
});

assert_eq!(statements[0].to_string(), "SELECT (SELECT y FROM z) FROM t LIMIT 3");

§Wrap column name in function call

This demonstrates how to effectively replace an expression with another more complicated one that references the original. This example avoids unnecessary allocations by using the std::mem family of functions.

let sql = "SELECT x, y FROM t";
let mut statements = Parser::parse_sql(&GenericDialect{}, sql).unwrap();

visit_expressions_mut(&mut statements, |expr| {
  if matches!(expr, Expr::Identifier(col_name) if col_name.value == "x") {
    let old_expr = std::mem::replace(expr, Expr::Value(Value::Null));
    *expr = Expr::Function(Function {
          name: ObjectName(vec![Ident::new("f")]),
          args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(old_expr))],
          null_treatment: None,
          filter: None, over: None, distinct: false, special: false, order_by: vec![],
     });
  }
  ControlFlow::<()>::Continue(())
});

assert_eq!(statements[0].to_string(), "SELECT f(x), y FROM t");