simplest query tree construction

main
Ziyang Hu 2 years ago
parent 419c4c3328
commit 5f3d2442a1

@ -1,38 +1,164 @@
// struct Filter;
//
// enum QueryPlan {
// Union {
// args: Vec<QueryPlan>
// },
// Intersection {
// args: Vec<QueryPlan>
// },
// Difference {
// left: Box<QueryPlan>,
// right: Box<QueryPlan>,
// },
// Selection {
// arg: Box<QueryPlan>,
// filter: (),
// },
// Projection {
// arg: Box<QueryPlan>,
// keys: (),
// fields: (),
// },
// Product {
// args: Vec<QueryPlan>
// },
// Join {
// args: Vec<QueryPlan>
// },
// LeftJoin {
// left: Box<QueryPlan>,
// right: Box<QueryPlan>
// },
// BaseRelation {
// relation: ()
// },
// }
use std::collections::BTreeMap;
use pest::iterators::Pair;
use crate::db::engine::Session;
use crate::db::query::{FromEl, Selection};
use crate::db::table::TableInfo;
use crate::relation::value::{StaticValue, Value};
use crate::parser::Rule;
use crate::error::Result;
#[derive(Clone, Eq, PartialEq, Debug)]
pub enum QueryPlan {
Union {
args: Vec<QueryPlan>
},
Intersection {
args: Vec<QueryPlan>
},
Difference {
left: Box<QueryPlan>,
right: Box<QueryPlan>,
},
Projection {
arg: Box<QueryPlan>,
projection: Selection,
},
Grouping {
arg: Box<QueryPlan>,
projection: Selection,
},
InnerJoinGroup {
args: Vec<QueryPlan>,
},
InnerJoin {
left: Box<QueryPlan>,
right: Box<QueryPlan>,
left_key: Vec<String>,
right_key: Vec<String>,
},
OuterJoin {
join_type: OuterJoinType,
left: Box<QueryPlan>,
right: Box<QueryPlan>,
left_key: Vec<String>,
right_key: Vec<String>,
},
Filter {
rel: Box<QueryPlan>,
filter: StaticValue,
},
BaseRelation {
table: String,
binding: String,
info: TableInfo,
},
}
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub enum OuterJoinType {
LeftJoin,
RightJoin,
FullOuterJoin,
}
impl<'a> Session<'a> {
pub fn query_to_plan(&self, pair: Pair<Rule>) -> Result<()> {
let mut pairs = pair.into_inner();
let from_data = self.parse_from_pattern(pairs.next().unwrap())?;
let mut nxt = pairs.next().unwrap();
let where_data = match nxt.as_rule() {
Rule::where_pattern => {
let r = self.parse_where_pattern(nxt)?.to_static();
nxt = pairs.next().unwrap();
r
}
_ => true.into()
};
let select_data = self.parse_select_pattern(nxt)?;
let plan = self.convert_from_data_to_plan(from_data)?;
let plan = self.convert_where_data_to_plan(plan, where_data)?;
let plan = self.convert_select_data_to_plan(plan, select_data)?;
println!("{:#?}", plan);
Ok(())
}
fn convert_from_data_to_plan(&self, mut from_data: Vec<FromEl>) -> Result<QueryPlan> {
let res = match from_data.pop().unwrap() {
FromEl::Simple(el) => {
QueryPlan::BaseRelation {
table: el.table,
binding: el.binding,
info: el.info,
}
}
FromEl::Chain(_) => todo!()
};
Ok(res)
}
fn convert_where_data_to_plan(&self, plan: QueryPlan, where_data: StaticValue) -> Result<QueryPlan> {
let where_data = self.partial_eval(where_data, &Default::default(), &Default::default());
let plan = match where_data?.1 {
Value::Bool(true) => plan,
v => {
QueryPlan::Filter { rel: Box::new(plan), filter: v }
}
};
Ok(plan)
}
fn convert_select_data_to_plan(&self, plan: QueryPlan, select_data: Selection) -> Result<QueryPlan> {
Ok(QueryPlan::Projection { arg: Box::new(plan), projection: select_data })
}
}
#[cfg(test)]
mod tests {
use std::fs;
use crate::db::engine::Engine;
use crate::parser::{Parser, Rule};
use pest::Parser as PestParser;
#[test]
fn plan() {
let db_path = "_test_db_plan";
let engine = Engine::new(db_path.to_string(), true).unwrap();
{
let mut sess = engine.session().unwrap();
let s = r#"
create node "Person" {
*id: Int,
name: Text,
email: ?Text,
habits: ?[?Text]
}
create edge (Person)-[Friend]->(Person) {
relation: ?Text
}
create node Z {
*id: Text
}
create assoc WorkInfo : Person {
work_id: Int
}
create assoc RelationshipData: Person {
status: Text
}
"#;
for p in Parser::parse(Rule::file, s).unwrap() {
if p.as_rule() == Rule::EOI {
break;
}
sess.run_definition(p).unwrap();
}
sess.commit().unwrap();
let s = r#"from p:Person select p {id, name}"#;
let parsed = Parser::parse(Rule::relational_query, s).unwrap().next().unwrap();
let plan = sess.query_to_plan(parsed).unwrap();
}
drop(engine);
let _ = fs::remove_dir_all(db_path);
}
}

