refactor get table info

main
Ziyang Hu 2 years ago
parent e0fb7c024a
commit 725d60f7da

@ -2,3 +2,4 @@ pub mod engine;
pub mod eval;
pub mod plan;
pub mod mutation;
pub mod table;

@ -33,7 +33,7 @@ pub trait Environment<'t, T: AsRef<[u8]>> where Self: Sized {
data.push_value(val);
self.define_data(name, data, in_root)
}
fn get_table_info(&self, id: i64, in_root: bool) -> Result<Option<Tuple<T>>>;
fn table_data(&self, id: i64, in_root: bool) -> Result<Option<Tuple<T>>>;
fn resolve(&self, name: &str) -> Result<Option<Tuple<T>>>;
fn resolve_related_tables(&self, name: &str) -> Result<Vec<(String, Tuple<SlicePtr>)>>;
fn resolve_param(&self, name: &str) -> Result<Value>;
@ -845,7 +845,7 @@ impl<'a, 't> Environment<'t, SlicePtr> for Session<'a, 't> {
self.params.insert(name.to_string(), val);
}
fn get_table_info(&self, id: i64, in_root: bool) -> Result<Option<Tuple<SlicePtr>>> {
fn table_data(&self, id: i64, in_root: bool) -> Result<Option<Tuple<SlicePtr>>> {
let mut key = Tuple::with_null_prefix();
key.push_bool(true);
key.push_int(id);

@ -5,13 +5,13 @@ use std::rc::Rc;
use pest::iterators::Pair;
use crate::db::engine::Session;
use crate::db::eval::Environment;
use crate::db::table::TableInfo;
use crate::error::CozoError::LogicError;
use crate::error::{CozoError, Result};
use crate::parser::Rule;
use crate::parser::text_identifier::build_name_in_def;
use crate::relation::data::DataKind;
use crate::relation::tuple::Tuple;
use crate::relation::typing::Typing;
use crate::relation::value::Value;
/// # key layouts
@ -33,7 +33,7 @@ use crate::relation::value::Value;
#[derive(Eq, PartialEq, Clone, Copy, Debug)]
enum MutationKind {
Upsert,
Insert
Insert,
}
impl<'a, 't> Session<'a, 't> {
@ -69,17 +69,12 @@ impl<'a, 't> Session<'a, 't> {
let mut mutation_manager = MutationManager::new(self, default_kind);
// Coercion
match kind {
MutationKind::Insert | MutationKind::Upsert => {
for item in expr {
let val_map = match item {
Value::Dict(d) => d,
_ => return Err(LogicError("Must be structs".to_string()))
};
mutation_manager.process_insert(kind == MutationKind::Insert, val_map)?;
}
}
_ => todo!()
for item in expr {
let val_map = match item {
Value::Dict(d) => d,
_ => return Err(LogicError("Must be structs".to_string()))
};
mutation_manager.process_insert(kind == MutationKind::Insert, val_map)?;
}
Ok(())
@ -88,135 +83,17 @@ impl<'a, 't> Session<'a, 't> {
struct MutationManager<'a, 'b, 't> {
sess: &'a Session<'b, 't>,
cache: RefCell<BTreeMap<String, Rc<KVCoercer>>>,
cache: RefCell<BTreeMap<String, Rc<TableInfo>>>,
default_tbl: Option<String>,
}
#[derive(Eq, PartialEq, Debug, Clone)]
struct KVCoercer {
kind: DataKind,
table_id: i64,
src_table_id: i64,
dst_table_id: i64,
in_root: bool,
data_keys: HashSet<String>,
key_typing: Vec<(String, Typing)>,
val_typing: Vec<(String, Typing)>,
src_key_typing: Vec<Typing>,
dst_key_typing: Vec<Typing>,
assocs: Vec<KVCoercer>,
}
impl<'a, 'b, 't> MutationManager<'a, 'b, 't> {
fn new(sess: &'a Session<'b, 't>, default_tbl: Option<String>) -> Self {
Self { sess, cache: RefCell::new(BTreeMap::new()), default_tbl }
}
fn get_table_info(&self, tbl_name: Cow<str>) -> Result<Rc<KVCoercer>> {
fn get_table_info(&self, tbl_name: Cow<str>) -> Result<Rc<TableInfo>> {
if !self.cache.borrow().contains_key(tbl_name.as_ref()) {
let coercer = match self.sess.resolve(&tbl_name)? {
None => return Err(CozoError::UndefinedType(tbl_name.to_string())),
Some(tpl) => {
let mut main_coercer = match tpl.data_kind()? {
DataKind::Node => {
let key_extractor = Typing::try_from(tpl.get_text(2)
.ok_or_else(|| CozoError::BadDataFormat(tpl.data.as_ref().to_vec()))?.as_ref())?
.extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?;
let val_extractor = Typing::try_from(tpl.get_text(3)
.ok_or_else(|| CozoError::BadDataFormat(tpl.data.as_ref().to_vec()))?.as_ref())?
.extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?;
let in_root = tpl.get_bool(0).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?;
let table_id = tpl.get_int(1).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?;
KVCoercer {
kind: DataKind::Node,
table_id,
in_root,
src_table_id: -1,
dst_table_id: -1,
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![],
assocs: vec![],
}
}
DataKind::Edge => {
let other_key_extractor = Typing::try_from(tpl.get_text(6)
.ok_or_else(|| CozoError::LogicError("Key extraction failed".to_string()))?.as_ref())?
.extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?;
let val_extractor = Typing::try_from(tpl.get_text(7)
.ok_or_else(|| CozoError::LogicError("Val extraction failed".to_string()))?.as_ref())?
.extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?;
let src_in_root = tpl.get_bool(2)
.ok_or_else(|| CozoError::LogicError("Src in root extraction failed".to_string()))?;
let src_id = tpl.get_int(3)
.ok_or_else(|| CozoError::LogicError("Src id extraction failed".to_string()))?;
let dst_in_root = tpl.get_bool(4)
.ok_or_else(|| CozoError::LogicError("Dst in root extraction failed".to_string()))?;
let dst_id = tpl.get_int(5)
.ok_or_else(|| CozoError::LogicError("Dst id extraction failed".to_string()))?;
let src = self.sess.get_table_info(src_id, src_in_root)?
.ok_or_else(|| CozoError::LogicError("Getting src failed".to_string()))?;
let src_key = Typing::try_from(src.get_text(2)
.ok_or_else(|| CozoError::BadDataFormat(tpl.data.as_ref().to_vec()))?.as_ref())?
.extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?;
let src_key_typing = src_key.into_iter().map(|(_, v)| v).collect();
let dst = self.sess.get_table_info(dst_id, dst_in_root)?
.ok_or_else(|| CozoError::LogicError("Getting dst failed".to_string()))?;
let dst_key = Typing::try_from(dst.get_text(2)
.ok_or_else(|| CozoError::BadDataFormat(tpl.data.as_ref().to_vec()))?.as_ref())?
.extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?;
let dst_key_typing = dst_key.into_iter().map(|(_, v)| v).collect();
let in_root = tpl.get_bool(0).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?;
let table_id = tpl.get_int(1).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?;
KVCoercer {
kind: DataKind::Edge,
table_id,
in_root,
src_table_id: src_id,
dst_table_id: dst_id,
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,
assocs: vec![],
}
}
_ => return Err(LogicError("Cannot insert into non-tables".to_string()))
};
let related = self.sess.resolve_related_tables(&tbl_name)?;
for (_n, d) in related {
let t = d.get_text(4)
.ok_or_else(|| CozoError::LogicError("Unable to extract typing from assoc".to_string()))?;
let t = Typing::try_from(t.as_ref())?
.extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?;
let in_root = d.get_bool(0).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?;
let table_id = d.get_int(1).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?;
let coercer = KVCoercer {
kind: DataKind::Assoc,
table_id,
in_root,
src_table_id: -1,
dst_table_id: -1,
data_keys: t.iter().map(|(k, _)| k.clone()).collect(),
key_typing: vec![],
val_typing: t,
src_key_typing: vec![],
dst_key_typing: vec![],
assocs: vec![],
};
main_coercer.assocs.push(coercer);
}
main_coercer
}
};
let coercer = self.sess.get_table_info(&tbl_name)?;
self.cache.borrow_mut().insert(tbl_name.as_ref().to_string(), Rc::new(coercer));
}
let cache = self.cache.borrow();
@ -330,7 +207,7 @@ impl<'a, 'b, 't> MutationManager<'a, 'b, 't> {
let existing_keys: HashSet<_> = val_map.iter().map(|(k, _)| k.to_string()).collect();
for assoc in &table_info.assocs {
for assoc in &table_info.associates {
if assoc.data_keys.is_subset(&existing_keys) {
let mut val_tuple = Tuple::with_data_prefix(DataKind::Data);
for (k, v) in &assoc.val_typing {

@ -33,4 +33,19 @@
// BaseRelation {
// relation: ()
// },
// }
// }
#[cfg(test)]
mod tests {
use super::*;
use crate::parser::{Parser, Rule};
use pest::Parser as PestParser;
#[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);
}
}

@ -0,0 +1,132 @@
use std::collections::HashSet;
use crate::db::engine::Session;
use crate::db::eval::Environment;
use crate::error::{CozoError, Result};
use crate::error::CozoError::LogicError;
use crate::relation::data::DataKind;
use crate::relation::typing::Typing;
#[derive(Eq, PartialEq, Debug, Clone)]
pub struct TableInfo {
pub kind: DataKind,
pub table_id: i64,
pub src_table_id: i64,
pub dst_table_id: i64,
pub in_root: bool,
pub data_keys: HashSet<String>,
pub key_typing: Vec<(String, Typing)>,
pub val_typing: Vec<(String, Typing)>,
pub src_key_typing: Vec<Typing>,
pub dst_key_typing: Vec<Typing>,
pub associates: Vec<TableInfo>,
}
impl<'a, 't> Session<'a, 't> {
pub fn get_table_info(&self, tbl_name: &str) -> Result<TableInfo> {
let table_info = match self.resolve(&tbl_name)? {
None => return Err(CozoError::UndefinedType(tbl_name.to_string())),
Some(tpl) => {
let mut main_coercer = match tpl.data_kind()? {
DataKind::Node => {
let key_extractor = Typing::try_from(tpl.get_text(2)
.ok_or_else(|| CozoError::BadDataFormat(tpl.data.as_ref().to_vec()))?.as_ref())?
.extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?;
let val_extractor = Typing::try_from(tpl.get_text(3)
.ok_or_else(|| CozoError::BadDataFormat(tpl.data.as_ref().to_vec()))?.as_ref())?
.extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?;
let in_root = tpl.get_bool(0).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?;
let table_id = tpl.get_int(1).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?;
TableInfo {
kind: DataKind::Node,
table_id,
in_root,
src_table_id: -1,
dst_table_id: -1,
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![],
}
}
DataKind::Edge => {
let other_key_extractor = Typing::try_from(tpl.get_text(6)
.ok_or_else(|| CozoError::LogicError("Key extraction failed".to_string()))?.as_ref())?
.extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?;
let val_extractor = Typing::try_from(tpl.get_text(7)
.ok_or_else(|| CozoError::LogicError("Val extraction failed".to_string()))?.as_ref())?
.extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?;
let src_in_root = tpl.get_bool(2)
.ok_or_else(|| CozoError::LogicError("Src in root extraction failed".to_string()))?;
let src_id = tpl.get_int(3)
.ok_or_else(|| CozoError::LogicError("Src id extraction failed".to_string()))?;
let dst_in_root = tpl.get_bool(4)
.ok_or_else(|| CozoError::LogicError("Dst in root extraction failed".to_string()))?;
let dst_id = tpl.get_int(5)
.ok_or_else(|| CozoError::LogicError("Dst id extraction failed".to_string()))?;
let src = self.table_data(src_id, src_in_root)?
.ok_or_else(|| CozoError::LogicError("Getting src failed".to_string()))?;
let src_key = Typing::try_from(src.get_text(2)
.ok_or_else(|| CozoError::BadDataFormat(tpl.data.as_ref().to_vec()))?.as_ref())?
.extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?;
let src_key_typing = src_key.into_iter().map(|(_, v)| v).collect();
let dst = self.table_data(dst_id, dst_in_root)?
.ok_or_else(|| CozoError::LogicError("Getting dst failed".to_string()))?;
let dst_key = Typing::try_from(dst.get_text(2)
.ok_or_else(|| CozoError::BadDataFormat(tpl.data.as_ref().to_vec()))?.as_ref())?
.extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?;
let dst_key_typing = dst_key.into_iter().map(|(_, v)| v).collect();
let in_root = tpl.get_bool(0).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?;
let table_id = tpl.get_int(1).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?;
TableInfo {
kind: DataKind::Edge,
table_id,
in_root,
src_table_id: src_id,
dst_table_id: dst_id,
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![],
}
}
_ => return Err(LogicError("Cannot insert into non-tables".to_string()))
};
let related = self.resolve_related_tables(&tbl_name)?;
for (_n, d) in related {
let t = d.get_text(4)
.ok_or_else(|| CozoError::LogicError("Unable to extract typing from assoc".to_string()))?;
let t = Typing::try_from(t.as_ref())?
.extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?;
let in_root = d.get_bool(0).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?;
let table_id = d.get_int(1).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?;
let coercer = TableInfo {
kind: DataKind::Assoc,
table_id,
in_root,
src_table_id: -1,
dst_table_id: -1,
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![],
};
main_coercer.associates.push(coercer);
}
main_coercer
}
};
Ok(table_info)
}
}

@ -165,4 +165,18 @@ mutation_filter = { (exclude|include) ~ name_in_def ~ ("," ~ name_in_def)* }
exclude = {"exclude"}
include = {"include"}
upsert = {"upsert"}
insert = {"insert"}
insert = {"insert"}
from_pattern = { "from" ~ (from_el ~ ",")* ~ from_el }
from_el = { simple_from_pattern | node_edge_pattern }
simple_from_pattern = { ident ~ ":" ~ name_in_def }
node_edge_pattern = { node_pattern? ~ (edge_pattern ~ node_pattern)* ~ edge_pattern? }
node_pattern = {"(" ~ ident? ~ ":" ~ name_in_def ~ ")"}
edge_pattern = _{ fwd_edge_pattern | bwd_edge_pattern }
fwd_edge_pattern = { "-" ~ edge_pattern_inner ~ "->" }
bwd_edge_pattern = { "<-" ~ edge_pattern_inner ~ "-" }
edge_pattern_inner = _{"[" ~ ident? ~ ":" ~ name_in_def ~ "]"}
where_pattern = { "where" ~ (expr ~ ",")* ~ expr }
Loading…
Cancel
Save