use std::{ops::Neg, sync::Arc};
use arrow_schema::SortOptions;
use crate::PhysicalExpr;
use datafusion_common::tree_node::{TreeNode, VisitRecursion};
use datafusion_common::Result;
#[derive(PartialEq, Debug, Clone, Copy, Default)]
pub enum SortProperties {
Ordered(SortOptions),
#[default]
Unordered,
Singleton,
}
impl SortProperties {
pub fn add(&self, rhs: &Self) -> Self {
match (self, rhs) {
(Self::Singleton, _) => *rhs,
(_, Self::Singleton) => *self,
(Self::Ordered(lhs), Self::Ordered(rhs))
if lhs.descending == rhs.descending =>
{
Self::Ordered(SortOptions {
descending: lhs.descending,
nulls_first: lhs.nulls_first || rhs.nulls_first,
})
}
_ => Self::Unordered,
}
}
pub fn sub(&self, rhs: &Self) -> Self {
match (self, rhs) {
(Self::Singleton, Self::Singleton) => Self::Singleton,
(Self::Singleton, Self::Ordered(rhs)) => Self::Ordered(SortOptions {
descending: !rhs.descending,
nulls_first: rhs.nulls_first,
}),
(_, Self::Singleton) => *self,
(Self::Ordered(lhs), Self::Ordered(rhs))
if lhs.descending != rhs.descending =>
{
Self::Ordered(SortOptions {
descending: lhs.descending,
nulls_first: lhs.nulls_first || rhs.nulls_first,
})
}
_ => Self::Unordered,
}
}
pub fn gt_or_gteq(&self, rhs: &Self) -> Self {
match (self, rhs) {
(Self::Singleton, Self::Ordered(rhs)) => Self::Ordered(SortOptions {
descending: !rhs.descending,
nulls_first: rhs.nulls_first,
}),
(_, Self::Singleton) => *self,
(Self::Ordered(lhs), Self::Ordered(rhs))
if lhs.descending != rhs.descending =>
{
*self
}
_ => Self::Unordered,
}
}
pub fn and_or(&self, rhs: &Self) -> Self {
match (self, rhs) {
(Self::Ordered(lhs), Self::Ordered(rhs))
if lhs.descending == rhs.descending =>
{
Self::Ordered(SortOptions {
descending: lhs.descending,
nulls_first: lhs.nulls_first || rhs.nulls_first,
})
}
(Self::Ordered(opt), Self::Singleton)
| (Self::Singleton, Self::Ordered(opt)) => Self::Ordered(SortOptions {
descending: opt.descending,
nulls_first: opt.nulls_first,
}),
(Self::Singleton, Self::Singleton) => Self::Singleton,
_ => Self::Unordered,
}
}
}
impl Neg for SortProperties {
type Output = Self;
fn neg(self) -> Self::Output {
match self {
SortProperties::Ordered(SortOptions {
descending,
nulls_first,
}) => SortProperties::Ordered(SortOptions {
descending: !descending,
nulls_first,
}),
SortProperties::Singleton => SortProperties::Singleton,
SortProperties::Unordered => SortProperties::Unordered,
}
}
}
#[derive(Debug)]
pub struct ExprOrdering {
pub expr: Arc<dyn PhysicalExpr>,
pub state: SortProperties,
pub children: Vec<ExprOrdering>,
}
impl ExprOrdering {
pub fn new(expr: Arc<dyn PhysicalExpr>) -> Self {
let children = expr.children();
Self {
expr,
state: Default::default(),
children: children.into_iter().map(Self::new).collect(),
}
}
pub fn children_state(&self) -> Vec<SortProperties> {
self.children.iter().map(|c| c.state).collect()
}
}
impl TreeNode for ExprOrdering {
fn apply_children<F>(&self, op: &mut F) -> Result<VisitRecursion>
where
F: FnMut(&Self) -> Result<VisitRecursion>,
{
for child in &self.children {
match op(child)? {
VisitRecursion::Continue => {}
VisitRecursion::Skip => return Ok(VisitRecursion::Continue),
VisitRecursion::Stop => return Ok(VisitRecursion::Stop),
}
}
Ok(VisitRecursion::Continue)
}
fn map_children<F>(mut self, transform: F) -> Result<Self>
where
F: FnMut(Self) -> Result<Self>,
{
if self.children.is_empty() {
Ok(self)
} else {
self.children = self
.children
.into_iter()
.map(transform)
.collect::<Result<Vec<_>>>()?;
Ok(self)
}
}
}