From 0a328d4f0afd99b51aa76b736a9f1be911e5c48d Mon Sep 17 00:00:00 2001 From: Tobie Morgan Hitchcock Date: Fri, 31 Mar 2023 18:50:11 +0100 Subject: [PATCH] Add initial support for additional functionality in graph expressions Related to #1658 --- lib/src/sql/field.rs | 10 ++++-- lib/src/sql/graph.rs | 33 +++++++++++++++++++ lib/src/sql/idiom.rs | 13 ++++++++ lib/src/sql/value/serde/ser/graph/mod.rs | 40 ++++++++++++++++++++++-- 4 files changed, 92 insertions(+), 4 deletions(-) diff --git a/lib/src/sql/field.rs b/lib/src/sql/field.rs index 4de3bc16..646961c2 100644 --- a/lib/src/sql/field.rs +++ b/lib/src/sql/field.rs @@ -21,12 +21,18 @@ use std::ops::Deref; pub struct Fields(pub Vec, pub bool); 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)) } + /// 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() { @@ -77,7 +83,7 @@ impl Fields { // let doc = doc.unwrap_or(&Value::None); // 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?, false => Value::base(), }; diff --git a/lib/src/sql/graph.rs b/lib/src/sql/graph.rs index 0a0a7e3a..719b0db0 100644 --- a/lib/src/sql/graph.rs +++ b/lib/src/sql/graph.rs @@ -3,7 +3,13 @@ use crate::sql::comment::shouldbespace; use crate::sql::cond::{cond, Cond}; use crate::sql::dir::{dir, Dir}; 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::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 nom::branch::alt; 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)] pub struct Graph { pub dir: Dir, + pub expr: Fields, pub what: Tables, pub cond: Option, + pub split: Option, + pub group: Option, + pub order: Option, + pub limit: Option, + pub start: Option, pub alias: Option, } @@ -45,6 +57,21 @@ impl Display for Graph { if let Some(ref v) = self.cond { 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 { write!(f, " AS {v}")? } @@ -60,9 +87,15 @@ pub fn graph(i: &str) -> IResult<&str, Graph> { i, Graph { dir, + expr: Fields::all(), what, cond, alias, + split: None, + group: None, + order: None, + limit: None, + start: None, }, )) } diff --git a/lib/src/sql/idiom.rs b/lib/src/sql/idiom.rs index a415a155..3ee77fe9 100644 --- a/lib/src/sql/idiom.rs +++ b/lib/src/sql/idiom.rs @@ -245,6 +245,7 @@ mod tests { use super::*; use crate::sql::dir::Dir; use crate::sql::expression::Expression; + use crate::sql::field::Fields; use crate::sql::graph::Graph; use crate::sql::number::Number; use crate::sql::param::Param; @@ -410,15 +411,27 @@ mod tests { Part::from("friend"), Part::Graph(Graph { dir: Dir::Out, + expr: Fields::all(), what: Table::from("like").into(), cond: None, alias: None, + split: None, + group: None, + order: None, + limit: None, + start: None, }), Part::Graph(Graph { dir: Dir::Out, + expr: Fields::all(), what: Table::from("person").into(), cond: None, alias: None, + split: None, + group: None, + order: None, + limit: None, + start: None, }), ]) ); diff --git a/lib/src/sql/value/serde/ser/graph/mod.rs b/lib/src/sql/value/serde/ser/graph/mod.rs index f0b4425d..d963da07 100644 --- a/lib/src/sql/value/serde/ser/graph/mod.rs +++ b/lib/src/sql/value/serde/ser/graph/mod.rs @@ -1,4 +1,10 @@ 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::Cond; use crate::sql::Dir; @@ -39,8 +45,14 @@ impl ser::Serializer for Serializer { #[derive(Default)] pub(super) struct SerializeGraph { dir: Option, + expr: Option, what: Option, cond: Option, + split: Option, + group: Option, + order: Option, + limit: Option, + start: Option, alias: Option, } @@ -56,12 +68,30 @@ impl serde::ser::SerializeStruct for SerializeGraph { "dir" => { self.dir = Some(value.serialize(ser::dir::Serializer.wrap())?); } + "expr" => { + self.expr = Some(value.serialize(ser::fields::Serializer.wrap())?); + } "what" => { self.what = Some(Tables(value.serialize(ser::table::vec::Serializer.wrap())?)); } "cond" => { 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" => { 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 { - match (self.dir, self.what) { - (Some(dir), Some(what)) => Ok(Graph { + match (self.dir, self.expr, self.what) { + (Some(dir), Some(expr), Some(what)) => Ok(Graph { dir, + expr, what, cond: self.cond, + split: self.split, + group: self.group, + order: self.order, + limit: self.limit, + start: self.start, alias: self.alias, }), _ => Err(Error::custom("`Graph` missing required field(s)")),