use arrow::datatypes::{TimeUnit, TimestampNanosecondType};
use datafusion::common::Result as DFResult;
#[cfg(test)]
use datafusion::logical_expr::ColumnarValue;
pub(super) fn extract_timestamps(
arr: &arrow::array::ArrayRef,
) -> DFResult<arrow::array::Int64Array> {
use arrow::array::{Array, AsArray, Int64Array};
use arrow::datatypes::DataType;
match arr.data_type() {
DataType::Timestamp(TimeUnit::Nanosecond, _) => {
let ts = arr.as_primitive::<TimestampNanosecondType>();
Ok(Int64Array::from(ts.iter().collect::<Vec<_>>()))
}
DataType::Int64 => {
let i = arr.as_any().downcast_ref::<Int64Array>().ok_or_else(|| {
datafusion::common::DataFusionError::Internal("expected Int64".into())
})?;
Ok(i.clone())
}
other => Err(datafusion::common::DataFusionError::Plan(format!(
"expected timestamp or int64, got {other}"
))),
}
}
#[cfg(test)]
pub(super) fn invoke_udf(
udf: &dyn datafusion::logical_expr::ScalarUDFImpl,
args: Vec<ColumnarValue>,
number_rows: usize,
) -> DFResult<ColumnarValue> {
use std::sync::Arc;
use arrow::datatypes::Field;
use datafusion::logical_expr::ScalarFunctionArgs;
let arg_types: Vec<_> = args.iter().map(ColumnarValue::data_type).collect();
let return_type = udf.return_type(&arg_types)?;
let arg_fields = arg_types
.iter()
.enumerate()
.map(|(i, t)| Arc::new(Field::new(format!("arg{i}"), t.clone(), true)))
.collect();
udf.invoke_with_args(ScalarFunctionArgs {
args,
arg_fields,
number_rows,
return_field: Arc::new(Field::new("result", return_type, true)),
config_options: Arc::new(datafusion::config::ConfigOptions::default()),
})
}