From e9bea3f9c927b032cc05f6b14a92e7a63b4dcd63 Mon Sep 17 00:00:00 2001 From: Ziyang Hu Date: Sat, 30 Apr 2022 19:17:42 +0800 Subject: [PATCH] collection of table coercion info --- src/db/mutation.rs | 144 ++++++++++++++++++++++++++++++++--------- src/relation/typing.rs | 10 ++- 2 files changed, 120 insertions(+), 34 deletions(-) diff --git a/src/db/mutation.rs b/src/db/mutation.rs index 633a3ebb..40b9f4a5 100644 --- a/src/db/mutation.rs +++ b/src/db/mutation.rs @@ -1,5 +1,5 @@ use std::borrow::Cow; -use std::collections::{BTreeMap}; +use std::collections::{BTreeMap, HashSet}; use pest::iterators::Pair; use crate::db::engine::Session; use crate::db::eval::Environment; @@ -63,49 +63,129 @@ impl<'a, 't> Session<'a, 't> { struct MutationManager<'a, 'b, 't> { sess: &'a Session<'b, 't>, - cache: BTreeMap, + cache: BTreeMap>, default_tbl: Option, } +#[derive(Eq, PartialEq, Debug, Clone)] +struct KVCoercer { + table_id: i64, + in_root: bool, + data_keys: HashSet, + key_typing: Vec<(String, Typing)>, + val_typing: Vec<(String, Typing)>, + src_key_typing: Vec, + dst_key_typing: Vec, +} + impl<'a, 'b, 't> MutationManager<'a, 'b, 't> { fn new(sess: &'a Session<'b, 't>, default_tbl: Option) -> Self { Self { sess, cache: BTreeMap::new(), default_tbl } } - fn get_table_info(&mut self, tbl_name: Cow) -> Result<()> { - match self.cache.get(tbl_name.as_ref()) { - None => { - match self.sess.resolve(&tbl_name)? { - None => return Err(CozoError::UndefinedType(tbl_name.to_string())), - Some(tpl) => { - println!("Found tuple {:?}", tpl); - 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())?; - let val_extractor = Typing::try_from(tpl.get_text(2) - .ok_or_else(|| CozoError::BadDataFormat(tpl.data.as_ref().to_vec()))?.as_ref())?; - println!("Found node {:?}, {:?}", key_extractor, val_extractor); - } - DataKind::Edge => { - let other_key_extractor = Typing::try_from(tpl.get_text(6) - .ok_or_else(|| CozoError::BadDataFormat(tpl.data.as_ref().to_vec()))?.as_ref())?; - let val_extractor = Typing::try_from(tpl.get_text(7) - .ok_or_else(|| CozoError::BadDataFormat(tpl.data.as_ref().to_vec()))?.as_ref())?; - println!("Found edge {:?}, {:?}", other_key_extractor, val_extractor); - } - _ => return Err(LogicError("Cannot insert into non-tables".to_string())) + fn get_table_info(&mut self, tbl_name: Cow) -> Result<&[KVCoercer]> { + if !self.cache.contains_key(tbl_name.as_ref()) { + let mut coercers = Vec::with_capacity(1); + match self.sess.resolve(&tbl_name)? { + None => return Err(CozoError::UndefinedType(tbl_name.to_string())), + Some(tpl) => { + 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()))?; + + let coercer = KVCoercer { + table_id, + in_root, + 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![], + }; + coercers.push(coercer); } - let related = self.sess.resolve_related_tables(&tbl_name)?; - for t in related { - println!("Found assoc {:?}", t); + 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()))?; + + let coercer = KVCoercer { + table_id, + 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, + }; + + coercers.push(coercer); } + _ => 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 { + table_id, + in_root, + data_keys: t.iter().map(|(k, _)| k.clone()).collect(), + key_typing: vec![], + val_typing: t, + src_key_typing: vec![], + dst_key_typing: vec![], + }; + + coercers.push(coercer); } } - // self.cache.insert(tbl_name.to_string(), ()); } - Some(_t) => {} + println!("Inserting info {} {:#?}", tbl_name, coercers); + self.cache.insert(tbl_name.as_ref().to_string(), coercers); } - Ok(()) + let info = self.cache.get(tbl_name.as_ref()) + .ok_or_else(|| CozoError::LogicError("Cannot resolve table".to_string()))?; + + Ok(info) } fn add(&mut self, val_map: BTreeMap, Value>) -> Result<()> { let tbl_name = match val_map.get("_type") { @@ -116,7 +196,7 @@ impl<'a, 'b, 't> MutationManager<'a, 'b, 't> { None => return Err(LogicError("Cannot determine table kind".to_string())) } }; - self.get_table_info(tbl_name); + self.get_table_info(tbl_name).unwrap(); Ok(()) } } diff --git a/src/relation/typing.rs b/src/relation/typing.rs index ea33c458..4ec49f28 100644 --- a/src/relation/typing.rs +++ b/src/relation/typing.rs @@ -110,6 +110,13 @@ impl Typing { }) } + pub fn extract_named_tuple(self) -> Option> { + match self { + Typing::NamedTuple(t) => Some(t), + _ => None + } + } + pub fn coerce<'a>(&self, v: Value<'a>) -> Result> { if *self == Typing::Any { return Ok(v); @@ -142,13 +149,12 @@ impl Typing { } Typing::UnnamedTuple(ut) => { todo!() - }, + } Typing::NamedTuple(nt) => { todo!() } Typing::Any => unreachable!(), Typing::Nullable(_) => unreachable!(), - } } fn coerce_bool<'a>(&self, v: Value<'a>) -> Result> {