Fixes parameter after fetch ()

Co-authored-by: Mees Delzenne <DelSkayn@users.noreply.github.com>
This commit is contained in:
Vignesh 2024-07-05 19:49:53 +05:30 committed by GitHub
parent 5706c9b368
commit 1baf7848db
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 123 additions and 23 deletions
core/src
dbs
sql
fetch.rs
statements
value/serde/ser/fetch/vec
syn/parser
lib/tests

View file

@ -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();
}

View file

@ -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
}

View file

@ -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?;
}
}
//

View file

@ -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(())
}

View file

@ -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>> {

View file

@ -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()
)]))])),
)])))])),
}),
)
}

View file

@ -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,

View file

@ -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(())
}