diff --git a/lib/src/sql/ending.rs b/lib/src/sql/ending.rs index b7500fb0..67d55288 100644 --- a/lib/src/sql/ending.rs +++ b/lib/src/sql/ending.rs @@ -1,13 +1,16 @@ use crate::sql::comment::comment; +use crate::sql::comment::shouldbespace; use crate::sql::error::IResult; use crate::sql::operator::{assigner, operator}; use nom::branch::alt; use nom::bytes::complete::tag; +use nom::bytes::complete::tag_no_case; use nom::character::complete::char; use nom::character::complete::multispace1; use nom::combinator::eof; use nom::combinator::map; use nom::combinator::peek; +use nom::sequence::preceded; pub fn number(i: &str) -> IResult<&str, ()> { peek(alt(( @@ -62,3 +65,17 @@ pub fn duration(i: &str) -> IResult<&str, ()> { map(eof, |_| ()), )))(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) +} diff --git a/lib/src/sql/subquery.rs b/lib/src/sql/subquery.rs index 80896776..ff214089 100644 --- a/lib/src/sql/subquery.rs +++ b/lib/src/sql/subquery.rs @@ -3,6 +3,7 @@ use crate::dbs::Options; use crate::dbs::Transaction; use crate::err::Error; use crate::sql::comment::mightbespace; +use crate::sql::ending::subquery as ending; use crate::sql::error::IResult; use crate::sql::statements::create::{create, CreateStatement}; use crate::sql::statements::delete::{delete, DeleteStatement}; @@ -222,7 +223,7 @@ impl Display for 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> { @@ -230,10 +231,35 @@ fn subquery_ifelse(i: &str) -> IResult<&str, Subquery> { 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, _) = 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(select, Subquery::Select), map(create, Subquery::Create), @@ -241,11 +267,7 @@ fn subquery_others(i: &str) -> IResult<&str, Subquery> { map(delete, Subquery::Delete), map(relate, Subquery::Relate), map(insert, Subquery::Insert), - map(value, Subquery::Value), - ))(i)?; - let (i, _) = mightbespace(i)?; - let (i, _) = char(')')(i)?; - Ok((i, v)) + ))(i) } #[cfg(test)] diff --git a/lib/tests/subquery.rs b/lib/tests/subquery.rs index f683b55e..73c96f31 100644 --- a/lib/tests/subquery.rs +++ b/lib/tests/subquery.rs @@ -110,19 +110,19 @@ async fn subquery_ifelse() -> Result<(), Error> { RETURN $record; -- Update the record field if it exists IF $record.count THEN - ( UPDATE person:test SET sport += 'football' RETURN sport ) + (UPDATE person:test SET sport += 'football' RETURN sport) ELSE - ( UPDATE person:test SET sport = ['basketball'] RETURN sport ) + (UPDATE person:test SET sport = ['basketball'] RETURN sport) END; -- 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 $record; -- Update the record field if it exists IF $record.count THEN - ( UPDATE person:test SET sport += 'football' RETURN sport ) + UPDATE person:test SET sport += 'football' RETURN sport ELSE - ( UPDATE person:test SET sport = ['basketball'] RETURN sport ) + UPDATE person:test SET sport = ['basketball'] RETURN sport END; "; let dbs = Datastore::new("memory").await?;