use super::eval::eval_expr;
use super::node::PlanNode;
use super::types::{ColumnMeta, Row, Schema};
use crate::sql::ast::Expr;
use sochdb_core::Result;
pub struct ProjectExpr {
pub expr: Expr,
pub alias: String,
}
pub struct ProjectNode {
input: Box<dyn PlanNode>,
exprs: Vec<ProjectExpr>,
output_schema: Schema,
}
impl ProjectNode {
pub fn new(input: Box<dyn PlanNode>, exprs: Vec<ProjectExpr>) -> Self {
let output_schema = Schema::new(
exprs
.iter()
.map(|e| ColumnMeta::new(e.alias.clone()))
.collect(),
);
Self {
input,
exprs,
output_schema,
}
}
pub fn columns(input: Box<dyn PlanNode>, columns: Vec<String>) -> Self {
let input_schema = input.schema().clone();
let exprs: Vec<ProjectExpr> = columns
.iter()
.map(|c| ProjectExpr {
expr: Expr::Column(crate::sql::ast::ColumnRef::new(c.clone())),
alias: c.clone(),
})
.collect();
let output_schema = Schema::new(
columns
.iter()
.map(|c| {
input_schema
.columns
.iter()
.find(|cm| cm.name == *c)
.cloned()
.unwrap_or_else(|| ColumnMeta::new(c.clone()))
})
.collect(),
);
Self {
input,
exprs,
output_schema,
}
}
}
impl PlanNode for ProjectNode {
fn schema(&self) -> &Schema {
&self.output_schema
}
fn next(&mut self) -> Result<Option<Row>> {
match self.input.next()? {
Some(row) => {
let input_schema = self.input.schema();
let mut output = Vec::with_capacity(self.exprs.len());
for pe in &self.exprs {
let val = eval_expr(&pe.expr, &row, input_schema)?;
output.push(val);
}
Ok(Some(output))
}
None => Ok(None),
}
}
fn reset(&mut self) -> Result<()> {
self.input.reset()
}
}
pub struct PassThroughNode {
input: Box<dyn PlanNode>,
}
impl PassThroughNode {
pub fn new(input: Box<dyn PlanNode>) -> Self {
Self { input }
}
}
impl PlanNode for PassThroughNode {
fn schema(&self) -> &Schema {
self.input.schema()
}
fn next(&mut self) -> Result<Option<Row>> {
self.input.next()
}
fn reset(&mut self) -> Result<()> {
self.input.reset()
}
}