Add initial support for additional functionality in graph expressions

Related to #1658
This commit is contained in:
Tobie Morgan Hitchcock 2023-03-31 18:50:11 +01:00
parent 2e0093c41d
commit 0a328d4f0a
4 changed files with 92 additions and 4 deletions

View file

@ -21,12 +21,18 @@ use std::ops::Deref;
pub struct Fields(pub Vec<Field>, pub bool); pub struct Fields(pub Vec<Field>, pub bool);
impl Fields { impl Fields {
pub fn all(&self) -> bool { 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)) self.0.iter().any(|v| matches!(v, Field::All))
} }
/// Get all fields which are not an * projection
pub fn other(&self) -> impl Iterator<Item = &Field> { pub fn other(&self) -> impl Iterator<Item = &Field> {
self.0.iter().filter(|v| !matches!(v, Field::All)) 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> { pub fn single(&self) -> Option<&Field> {
match (self.0.len(), self.1) { match (self.0.len(), self.1) {
(1, true) => match self.0.first() { (1, true) => match self.0.first() {
@ -77,7 +83,7 @@ impl Fields {
// //
let doc = doc.unwrap_or(&Value::None); let doc = doc.unwrap_or(&Value::None);
// Process the desired output // Process the desired output
let mut out = match self.all() { let mut out = match self.is_all() {
true => doc.compute(ctx, opt, txn, Some(doc)).await?, true => doc.compute(ctx, opt, txn, Some(doc)).await?,
false => Value::base(), false => Value::base(),
}; };

View file

@ -3,7 +3,13 @@ use crate::sql::comment::shouldbespace;
use crate::sql::cond::{cond, Cond}; use crate::sql::cond::{cond, Cond};
use crate::sql::dir::{dir, Dir}; use crate::sql::dir::{dir, Dir};
use crate::sql::error::IResult; use crate::sql::error::IResult;
use crate::sql::field::Fields;
use crate::sql::group::Groups;
use crate::sql::idiom::{plain as idiom, Idiom}; use crate::sql::idiom::{plain as idiom, Idiom};
use crate::sql::limit::Limit;
use crate::sql::order::Orders;
use crate::sql::split::Splits;
use crate::sql::start::Start;
use crate::sql::table::{table, tables, Tables}; use crate::sql::table::{table, tables, Tables};
use nom::branch::alt; use nom::branch::alt;
use nom::bytes::complete::tag_no_case; use nom::bytes::complete::tag_no_case;
@ -16,8 +22,14 @@ use std::fmt::{self, Display, Formatter, Write};
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)] #[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
pub struct Graph { pub struct Graph {
pub dir: Dir, pub dir: Dir,
pub expr: Fields,
pub what: Tables, pub what: Tables,
pub cond: Option<Cond>, pub cond: Option<Cond>,
pub split: Option<Splits>,
pub group: Option<Groups>,
pub order: Option<Orders>,
pub limit: Option<Limit>,
pub start: Option<Start>,
pub alias: Option<Idiom>, pub alias: Option<Idiom>,
} }
@ -45,6 +57,21 @@ impl Display for Graph {
if let Some(ref v) = self.cond { if let Some(ref v) = self.cond {
write!(f, " {v}")? write!(f, " {v}")?
} }
if let Some(ref v) = self.split {
write!(f, " {v}")?
}
if let Some(ref v) = self.group {
write!(f, " {v}")?
}
if let Some(ref v) = self.order {
write!(f, " {v}")?
}
if let Some(ref v) = self.limit {
write!(f, " {v}")?
}
if let Some(ref v) = self.start {
write!(f, " {v}")?
}
if let Some(ref v) = self.alias { if let Some(ref v) = self.alias {
write!(f, " AS {v}")? write!(f, " AS {v}")?
} }
@ -60,9 +87,15 @@ pub fn graph(i: &str) -> IResult<&str, Graph> {
i, i,
Graph { Graph {
dir, dir,
expr: Fields::all(),
what, what,
cond, cond,
alias, alias,
split: None,
group: None,
order: None,
limit: None,
start: None,
}, },
)) ))
} }

View file

@ -245,6 +245,7 @@ mod tests {
use super::*; use super::*;
use crate::sql::dir::Dir; use crate::sql::dir::Dir;
use crate::sql::expression::Expression; use crate::sql::expression::Expression;
use crate::sql::field::Fields;
use crate::sql::graph::Graph; use crate::sql::graph::Graph;
use crate::sql::number::Number; use crate::sql::number::Number;
use crate::sql::param::Param; use crate::sql::param::Param;
@ -410,15 +411,27 @@ mod tests {
Part::from("friend"), Part::from("friend"),
Part::Graph(Graph { Part::Graph(Graph {
dir: Dir::Out, dir: Dir::Out,
expr: Fields::all(),
what: Table::from("like").into(), what: Table::from("like").into(),
cond: None, cond: None,
alias: None, alias: None,
split: None,
group: None,
order: None,
limit: None,
start: None,
}), }),
Part::Graph(Graph { Part::Graph(Graph {
dir: Dir::Out, dir: Dir::Out,
expr: Fields::all(),
what: Table::from("person").into(), what: Table::from("person").into(),
cond: None, cond: None,
alias: None, alias: None,
split: None,
group: None,
order: None,
limit: None,
start: None,
}), }),
]) ])
); );

