Simplify metadict semantics

next
Sayan Nandan 1 year ago
parent 263e70905d
commit 3d2e4f2014
No known key found for this signature in database
GPG Key ID: 42EEDF4AE9D96B54

@ -79,9 +79,9 @@ fn no_field(mr: &IWModel, new: &str) -> bool {
!mr.fields().st_contains(new)
}
fn check_nullable(props: &mut HashMap<Box<str>, Option<DictEntryGeneric>>) -> DatabaseResult<bool> {
fn check_nullable(props: &mut HashMap<Box<str>, DictEntryGeneric>) -> DatabaseResult<bool> {
match props.remove("nullable") {
Some(Some(DictEntryGeneric::Lit(b))) if b.kind() == TagClass::Bool => Ok(b.bool()),
Some(DictEntryGeneric::Lit(b)) if b.kind() == TagClass::Bool => Ok(b.bool()),
Some(_) => Err(DatabaseError::DdlModelAlterBadProperty),
None => Ok(false),
}

@ -27,7 +27,7 @@
use {
crate::engine::{
core::{model::ModelData, RWLIdx},
data::{md_dict, DictEntryGeneric, MetaDict},
data::{dict, DictEntryGeneric, MetaDict},
error::{DatabaseError, DatabaseResult},
idx::{IndexST, STIndex},
ql::ddl::{alt::AlterSpace, crt::CreateSpace, drop::DropSpace},
@ -123,8 +123,8 @@ impl Space {
let space_name = space_name.to_string().into_boxed_str();
// check env
let env = match props.remove(SpaceMeta::KEY_ENV) {
Some(Some(DictEntryGeneric::Map(m))) if props.is_empty() => m,
Some(None) | None if props.is_empty() => IndexST::default(),
Some(DictEntryGeneric::Map(m)) if props.is_empty() => m,
Some(DictEntryGeneric::Null) | None if props.is_empty() => IndexST::default(),
_ => {
return Err(DatabaseError::DdlSpaceBadProperty);
}
@ -135,7 +135,7 @@ impl Space {
IndexST::default(),
SpaceMeta::with_env(
// FIXME(@ohsayan): see this is bad. attempt to do it at AST build time
md_dict::rflatten_metadata(env),
dict::rflatten_metadata(env),
),
),
})
@ -164,12 +164,12 @@ impl Space {
gns.with_space(&space_name, |space| {
let mut space_env = space.meta.env.write();
match updated_props.remove(SpaceMeta::KEY_ENV) {
Some(Some(DictEntryGeneric::Map(env))) if updated_props.is_empty() => {
if !md_dict::rmerge_metadata(&mut space_env, env) {
Some(DictEntryGeneric::Map(env)) if updated_props.is_empty() => {
if !dict::rmerge_metadata(&mut space_env, env) {
return Err(DatabaseError::DdlSpaceBadProperty);
}
}
Some(None) if updated_props.is_empty() => space_env.clear(),
Some(DictEntryGeneric::Null) if updated_props.is_empty() => space_env.clear(),
None => {}
_ => return Err(DatabaseError::DdlSpaceBadProperty),
}

@ -37,18 +37,28 @@ use {
/*
dict kinds: one is from a generic parse while the other one is the stored metadata
- MetaDict -> only non-null values
- DictGeneric -> null allowed
*/
/// A metadata dictionary
pub type MetaDict = HashMap<Box<str>, MetaDictEntry>;
/// A generic dictionary built from scratch from syntactical elements
pub type DictGeneric = HashMap<Box<str>, Option<DictEntryGeneric>>;
pub type DictGeneric = HashMap<Box<str>, DictEntryGeneric>;
#[derive(Debug, PartialEq)]
/// A generic dict entry: either a literal or a recursive dictionary
pub enum DictEntryGeneric {
/// A literal
Lit(Datacell),
/// A map
Map(DictGeneric),
/// A null
///
/// This distinction is important because we currently only allow [`Datacell`] to store information about the intialization state (as it should be)
/// and it can't distinct between "null-but-concrete-types" (that's the task of our engine: to enforce the schema but it's not DC's task). Hence this
/// specific flag tells us that this is null (and neither a lit nor a map)
Null,
}
#[derive(Debug, PartialEq)]
@ -80,17 +90,16 @@ pub fn rflatten_metadata(new: DictGeneric) -> MetaDict {
fn _rflatten_metadata(new: DictGeneric, empty: &mut MetaDict) {
for (key, val) in new {
if let Some(v) = val {
match v {
DictEntryGeneric::Lit(l) => {
empty.insert(key, MetaDictEntry::Data(l));
}
DictEntryGeneric::Map(m) => {
let mut rnew = MetaDict::new();
_rflatten_metadata(m, &mut rnew);
empty.insert(key, MetaDictEntry::Map(rnew));
}
match val {
DictEntryGeneric::Lit(l) => {
empty.insert(key, MetaDictEntry::Data(l));
}
DictEntryGeneric::Map(m) => {
let mut rnew = MetaDict::new();
_rflatten_metadata(m, &mut rnew);
empty.insert(key, MetaDictEntry::Map(rnew));
}
DictEntryGeneric::Null => {}
}
}
}
@ -144,9 +153,9 @@ fn rmerge_metadata_prepare_patch(
let mut okay = true;
while new.len() != 0 && okay {
let (key, new_entry) = new.next().unwrap();
match (current.get(&key), new_entry) {
match (current.get(&key), &new_entry) {
// non-null -> non-null: merge flatten update
(Some(this_current), Some(new_entry)) => {
(Some(this_current), DictEntryGeneric::Lit(_) | DictEntryGeneric::Map(_)) => {
okay &= {
match (this_current, new_entry) {
(MetaDictEntry::Data(this_data), DictEntryGeneric::Lit(new_data))
@ -177,7 +186,7 @@ fn rmerge_metadata_prepare_patch(
};
}
// null -> non-null: flatten insert
(None, Some(new_entry)) => match new_entry {
(None, DictEntryGeneric::Lit(_) | DictEntryGeneric::Map(_)) => match new_entry {
DictEntryGeneric::Lit(d) => {
let _ = patch.0.insert(key, Some(MetaDictPatchEntry::Data(d)));
}
@ -188,12 +197,13 @@ fn rmerge_metadata_prepare_patch(
.0
.insert(key, Some(MetaDictPatchEntry::Map(this_patch)));
}
_ => unreachable!(),
},
// non-null -> null: remove
(Some(_), None) => {
(Some(_), DictEntryGeneric::Null) => {
patch.0.insert(key, None);
}
(None, None) => {
(None, DictEntryGeneric::Null) => {
// ignore
}
}

@ -27,11 +27,11 @@
#[macro_use]
mod macros;
pub mod cell;
pub mod dict;
pub mod lit;
pub mod md_dict;
pub mod spec;
pub mod tag;
#[cfg(test)]
mod tests;
pub use md_dict::{DictEntryGeneric, DictGeneric, MetaDict};
pub use dict::{DictEntryGeneric, DictGeneric, MetaDict};

@ -26,19 +26,19 @@
use crate::engine::data::{
cell::Datacell,
md_dict::{self, DictEntryGeneric, DictGeneric, MetaDict, MetaDictEntry},
dict::{self, DictEntryGeneric, DictGeneric, MetaDict, MetaDictEntry},
};
#[test]
fn t_simple_flatten() {
let generic_dict: DictGeneric = into_dict! {
"a_valid_key" => Some(DictEntryGeneric::Lit(100u64.into())),
"a_null_key" => None,
"a_valid_key" => DictEntryGeneric::Lit(100u64.into()),
"a_null_key" => DictEntryGeneric::Null,
};
let expected: MetaDict = into_dict!(
"a_valid_key" => Datacell::new_uint(100)
);
let ret = md_dict::rflatten_metadata(generic_dict);
let ret = dict::rflatten_metadata(generic_dict);
assert_eq!(ret, expected);
}
@ -50,15 +50,15 @@ fn t_simple_patch() {
"z" => Datacell::new_sint(-100),
};
let new: DictGeneric = into_dict! {
"a" => Some(Datacell::new_uint(1).into()),
"b" => Some(Datacell::new_uint(2).into()),
"z" => None,
"a" => Datacell::new_uint(1),
"b" => Datacell::new_uint(2),
"z" => DictEntryGeneric::Null,
};
let expected: MetaDict = into_dict! {
"a" => Datacell::new_uint(1),
"b" => Datacell::new_uint(2),
};
assert!(md_dict::rmerge_metadata(&mut current, new));
assert!(dict::rmerge_metadata(&mut current, new));
assert_eq!(current, expected);
}
@ -71,11 +71,11 @@ fn t_bad_patch() {
};
let backup = current.clone();
let new: DictGeneric = into_dict! {
"a" => Some(Datacell::new_uint(1).into()),
"b" => Some(Datacell::new_uint(2).into()),
"z" => Some(Datacell::new_str("omg".into()).into()),
"a" => Datacell::new_uint(1),
"b" => Datacell::new_uint(2),
"z" => Datacell::new_str("omg".into()),
};
assert!(!md_dict::rmerge_metadata(&mut current, new));
assert!(!dict::rmerge_metadata(&mut current, new));
assert_eq!(current, backup);
}
@ -94,10 +94,10 @@ fn patch_null_out_dict() {
"b" => Datacell::new_uint(3),
};
let new: DictGeneric = into_dict! {
"a" => Some(Datacell::new_uint(2).into()),
"b" => Some(Datacell::new_uint(3).into()),
"z" => None,
"a" => Datacell::new_uint(2),
"b" => Datacell::new_uint(3),
"z" => DictEntryGeneric::Null,
};
assert!(md_dict::rmerge_metadata(&mut current, new));
assert!(dict::rmerge_metadata(&mut current, new));
assert_eq!(current, expected);
}

@ -46,7 +46,7 @@
use crate::{
engine::{
data::DictGeneric,
data::dict::{DictEntryGeneric, DictGeneric},
error::{LangError, LangResult},
ql::{
ast::{QueryData, State},
@ -151,10 +151,10 @@ where
}
(tok, DictFoldState::LIT_OR_OB) if state.can_read_lit_from(tok) => {
// found lit
let v = Some(unsafe {
let v = unsafe {
// UNSAFE(@ohsayan): verified at guard
state.read_lit_unchecked_from(tok).into()
});
};
state.poison_if_not(
dict.insert(
unsafe {
@ -176,7 +176,7 @@ where
// UNSAFE(@ohsayan): we only switch to this when we've already read in a key
key.take().as_str().into()
},
None,
DictEntryGeneric::Null,
)
.is_none(),
);
@ -193,7 +193,7 @@ where
// UNSAFE(@ohsayan): correct again because whenever we hit an expression position, we've already read in a key (ident)
key.take().as_str().into()
},
Some(ndict.into()),
DictEntryGeneric::Map(ndict),
)
.is_none(),
);

@ -76,24 +76,24 @@ fn nullable_datatype(v: impl NullableData<Datacell>) -> Datacell {
}
pub trait NullableDictEntry {
fn data(self) -> Option<crate::engine::data::DictEntryGeneric>;
fn data(self) -> crate::engine::data::DictEntryGeneric;
}
impl NullableDictEntry for Null {
fn data(self) -> Option<crate::engine::data::DictEntryGeneric> {
None
fn data(self) -> crate::engine::data::DictEntryGeneric {
crate::engine::data::DictEntryGeneric::Null
}
}
impl<'a> NullableDictEntry for crate::engine::data::lit::Lit<'a> {
fn data(self) -> Option<crate::engine::data::DictEntryGeneric> {
Some(crate::engine::data::DictEntryGeneric::from(self.as_ir()))
fn data(self) -> crate::engine::data::DictEntryGeneric {
crate::engine::data::DictEntryGeneric::from(self.as_ir())
}
}
impl NullableDictEntry for crate::engine::data::DictGeneric {
fn data(self) -> Option<crate::engine::data::DictEntryGeneric> {
Some(crate::engine::data::DictEntryGeneric::Map(self))
fn data(self) -> crate::engine::data::DictEntryGeneric {
crate::engine::data::DictEntryGeneric::Map(self)
}
}

Loading…
Cancel
Save