use std::borrow::Cow;
use std::{ops::Neg, sync::Arc};
use arrow_schema::SortOptions;
use crate::PhysicalExpr;
use datafusion_common::tree_node::TreeNode;
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, Clone)]
pub struct ExprOrdering {
pub expr: Arc<dyn PhysicalExpr>,
pub state: SortProperties,
pub children: Vec<Self>,
}
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 children_nodes(&self) -> Vec<Cow<Self>> {
self.children.iter().map(Cow::Borrowed).collect()
}
fn map_children<F>(mut self, transform: F) -> Result<Self>
where
F: FnMut(Self) -> Result<Self>,
{
if !self.children.is_empty() {
self.children = self
.children
.into_iter()
.map(transform)
.collect::<Result<_>>()?;
}
Ok(self)
}
}