Only allow for single values in RELATE statements

This commit is contained in:
Tobie Morgan Hitchcock 2022-06-10 00:01:58 +01:00
parent 37a3efc81b
commit 18cee9091a

View file

@ -6,18 +6,23 @@ use crate::dbs::Options;
use crate::dbs::Statement; use crate::dbs::Statement;
use crate::dbs::Transaction; use crate::dbs::Transaction;
use crate::err::Error; use crate::err::Error;
use crate::sql::array::array;
use crate::sql::comment::mightbespace; use crate::sql::comment::mightbespace;
use crate::sql::comment::shouldbespace; use crate::sql::comment::shouldbespace;
use crate::sql::data::{data, Data}; use crate::sql::data::{data, Data};
use crate::sql::error::IResult; use crate::sql::error::IResult;
use crate::sql::output::{output, Output}; use crate::sql::output::{output, Output};
use crate::sql::param::param;
use crate::sql::subquery::subquery;
use crate::sql::table::{table, Table}; use crate::sql::table::{table, Table};
use crate::sql::thing::thing;
use crate::sql::timeout::{timeout, Timeout}; use crate::sql::timeout::{timeout, Timeout};
use crate::sql::value::{whats, Value, Values}; use crate::sql::value::Value;
use derive::Store; use derive::Store;
use nom::branch::alt; use nom::branch::alt;
use nom::bytes::complete::tag_no_case; use nom::bytes::complete::tag_no_case;
use nom::character::complete::char; use nom::character::complete::char;
use nom::combinator::map;
use nom::combinator::opt; use nom::combinator::opt;
use nom::sequence::preceded; use nom::sequence::preceded;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -26,8 +31,8 @@ use std::fmt;
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store)] #[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store)]
pub struct RelateStatement { pub struct RelateStatement {
pub kind: Table, pub kind: Table,
pub from: Values, pub from: Value,
pub with: Values, pub with: Value,
pub uniq: bool, pub uniq: bool,
pub data: Option<Data>, pub data: Option<Data>,
pub output: Option<Output>, pub output: Option<Output>,
@ -56,89 +61,84 @@ impl RelateStatement {
// Loop over the from targets // Loop over the from targets
let from = { let from = {
let mut out = Vec::new(); let mut out = Vec::new();
for w in self.from.0.iter() { match self.from.compute(ctx, opt, txn, doc).await? {
let v = w.compute(ctx, opt, txn, doc).await?; Value::Thing(v) => out.push(v),
match v { Value::Array(v) => {
Value::Thing(v) => out.push(v), for v in v {
Value::Array(v) => { match v {
for v in v { Value::Thing(v) => out.push(v),
match v { Value::Object(v) => match v.rid() {
Value::Thing(v) => out.push(v), Some(v) => out.push(v),
Value::Object(v) => match v.rid() { _ => {
Some(v) => out.push(v),
_ => {
return Err(Error::RelateStatement {
value: v.to_string(),
})
}
},
v => {
return Err(Error::RelateStatement { return Err(Error::RelateStatement {
value: v.to_string(), value: v.to_string(),
}) })
} }
},
v => {
return Err(Error::RelateStatement {
value: v.to_string(),
})
} }
} }
} }
Value::Object(v) => match v.rid() { }
Some(v) => out.push(v), Value::Object(v) => match v.rid() {
None => { Some(v) => out.push(v),
return Err(Error::RelateStatement { None => {
value: v.to_string(),
})
}
},
v => {
return Err(Error::RelateStatement { return Err(Error::RelateStatement {
value: v.to_string(), value: v.to_string(),
}) })
} }
}; },
} v => {
return Err(Error::RelateStatement {
value: v.to_string(),
})
}
};
// }
out out
}; };
// Loop over the with targets // Loop over the with targets
let with = { let with = {
let mut out = Vec::new(); let mut out = Vec::new();
for w in self.with.0.iter() { match self.with.compute(ctx, opt, txn, doc).await? {
let v = w.compute(ctx, opt, txn, doc).await?; Value::Thing(v) => out.push(v),
match v { Value::Array(v) => {
Value::Thing(v) => out.push(v), for v in v {
Value::Array(v) => { match v {
for v in v { Value::Thing(v) => out.push(v),
match v { Value::Object(v) => match v.rid() {
Value::Thing(v) => out.push(v), Some(v) => out.push(v),
Value::Object(v) => match v.rid() { None => {
Some(v) => out.push(v),
None => {
return Err(Error::RelateStatement {
value: v.to_string(),
})
}
},
v => {
return Err(Error::RelateStatement { return Err(Error::RelateStatement {
value: v.to_string(), value: v.to_string(),
}) })
} }
},
v => {
return Err(Error::RelateStatement {
value: v.to_string(),
})
} }
} }
} }
Value::Object(v) => match v.rid() { }
Some(v) => out.push(v), Value::Object(v) => match v.rid() {
None => { Some(v) => out.push(v),
return Err(Error::RelateStatement { None => {
value: v.to_string(),
})
}
},
v => {
return Err(Error::RelateStatement { return Err(Error::RelateStatement {
value: v.to_string(), value: v.to_string(),
}) })
} }
}; },
} v => {
return Err(Error::RelateStatement {
value: v.to_string(),
})
}
};
out out
}; };
// //
@ -203,8 +203,13 @@ pub fn relate(i: &str) -> IResult<&str, RelateStatement> {
)) ))
} }
fn relate_o(i: &str) -> IResult<&str, (Table, Values, Values)> { fn relate_o(i: &str) -> IResult<&str, (Table, Value, Value)> {
let (i, from) = whats(i)?; let (i, from) = alt((
map(subquery, Value::from),
map(array, Value::from),
map(param, Value::from),
map(thing, Value::from),
))(i)?;
let (i, _) = mightbespace(i)?; let (i, _) = mightbespace(i)?;
let (i, _) = char('-')(i)?; let (i, _) = char('-')(i)?;
let (i, _) = char('>')(i)?; let (i, _) = char('>')(i)?;
@ -214,12 +219,22 @@ fn relate_o(i: &str) -> IResult<&str, (Table, Values, Values)> {
let (i, _) = char('-')(i)?; let (i, _) = char('-')(i)?;
let (i, _) = char('>')(i)?; let (i, _) = char('>')(i)?;
let (i, _) = mightbespace(i)?; let (i, _) = mightbespace(i)?;
let (i, with) = whats(i)?; let (i, with) = alt((
map(subquery, Value::from),
map(array, Value::from),
map(param, Value::from),
map(thing, Value::from),
))(i)?;
Ok((i, (kind, from, with))) Ok((i, (kind, from, with)))
} }
fn relate_i(i: &str) -> IResult<&str, (Table, Values, Values)> { fn relate_i(i: &str) -> IResult<&str, (Table, Value, Value)> {
let (i, with) = whats(i)?; let (i, with) = alt((
map(subquery, Value::from),
map(array, Value::from),
map(param, Value::from),
map(thing, Value::from),
))(i)?;
let (i, _) = mightbespace(i)?; let (i, _) = mightbespace(i)?;
let (i, _) = char('<')(i)?; let (i, _) = char('<')(i)?;
let (i, _) = char('-')(i)?; let (i, _) = char('-')(i)?;
@ -229,7 +244,12 @@ fn relate_i(i: &str) -> IResult<&str, (Table, Values, Values)> {
let (i, _) = char('<')(i)?; let (i, _) = char('<')(i)?;
let (i, _) = char('-')(i)?; let (i, _) = char('-')(i)?;
let (i, _) = mightbespace(i)?; let (i, _) = mightbespace(i)?;
let (i, from) = whats(i)?; let (i, from) = alt((
map(subquery, Value::from),
map(array, Value::from),
map(param, Value::from),
map(thing, Value::from),
))(i)?;
Ok((i, (kind, from, with))) Ok((i, (kind, from, with)))
} }
@ -240,28 +260,19 @@ mod tests {
#[test] #[test]
fn relate_statement_in() { fn relate_statement_in() {
let sql = "RELATE person->like->animal"; let sql = "RELATE person:tobie->like->animal:koala";
let res = relate(sql); let res = relate(sql);
assert!(res.is_ok()); assert!(res.is_ok());
let out = res.unwrap().1; let out = res.unwrap().1;
assert_eq!("RELATE person -> like -> animal", format!("{}", out)) assert_eq!("RELATE person:tobie -> like -> animal:koala", format!("{}", out))
} }
#[test] #[test]
fn relate_statement_out() { fn relate_statement_out() {
let sql = "RELATE animal<-like<-person"; let sql = "RELATE animal:koala<-like<-person:tobie";
let res = relate(sql); let res = relate(sql);
assert!(res.is_ok()); assert!(res.is_ok());
let out = res.unwrap().1; let out = res.unwrap().1;
assert_eq!("RELATE person -> like -> animal", format!("{}", out)) assert_eq!("RELATE person:tobie -> like -> animal:koala", format!("{}", out))
}
#[test]
fn relate_statement_thing() {
let sql = "RELATE person:tobie->like->person:jaime";
let res = relate(sql);
assert!(res.is_ok());
let out = res.unwrap().1;
assert_eq!("RELATE person:tobie -> like -> person:jaime", format!("{}", out))
} }
} }