parsing from chain

main
Ziyang Hu 2 years ago
parent 725d60f7da
commit 0611430262

@ -35,17 +35,178 @@
// },
// }
use pest::iterators::Pair;
use crate::db::engine::Session;
use crate::db::table::TableInfo;
use crate::error::CozoError::LogicError;
use crate::parser::Rule;
use crate::error::Result;
use crate::parser::text_identifier::build_name_in_def;
use crate::relation::data::DataKind;
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum FromEl {
Simple(Box<SimpleFromEl>),
Chain(Vec<EdgeOrNodeEl>),
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct SimpleFromEl {
pub table: String,
pub binding: String,
pub info: TableInfo,
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum EdgeOrNodeKind {
FwdEdge,
BwdEdge,
Node,
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct EdgeOrNodeEl {
pub table: String,
pub binding: Option<String>,
pub info: TableInfo,
pub kind: EdgeOrNodeKind,
}
impl<'a, 't> Session<'a, 't> {
pub fn parse_from_pattern(&self, pair: Pair<Rule>) -> Result<()> {
let res: Result<Vec<_>> = pair.into_inner().map(|p| {
match p.as_rule() {
Rule::simple_from_pattern => self.parse_simple_from_pattern(p),
Rule::node_edge_pattern => self.parse_node_edge_pattern(p),
_ => unreachable!()
}
}).collect();
Ok(())
}
fn parse_simple_from_pattern(&self, pair: Pair<Rule>) -> Result<()> {
let mut pairs = pair.into_inner();
let name = pairs.next().unwrap().as_str();
if name.starts_with('_') {
return Err(LogicError("Pattern binding cannot start with underscore".to_string()));
}
let table_name = build_name_in_def(pairs.next().unwrap(), true)?;
let table_info = self.get_table_info(&table_name)?;
let ret = FromEl::Simple(Box::new(SimpleFromEl { binding: name.to_string(), table: table_name, info: table_info }));
println!("{:#?}", ret);
Ok(())
}
fn parse_node_edge_pattern(&self, pair: Pair<Rule>) -> Result<()> {
let res: Result<Vec<_>> = pair.into_inner().map(|p| {
match p.as_rule() {
Rule::node_pattern => self.parse_node_pattern(p),
Rule::fwd_edge_pattern => self.parse_edge_pattern(p, true),
Rule::bwd_edge_pattern => self.parse_edge_pattern(p, false),
_ => unreachable!()
}
}).collect();
// TODO check the chain connects!
println!("{:#?}", res);
Ok(())
}
fn parse_node_pattern(&self, pair: Pair<Rule>) -> Result<EdgeOrNodeEl> {
let (table, binding, info) = self.parse_node_or_edge(pair)?;
if info.kind != DataKind::Node {
return Err(LogicError(format!("{} is not a node", table)));
}
Ok(EdgeOrNodeEl {
table,
binding,
info,
kind: EdgeOrNodeKind::Node,
})
}
fn parse_edge_pattern(&self, pair: Pair<Rule>, is_fwd: bool) -> Result<EdgeOrNodeEl> {
let (table, binding, info) = self.parse_node_or_edge(pair)?;
if info.kind != DataKind::Edge {
return Err(LogicError(format!("{} is not an edge", table)));
}
Ok(EdgeOrNodeEl {
table,
binding,
info,
kind: if is_fwd { EdgeOrNodeKind::FwdEdge } else { EdgeOrNodeKind::BwdEdge },
})
}
fn parse_node_or_edge(&self, pair: Pair<Rule>) -> Result<(String, Option<String>, TableInfo)> {
let name;
let mut pairs = pair.into_inner();
let mut cur_pair = pairs.next().unwrap();
if cur_pair.as_rule() == Rule::ident {
name = Some(cur_pair.as_str());
cur_pair = pairs.next().unwrap();
} else {
name = None;
}
let table_name = build_name_in_def(cur_pair, true)?;
let table_info = self.get_table_info(&table_name)?;
// println!("{:?}, {}, {:?}", name, table_name, table_info);
Ok((table_name, name.map(|v| v.to_string()), table_info))
}
}
#[cfg(test)]
mod tests {
use std::fs;
use super::*;
use crate::parser::{Parser, Rule};
use pest::Parser as PestParser;
use crate::db::engine::Engine;
use crate::db::eval::Environment;
#[test]
fn parse_patterns() {
let s = "from a:Friend, (b:Person)-[:Friend]->(c:Person), x:GGG";
let parsed = Parser::parse(Rule::from_pattern, s).unwrap().next().unwrap();
assert_eq!(parsed.as_rule(), Rule::from_pattern);
println!("{:#?}", parsed);
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 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 = "from a:Friend, (b:Person)-[:Friend]->(c:Person), x:Person";
let parsed = Parser::parse(Rule::from_pattern, s).unwrap().next().unwrap();
assert_eq!(parsed.as_rule(), Rule::from_pattern);
sess.parse_from_pattern(parsed);
}
drop(engine);
let _ = fs::remove_dir_all(db_path);
}
}

@ -12,6 +12,8 @@ pub struct TableInfo {
pub table_id: i64,
pub src_table_id: i64,
pub dst_table_id: i64,
pub src_in_root: bool,
pub dst_in_root: bool,
pub in_root: bool,
pub data_keys: HashSet<String>,
pub key_typing: Vec<(String, Typing)>,
@ -43,12 +45,14 @@ impl<'a, 't> Session<'a, 't> {
in_root,
src_table_id: -1,
dst_table_id: -1,
src_in_root: false,
data_keys: val_extractor.iter().map(|(k, _)| k.clone()).collect(),
key_typing: key_extractor,
val_typing: val_extractor,
src_key_typing: vec![],
dst_key_typing: vec![],
associates: vec![],
dst_in_root: false
}
}
DataKind::Edge => {
@ -89,12 +93,14 @@ impl<'a, 't> Session<'a, 't> {
in_root,
src_table_id: src_id,
dst_table_id: dst_id,
src_in_root,
data_keys: val_extractor.iter().map(|(k, _)| k.clone()).collect(),
key_typing: other_key_extractor,
val_typing: val_extractor,
src_key_typing,
dst_key_typing,
associates: vec![],
dst_in_root
}
}
_ => return Err(LogicError("Cannot insert into non-tables".to_string()))
@ -114,12 +120,14 @@ impl<'a, 't> Session<'a, 't> {
in_root,
src_table_id: -1,
dst_table_id: -1,
src_in_root: false,
data_keys: t.iter().map(|(k, _)| k.clone()).collect(),
key_typing: vec![],
val_typing: t,
src_key_typing: vec![],
dst_key_typing: vec![],
associates: vec![],
dst_in_root: false
};
main_coercer.associates.push(coercer);

@ -168,7 +168,7 @@ upsert = {"upsert"}
insert = {"insert"}
from_pattern = { "from" ~ (from_el ~ ",")* ~ from_el }
from_el = { simple_from_pattern | node_edge_pattern }
from_el = _{ simple_from_pattern | node_edge_pattern }
simple_from_pattern = { ident ~ ":" ~ name_in_def }

Loading…
Cancel
Save