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);
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<Item = &Field> {
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(),
};

View file

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

View file

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

View file

@ -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<Dir>,
expr: Option<Fields>,
what: Option<Tables>,
cond: Option<Cond>,
split: Option<Splits>,
group: Option<Groups>,
order: Option<Orders>,
limit: Option<Limit>,
start: Option<Start>,
alias: Option<Idiom>,
}
@ -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<Self::Ok, Error> {
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)")),