use {
super::{try_visit_expr, visit_mut_expr},
crate::{
plan::{AggregateExprPlan, AggregateFunctionPlan, CountArgExprPlan, ExprPlan},
planner::PlannerError,
},
};
macro_rules! apply_mut {
($visit:expr) => {
$visit
};
}
macro_rules! apply_try {
($visit:expr) => {
$visit?
};
}
macro_rules! visit_aggregate_children {
($func:expr, $visit_expr:ident, $f:expr, $apply:ident) => {
match $func {
AggregateFunctionPlan::Count(count_arg) => {
if let CountArgExprPlan::Expr(expr) = count_arg {
$apply!($visit_expr(expr, $f));
}
}
AggregateFunctionPlan::Sum(expr)
| AggregateFunctionPlan::Min(expr)
| AggregateFunctionPlan::Max(expr)
| AggregateFunctionPlan::Avg(expr)
| AggregateFunctionPlan::Variance(expr)
| AggregateFunctionPlan::Stdev(expr) => {
$apply!($visit_expr(expr, $f));
}
}
};
}
pub fn visit_mut_aggregate<F>(aggr: &mut AggregateExprPlan, f: &mut F)
where
F: FnMut(&mut ExprPlan),
{
visit_aggregate_children!(&mut aggr.func, visit_mut_expr, f, apply_mut);
}
pub fn try_visit_aggregate<F>(aggr: &AggregateExprPlan, f: &mut F) -> Result<(), PlannerError>
where
F: FnMut(&ExprPlan) -> Result<(), PlannerError>,
{
visit_aggregate_children!(&aggr.func, try_visit_expr, f, apply_try);
Ok(())
}
#[cfg(test)]
mod tests {
use {
super::{try_visit_expr, visit_mut_expr},
crate::{
parse_sql::parse_expr,
plan::ExprPlan,
planner::PlannerError,
translate::{NO_PARAMS, translate_expr},
},
};
fn test(input: &str, expected: &str) {
let parsed = parse_expr(input).expect(input);
let mut expr = ExprPlan::from(translate_expr(&parsed, NO_PARAMS).expect(input));
visit_mut_expr(&mut expr, &mut |e| {
if let ExprPlan::Identifier(ident) = e {
*e = ExprPlan::Identifier(format!("_{ident}"));
}
});
let expected_parsed = parse_expr(expected).expect(expected);
let expected = ExprPlan::from(translate_expr(&expected_parsed, NO_PARAMS).expect(expected));
assert_eq!(expr, expected, "\ninput: {input}\nexpected: {expected:?}");
}
#[test]
fn visit_mut_aggregate_variants() {
test("SUM(x)", "SUM(_x)");
test("COUNT(x)", "COUNT(_x)");
test("COUNT(*)", "COUNT(*)");
test("MIN(x)", "MIN(_x)");
test("MAX(x)", "MAX(_x)");
test("AVG(x)", "AVG(_x)");
}
#[test]
fn try_visit_aggregate_propagates_error() {
let parsed = parse_expr("SUM(x)").expect("SUM(x)");
let expr = ExprPlan::from(translate_expr(&parsed, NO_PARAMS).expect("SUM(x)"));
let result = try_visit_expr(&expr, &mut |_| Err(PlannerError::Unreachable));
assert_eq!(result, Err(PlannerError::Unreachable));
}
}