use rudb_common::Result;
use rudb_plan::{ExprRef, Plan, Slice};
use rudb_vector::{Chunk, Selection};
use crate::operator::Operator;
use crate::prepared::{Prepared, Scratch};
use crate::schema::Schema;
#[derive(Debug)]
pub(crate) struct Filter<'a> {
input: Box<dyn Operator + 'a>,
predicate: Prepared,
scratch: Scratch,
schema: Schema,
}
impl<'a> Filter<'a> {
pub(crate) fn new(
plan: &'a Plan,
input: Box<dyn Operator + 'a>,
predicate: ExprRef,
) -> Result<Self> {
let schema = input.schema().clone();
let predicate = Prepared::one(plan, predicate, &schema)?;
let scratch = predicate.scratch();
Ok(Self { input, predicate, scratch, schema })
}
}
impl Operator for Filter<'_> {
fn schema(&self) -> &Schema {
&self.schema
}
fn next(&mut self) -> Result<Option<Chunk>> {
while let Some(chunk) = self.input.next()? {
let kept = self.predicate.evaluate_filter(&chunk, &mut self.scratch)?;
if kept.is_empty() {
continue;
}
if kept.len() == chunk.len() {
return Ok(Some(chunk));
}
return Ok(Some(chunk.select(&kept)?));
}
Ok(None)
}
}
#[derive(Debug)]
pub(crate) struct Project<'a> {
input: Box<dyn Operator + 'a>,
exprs: Prepared,
scratch: Scratch,
schema: Schema,
}
impl<'a> Project<'a> {
pub(crate) fn new(
plan: &'a Plan,
input: Box<dyn Operator + 'a>,
index: u32,
exprs: Slice,
names: Slice,
) -> Result<Self> {
let exprs: Vec<ExprRef> = plan.expr_list(exprs).to_vec();
let names = plan.name_list(names);
if names.len() != exprs.len() {
return Err(rudb_common::Error::internal(format!(
"a projection of {} expressions under {} names",
exprs.len(),
names.len()
)));
}
let fields = exprs
.iter()
.zip(names)
.map(|(&expr, &name)| {
rudb_common::Field::new(plan.string(name), plan.expr_type(expr).clone())
})
.collect();
let input_schema = input.schema().clone();
let exprs = Prepared::new(plan, &exprs, &input_schema)?;
let scratch = exprs.scratch();
Ok(Self { input, exprs, scratch, schema: Schema::numbered(fields, index) })
}
}
impl Operator for Project<'_> {
fn schema(&self) -> &Schema {
&self.schema
}
fn next(&mut self) -> Result<Option<Chunk>> {
let Some(chunk) = self.input.next()? else {
return Ok(None);
};
let mut columns = Vec::with_capacity(self.exprs.len());
self.exprs.evaluate(&chunk, &mut self.scratch, &mut columns)?;
Ok(Some(Chunk::with_rows(columns, chunk.len())?))
}
}
#[derive(Debug)]
pub(crate) struct Limit<'a> {
input: Box<dyn Operator + 'a>,
schema: Schema,
count: Option<u64>,
offset: u64,
skipped: u64,
emitted: u64,
}
impl<'a> Limit<'a> {
pub(crate) fn new(input: Box<dyn Operator + 'a>, count: Option<u64>, offset: u64) -> Self {
let schema = input.schema().clone();
Self { input, schema, count, offset, skipped: 0, emitted: 0 }
}
fn room(&self) -> Option<u64> {
self.count.map(|count| count.saturating_sub(self.emitted))
}
}
impl Operator for Limit<'_> {
fn schema(&self) -> &Schema {
&self.schema
}
fn next(&mut self) -> Result<Option<Chunk>> {
loop {
if self.room() == Some(0) {
return Ok(None);
}
let Some(chunk) = self.input.next()? else {
return Ok(None);
};
let rows = chunk.len() as u64;
let skipping = (self.offset - self.skipped).min(rows);
self.skipped += skipping;
let available = rows - skipping;
if available == 0 {
continue;
}
let taking = match self.room() {
Some(room) => room.min(available),
None => available,
};
self.emitted += taking;
if skipping == 0 && taking == rows {
return Ok(Some(chunk));
}
let mut kept = Selection::with_capacity(taking as usize);
for row in skipping..skipping + taking {
kept.push(row as usize);
}
return Ok(Some(chunk.select(&kept)?));
}
}
}