add field and idx accessors

main
Ziyang Hu 2 years ago
parent 62a5876cc2
commit 35c250d410

@ -28,17 +28,17 @@ impl<'s> Session<'s> {
self.define_data(name, data, in_root)
}
fn resolve_value(&self, name: &str) -> Result<Option<Value>> {
match self.resolve(name)? {
None => Ok(None),
Some(t) => {
match t.data_kind()? {
DataKind::Value => Ok(Some(t.get(0)
.ok_or_else(|| CozoError::LogicError("Corrupt".to_string()))?
.to_static())),
k => Err(CozoError::UnexpectedDataKind(k))
}
match self.resolve(name)? {
None => Ok(None),
Some(t) => {
match t.data_kind()? {
DataKind::Value => Ok(Some(t.get(0)
.ok_or_else(|| CozoError::LogicError("Corrupt".to_string()))?
.to_static())),
k => Err(CozoError::UnexpectedDataKind(k))
}
}
}
}
fn encode_definable_key(&self, name: &str, in_root: bool) -> OwnTuple {
let depth_code = if in_root { 0 } else { self.get_stack_depth() as i64 };
@ -289,8 +289,12 @@ impl<'s> Session<'s> {
Ok((is_ev, v.into()))
}
Value::Variable(v) => {
if let Some(d) = params.get(v.as_ref()) {
Ok((true, d.clone()))
if v.starts_with('$') {
Ok(if let Some(d) = params.get(v.as_ref()) {
(true, d.clone())
} else {
(false, Value::Variable(v))
})
} else {
Ok(match self.resolve_value(&v)? {
None => (false, Value::Variable(v)),
@ -300,7 +304,37 @@ impl<'s> Session<'s> {
})
}
}
Value::FieldAccess(field, arg) => {
match *arg {
v @ (Value::Variable(_) |
Value::IdxAccess(_, _) |
Value::FieldAccess(_, _) |
Value::Apply(_, _)) => Ok((false, Value::FieldAccess(field, v.into()))),
Value::Dict(mut d) => {
Ok(d.remove(field.as_ref())
.map(|v| (v.is_evaluated(), v))
.unwrap_or((true, Value::Null)))
}
_ => Err(LogicError("Field access failed".to_string()))
}
}
Value::IdxAccess(idx, arg) => {
match *arg {
v @ (Value::Variable(_) |
Value::IdxAccess(_, _) |
Value::FieldAccess(_, _) |
Value::Apply(_, _)) => Ok((false, Value::IdxAccess(idx, v.into()))),
Value::List(mut l) => {
if idx >= l.len() {
Ok((true, Value::Null))
} else {
let v = l.swap_remove(idx);
Ok((v.is_evaluated(), v))
}
}
_ => Err(LogicError("Idx access failed".to_string()))
}
}
Value::Apply(op, args) => {
Ok(match op.as_ref() {
value::OP_ADD => self.add_values(args)?,
@ -619,6 +653,8 @@ impl<'s> Session<'s> {
Value::List(_) |
Value::Dict(_) => Err(Err(CozoError::InvalidArgument)),
cur_val @ (Value::Variable(_) |
Value::IdxAccess(_, _) |
Value::FieldAccess(_, _) |
Value::Apply(_, _)) => {
collected.push(cur_val);
Ok((false, has_null, collected))
@ -679,6 +715,8 @@ impl<'s> Session<'s> {
Value::List(_) |
Value::Dict(_) => Err(Err(CozoError::InvalidArgument)),
cur_val @ (Value::Variable(_) |
Value::IdxAccess(_, _) |
Value::FieldAccess(_, _) |
Value::Apply(_, _)) => {
collected.push(cur_val);
Ok((false, has_null, collected))

@ -184,6 +184,7 @@ mod tests {
use crate::parser::{Parser, Rule};
use pest::Parser as PestParser;
use crate::db::engine::Engine;
use crate::relation::value::Value;
#[test]
fn parse_patterns() {
@ -223,16 +224,21 @@ mod tests {
}
sess.commit().unwrap();
let s = "from a:Friend, (b:Person)-[:Friend]->(c:Z), x:Person";
let parsed = Parser::parse(Rule::from_pattern, s).unwrap().next().unwrap();
assert_eq!(parsed.as_rule(), Rule::from_pattern);
assert!(sess.parse_from_pattern(parsed).is_err());
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).unwrap();
let s = "from a:Friend, (b:Person)-[:Friend]->(c:Z), x:Person";
let parsed = Parser::parse(Rule::from_pattern, s).unwrap().next().unwrap();
assert_eq!(parsed.as_rule(), Rule::from_pattern);
assert!(sess.parse_from_pattern(parsed).is_err());
let s = "where b.id > c.id, a.id == 5, x.name == 'Joe', x.name.len() == 3";
let parsed = Parser::parse(Rule::where_pattern, s).unwrap().next().unwrap();
let first = parsed.into_inner().next().unwrap();
println!("{:#?}", first);
println!("{:#?}", Value::from_pair(first));
}
drop(engine);
let _ = fs::remove_dir_all(db_path);

@ -85,9 +85,11 @@ impl<T: AsRef<[u8]>> Tuple<T> {
let slen = slen as usize;
start + slen + offset
}
Tag::List => start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize,
Tag::Apply => start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize,
Tag::Dict => start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize,
Tag::List |
Tag::Apply |
Tag::Dict |
Tag::IdxAccess |
Tag::FieldAccess => start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize,
Tag::MaxTag => panic!(),
};
self.idx_cache.borrow_mut().push(nxt);
@ -296,6 +298,29 @@ impl<T: AsRef<[u8]>> Tuple<T> {
(end_pos, collected.into())
}
Tag::MaxTag => (start, Value::EndSentinel),
Tag::IdxAccess => {
let end_pos = start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize;
let mut start_pos = start + 4;
let (idx, offset) = self.parse_varint(start_pos);
start_pos += offset;
let (val, _) = self.parse_value_at(start_pos);
(end_pos, Value::IdxAccess(idx as usize, val.into()))
}
Tag::FieldAccess => {
let end_pos = start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize;
let mut start_pos = start + 4;
let (slen, offset) = self.parse_varint(start);
let slen = slen as usize;
let field = unsafe {
std::str::from_utf8_unchecked(&data[start + offset..start + offset + slen])
};
start_pos += slen + offset;
let (val, _) = self.parse_value_at(start_pos);
(end_pos, Value::FieldAccess(field.into(), val.into()))
}
};
(val, nxt)
}
@ -465,6 +490,35 @@ impl OwnTuple {
cache.truncate(start_len);
cache.push(self.data.len());
}
Value::FieldAccess(field, arg) => {
self.push_tag(Tag::IdxAccess);
let start_pos = self.data.len();
let start_len = self.idx_cache.borrow().len();
self.data.extend(0u32.to_be_bytes());
self.push_varint(field.len() as u64);
self.data.extend_from_slice(field.as_bytes());
self.push_value(arg);
let length = (self.data.len() - start_pos) as u32;
let length_bytes = length.to_be_bytes();
self.data[start_pos..(4 + start_pos)].clone_from_slice(&length_bytes[..4]);
let mut cache = self.idx_cache.borrow_mut();
cache.truncate(start_len);
cache.push(self.data.len());
}
Value::IdxAccess(idx, arg) => {
self.push_tag(Tag::IdxAccess);
let start_pos = self.data.len();
let start_len = self.idx_cache.borrow().len();
self.data.extend(0u32.to_be_bytes());
self.push_varint(*idx as u64);
self.push_value(arg);
let length = (self.data.len() - start_pos) as u32;
let length_bytes = length.to_be_bytes();
self.data[start_pos..(4 + start_pos)].clone_from_slice(&length_bytes[..4]);
let mut cache = self.idx_cache.borrow_mut();
cache.truncate(start_len);
cache.push(self.data.len());
}
Value::Dict(d) => {
self.push_tag(Tag::Dict);
let start_pos = self.data.len();

@ -27,6 +27,8 @@ pub enum Tag {
List = 128,
Dict = 129,
IdxAccess = 251,
FieldAccess = 252,
Variable = 253,
Apply = 254,
MaxTag = 255,
@ -47,6 +49,8 @@ impl TryFrom<u8> for Tag {
7 => Uuid,
128 => List,
129 => Dict,
251 => IdxAccess,
252 => FieldAccess,
253 => Variable,
254 => Apply,
255 => MaxTag,
@ -94,6 +98,8 @@ pub enum Value<'a> {
Dict(BTreeMap<Cow<'a, str>, Value<'a>>),
Variable(Cow<'a, str>),
Apply(Cow<'a, str>, Vec<Value<'a>>),
FieldAccess(Cow<'a, str>, Box<Value<'a>>),
IdxAccess(usize, Box<Value<'a>>),
EndSentinel,
}
@ -119,6 +125,12 @@ impl<'a> Value<'a> {
.map(|(k, v)| (Cow::Owned(k.into_owned()), v.to_static()))
.collect::<BTreeMap<Cow<'static, str>, StaticValue>>().into(),
Value::EndSentinel => panic!("Cannot process sentinel value"),
Value::FieldAccess(field, value) => {
Value::FieldAccess(Cow::from(field.into_owned()),value.to_static().into())
}
Value::IdxAccess(idx, value) => {
Value::IdxAccess(idx,value.to_static().into())
}
}
}
#[inline]
@ -134,7 +146,9 @@ impl<'a> Value<'a> {
Value::List(l) => l.iter().all(|v| v.is_evaluated()),
Value::Dict(d) => d.values().all(|v| v.is_evaluated()),
Value::Variable(_) => false,
Value::Apply(_, _) => false
Value::Apply(_, _) => false,
Value::FieldAccess(_, _) => false,
Value::IdxAccess(_, _) => false
}
}
#[inline]
@ -290,6 +304,12 @@ impl<'a> Display for Value<'a> {
write!(f, "({} {})", op,
args.iter().map(|v| v.to_string()).collect::<Vec<_>>().join(" "))?;
}
Value::FieldAccess(field, value) => {
write!(f, "(.{} {})", field, value)?;
}
Value::IdxAccess(idx, value) => {
write!(f, "(.{} {})", idx, value)?;
}
}
Ok(())
}
@ -360,7 +380,20 @@ fn build_expr_infix<'a>(lhs: Result<Value<'a>>, op: Pair<Rule>, rhs: Result<Valu
fn build_expr_primary(pair: Pair<Rule>) -> Result<Value> {
match pair.as_rule() {
Rule::expr => build_expr_primary(pair.into_inner().next().unwrap()),
Rule::term => build_expr_primary(pair.into_inner().next().unwrap()),
Rule::term => {
let mut pairs = pair.into_inner();
let mut head = build_expr_primary(pairs.next().unwrap())?;
for p in pairs {
match p.as_rule() {
Rule::accessor => {
let accessor_key = p.into_inner().next().unwrap().as_str();
head = Value::Apply(".".into(), vec![accessor_key.into()])
}
_ => todo!()
}
}
Ok(head)
}
Rule::grouping => Value::from_pair(pair.into_inner().next().unwrap()),
Rule::unary => {

Loading…
Cancel
Save