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::ending::field as ending; use crate::sql::error::IResult; use crate::sql::fmt::Fmt; use crate::sql::idiom::{plain as idiom, Idiom}; use crate::sql::part::Part; use crate::sql::value::{value, Value}; use nom::branch::alt; use nom::bytes::complete::tag_no_case; use nom::multi::separated_list1; use serde::{Deserialize, Serialize}; use std::fmt::{self, Display, Formatter, Write}; use std::ops::Deref; #[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] pub struct Fields(pub Vec, pub bool); impl Fields { pub fn all() -> Self { Self(vec![Field::All], false) } /// Check to see if this field is a * projection pub fn is_all(&self) -> bool { self.0.iter().any(|v| matches!(v, Field::All)) } /// Get all fields which are not an * projection pub fn other(&self) -> impl Iterator { self.0.iter().filter(|v| !matches!(v, Field::All)) } /// Check to see if this field is a single VALUE clause pub fn single(&self) -> Option<&Field> { match (self.0.len(), self.1) { (1, true) => match self.0.first() { Some(Field::All) => None, Some(v) => Some(v), _ => None, }, _ => None, } } } impl Deref for Fields { type Target = Vec; fn deref(&self) -> &Self::Target { &self.0 } } impl IntoIterator for Fields { type Item = Field; type IntoIter = std::vec::IntoIter; fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } } impl Display for Fields { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self.single() { Some(v) => write!(f, "VALUE {}", &v), None => Display::fmt(&Fmt::comma_separated(&self.0), f), } } } impl Fields { pub(crate) async fn compute( &self, ctx: &Context<'_>, opt: &Options, txn: &Transaction, doc: Option<&Value>, group: bool, ) -> Result { // 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.is_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 grouped aggregate function Value::Function(f) if group && f.is_aggregate() => { let x = match f.args().len() { // If no function arguments, then compute the result 0 => f.compute(ctx, opt, txn, Some(doc)).await?, // If arguments, then pass the first value through _ => f.args()[0].compute(ctx, opt, txn, Some(doc)).await?, }; // Check if this is a single VALUE field expression match self.single().is_some() { false => out.set(ctx, opt, txn, v.to_idiom().as_ref(), x).await?, true => out = x, } } // 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, Some(doc), v) .await? .compute(ctx, opt, txn, Some(doc)) .await? .flatten(); // 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(a) => out.set(ctx, opt, txn, a, 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?; // Check if this is a single VALUE field expression match self.single().is_some() { false => out.set(ctx, opt, txn, v.to_idiom().as_ref(), x).await?, true => out = x, } } }, Field::Alias(v, i) => match v { // This expression is a grouped aggregate function Value::Function(f) if group && f.is_aggregate() => { let x = match f.args().len() { // If no function arguments, then compute the result 0 => f.compute(ctx, opt, txn, Some(doc)).await?, // If arguments, then pass the first value through _ => f.args()[0].compute(ctx, opt, txn, Some(doc)).await?, }; // Check if this is a single VALUE field expression match self.single().is_some() { false => out.set(ctx, opt, txn, i, x).await?, true => out = x, } } // 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, Some(doc), v) .await? .compute(ctx, opt, txn, Some(doc)) .await? .flatten(); // 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(a) => { let v = x.clone(); out.set(ctx, opt, txn, a, x).await?; out.set(ctx, opt, txn, i, v).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(doc)).await?; // Check if this is a single VALUE field expression match self.single().is_some() { false => out.set(ctx, opt, txn, i, x).await?, true => out = x, } } }, } } Ok(out) } } pub fn fields(i: &str) -> IResult<&str, Fields> { alt((field_one, field_many))(i) } fn field_one(i: &str) -> IResult<&str, Fields> { let (i, _) = tag_no_case("VALUE")(i)?; let (i, _) = shouldbespace(i)?; let (i, f) = alt((alias, alone))(i)?; let (i, _) = ending(i)?; Ok((i, Fields(vec![f], true))) } fn field_many(i: &str) -> IResult<&str, Fields> { let (i, v) = separated_list1(commas, field)(i)?; Ok((i, Fields(v, false))) } #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] pub enum Field { All, Alone(Value), Alias(Value, Idiom), } impl Default for Field { fn default() -> Self { Self::All } } impl Display for Field { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { Self::All => f.write_char('*'), Self::Alone(e) => Display::fmt(e, f), Self::Alias(e, a) => write!(f, "{e} AS {a}"), } } } pub fn field(i: &str) -> IResult<&str, Field> { alt((all, alias, alone))(i) } pub fn all(i: &str) -> IResult<&str, Field> { let (i, _) = tag_no_case("*")(i)?; Ok((i, Field::All)) } pub fn alone(i: &str) -> IResult<&str, Field> { let (i, f) = value(i)?; Ok((i, Field::Alone(f))) } pub fn alias(i: &str) -> IResult<&str, Field> { let (i, f) = value(i)?; let (i, _) = shouldbespace(i)?; let (i, _) = tag_no_case("AS")(i)?; let (i, _) = shouldbespace(i)?; let (i, a) = idiom(i)?; Ok((i, Field::Alias(f, a))) } #[cfg(test)] mod tests { use super::*; #[test] fn field_all() { let sql = "*"; let res = fields(sql); assert!(res.is_ok()); let out = res.unwrap().1; assert_eq!("*", format!("{}", out)); } #[test] fn field_one() { let sql = "field"; let res = fields(sql); assert!(res.is_ok()); let out = res.unwrap().1; assert_eq!("field", format!("{}", out)); } #[test] fn field_value() { let sql = "VALUE field"; let res = fields(sql); assert!(res.is_ok()); let out = res.unwrap().1; assert_eq!("VALUE field", format!("{}", out)); } #[test] fn field_alias() { let sql = "field AS one"; let res = fields(sql); assert!(res.is_ok()); let out = res.unwrap().1; assert_eq!("field AS one", format!("{}", out)); } #[test] fn field_value_alias() { let sql = "VALUE field AS one"; let res = fields(sql); assert!(res.is_ok()); let out = res.unwrap().1; assert_eq!("VALUE field AS one", format!("{}", out)); } #[test] fn field_multiple() { let sql = "field, other.field"; let res = fields(sql); assert!(res.is_ok()); let out = res.unwrap().1; assert_eq!("field, other.field", format!("{}", out)); } #[test] fn field_aliases() { let sql = "field AS one, other.field AS two"; let res = fields(sql); assert!(res.is_ok()); let out = res.unwrap().1; assert_eq!("field AS one, other.field AS two", format!("{}", out)); } #[test] fn field_value_only_one() { let sql = "VALUE field, other.field"; let res = fields(sql); assert!(res.is_ok()); } }