use vortex_array::dtype::DType;
use vortex_array::dtype::Nullability;
use vortex_array::expr::BoundExpression;
use vortex_array::expr::bound::not;
use vortex_array::scalar_fn::fns::is_not_null::IsNotNull;
use vortex_array::scalar_fn::fns::is_null::IsNull;
use vortex_array::scalar_fn::fns::list_length::ListLength;
use vortex_error::VortexResult;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub(super) enum ListChildrenNeeded {
Validity,
OffsetsAndValidity,
All,
}
pub(super) fn get_necessary_bound_list_children(expr: &BoundExpression) -> ListChildrenNeeded {
if is_bound_null_root(expr) {
return ListChildrenNeeded::Validity;
}
if is_bound_list_length_root(expr) {
return ListChildrenNeeded::OffsetsAndValidity;
}
if expr.is_root() {
return ListChildrenNeeded::All;
}
expr.children()
.iter()
.map(get_necessary_bound_list_children)
.max()
.unwrap_or(ListChildrenNeeded::Validity)
}
fn is_bound_null_root(expr: &BoundExpression) -> bool {
(expr.as_scalar().is_some_and(|f| f.is::<IsNull>())
|| expr.as_scalar().is_some_and(|f| f.is::<IsNotNull>()))
&& expr.children().len() == 1
&& expr.children()[0].is_root()
}
fn is_bound_list_length_root(expr: &BoundExpression) -> bool {
expr.as_scalar().is_some_and(|f| f.is::<ListLength>())
&& expr.children().len() == 1
&& expr.children()[0].is_root()
}
pub(super) fn rewrite_validity_expr(expr: &BoundExpression) -> VortexResult<BoundExpression> {
let validity_dtype = DType::Bool(Nullability::NonNullable);
rewrite_validity_expr_with_root(expr, &validity_dtype)
}
fn rewrite_validity_expr_with_root(
expr: &BoundExpression,
root_dtype: &DType,
) -> VortexResult<BoundExpression> {
if expr.as_scalar().is_some_and(|f| f.is::<IsNotNull>())
&& expr.children().len() == 1
&& expr.children()[0].is_root()
{
return Ok(BoundExpression::new_root(root_dtype.clone()));
}
if expr.as_scalar().is_some_and(|f| f.is::<IsNull>())
&& expr.children().len() == 1
&& expr.children()[0].is_root()
{
return Ok(not(BoundExpression::new_root(root_dtype.clone())));
}
if expr.is_root() {
return Ok(BoundExpression::new_root(root_dtype.clone()));
}
let children = expr
.children()
.iter()
.map(|child| rewrite_validity_expr_with_root(child, root_dtype))
.collect::<VortexResult<Vec<_>>>()?;
expr.clone().with_children(children)
}
pub(super) fn rewrite_offsets_expr(
expr: &BoundExpression,
lengths_dtype: &DType,
) -> VortexResult<BoundExpression> {
if is_bound_list_length_root(expr) || expr.is_root() {
return Ok(BoundExpression::new_root(lengths_dtype.clone()));
}
let children = expr
.children()
.iter()
.map(|child| rewrite_offsets_expr(child, lengths_dtype))
.collect::<VortexResult<Vec<_>>>()?;
expr.clone().with_children(children)
}