use std::cmp::Ordering;
use rudb_common::{Error, Result, Value};
use rudb_plan::{Plan, Slice, SortKey};
use rudb_vector::Chunk;
use crate::expr::evaluate_all;
use crate::operator::Operator;
use crate::rows;
use crate::schema::Schema;
#[derive(Debug)]
pub(crate) struct Sort<'a> {
input: Box<dyn Operator + 'a>,
plan: &'a Plan,
keys: Vec<SortKey>,
schema: Schema,
built: bool,
chunks: Vec<Chunk>,
at: usize,
}
impl<'a> Sort<'a> {
pub(crate) fn new(plan: &'a Plan, input: Box<dyn Operator + 'a>, keys: Slice) -> Self {
let schema = input.schema().clone();
Self {
input,
plan,
keys: plan.sort_key_list(keys).to_vec(),
schema,
built: false,
chunks: Vec::new(),
at: 0,
}
}
fn build(&mut self) -> Result<()> {
let exprs: Vec<_> = self.keys.iter().map(|key| key.expr).collect();
let mut sortable: Vec<(Vec<Value>, Vec<Value>)> = Vec::new();
while let Some(chunk) = self.input.next()? {
let keys = evaluate_all(self.plan, &exprs, &self.schema, &chunk)?;
for row in 0..chunk.len() {
let key = keys.iter().map(|column| column.value_at(row)).collect();
sortable.push((key, chunk.row(row).collect()));
}
}
let mut failure: Option<Error> = None;
sortable.sort_by(|left, right| {
for (at, key) in self.keys.iter().enumerate() {
let ordering = match rank(&left.0[at], &right.0[at], *key) {
Ok(ordering) => ordering,
Err(error) => {
failure.get_or_insert(error);
Ordering::Equal
}
};
if ordering != Ordering::Equal {
return ordering;
}
}
Ordering::Equal
});
if let Some(error) = failure {
return Err(error);
}
let ordered: Vec<Vec<Value>> = sortable.into_iter().map(|(_, row)| row).collect();
self.chunks = rows::chunks(&self.schema.types(), &ordered)?;
Ok(())
}
}
fn rank(left: &Value, right: &Value, key: SortKey) -> Result<Ordering> {
match (left.is_null(), right.is_null()) {
(true, true) => Ok(Ordering::Equal),
(true, false) => Ok(if key.nulls_first { Ordering::Less } else { Ordering::Greater }),
(false, true) => Ok(if key.nulls_first { Ordering::Greater } else { Ordering::Less }),
(false, false) => {
let ordering = rudb_kernels::order(left, right)?;
Ok(if key.descending { ordering.reverse() } else { ordering })
}
}
}
impl Operator for Sort<'_> {
fn schema(&self) -> &Schema {
&self.schema
}
fn next(&mut self) -> Result<Option<Chunk>> {
if !self.built {
self.build()?;
self.built = true;
}
if self.at >= self.chunks.len() {
return Ok(None);
}
let chunk = self.chunks[self.at].clone();
self.at += 1;
Ok(Some(chunk))
}
}