Allow raw SQL subqueries without surrounding brackets

Related to #247
Related to #225
Related to #1319
This commit is contained in:
Tobie Morgan Hitchcock 2023-02-20 14:24:37 +00:00
parent 275cf18a3a
commit 185eb91f22
3 changed files with 52 additions and 13 deletions

View file

@ -1,13 +1,16 @@
use crate::sql::comment::comment; use crate::sql::comment::comment;
use crate::sql::comment::shouldbespace;
use crate::sql::error::IResult; use crate::sql::error::IResult;
use crate::sql::operator::{assigner, operator}; use crate::sql::operator::{assigner, operator};
use nom::branch::alt; use nom::branch::alt;
use nom::bytes::complete::tag; use nom::bytes::complete::tag;
use nom::bytes::complete::tag_no_case;
use nom::character::complete::char; use nom::character::complete::char;
use nom::character::complete::multispace1; use nom::character::complete::multispace1;
use nom::combinator::eof; use nom::combinator::eof;
use nom::combinator::map; use nom::combinator::map;
use nom::combinator::peek; use nom::combinator::peek;
use nom::sequence::preceded;
pub fn number(i: &str) -> IResult<&str, ()> { pub fn number(i: &str) -> IResult<&str, ()> {
peek(alt(( peek(alt((
@ -62,3 +65,17 @@ pub fn duration(i: &str) -> IResult<&str, ()> {
map(eof, |_| ()), map(eof, |_| ()),
)))(i) )))(i)
} }
pub fn subquery(i: &str) -> IResult<&str, ()> {
peek(alt((
map(preceded(shouldbespace, tag_no_case("THEN")), |_| ()),
map(preceded(shouldbespace, tag_no_case("ELSE")), |_| ()),
map(preceded(shouldbespace, tag_no_case("END")), |_| ()),
map(comment, |_| ()),
map(char(']'), |_| ()),
map(char('}'), |_| ()),
map(char(';'), |_| ()),
map(char(','), |_| ()),
map(eof, |_| ()),
)))(i)
}

View file

@ -3,6 +3,7 @@ use crate::dbs::Options;
use crate::dbs::Transaction; use crate::dbs::Transaction;
use crate::err::Error; use crate::err::Error;
use crate::sql::comment::mightbespace; use crate::sql::comment::mightbespace;
use crate::sql::ending::subquery as ending;
use crate::sql::error::IResult; use crate::sql::error::IResult;
use crate::sql::statements::create::{create, CreateStatement}; use crate::sql::statements::create::{create, CreateStatement};
use crate::sql::statements::delete::{delete, DeleteStatement}; use crate::sql::statements::delete::{delete, DeleteStatement};
@ -222,7 +223,7 @@ impl Display for Subquery {
} }
pub fn subquery(i: &str) -> IResult<&str, Subquery> { pub fn subquery(i: &str) -> IResult<&str, Subquery> {
alt((subquery_ifelse, subquery_others))(i) alt((subquery_ifelse, subquery_other, subquery_value))(i)
} }
fn subquery_ifelse(i: &str) -> IResult<&str, Subquery> { fn subquery_ifelse(i: &str) -> IResult<&str, Subquery> {
@ -230,10 +231,35 @@ fn subquery_ifelse(i: &str) -> IResult<&str, Subquery> {
Ok((i, v)) Ok((i, v))
} }
fn subquery_others(i: &str) -> IResult<&str, Subquery> { fn subquery_value(i: &str) -> IResult<&str, Subquery> {
let (i, _) = char('(')(i)?; let (i, _) = char('(')(i)?;
let (i, _) = mightbespace(i)?; let (i, _) = mightbespace(i)?;
let (i, v) = alt(( 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(output, Subquery::Output),
map(select, Subquery::Select), map(select, Subquery::Select),
map(create, Subquery::Create), map(create, Subquery::Create),
@ -241,11 +267,7 @@ fn subquery_others(i: &str) -> IResult<&str, Subquery> {
map(delete, Subquery::Delete), map(delete, Subquery::Delete),
map(relate, Subquery::Relate), map(relate, Subquery::Relate),
map(insert, Subquery::Insert), map(insert, Subquery::Insert),
map(value, Subquery::Value), ))(i)
))(i)?;
let (i, _) = mightbespace(i)?;
let (i, _) = char(')')(i)?;
Ok((i, v))
} }
#[cfg(test)] #[cfg(test)]

View file

@ -110,19 +110,19 @@ async fn subquery_ifelse() -> Result<(), Error> {
RETURN $record; RETURN $record;
-- Update the record field if it exists -- Update the record field if it exists
IF $record.count THEN IF $record.count THEN
( UPDATE person:test SET sport += 'football' RETURN sport ) (UPDATE person:test SET sport += 'football' RETURN sport)
ELSE ELSE
( UPDATE person:test SET sport = ['basketball'] RETURN sport ) (UPDATE person:test SET sport = ['basketball'] RETURN sport)
END; END;
-- Check if the record exists -- Check if the record exists
LET $record = (SELECT *, count() AS count FROM person:test); LET $record = SELECT *, count() AS count FROM person:test;
-- Return the specified record -- Return the specified record
RETURN $record; RETURN $record;
-- Update the record field if it exists -- Update the record field if it exists
IF $record.count THEN IF $record.count THEN
( UPDATE person:test SET sport += 'football' RETURN sport ) UPDATE person:test SET sport += 'football' RETURN sport
ELSE ELSE
( UPDATE person:test SET sport = ['basketball'] RETURN sport ) UPDATE person:test SET sport = ['basketball'] RETURN sport
END; END;
"; ";
let dbs = Datastore::new("memory").await?; let dbs = Datastore::new("memory").await?;