Fixes parameter after fetch (#4086)
Co-authored-by: Mees Delzenne <DelSkayn@users.noreply.github.com>
This commit is contained in:
parent
5706c9b368
commit
1baf7848db
8 changed files with 123 additions and 23 deletions
core/src
dbs
sql
syn/parser
lib/tests
|
@ -16,6 +16,9 @@ use crate::sql::range::Range;
|
|||
use crate::sql::table::Table;
|
||||
use crate::sql::thing::Thing;
|
||||
use crate::sql::value::Value;
|
||||
use crate::sql::Ident;
|
||||
use crate::sql::Idiom;
|
||||
use crate::sql::Part;
|
||||
use reblessive::tree::Stk;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use reblessive::TreeStack;
|
||||
|
@ -444,11 +447,27 @@ impl Iterator {
|
|||
) -> Result<(), Error> {
|
||||
if let Some(fetchs) = stm.fetch() {
|
||||
for fetch in fetchs.iter() {
|
||||
let i: &Idiom;
|
||||
let new_idiom: Idiom;
|
||||
if let Value::Idiom(idiom) = &fetch.0 {
|
||||
i = idiom;
|
||||
} else if let Value::Param(param) = &fetch.0 {
|
||||
let p = param.compute(stk, ctx, opt, None).await?;
|
||||
if let Value::Strand(s) = p {
|
||||
let p: Part = Part::Field(Ident(s.0));
|
||||
new_idiom = Idiom(vec![p]);
|
||||
i = &new_idiom;
|
||||
} else {
|
||||
return Err(Error::Thrown("Parameter should be a string".to_string()));
|
||||
}
|
||||
} else {
|
||||
return Err(Error::Thrown("Invalid field".to_string()));
|
||||
}
|
||||
let mut values = self.results.take()?;
|
||||
// Loop over each result value
|
||||
for obj in &mut values {
|
||||
// Fetch the value at the path
|
||||
stk.run(|stk| obj.fetch(stk, ctx, opt, fetch)).await?;
|
||||
stk.run(|stk| obj.fetch(stk, ctx, opt, i)).await?;
|
||||
}
|
||||
self.results = values.into();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use crate::sql::fmt::Fmt;
|
||||
use crate::sql::idiom::Idiom;
|
||||
use crate::sql::statements::info::InfoStructure;
|
||||
use crate::sql::Value;
|
||||
use revision::revisioned;
|
||||
|
@ -44,10 +43,10 @@ impl InfoStructure for Fetchs {
|
|||
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[non_exhaustive]
|
||||
pub struct Fetch(pub Idiom);
|
||||
pub struct Fetch(pub Value);
|
||||
|
||||
impl Deref for Fetch {
|
||||
type Target = Idiom;
|
||||
type Target = Value;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::doc::CursorDoc;
|
||||
use crate::err::Error;
|
||||
use crate::sql::fetch::Fetchs;
|
||||
use crate::sql::value::Value;
|
||||
use crate::sql::{Ident, Idiom};
|
||||
use crate::{ctx::Context, sql::Part};
|
||||
use derive::Store;
|
||||
use reblessive::tree::Stk;
|
||||
use revision::revisioned;
|
||||
|
@ -39,7 +40,23 @@ impl OutputStatement {
|
|||
// Fetch any
|
||||
if let Some(fetchs) = &self.fetch {
|
||||
for fetch in fetchs.iter() {
|
||||
value.fetch(stk, ctx, opt, fetch).await?;
|
||||
let i: &Idiom;
|
||||
let new_idiom: Idiom;
|
||||
if let Value::Idiom(idiom) = &fetch.0 {
|
||||
i = idiom;
|
||||
} else if let Value::Param(param) = &fetch.0 {
|
||||
let p = param.compute(stk, ctx, opt, None).await?;
|
||||
if let Value::Strand(s) = p {
|
||||
let p: Part = Part::Field(Ident(s.0));
|
||||
new_idiom = Idiom(vec![p]);
|
||||
i = &new_idiom;
|
||||
} else {
|
||||
return Err(Error::Thrown("Parameter should be a string".to_string()));
|
||||
}
|
||||
} else {
|
||||
return Err(Error::Thrown("Invalid field".to_string()));
|
||||
}
|
||||
value.fetch(stk, ctx, opt, i).await?;
|
||||
}
|
||||
}
|
||||
//
|
||||
|
|
|
@ -3,7 +3,6 @@ pub mod opt;
|
|||
use crate::err::Error;
|
||||
use crate::sql::value::serde::ser;
|
||||
use crate::sql::Fetch;
|
||||
use crate::sql::Idiom;
|
||||
use ser::Serializer as _;
|
||||
use serde::ser::Impossible;
|
||||
use serde::ser::Serialize;
|
||||
|
@ -53,7 +52,7 @@ impl serde::ser::SerializeSeq for SerializeFetchVec {
|
|||
where
|
||||
T: Serialize + ?Sized,
|
||||
{
|
||||
self.0.push(Fetch(Idiom(value.serialize(ser::part::vec::Serializer.wrap())?)));
|
||||
self.0.push(Fetch(value.serialize(ser::value::Serializer.wrap())?));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -4,9 +4,10 @@ use reblessive::Stk;
|
|||
|
||||
use crate::{
|
||||
sql::{
|
||||
changefeed::ChangeFeed, index::Distance, index::VectorType, Base, Cond, Data, Duration,
|
||||
Fetch, Fetchs, Field, Fields, Group, Groups, Ident, Idiom, Output, Permission, Permissions,
|
||||
Tables, Timeout, Value, View,
|
||||
changefeed::ChangeFeed,
|
||||
index::{Distance, VectorType},
|
||||
Base, Cond, Data, Duration, Fetch, Fetchs, Field, Fields, Group, Groups, Ident, Idiom,
|
||||
Output, Permission, Permissions, Tables, Timeout, Value, View,
|
||||
},
|
||||
syn::{
|
||||
parser::{
|
||||
|
@ -107,8 +108,19 @@ impl Parser<'_> {
|
|||
if !self.eat(t!("FETCH")) {
|
||||
return Ok(None);
|
||||
}
|
||||
let v = self.parse_idiom_list(ctx).await?.into_iter().map(Fetch).collect();
|
||||
Ok(Some(Fetchs(v)))
|
||||
let mut fetchs = vec![Fetch(self.try_parse_param_or_idiom(ctx).await?)];
|
||||
while self.eat(t!(",")) {
|
||||
fetchs.push(Fetch(self.try_parse_param_or_idiom(ctx).await?));
|
||||
}
|
||||
Ok(Some(Fetchs(fetchs)))
|
||||
}
|
||||
|
||||
pub async fn try_parse_param_or_idiom(&mut self, ctx: &mut Stk) -> ParseResult<Value> {
|
||||
if self.peek().kind == t!("$param") {
|
||||
Ok(Value::Param(self.next_token_value()?))
|
||||
} else {
|
||||
Ok(Value::Idiom(self.parse_plain_idiom(ctx).await?))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn try_parse_condition(&mut self, ctx: &mut Stk) -> ParseResult<Option<Cond>> {
|
||||
|
|
|
@ -1689,7 +1689,9 @@ SELECT bar as foo,[1,2],bar OMIT bar FROM ONLY a,1
|
|||
start: Some(Start(Value::Object(Object(
|
||||
[("a".to_owned(), Value::Bool(true))].into_iter().collect()
|
||||
)))),
|
||||
fetch: Some(Fetchs(vec![Fetch(Idiom(vec![Part::Field(Ident("foo".to_owned()))]))])),
|
||||
fetch: Some(Fetchs(vec![Fetch(Value::Idiom(Idiom(vec![Part::Field(Ident(
|
||||
"foo".to_owned()
|
||||
))])))])),
|
||||
version: Some(Version(Datetime(expected_datetime))),
|
||||
timeout: None,
|
||||
parallel: false,
|
||||
|
@ -1951,11 +1953,11 @@ fn parse_live() {
|
|||
assert_eq!(
|
||||
stmt.fetch,
|
||||
Some(Fetchs(vec![
|
||||
Fetch(Idiom(vec![
|
||||
Fetch(Value::Idiom(Idiom(vec![
|
||||
Part::Field(Ident("a".to_owned())),
|
||||
Part::Where(Value::Idiom(Idiom(vec![Part::Field(Ident("foo".to_owned()))]))),
|
||||
])),
|
||||
Fetch(Idiom(vec![Part::Field(Ident("b".to_owned()))])),
|
||||
]))),
|
||||
Fetch(Value::Idiom(Idiom(vec![Part::Field(Ident("b".to_owned()))]))),
|
||||
])),
|
||||
)
|
||||
}
|
||||
|
@ -1979,9 +1981,9 @@ fn parse_return() {
|
|||
res,
|
||||
Statement::Output(OutputStatement {
|
||||
what: Value::Idiom(Idiom(vec![Part::Field(Ident("RETRUN".to_owned()))])),
|
||||
fetch: Some(Fetchs(vec![Fetch(Idiom(vec![Part::Field(
|
||||
fetch: Some(Fetchs(vec![Fetch(Value::Idiom(Idiom(vec![Part::Field(
|
||||
Ident("RETURN".to_owned()).to_owned()
|
||||
)]))])),
|
||||
)])))])),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -503,7 +503,9 @@ fn statements() -> Vec<Statement> {
|
|||
start: Some(Start(Value::Object(Object(
|
||||
[("a".to_owned(), Value::Bool(true))].into_iter().collect(),
|
||||
)))),
|
||||
fetch: Some(Fetchs(vec![Fetch(Idiom(vec![Part::Field(Ident("foo".to_owned()))]))])),
|
||||
fetch: Some(Fetchs(vec![Fetch(Value::Idiom(Idiom(vec![Part::Field(Ident(
|
||||
"foo".to_owned(),
|
||||
))])))])),
|
||||
version: Some(Version(Datetime(expected_datetime))),
|
||||
timeout: None,
|
||||
parallel: false,
|
||||
|
@ -591,9 +593,9 @@ fn statements() -> Vec<Statement> {
|
|||
}),
|
||||
Statement::Output(OutputStatement {
|
||||
what: Value::Idiom(Idiom(vec![Part::Field(Ident("RETRUN".to_owned()))])),
|
||||
fetch: Some(Fetchs(vec![Fetch(Idiom(vec![Part::Field(
|
||||
fetch: Some(Fetchs(vec![Fetch(Value::Idiom(Idiom(vec![Part::Field(
|
||||
Ident("RETURN".to_owned()).to_owned(),
|
||||
)]))])),
|
||||
)])))])),
|
||||
}),
|
||||
Statement::Relate(RelateStatement {
|
||||
only: true,
|
||||
|
|
|
@ -21,11 +21,13 @@ async fn create_relate_select() -> Result<(), Error> {
|
|||
SELECT *, ->bought->product.* AS products FROM user;
|
||||
SELECT *, ->bought AS products FROM user FETCH products;
|
||||
SELECT *, ->(bought AS purchases) FROM user FETCH purchases, purchases.out;
|
||||
LET $param1 = \"purchases\";
|
||||
SELECT *, ->(bought AS purchases) FROM user FETCH $param1, purchases.out;
|
||||
";
|
||||
let dbs = new_ds().await?;
|
||||
let ses = Session::owner().with_ns("test").with_db("test");
|
||||
let res = &mut dbs.execute(sql, &ses, None).await?;
|
||||
assert_eq!(res.len(), 12);
|
||||
assert_eq!(res.len(), 14);
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse(
|
||||
|
@ -277,5 +279,53 @@ async fn create_relate_select() -> Result<(), Error> {
|
|||
);
|
||||
assert_eq!(tmp, val);
|
||||
//
|
||||
// Remove LET statement result
|
||||
res.remove(0);
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse(
|
||||
"[
|
||||
{
|
||||
id: user:jaime,
|
||||
name: 'Jaime',
|
||||
purchases: [
|
||||
{
|
||||
id: bought:3,
|
||||
in: user:jaime,
|
||||
out: {
|
||||
id: product:laptop,
|
||||
price: 3000
|
||||
},
|
||||
payment_method: 'VISA'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: user:tobie,
|
||||
name: 'Tobie',
|
||||
purchases: [
|
||||
{
|
||||
id: bought:1,
|
||||
in: user:tobie,
|
||||
out: {
|
||||
id: product:phone,
|
||||
price: 1000
|
||||
},
|
||||
payment_method: 'VISA'
|
||||
},
|
||||
{
|
||||
id: bought:2,
|
||||
in: user:tobie,
|
||||
out: {
|
||||
id: product:laptop,
|
||||
price: 3000
|
||||
},
|
||||
payment_method: 'VISA'
|
||||
}
|
||||
]
|
||||
}
|
||||
]",
|
||||
);
|
||||
assert_eq!(tmp, val);
|
||||
//
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue