|
|
@ -1,5 +1,5 @@
|
|
|
|
use std::borrow::Cow;
|
|
|
|
use std::borrow::Cow;
|
|
|
|
use std::collections::{BTreeMap};
|
|
|
|
use std::collections::{BTreeMap, HashSet};
|
|
|
|
use pest::iterators::Pair;
|
|
|
|
use pest::iterators::Pair;
|
|
|
|
use crate::db::engine::Session;
|
|
|
|
use crate::db::engine::Session;
|
|
|
|
use crate::db::eval::Environment;
|
|
|
|
use crate::db::eval::Environment;
|
|
|
@ -63,49 +63,129 @@ impl<'a, 't> Session<'a, 't> {
|
|
|
|
|
|
|
|
|
|
|
|
struct MutationManager<'a, 'b, 't> {
|
|
|
|
struct MutationManager<'a, 'b, 't> {
|
|
|
|
sess: &'a Session<'b, 't>,
|
|
|
|
sess: &'a Session<'b, 't>,
|
|
|
|
cache: BTreeMap<String, ()>,
|
|
|
|
cache: BTreeMap<String, Vec<KVCoercer>>,
|
|
|
|
default_tbl: Option<String>,
|
|
|
|
default_tbl: Option<String>,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Eq, PartialEq, Debug, Clone)]
|
|
|
|
|
|
|
|
struct KVCoercer {
|
|
|
|
|
|
|
|
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>,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl<'a, 'b, 't> MutationManager<'a, 'b, 't> {
|
|
|
|
impl<'a, 'b, 't> MutationManager<'a, 'b, 't> {
|
|
|
|
fn new(sess: &'a Session<'b, 't>, default_tbl: Option<String>) -> Self {
|
|
|
|
fn new(sess: &'a Session<'b, 't>, default_tbl: Option<String>) -> Self {
|
|
|
|
Self { sess, cache: BTreeMap::new(), default_tbl }
|
|
|
|
Self { sess, cache: BTreeMap::new(), default_tbl }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn get_table_info(&mut self, tbl_name: Cow<str>) -> Result<()> {
|
|
|
|
fn get_table_info(&mut self, tbl_name: Cow<str>) -> Result<&[KVCoercer]> {
|
|
|
|
match self.cache.get(tbl_name.as_ref()) {
|
|
|
|
if !self.cache.contains_key(tbl_name.as_ref()) {
|
|
|
|
None => {
|
|
|
|
let mut coercers = Vec::with_capacity(1);
|
|
|
|
match self.sess.resolve(&tbl_name)? {
|
|
|
|
match self.sess.resolve(&tbl_name)? {
|
|
|
|
None => return Err(CozoError::UndefinedType(tbl_name.to_string())),
|
|
|
|
None => return Err(CozoError::UndefinedType(tbl_name.to_string())),
|
|
|
|
Some(tpl) => {
|
|
|
|
Some(tpl) => {
|
|
|
|
println!("Found tuple {:?}", tpl);
|
|
|
|
|
|
|
|
match tpl.data_kind()? {
|
|
|
|
match tpl.data_kind()? {
|
|
|
|
DataKind::Node => {
|
|
|
|
DataKind::Node => {
|
|
|
|
let key_extractor = Typing::try_from(tpl.get_text(2)
|
|
|
|
let key_extractor = Typing::try_from(tpl.get_text(2)
|
|
|
|
.ok_or_else(|| CozoError::BadDataFormat(tpl.data.as_ref().to_vec()))?.as_ref())?;
|
|
|
|
.ok_or_else(|| CozoError::BadDataFormat(tpl.data.as_ref().to_vec()))?.as_ref())?
|
|
|
|
let val_extractor = Typing::try_from(tpl.get_text(2)
|
|
|
|
.extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?;
|
|
|
|
.ok_or_else(|| CozoError::BadDataFormat(tpl.data.as_ref().to_vec()))?.as_ref())?;
|
|
|
|
let val_extractor = Typing::try_from(tpl.get_text(3)
|
|
|
|
println!("Found node {:?}, {:?}", key_extractor, val_extractor);
|
|
|
|
.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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DataKind::Edge => {
|
|
|
|
DataKind::Edge => {
|
|
|
|
let other_key_extractor = Typing::try_from(tpl.get_text(6)
|
|
|
|
let other_key_extractor = Typing::try_from(tpl.get_text(6)
|
|
|
|
.ok_or_else(|| CozoError::BadDataFormat(tpl.data.as_ref().to_vec()))?.as_ref())?;
|
|
|
|
.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)
|
|
|
|
let val_extractor = Typing::try_from(tpl.get_text(7)
|
|
|
|
.ok_or_else(|| CozoError::BadDataFormat(tpl.data.as_ref().to_vec()))?.as_ref())?;
|
|
|
|
.ok_or_else(|| CozoError::LogicError("Val extraction failed".to_string()))?.as_ref())?
|
|
|
|
println!("Found edge {:?}, {:?}", other_key_extractor, val_extractor);
|
|
|
|
.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()))
|
|
|
|
_ => return Err(LogicError("Cannot insert into non-tables".to_string()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let related = self.sess.resolve_related_tables(&tbl_name)?;
|
|
|
|
let related = self.sess.resolve_related_tables(&tbl_name)?;
|
|
|
|
for t in related {
|
|
|
|
for (_n, d) in related {
|
|
|
|
println!("Found assoc {:?}", t);
|
|
|
|
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<Cow<str>, Value>) -> Result<()> {
|
|
|
|
fn add(&mut self, val_map: BTreeMap<Cow<str>, Value>) -> Result<()> {
|
|
|
|
let tbl_name = match val_map.get("_type") {
|
|
|
|
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()))
|
|
|
|
None => return Err(LogicError("Cannot determine table kind".to_string()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
self.get_table_info(tbl_name);
|
|
|
|
self.get_table_info(tbl_name).unwrap();
|
|
|
|
Ok(())
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|