use crate::{Accumulator, BuiltinScalarFunction, PartitionEvaluator, Signature};
use crate::{AggregateFunction, BuiltInWindowFunction, ColumnarValue};
use arrow::datatypes::DataType;
use datafusion_common::utils::datafusion_strsim;
use datafusion_common::Result;
use std::sync::Arc;
use strum::IntoEnumIterator;
pub type ScalarFunctionImplementation =
Arc<dyn Fn(&[ColumnarValue]) -> Result<ColumnarValue> + Send + Sync>;
pub type ReturnTypeFunction =
Arc<dyn Fn(&[DataType]) -> Result<Arc<DataType>> + Send + Sync>;
pub type AccumulatorFactoryFunction =
Arc<dyn Fn(&DataType) -> Result<Box<dyn Accumulator>> + Send + Sync>;
pub type PartitionEvaluatorFactory =
Arc<dyn Fn() -> Result<Box<dyn PartitionEvaluator>> + Send + Sync>;
pub type StateTypeFunction =
Arc<dyn Fn(&DataType) -> Result<Arc<Vec<DataType>>> + Send + Sync>;
#[deprecated(
since = "27.0.0",
note = "please use `BuiltinScalarFunction::return_type` instead"
)]
pub fn return_type(
fun: &BuiltinScalarFunction,
input_expr_types: &[DataType],
) -> Result<DataType> {
fun.return_type(input_expr_types)
}
#[deprecated(
since = "27.0.0",
note = "please use `BuiltinScalarFunction::signature` instead"
)]
pub fn signature(fun: &BuiltinScalarFunction) -> Signature {
fun.signature()
}
pub fn suggest_valid_function(input_function_name: &str, is_window_func: bool) -> String {
let valid_funcs = if is_window_func {
AggregateFunction::iter()
.map(|func| func.to_string())
.chain(BuiltInWindowFunction::iter().map(|func| func.to_string()))
.collect()
} else {
BuiltinScalarFunction::iter()
.map(|func| func.to_string())
.chain(AggregateFunction::iter().map(|func| func.to_string()))
.collect()
};
find_closest_match(valid_funcs, input_function_name)
}
fn find_closest_match(candidates: Vec<String>, target: &str) -> String {
let target = target.to_lowercase();
candidates
.into_iter()
.min_by_key(|candidate| {
datafusion_strsim::levenshtein(&candidate.to_lowercase(), &target)
})
.expect("No candidates provided.") }