use rudb_catalog::{Catalog, QualifiedName};
use rudb_common::{Cancel, Memory, Result};
use rudb_functions::TableFunction;
use rudb_plan::{Node, NodeRef, Plan};
use crate::adapt::{Broken, Streamed};
use crate::cancel::Guarded;
use crate::group::{Aggregate, Distinct};
use crate::join::{CrossProduct, Join};
use crate::operator::Operator;
use crate::setop::SetOp;
use crate::sort::Sort;
use crate::source::{Dummy, FileScan, Scan, Series, Values};
use crate::strategies::Strategies;
use crate::stream::{Filter, Limit, Project};
use crate::topn::TopN;
pub fn build<'a>(plan: &'a Plan, catalog: &'a Catalog) -> Result<Box<dyn Operator + 'a>> {
build_with(plan, catalog, &Cancel::new(), &Memory::unlimited())
}
pub fn build_with<'a>(
plan: &'a Plan,
catalog: &'a Catalog,
cancel: &Cancel,
memory: &Memory,
) -> Result<Box<dyn Operator + 'a>> {
node(plan, catalog, cancel, memory, plan.root())
}
fn node<'a>(
plan: &'a Plan,
catalog: &'a Catalog,
cancel: &Cancel,
memory: &Memory,
reference: NodeRef,
) -> Result<Box<dyn Operator + 'a>> {
let inner: Box<dyn Operator + 'a> = match *plan.node(reference) {
Node::Get { catalog: database, schema, table, index, columns, .. } => {
let name =
QualifiedName::new(plan.string(database), plan.string(schema), plan.string(table));
Box::new(Scan::new(plan, catalog.table(&name)?, index, columns)?)
}
Node::Dummy => Box::new(Dummy::new()),
Node::Values { index, columns, rows } => Box::new(Values::new(plan, index, columns, rows)?),
Node::TableFunction { index, function, args, options, settings, columns } => {
match TableFunction::lookup(plan.string(function)) {
Some(function @ (TableFunction::ReadParquet | TableFunction::ReadCsv)) => Box::new(
FileScan::new(plan, index, function, args, options, settings, columns)?,
),
Some(TableFunction::RudbStrategies) => {
Box::new(Strategies::new(plan, index, columns)?)
}
_ => Box::new(Series::new(plan, index, plan.string(function), args)?),
}
}
Node::Filter { input, predicate } => {
let input = node(plan, catalog, cancel, memory, input)?;
let schema = input.schema().clone();
let filter = Filter::new(plan, predicate, &schema)?;
Box::new(Streamed::new(input, filter, schema))
}
Node::Project { input, index, exprs, names } => {
let input = node(plan, catalog, cancel, memory, input)?;
let project = Project::new(plan, input.schema(), index, exprs, names)?;
let schema = project.schema().clone();
Box::new(Streamed::new(input, project, schema))
}
Node::Aggregate { input, index, groups, aggregates } => Box::new(Aggregate::new(
plan,
node(plan, catalog, cancel, memory, input)?,
index,
groups,
aggregates,
memory,
)?),
Node::Sort { input, keys } => {
let input = node(plan, catalog, cancel, memory, input)?;
let schema = input.schema().clone();
let (sort, out) = Sort::new(plan, &schema, keys, memory)?;
Box::new(Broken::new(input, sort, out, schema))
}
Node::Limit { input, count, offset } => {
let input = node(plan, catalog, cancel, memory, input)?;
let schema = input.schema().clone();
Box::new(Streamed::new(input, Limit::new(count, offset), schema))
}
Node::TopN { input, keys, count, offset } => {
let input = node(plan, catalog, cancel, memory, input)?;
let schema = input.schema().clone();
let (top, out) = TopN::new(plan, &schema, keys, count, offset, memory)?;
Box::new(Broken::new(input, top, out, schema))
}
Node::Distinct { input, on } => {
Box::new(Distinct::new(plan, node(plan, catalog, cancel, memory, input)?, on, memory))
}
Node::Join { left, right, kind, conditions } => Box::new(Join::new(
plan,
node(plan, catalog, cancel, memory, left)?,
node(plan, catalog, cancel, memory, right)?,
kind,
conditions,
cancel,
memory,
)),
Node::CrossProduct { left, right } => Box::new(CrossProduct::new(
node(plan, catalog, cancel, memory, left)?,
node(plan, catalog, cancel, memory, right)?,
memory,
)),
Node::SetOp { left, right, kind, all, index } => Box::new(SetOp::new(
node(plan, catalog, cancel, memory, left)?,
node(plan, catalog, cancel, memory, right)?,
kind,
all,
index,
memory,
)),
};
Ok(Box::new(Guarded::new(inner, cancel.clone())))
}