use super::super::super::builder::SelectExecutor;
use crate::{
errors::ExecutorError,
evaluator::{CombinedExpressionEvaluator, ExpressionEvaluator},
};
pub(super) fn evaluate(
executor: &SelectExecutor,
expr: &vibesql_ast::Expression,
group_rows: &[vibesql_storage::Row],
group_key: &[vibesql_types::SqlValue],
evaluator: &CombinedExpressionEvaluator,
) -> Result<vibesql_types::SqlValue, ExecutorError> {
let (name, args, character_unit) = match expr {
vibesql_ast::Expression::Function { name, args, character_unit } => {
(name, args, character_unit)
}
_ => unreachable!("evaluate called with non-function expression"),
};
let name_upper = name.to_uppercase();
let is_aggregate = match name_upper.as_str() {
"COUNT" | "SUM" | "AVG" | "TOTAL" | "GROUP_CONCAT" | "STRING_AGG" | "JSON_GROUP_ARRAY"
| "MD5SUM" => true,
"MIN" | "MAX" => args.len() <= 1, _ => false,
};
if is_aggregate {
let agg_expr = vibesql_ast::Expression::AggregateFunction {
name: name.clone(),
distinct: false,
args: args.clone(),
order_by: None,
filter: None,
};
return super::aggregate_function::evaluate(executor, &agg_expr, group_rows, evaluator);
}
let evaluated_args: Result<Vec<_>, _> = args
.iter()
.map(|arg| executor.evaluate_with_aggregates(arg, group_rows, group_key, evaluator))
.collect();
let evaluated_args = evaluated_args?;
let temp_row = vibesql_storage::Row::new(evaluated_args);
let literal_args: Vec<vibesql_ast::Expression> =
temp_row.values.iter().map(|val| vibesql_ast::Expression::Literal(val.clone())).collect();
let new_func_expr = vibesql_ast::Expression::Function {
name: name.clone(),
args: literal_args,
character_unit: character_unit.clone(),
};
if let Some(first_row) = group_rows.first() {
evaluator.eval(&new_func_expr, first_row)
} else {
let temp_schema = vibesql_catalog::TableSchema::new("temp".to_string(), vec![]);
let temp_evaluator = ExpressionEvaluator::with_database(&temp_schema, executor.database);
temp_evaluator.eval(&new_func_expr, &vibesql_storage::Row::new(vec![]))
}
}