@ -8,7 +8,7 @@ use crate::error::{CozoError, Result};
use crate::parser::text_identifier::{build_name_in_def, parse_string};
use crate::relation::data::DataKind;
use crate::relation::value;
use crate::relation::value::{build_expr_primary, METHOD_MERGE, Value};
use crate::relation::value::{build_expr_primary, METHOD_MERGE, StaticValue, Value};
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum FromEl {
@ -173,7 +173,7 @@ impl<'a> Session<'a> {
Ok(Value::Apply(value::OP_AND.into(), conditions).to_static())
}
pub fn parse_select_pattern<'i>(&self, pair: Pair<'i, Rule>) -> Result<Selection<'i>> {
pub fn parse_select_pattern(&self, pair: Pair<Rule>) -> Result<Selection> {
let mut pairs = pair.into_inner();
let mut nxt = pairs.next().unwrap();
let scoped = match nxt.as_rule() {
@ -196,7 +196,7 @@ impl<'a> Session<'a> {
let mut pp = p.into_inner();
let id = parse_string(pp.next().unwrap())?;
let val = Value::from_pair(pp.next().unwrap())?;
keys.insert(id, val);
keys.insert(id, val.to_static());
}
Rule::dict_pair => {
let mut inner = p.into_inner();
@ -228,12 +228,12 @@ impl<'a> Session<'a> {
}
let vals = if merged.is_empty() {
Value::Dict(collected_vals)
Value::Dict(collected_vals).to_static()
} else {
if !collected_vals.is_empty() {
merged.push(Value::Dict(collected_vals));
}
Value::Apply(METHOD_MERGE.into(), merged)
Value::Apply(METHOD_MERGE.into(), merged).to_static()
};
let mut ordering = vec![];
@ -276,10 +276,10 @@ impl<'a> Session<'a> {
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct Selection<'a> {
pub struct Selection {
pub scoped: Option<String>,
pub keys: BTreeMap<String, Value<'a>>,
pub vals: Value<'a>,
pub keys: BTreeMap<String, StaticValue>,
pub vals: StaticValue,
pub ordering: Vec<(bool, String)>,
pub limit: Option<i64>,
pub offset: Option<i64>
@ -295,7 +295,7 @@ mod tests {
#[test]
fn parse_patterns() {
let db_path = "_test_db_plan";
let db_path = "_test_db_query";
let engine = Engine::new(db_path.to_string(), true).unwrap();
{
let mut sess = engine.session().unwrap();

Loading…
Cancel
Save