use toasty_core::stmt::{
Expr, ExprAnd, ExprNot, ExprOr, ExprVariant, Query, Statement, Visit, VisitMut,
};
use super::Normalize;
impl Normalize<'_> {
pub(super) fn normalize_conjunction(&mut self, and: &mut ExprAnd) {
let depth = self.guards.len();
self.guards
.extend(and.operands.iter().filter(|e| is_guard(e)).cloned());
for mut operand in std::mem::take(&mut and.operands) {
self.visit_expr_mut(&mut operand);
match operand {
Expr::And(inner) => {
for operand in inner.operands {
if is_guard(&operand) && !self.guards.contains(&operand) {
self.guards.push(operand.clone());
}
and.operands.push(operand);
}
}
operand => and.operands.push(operand),
}
}
self.guards.truncate(depth);
}
pub(super) fn normalize_predicate_guards(&mut self, expr: &mut Expr) {
let mut guards = vec![];
let mut collect = CollectGuards {
guards: &mut guards,
existing_guards: &self.guards,
};
match expr {
Expr::BinaryOp(e) if e.op.is_arithmetic() => return,
Expr::AllOp(_)
| Expr::AnyOp(_)
| Expr::Between(_)
| Expr::BinaryOp(_)
| Expr::InList(_)
| Expr::InSubquery(_)
| Expr::Intersects(_)
| Expr::IsNull(_)
| Expr::IsSuperset(_)
| Expr::IsVariant(_)
| Expr::Like(_)
| Expr::StartsWith(_) => collect.visit_expr(expr),
Expr::Not(e) => collect.visit_expr(&e.expr),
_ => return,
}
let mut predicate = expr.take();
let negated = match &mut predicate {
Expr::IsNull(e) => std::mem::take(&mut e.negated),
Expr::InSubquery(e) => std::mem::take(&mut e.negated),
_ => false,
};
if negated {
predicate = Expr::not(predicate);
}
*expr = if guards.is_empty() {
predicate
} else {
guards.push(predicate);
Expr::and_from_vec(guards)
};
}
}
fn is_guard(expr: &Expr) -> bool {
matches!(expr, Expr::IsVariant(_))
}
struct CollectGuards<'a> {
guards: &'a mut Vec<Expr>,
existing_guards: &'a [Expr],
}
impl Visit for CollectGuards<'_> {
fn visit_expr_variant(&mut self, i: &ExprVariant) {
self.visit_expr(&i.base);
let guard = Expr::is_variant((*i.base).clone(), i.variant);
if !self.existing_guards.contains(&guard) && !self.guards.contains(&guard) {
self.guards.push(guard);
}
}
fn visit_expr_and(&mut self, _: &ExprAnd) {}
fn visit_expr_or(&mut self, _: &ExprOr) {}
fn visit_expr_not(&mut self, _: &ExprNot) {}
fn visit_stmt(&mut self, _: &Statement) {}
fn visit_stmt_query(&mut self, _: &Query) {}
}