surrealpatch/lib/src/sql/subquery.rs

331 lines
9.2 KiB
Rust
Raw Normal View History

2021-03-29 15:43:37 +00:00
use crate::ctx::Context;
use crate::dbs::Options;
use crate::dbs::Transaction;
2021-03-29 15:43:37 +00:00
use crate::err::Error;
use crate::sql::comment::mightbespace;
use crate::sql::ending::subquery as ending;
2022-01-16 20:31:50 +00:00
use crate::sql::error::IResult;
use crate::sql::serde::is_internal_serialization;
2020-06-29 15:36:01 +00:00
use crate::sql::statements::create::{create, CreateStatement};
use crate::sql::statements::delete::{delete, DeleteStatement};
use crate::sql::statements::ifelse::{ifelse, IfelseStatement};
use crate::sql::statements::insert::{insert, InsertStatement};
use crate::sql::statements::output::{output, OutputStatement};
2020-06-29 15:36:01 +00:00
use crate::sql::statements::relate::{relate, RelateStatement};
use crate::sql::statements::select::{select, SelectStatement};
use crate::sql::statements::update::{update, UpdateStatement};
use crate::sql::value::{value, Value};
2020-06-29 15:36:01 +00:00
use nom::branch::alt;
use nom::character::complete::char;
2020-06-29 15:36:01 +00:00
use nom::combinator::map;
use serde::{Deserialize, Serialize};
2021-03-29 15:43:37 +00:00
use std::cmp::Ordering;
use std::fmt::{self, Display, Formatter};
2020-06-29 15:36:01 +00:00
pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Subquery";
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Hash)]
2020-06-29 15:36:01 +00:00
pub enum Subquery {
Value(Value),
2020-06-29 15:36:01 +00:00
Ifelse(IfelseStatement),
Output(OutputStatement),
Select(SelectStatement),
Create(CreateStatement),
Update(UpdateStatement),
Delete(DeleteStatement),
Relate(RelateStatement),
Insert(InsertStatement),
2020-06-29 15:36:01 +00:00
}
2021-03-29 15:43:37 +00:00
impl PartialOrd for Subquery {
#[inline]
fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
2022-03-23 11:56:39 +00:00
None
2021-03-29 15:43:37 +00:00
}
}
2022-01-14 08:12:56 +00:00
impl Subquery {
pub(crate) fn writeable(&self) -> bool {
match self {
Self::Value(v) => v.writeable(),
Self::Ifelse(v) => v.writeable(),
Self::Output(v) => v.writeable(),
Self::Select(v) => v.writeable(),
Self::Create(v) => v.writeable(),
Self::Update(v) => v.writeable(),
Self::Delete(v) => v.writeable(),
Self::Relate(v) => v.writeable(),
Self::Insert(v) => v.writeable(),
}
}
pub(crate) async fn compute(
2021-03-29 15:43:37 +00:00
&self,
ctx: &Context<'_>,
opt: &Options,
txn: &Transaction,
doc: Option<&Value>,
) -> Result<Value, Error> {
// Prevent deep recursion
let opt = &opt.dive(2)?;
// Process the subquery
2021-03-29 15:43:37 +00:00
match self {
Self::Value(ref v) => v.compute(ctx, opt, txn, doc).await,
Self::Ifelse(ref v) => v.compute(ctx, opt, txn, doc).await,
Self::Output(ref v) => v.compute(ctx, opt, txn, doc).await,
Self::Select(ref v) => {
// Is this a single output?
let one = v.single();
// Duplicate context
2021-03-29 15:43:37 +00:00
let mut ctx = Context::new(ctx);
// Add parent document
if let Some(doc) = doc {
2022-04-04 22:23:31 +00:00
ctx.add_value("parent".into(), doc);
2021-03-29 15:43:37 +00:00
}
// Process subquery
match v.compute(&ctx, opt, txn, doc).await? {
// This is a single record result
Value::Array(mut a) if one => match a.len() {
// There was at least one result
v if v > 0 => Ok(a.remove(0)),
// There were no results
_ => Ok(Value::None),
},
// This is standard query result
v => Ok(v),
}
2021-03-29 15:43:37 +00:00
}
Self::Create(ref v) => {
// Is this a single output?
let one = v.single();
// Duplicate context
2021-03-29 15:43:37 +00:00
let mut ctx = Context::new(ctx);
// Add parent document
if let Some(doc) = doc {
2022-04-04 22:23:31 +00:00
ctx.add_value("parent".into(), doc);
2021-03-29 15:43:37 +00:00
}
// Process subquery
match v.compute(&ctx, opt, txn, doc).await? {
// This is a single record result
Value::Array(mut a) if one => match a.len() {
// There was at least one result
v if v > 0 => Ok(a.remove(0)),
// There were no results
_ => Ok(Value::None),
},
// This is standard query result
v => Ok(v),
}
2021-03-29 15:43:37 +00:00
}
Self::Update(ref v) => {
// Is this a single output?
let one = v.single();
// Duplicate context
2021-03-29 15:43:37 +00:00
let mut ctx = Context::new(ctx);
// Add parent document
if let Some(doc) = doc {
2022-04-04 22:23:31 +00:00
ctx.add_value("parent".into(), doc);
2021-03-29 15:43:37 +00:00
}
// Process subquery
match v.compute(&ctx, opt, txn, doc).await? {
// This is a single record result
Value::Array(mut a) if one => match a.len() {
// There was at least one result
v if v > 0 => Ok(a.remove(0)),
// There were no results
_ => Ok(Value::None),
},
// This is standard query result
v => Ok(v),
}
2021-03-29 15:43:37 +00:00
}
Self::Delete(ref v) => {
// Is this a single output?
let one = v.single();
// Duplicate context
2021-03-29 15:43:37 +00:00
let mut ctx = Context::new(ctx);
// Add parent document
if let Some(doc) = doc {
2022-04-04 22:23:31 +00:00
ctx.add_value("parent".into(), doc);
2021-03-29 15:43:37 +00:00
}
// Process subquery
match v.compute(&ctx, opt, txn, doc).await? {
// This is a single record result
Value::Array(mut a) if one => match a.len() {
// There was at least one result
v if v > 0 => Ok(a.remove(0)),
// There were no results
_ => Ok(Value::None),
},
// This is standard query result
v => Ok(v),
}
2021-03-29 15:43:37 +00:00
}
Self::Relate(ref v) => {
// Is this a single output?
let one = v.single();
// Duplicate context
2021-03-29 15:43:37 +00:00
let mut ctx = Context::new(ctx);
// Add parent document
if let Some(doc) = doc {
2022-04-04 22:23:31 +00:00
ctx.add_value("parent".into(), doc);
2021-03-29 15:43:37 +00:00
}
// Process subquery
match v.compute(&ctx, opt, txn, doc).await? {
// This is a single record result
Value::Array(mut a) if one => match a.len() {
// There was at least one result
v if v > 0 => Ok(a.remove(0)),
// There were no results
_ => Ok(Value::None),
},
// This is standard query result
v => Ok(v),
}
2021-03-29 15:43:37 +00:00
}
Self::Insert(ref v) => {
// Is this a single output?
let one = v.single();
// Duplicate context
2021-03-29 15:43:37 +00:00
let mut ctx = Context::new(ctx);
// Add parent document
if let Some(doc) = doc {
2022-04-04 22:23:31 +00:00
ctx.add_value("parent".into(), doc);
2021-03-29 15:43:37 +00:00
}
// Process subquery
match v.compute(&ctx, opt, txn, doc).await? {
// This is a single record result
Value::Array(mut a) if one => match a.len() {
// There was at least one result
v if v > 0 => Ok(a.remove(0)),
// There were no results
_ => Ok(Value::None),
},
// This is standard query result
v => Ok(v),
2021-03-29 15:43:37 +00:00
}
}
}
}
}
impl Display for Subquery {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
2022-01-14 08:12:56 +00:00
match self {
2023-02-03 11:47:07 +00:00
Self::Value(v) => write!(f, "({v})"),
Self::Output(v) => write!(f, "({v})"),
2023-02-03 11:47:07 +00:00
Self::Select(v) => write!(f, "({v})"),
Self::Create(v) => write!(f, "({v})"),
Self::Update(v) => write!(f, "({v})"),
Self::Delete(v) => write!(f, "({v})"),
Self::Relate(v) => write!(f, "({v})"),
Self::Insert(v) => write!(f, "({v})"),
Self::Ifelse(v) => Display::fmt(v, f),
2022-01-14 08:12:56 +00:00
}
}
}
impl Serialize for Subquery {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
if is_internal_serialization() {
match self {
Self::Value(v) => serializer.serialize_newtype_variant(TOKEN, 0, "Value", v),
Self::Ifelse(v) => serializer.serialize_newtype_variant(TOKEN, 1, "Ifelse", v),
Self::Output(v) => serializer.serialize_newtype_variant(TOKEN, 2, "Output", v),
Self::Select(v) => serializer.serialize_newtype_variant(TOKEN, 3, "Select", v),
Self::Create(v) => serializer.serialize_newtype_variant(TOKEN, 4, "Create", v),
Self::Update(v) => serializer.serialize_newtype_variant(TOKEN, 5, "Update", v),
Self::Delete(v) => serializer.serialize_newtype_variant(TOKEN, 6, "Delete", v),
Self::Relate(v) => serializer.serialize_newtype_variant(TOKEN, 7, "Relate", v),
Self::Insert(v) => serializer.serialize_newtype_variant(TOKEN, 8, "Insert", v),
}
} else {
serializer.serialize_none()
}
}
}
2020-06-29 15:36:01 +00:00
pub fn subquery(i: &str) -> IResult<&str, Subquery> {
alt((subquery_ifelse, subquery_other, subquery_value))(i)
2020-06-29 15:36:01 +00:00
}
fn subquery_ifelse(i: &str) -> IResult<&str, Subquery> {
let (i, v) = map(ifelse, Subquery::Ifelse)(i)?;
2020-06-29 15:36:01 +00:00
Ok((i, v))
}
fn subquery_value(i: &str) -> IResult<&str, Subquery> {
let (i, _) = char('(')(i)?;
let (i, _) = mightbespace(i)?;
let (i, v) = map(value, Subquery::Value)(i)?;
let (i, _) = mightbespace(i)?;
let (i, _) = char(')')(i)?;
Ok((i, v))
}
fn subquery_other(i: &str) -> IResult<&str, Subquery> {
alt((
|i| {
let (i, _) = char('(')(i)?;
let (i, _) = mightbespace(i)?;
let (i, v) = subquery_inner(i)?;
let (i, _) = mightbespace(i)?;
let (i, _) = char(')')(i)?;
Ok((i, v))
},
|i| {
let (i, v) = subquery_inner(i)?;
let (i, _) = ending(i)?;
Ok((i, v))
},
))(i)
}
fn subquery_inner(i: &str) -> IResult<&str, Subquery> {
alt((
map(output, Subquery::Output),
map(select, Subquery::Select),
map(create, Subquery::Create),
map(update, Subquery::Update),
map(delete, Subquery::Delete),
map(relate, Subquery::Relate),
map(insert, Subquery::Insert),
))(i)
2020-06-29 15:36:01 +00:00
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn subquery_expression_statement() {
let sql = "(1 + 2 + 3)";
let res = subquery(sql);
assert!(res.is_ok());
let out = res.unwrap().1;
assert_eq!("(1 + 2 + 3)", format!("{}", out))
}
#[test]
fn subquery_ifelse_statement() {
let sql = "IF true THEN false END";
let res = subquery(sql);
assert!(res.is_ok());
let out = res.unwrap().1;
assert_eq!("IF true THEN false END", format!("{}", out))
}
#[test]
fn subquery_select_statement() {
let sql = "(SELECT * FROM test)";
let res = subquery(sql);
assert!(res.is_ok());
let out = res.unwrap().1;
assert_eq!("(SELECT * FROM test)", format!("{}", out))
}
}