Consolidate field expression code into single location
This commit is contained in:
parent
b0bcecf5da
commit
db7ed18119
2 changed files with 106 additions and 201 deletions
|
@ -4,10 +4,8 @@ use crate::dbs::Statement;
|
|||
use crate::dbs::Transaction;
|
||||
use crate::doc::Document;
|
||||
use crate::err::Error;
|
||||
use crate::sql::field::Field;
|
||||
use crate::sql::idiom::Idiom;
|
||||
use crate::sql::output::Output;
|
||||
use crate::sql::part::Part;
|
||||
use crate::sql::permission::Permission;
|
||||
use crate::sql::value::Value;
|
||||
|
||||
|
@ -29,207 +27,10 @@ impl<'a> Document<'a> {
|
|||
Output::Diff => Ok(self.initial.diff(&self.current, Idiom::default()).into()),
|
||||
Output::After => self.current.compute(ctx, opt, txn, Some(&self.current)).await,
|
||||
Output::Before => self.initial.compute(ctx, opt, txn, Some(&self.initial)).await,
|
||||
Output::Fields(v) => {
|
||||
let mut out = match v.all() {
|
||||
true => self.current.compute(ctx, opt, txn, Some(&self.current)).await?,
|
||||
false => Value::base(),
|
||||
};
|
||||
for v in v.other() {
|
||||
match v {
|
||||
Field::All => (),
|
||||
Field::Alone(v) => match v {
|
||||
// This expression is a multi-output graph traversal
|
||||
Value::Idiom(v) if v.is_multi_yield() => {
|
||||
// Store the different output yields here
|
||||
let mut res: Vec<(&[Part], Value)> = Vec::new();
|
||||
// Split the expression by each output alias
|
||||
for v in v.split_inclusive(Idiom::split_multi_yield) {
|
||||
// Use the last fetched value for each fetch
|
||||
let x = match res.last() {
|
||||
Some((_, r)) => r,
|
||||
None => self.current.as_ref(),
|
||||
};
|
||||
// Continue fetching the next idiom part
|
||||
let x = x
|
||||
.get(ctx, opt, txn, v)
|
||||
.await?
|
||||
.compute(ctx, opt, txn, Some(&self.current))
|
||||
.await?;
|
||||
// Add the result to the temporary store
|
||||
res.push((v, x));
|
||||
}
|
||||
// Assign each fetched yield to the output
|
||||
for (p, x) in res {
|
||||
match p.last().unwrap().alias() {
|
||||
// This is an alias expression part
|
||||
Some(i) => out.set(ctx, opt, txn, i, x).await?,
|
||||
// This is the end of the expression
|
||||
None => out.set(ctx, opt, txn, v, x).await?,
|
||||
}
|
||||
}
|
||||
}
|
||||
// This expression is a normal field expression
|
||||
_ => {
|
||||
let x = v.compute(ctx, opt, txn, Some(&self.current)).await?;
|
||||
out.set(ctx, opt, txn, v.to_idiom().as_ref(), x).await?
|
||||
}
|
||||
},
|
||||
Field::Alias(v, i) => match v {
|
||||
// This expression is a multi-output graph traversal
|
||||
Value::Idiom(v) if v.is_multi_yield() => {
|
||||
// Store the different output yields here
|
||||
let mut res: Vec<(&[Part], Value)> = Vec::new();
|
||||
// Split the expression by each output alias
|
||||
for v in v.split_inclusive(Idiom::split_multi_yield) {
|
||||
// Use the last fetched value for each fetch
|
||||
let x = match res.last() {
|
||||
Some((_, r)) => r,
|
||||
None => self.current.as_ref(),
|
||||
};
|
||||
// Continue fetching the next idiom part
|
||||
let x = x
|
||||
.get(ctx, opt, txn, v)
|
||||
.await?
|
||||
.compute(ctx, opt, txn, Some(&self.current))
|
||||
.await?;
|
||||
// Add the result to the temporary store
|
||||
res.push((v, x));
|
||||
}
|
||||
// Assign each fetched yield to the output
|
||||
for (p, x) in res {
|
||||
match p.last().unwrap().alias() {
|
||||
// This is an alias expression part
|
||||
Some(i) => out.set(ctx, opt, txn, i, x).await?,
|
||||
// This is the end of the expression
|
||||
None => out.set(ctx, opt, txn, i, x).await?,
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let x = v.compute(ctx, opt, txn, Some(&self.current)).await?;
|
||||
out.set(ctx, opt, txn, i, x).await?
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
Output::Fields(v) => v.compute(ctx, opt, txn, Some(&self.current)).await,
|
||||
},
|
||||
None => match stm {
|
||||
Statement::Select(s) => {
|
||||
let mut out = match s.expr.all() {
|
||||
true => self.current.compute(ctx, opt, txn, Some(&self.current)).await?,
|
||||
false => Value::base(),
|
||||
};
|
||||
for v in s.expr.other() {
|
||||
match v {
|
||||
Field::All => (),
|
||||
Field::Alone(v) => match v {
|
||||
// This expression is a grouped aggregate function
|
||||
Value::Function(f) if s.group.is_some() && f.is_aggregate() => {
|
||||
let x = match f.args().len() {
|
||||
// If no function arguments, then compute the result
|
||||
0 => f.compute(ctx, opt, txn, Some(&self.current)).await?,
|
||||
// If arguments, then pass the first value through
|
||||
_ => {
|
||||
f.args()[0]
|
||||
.compute(ctx, opt, txn, Some(&self.current))
|
||||
.await?
|
||||
}
|
||||
};
|
||||
out.set(ctx, opt, txn, v.to_idiom().as_ref(), x).await?;
|
||||
}
|
||||
// This expression is a multi-output graph traversal
|
||||
Value::Idiom(v) if v.is_multi_yield() => {
|
||||
// Store the different output yields here
|
||||
let mut res: Vec<(&[Part], Value)> = Vec::new();
|
||||
// Split the expression by each output alias
|
||||
for v in v.split_inclusive(Idiom::split_multi_yield) {
|
||||
// Use the last fetched value for each fetch
|
||||
let x = match res.last() {
|
||||
Some((_, r)) => r,
|
||||
None => self.current.as_ref(),
|
||||
};
|
||||
// Continue fetching the next idiom part
|
||||
let x = x
|
||||
.get(ctx, opt, txn, v)
|
||||
.await?
|
||||
.compute(ctx, opt, txn, Some(&self.current))
|
||||
.await?;
|
||||
// Add the result to the temporary store
|
||||
res.push((v, x));
|
||||
}
|
||||
// Assign each fetched yield to the output
|
||||
for (p, x) in res {
|
||||
match p.last().unwrap().alias() {
|
||||
// This is an alias expression part
|
||||
Some(i) => out.set(ctx, opt, txn, i, x).await?,
|
||||
// This is the end of the expression
|
||||
None => out.set(ctx, opt, txn, v, x).await?,
|
||||
}
|
||||
}
|
||||
}
|
||||
// This expression is a normal field expression
|
||||
_ => {
|
||||
let x = v.compute(ctx, opt, txn, Some(&self.current)).await?;
|
||||
out.set(ctx, opt, txn, v.to_idiom().as_ref(), x).await?;
|
||||
}
|
||||
},
|
||||
Field::Alias(v, i) => match v {
|
||||
// This expression is a grouped aggregate function
|
||||
Value::Function(f) if s.group.is_some() && f.is_aggregate() => {
|
||||
let x = match f.args().len() {
|
||||
// If no function arguments, then compute the result
|
||||
0 => f.compute(ctx, opt, txn, Some(&self.current)).await?,
|
||||
// If arguments, then pass the first value through
|
||||
_ => {
|
||||
f.args()[0]
|
||||
.compute(ctx, opt, txn, Some(&self.current))
|
||||
.await?
|
||||
}
|
||||
};
|
||||
out.set(ctx, opt, txn, i, x).await?;
|
||||
}
|
||||
// This expression is a multi-output graph traversal
|
||||
Value::Idiom(v) if v.is_multi_yield() => {
|
||||
// Store the different output yields here
|
||||
let mut res: Vec<(&[Part], Value)> = Vec::new();
|
||||
// Split the expression by each output alias
|
||||
for v in v.split_inclusive(Idiom::split_multi_yield) {
|
||||
// Use the last fetched value for each fetch
|
||||
let x = match res.last() {
|
||||
Some((_, r)) => r,
|
||||
None => self.current.as_ref(),
|
||||
};
|
||||
// Continue fetching the next idiom part
|
||||
let x = x
|
||||
.get(ctx, opt, txn, v)
|
||||
.await?
|
||||
.compute(ctx, opt, txn, Some(&self.current))
|
||||
.await?;
|
||||
// Add the result to the temporary store
|
||||
res.push((v, x));
|
||||
}
|
||||
// Assign each fetched yield to the output
|
||||
for (p, x) in res {
|
||||
match p.last().unwrap().alias() {
|
||||
// This is an alias expression part
|
||||
Some(i) => out.set(ctx, opt, txn, i, x).await?,
|
||||
// This is the end of the expression
|
||||
None => out.set(ctx, opt, txn, i, x).await?,
|
||||
}
|
||||
}
|
||||
}
|
||||
// This expression is a normal field expression
|
||||
_ => {
|
||||
let x = v.compute(ctx, opt, txn, Some(&self.current)).await?;
|
||||
out.set(ctx, opt, txn, i, x).await?;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
Statement::Select(s) => s.expr.compute(ctx, opt, txn, Some(&self.current)).await,
|
||||
Statement::Create(_) => {
|
||||
self.current.compute(ctx, opt, txn, Some(&self.current)).await
|
||||
}
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
use crate::ctx::Context;
|
||||
use crate::dbs::Options;
|
||||
use crate::dbs::Transaction;
|
||||
use crate::err::Error;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::common::commas;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::idiom::{idiom, Idiom};
|
||||
use crate::sql::part::Part;
|
||||
use crate::sql::value::{value, Value};
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
|
@ -54,6 +59,105 @@ impl fmt::Display for Fields {
|
|||
}
|
||||
}
|
||||
|
||||
impl Fields {
|
||||
pub(crate) async fn compute(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
opt: &Options,
|
||||
txn: &Transaction,
|
||||
doc: Option<&Value>,
|
||||
) -> Result<Value, Error> {
|
||||
// Ensure futures are run
|
||||
let opt = &opt.futures(true);
|
||||
//
|
||||
let doc = doc.unwrap_or(&Value::None);
|
||||
// Process the desired output
|
||||
let mut out = match self.all() {
|
||||
true => doc.compute(ctx, opt, txn, Some(doc)).await?,
|
||||
false => Value::base(),
|
||||
};
|
||||
for v in self.other() {
|
||||
match v {
|
||||
Field::All => (),
|
||||
Field::Alone(v) => match v {
|
||||
// This expression is a multi-output graph traversal
|
||||
Value::Idiom(v) if v.is_multi_yield() => {
|
||||
// Store the different output yields here
|
||||
let mut res: Vec<(&[Part], Value)> = Vec::new();
|
||||
// Split the expression by each output alias
|
||||
for v in v.split_inclusive(Idiom::split_multi_yield) {
|
||||
// Use the last fetched value for each fetch
|
||||
let x = match res.last() {
|
||||
Some((_, r)) => r,
|
||||
None => doc,
|
||||
};
|
||||
// Continue fetching the next idiom part
|
||||
let x = x
|
||||
.get(ctx, opt, txn, v)
|
||||
.await?
|
||||
.compute(ctx, opt, txn, Some(doc))
|
||||
.await?;
|
||||
// Add the result to the temporary store
|
||||
res.push((v, x));
|
||||
}
|
||||
// Assign each fetched yield to the output
|
||||
for (p, x) in res {
|
||||
match p.last().unwrap().alias() {
|
||||
// This is an alias expression part
|
||||
Some(i) => out.set(ctx, opt, txn, i, x).await?,
|
||||
// This is the end of the expression
|
||||
None => out.set(ctx, opt, txn, v, x).await?,
|
||||
}
|
||||
}
|
||||
}
|
||||
// This expression is a normal field expression
|
||||
_ => {
|
||||
let x = v.compute(ctx, opt, txn, Some(doc)).await?;
|
||||
out.set(ctx, opt, txn, v.to_idiom().as_ref(), x).await?;
|
||||
}
|
||||
},
|
||||
Field::Alias(v, i) => match v {
|
||||
// This expression is a multi-output graph traversal
|
||||
Value::Idiom(v) if v.is_multi_yield() => {
|
||||
// Store the different output yields here
|
||||
let mut res: Vec<(&[Part], Value)> = Vec::new();
|
||||
// Split the expression by each output alias
|
||||
for v in v.split_inclusive(Idiom::split_multi_yield) {
|
||||
// Use the last fetched value for each fetch
|
||||
let x = match res.last() {
|
||||
Some((_, r)) => r,
|
||||
None => doc,
|
||||
};
|
||||
// Continue fetching the next idiom part
|
||||
let x = x
|
||||
.get(ctx, opt, txn, v)
|
||||
.await?
|
||||
.compute(ctx, opt, txn, Some(doc))
|
||||
.await?;
|
||||
// Add the result to the temporary store
|
||||
res.push((v, x));
|
||||
}
|
||||
// Assign each fetched yield to the output
|
||||
for (p, x) in res {
|
||||
match p.last().unwrap().alias() {
|
||||
// This is an alias expression part
|
||||
Some(i) => out.set(ctx, opt, txn, i, x).await?,
|
||||
// This is the end of the expression
|
||||
None => out.set(ctx, opt, txn, i, x).await?,
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let x = v.compute(ctx, opt, txn, Some(doc)).await?;
|
||||
out.set(ctx, opt, txn, i, x).await?;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fields(i: &str) -> IResult<&str, Fields> {
|
||||
let (i, v) = separated_list1(commas, field)(i)?;
|
||||
Ok((i, Fields(v)))
|
||||
|
|
Loading…
Reference in a new issue