use super::data::*;
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct Schema {
pub columns: Vec<Field>
}
impl Schema {
pub fn empty() -> Self { Schema { columns: vec![] } }
pub fn new(columns: Vec<Field>) -> Self { Schema { columns: columns } }
pub fn column(&self, name: &str) -> Option<(usize, &Field)> {
self.columns.iter()
.enumerate()
.find(|&(_,c)| c.name == name)
}
pub fn to_string(&self) -> String {
let s : Vec<String> = self.columns.iter()
.map(|c| c.to_string())
.collect();
s.join(",")
}
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub struct FunctionMeta {
pub name: String,
pub args: Vec<Field>,
pub return_type: DataType
}
pub trait Row {
fn get(&self, index: usize) -> &Value;
fn to_string(&self) -> String;
}
impl Row for Vec<Value> {
fn get(&self, index: usize) -> &Value {
&self[index]
}
fn to_string(&self) -> String {
let value_strings : Vec<String> = self.iter()
.map(|v| v.to_string())
.collect();
value_strings.join(",")
}
}
#[derive(Debug,Clone,Serialize,Deserialize)]
pub enum Operator {
Eq,
NotEq,
Lt,
LtEq,
Gt,
GtEq,
Plus,
Minus,
Multiply,
Divide,
Modulus
}
#[derive(Debug,Clone,Serialize, Deserialize)]
pub enum Expr {
Column(usize),
Literal(Value),
BinaryExpr { left: Box<Expr>, op: Operator, right: Box<Expr> },
Sort { expr: Box<Expr>, asc: bool },
ScalarFunction { name: String, args: Vec<Expr> }
}
impl Expr {
pub fn eq(&self, other: &Expr) -> Expr {
Expr::BinaryExpr {
left: Box::new(self.clone()),
op: Operator::Eq,
right: Box::new(other.clone())
}
}
pub fn gt(&self, other: &Expr) -> Expr {
Expr::BinaryExpr {
left: Box::new(self.clone()),
op: Operator::Gt,
right: Box::new(other.clone())
}
}
pub fn lt(&self, other: &Expr) -> Expr {
Expr::BinaryExpr {
left: Box::new(self.clone()),
op: Operator::Lt,
right: Box::new(other.clone())
}
}
}
#[derive(Debug,Clone,Serialize, Deserialize)]
pub enum LogicalPlan {
Limit { limit: usize, input: Box<LogicalPlan>, schema: Schema },
Projection { expr: Vec<Expr>, input: Box<LogicalPlan>, schema: Schema },
Selection { expr: Expr, input: Box<LogicalPlan>, schema: Schema },
Sort { expr: Vec<Expr>, input: Box<LogicalPlan>, schema: Schema },
TableScan { schema_name: String, table_name: String, schema: Schema },
CsvFile { filename: String, schema: Schema },
EmptyRelation
}
impl LogicalPlan {
pub fn schema(&self) -> Schema {
match self {
&LogicalPlan::EmptyRelation => Schema::empty(),
&LogicalPlan::TableScan { ref schema, .. } => schema.clone(),
&LogicalPlan::CsvFile { ref schema, .. } => schema.clone(),
&LogicalPlan::Projection { ref schema, .. } => schema.clone(),
&LogicalPlan::Selection { ref schema, .. } => schema.clone(),
&LogicalPlan::Sort { ref schema, .. } => schema.clone(),
&LogicalPlan::Limit { ref schema, .. } => schema.clone(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use super::LogicalPlan::*;
use super::Expr::*;
use super::Value::*;
extern crate serde_json;
#[test]
fn serde() {
let schema = Schema {
columns: vec![
Field { name: "id".to_string(), data_type: DataType::UnsignedLong, nullable: false },
Field { name: "name".to_string(), data_type: DataType::String, nullable: false }
]
};
let csv = CsvFile { filename: "test/data/people.csv".to_string(), schema: schema.clone() };
let filter_expr = BinaryExpr {
left: Box::new(Column(0)),
op: Operator::Eq,
right: Box::new(Literal(Long(2)))
};
let plan = Selection {
expr: filter_expr,
input: Box::new(csv),
schema: schema.clone()
};
let s = serde_json::to_string(&plan).unwrap();
println!("serialized: {}", s);
}
}