use crate::{
db::query::{
explain::ExplainPredicate,
plan::expr::{
CaseWhenArm, Expr, Function, derive_normalized_bool_expr_predicate_subset,
normalize_bool_expr,
},
},
value::Value,
};
pub(in crate::db) fn explain_predicate_from_expr(expr: &Expr) -> Option<ExplainPredicate> {
let normalized = normalize_bool_expr(strip_explain_bool_false_guards(expr.clone()));
derive_normalized_bool_expr_predicate_subset(&normalized)
.map(|predicate| ExplainPredicate::from_predicate(&predicate))
}
fn strip_explain_bool_false_guards(expr: Expr) -> Expr {
match expr {
Expr::Unary { op, expr } => Expr::Unary {
op,
expr: Box::new(strip_explain_bool_false_guards(*expr)),
},
Expr::Binary { op, left, right } => Expr::Binary {
op,
left: Box::new(strip_explain_bool_false_guards(*left)),
right: Box::new(strip_explain_bool_false_guards(*right)),
},
Expr::FunctionCall {
function: Function::Coalesce,
args,
} => match args.as_slice() {
[inner, Expr::Literal(Value::Bool(false))] => {
strip_explain_bool_false_guards(inner.clone())
}
_ => Expr::FunctionCall {
function: Function::Coalesce,
args: args
.into_iter()
.map(strip_explain_bool_false_guards)
.collect(),
},
},
Expr::FunctionCall { function, args } => Expr::FunctionCall {
function,
args: args
.into_iter()
.map(strip_explain_bool_false_guards)
.collect(),
},
Expr::Case {
when_then_arms,
else_expr,
} => Expr::Case {
when_then_arms: when_then_arms
.into_iter()
.map(|arm| {
CaseWhenArm::new(
strip_explain_bool_false_guards(arm.condition().clone()),
strip_explain_bool_false_guards(arm.result().clone()),
)
})
.collect(),
else_expr: Box::new(strip_explain_bool_false_guards(*else_expr)),
},
other => other,
}
}