Improve graph traversal expression parsing code

This commit is contained in:
Tobie Morgan Hitchcock 2022-06-08 19:50:29 +01:00
parent 1333ecf0df
commit 8ce5d01727

View file

@ -1,10 +1,10 @@
use crate::sql::comment::mightbespace;
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::idiom::{idiom, Idiom};
use crate::sql::table::{table, tables, Tables};
use crate::sql::value::{value, Value};
use nom::branch::alt;
use nom::bytes::complete::tag_no_case;
use nom::character::complete::char;
@ -17,7 +17,7 @@ use std::fmt;
pub struct Graph {
pub dir: Dir,
pub what: Tables,
pub cond: Option<Value>,
pub cond: Option<Cond>,
pub alias: Option<Idiom>,
}
@ -36,7 +36,7 @@ impl fmt::Display for Graph {
_ => write!(f, "{}", self.what),
}?;
if let Some(ref v) = self.cond {
write!(f, " WHERE {}", v)?
write!(f, " {}", v)?
}
if let Some(ref v) = self.alias {
write!(f, " AS {}", v)?
@ -47,17 +47,12 @@ impl fmt::Display for Graph {
}
pub fn graph(i: &str) -> IResult<&str, Graph> {
alt((graph_in, graph_out, graph_both))(i)
}
fn graph_in(i: &str) -> IResult<&str, Graph> {
let (i, _) = char('<')(i)?;
let (i, _) = char('-')(i)?;
let (i, dir) = dir(i)?;
let (i, (what, cond, alias)) = alt((simple, custom))(i)?;
Ok((
i,
Graph {
dir: Dir::In,
dir,
what,
cond,
alias,
@ -65,83 +60,41 @@ fn graph_in(i: &str) -> IResult<&str, Graph> {
))
}
fn graph_out(i: &str) -> IResult<&str, Graph> {
let (i, _) = char('-')(i)?;
let (i, _) = char('>')(i)?;
let (i, (what, cond, alias)) = alt((simple, custom))(i)?;
Ok((
i,
Graph {
dir: Dir::Out,
what,
cond,
alias,
},
))
}
fn graph_both(i: &str) -> IResult<&str, Graph> {
let (i, _) = char('<')(i)?;
let (i, _) = char('-')(i)?;
let (i, _) = char('>')(i)?;
let (i, (what, cond, alias)) = alt((simple, custom))(i)?;
Ok((
i,
Graph {
dir: Dir::Both,
what,
cond,
alias,
},
))
}
fn simple(i: &str) -> IResult<&str, (Tables, Option<Value>, Option<Idiom>)> {
let (i, w) = alt((any, single))(i)?;
fn simple(i: &str) -> IResult<&str, (Tables, Option<Cond>, Option<Idiom>)> {
let (i, w) = alt((any, one))(i)?;
Ok((i, (w, None, None)))
}
fn custom(i: &str) -> IResult<&str, (Tables, Option<Value>, Option<Idiom>)> {
fn custom(i: &str) -> IResult<&str, (Tables, Option<Cond>, Option<Idiom>)> {
let (i, _) = char('(')(i)?;
let (i, _) = mightbespace(i)?;
let (i, w) = alt((any, multi))(i)?;
let (i, c) = opt(cond)(i)?;
let (i, a) = opt(alias)(i)?;
let (i, w) = alt((any, tables))(i)?;
let (i, c) = opt(|i| {
let (i, _) = shouldbespace(i)?;
let (i, v) = cond(i)?;
Ok((i, v))
})(i)?;
let (i, a) = opt(|i| {
let (i, _) = shouldbespace(i)?;
let (i, _) = tag_no_case("AS")(i)?;
let (i, _) = shouldbespace(i)?;
let (i, v) = idiom(i)?;
Ok((i, v))
})(i)?;
let (i, _) = mightbespace(i)?;
let (i, _) = char(')')(i)?;
Ok((i, (w, c, a)))
}
fn single(i: &str) -> IResult<&str, Tables> {
fn one(i: &str) -> IResult<&str, Tables> {
let (i, v) = table(i)?;
Ok((i, Tables::from(v)))
}
fn multi(i: &str) -> IResult<&str, Tables> {
let (i, v) = tables(i)?;
Ok((i, Tables::from(v)))
}
fn any(i: &str) -> IResult<&str, Tables> {
map(char('?'), |_| Tables::default())(i)
}
fn cond(i: &str) -> IResult<&str, Value> {
let (i, _) = shouldbespace(i)?;
let (i, _) = tag_no_case("WHERE")(i)?;
let (i, _) = shouldbespace(i)?;
let (i, v) = value(i)?;
Ok((i, v))
}
fn alias(i: &str) -> IResult<&str, Idiom> {
let (i, _) = shouldbespace(i)?;
let (i, _) = tag_no_case("AS")(i)?;
let (i, _) = shouldbespace(i)?;
let (i, v) = idiom(i)?;
Ok((i, v))
}
#[cfg(test)]
mod tests {