use std::any::Any;
use arrow::datatypes::DataType;
use datafusion_common::Result;
use datafusion_expr::{
ColumnarValue, Expr, ExpressionPlacement, ScalarFunctionArgs, ScalarUDF,
ScalarUDFImpl, Signature, TypeSignature,
};
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct PlacementTestUDF {
signature: Signature,
placement: ExpressionPlacement,
id: usize,
}
impl Default for PlacementTestUDF {
fn default() -> Self {
Self::new()
}
}
impl PlacementTestUDF {
pub fn new() -> Self {
Self {
signature: Signature::new(
TypeSignature::OneOf(vec![TypeSignature::Any(1), TypeSignature::Any(2)]),
datafusion_expr::Volatility::Immutable,
),
placement: ExpressionPlacement::MoveTowardsLeafNodes,
id: 0,
}
}
pub fn with_placement(mut self, placement: ExpressionPlacement) -> Self {
self.placement = placement;
self
}
pub fn with_id(mut self, id: usize) -> Self {
self.id = id;
self
}
}
impl ScalarUDFImpl for PlacementTestUDF {
fn as_any(&self) -> &dyn Any {
self
}
fn name(&self) -> &str {
match self.placement {
ExpressionPlacement::MoveTowardsLeafNodes => "leaf_udf",
ExpressionPlacement::KeepInPlace => "keep_in_place_udf",
ExpressionPlacement::Column => "column_udf",
ExpressionPlacement::Literal => "literal_udf",
}
}
fn signature(&self) -> &Signature {
&self.signature
}
fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
Ok(DataType::UInt32)
}
fn invoke_with_args(&self, _args: ScalarFunctionArgs) -> Result<ColumnarValue> {
panic!("PlacementTestUDF: not intended for execution")
}
fn placement(&self, _args: &[ExpressionPlacement]) -> ExpressionPlacement {
self.placement
}
}
pub fn leaf_udf_expr(arg: Expr) -> Expr {
let udf = ScalarUDF::new_from_impl(
PlacementTestUDF::new().with_placement(ExpressionPlacement::MoveTowardsLeafNodes),
);
udf.call(vec![arg])
}