use rudb_common::Result;
use rudb_kernels::is_true;
use rudb_plan::{ExprRef, Plan, Slice};
use rudb_vector::{Chunk, Selection};
use crate::expr::{evaluate, evaluate_all};
use crate::operator::Operator;
use crate::schema::Schema;
#[derive(Debug)]
pub(crate) struct Filter<'a> {
input: Box<dyn Operator + 'a>,
plan: &'a Plan,
predicate: ExprRef,
schema: Schema,
}
impl<'a> Filter<'a> {
pub(crate) fn new(plan: &'a Plan, input: Box<dyn Operator + 'a>, predicate: ExprRef) -> Self {
let schema = input.schema().clone();
Self { input, plan, predicate, 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 flags = evaluate(self.plan, self.predicate, &self.schema, &chunk)?;
let mut kept = Selection::with_capacity(chunk.len());
for row in 0..chunk.len() {
if is_true(&flags.value_at(row)) {
kept.push(row);
}
}
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>,
plan: &'a Plan,
exprs: Vec<ExprRef>,
input_schema: Schema,
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();
Ok(Self { input, plan, exprs, input_schema, 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 columns = evaluate_all(self.plan, &self.exprs, &self.input_schema, &chunk)?;
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)?));
}
}
}