View file

@ -1,4 +1,10 @@
use crate::err::Error; use crate::err::Error;
use crate::sql::field::Fields;
use crate::sql::group::Groups;
use crate::sql::limit::Limit;
use crate::sql::order::Orders;
use crate::sql::split::Splits;
use crate::sql::start::Start;
use crate::sql::value::serde::ser; use crate::sql::value::serde::ser;
use crate::sql::Cond; use crate::sql::Cond;
use crate::sql::Dir; use crate::sql::Dir;
@ -39,8 +45,14 @@ impl ser::Serializer for Serializer {
#[derive(Default)] #[derive(Default)]
pub(super) struct SerializeGraph { pub(super) struct SerializeGraph {
dir: Option<Dir>, dir: Option<Dir>,
expr: Option<Fields>,
what: Option<Tables>, what: Option<Tables>,
cond: Option<Cond>, cond: Option<Cond>,
split: Option<Splits>,
group: Option<Groups>,
order: Option<Orders>,
limit: Option<Limit>,
start: Option<Start>,
alias: Option<Idiom>, alias: Option<Idiom>,
} }
@ -56,12 +68,30 @@ impl serde::ser::SerializeStruct for SerializeGraph {
"dir" => { "dir" => {
self.dir = Some(value.serialize(ser::dir::Serializer.wrap())?); self.dir = Some(value.serialize(ser::dir::Serializer.wrap())?);
} }
"expr" => {
self.expr = Some(value.serialize(ser::fields::Serializer.wrap())?);
}
"what" => { "what" => {
self.what = Some(Tables(value.serialize(ser::table::vec::Serializer.wrap())?)); self.what = Some(Tables(value.serialize(ser::table::vec::Serializer.wrap())?));
} }
"cond" => { "cond" => {
self.cond = value.serialize(ser::cond::opt::Serializer.wrap())?; self.cond = value.serialize(ser::cond::opt::Serializer.wrap())?;
} }
"split" => {
self.split = value.serialize(ser::split::vec::opt::Serializer.wrap())?.map(Splits);
}
"group" => {
self.group = value.serialize(ser::group::vec::opt::Serializer.wrap())?.map(Groups);
}
"order" => {
self.order = value.serialize(ser::order::vec::opt::Serializer.wrap())?.map(Orders);
}
"limit" => {
self.limit = value.serialize(ser::limit::opt::Serializer.wrap())?;
}
"start" => {
self.start = value.serialize(ser::start::opt::Serializer.wrap())?;
}
"alias" => { "alias" => {
self.alias = value.serialize(ser::part::vec::opt::Serializer.wrap())?.map(Idiom); self.alias = value.serialize(ser::part::vec::opt::Serializer.wrap())?.map(Idiom);
} }
@ -73,11 +103,17 @@ impl serde::ser::SerializeStruct for SerializeGraph {
} }
fn end(self) -> Result<Self::Ok, Error> { fn end(self) -> Result<Self::Ok, Error> {
match (self.dir, self.what) { match (self.dir, self.expr, self.what) {
(Some(dir), Some(what)) => Ok(Graph { (Some(dir), Some(expr), Some(what)) => Ok(Graph {
dir, dir,
expr,
what, what,
cond: self.cond, cond: self.cond,
split: self.split,
group: self.group,
order: self.order,
limit: self.limit,
start: self.start,
alias: self.alias, alias: self.alias,
}), }),
_ => Err(Error::custom("`Graph` missing required field(s)")), _ => Err(Error::custom("`Graph` missing required field(s)")),