use crate::utils::compare_rows;
use crate::{Result, ScalarValue, error::_plan_err};
use arrow::compute::SortOptions;
use std::cmp::Ordering;
use std::fmt::{self, Display};
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Hash)]
pub struct SplitPoint {
values: Vec<ScalarValue>,
}
impl SplitPoint {
pub fn new(values: Vec<ScalarValue>) -> Self {
Self { values }
}
pub fn values(&self) -> &[ScalarValue] {
&self.values
}
}
impl Display for SplitPoint {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let values = self
.values
.iter()
.map(ToString::to_string)
.collect::<Vec<_>>()
.join(", ");
write!(f, "({values})")
}
}
pub fn validate_range_split_points(
split_points: &[SplitPoint],
sort_options: &[SortOptions],
) -> Result<()> {
let width = sort_options.len();
for (idx, split_point) in split_points.iter().enumerate() {
let split_point_width = split_point.values().len();
if split_point_width != width {
return _plan_err!(
"Range partitioning split point {idx} has width {split_point_width}, but ordering has width {width}"
);
}
}
for (idx, split_points) in split_points.windows(2).enumerate() {
if compare_rows(
split_points[0].values(),
split_points[1].values(),
sort_options,
)? != Ordering::Less
{
return _plan_err!(
"Range partitioning split points must be strictly ordered: split point {idx} ({}) must be less than split point {} ({})",
split_points[0],
idx + 1,
split_points[1]
);
}
}
Ok(())
}