feophant 0.9.0

A SQL database server written in Rust and inspired by PostreSQL
Documentation
use nom::{
    bytes::complete::tag_no_case,
    combinator::cut,
    error::{ContextError, ParseError},
    multi::separated_list0,
    sequence::tuple,
    IResult,
};

use crate::engine::objects::{ParseTree, RawSelectCommand};

use super::common::{
    match_column_name, match_comma, maybe_take_whitespace, parse_sql_identifier, take_whitespace,
};

pub(super) fn parse_select<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
    input: &'a str,
) -> IResult<&'a str, ParseTree, E> {
    let (input, (_, (columns, _, _, table))) = tuple((
        match_select,
        cut(tuple((
            separated_list0(match_comma, match_column_name),
            maybe_take_whitespace,
            match_from,
            parse_sql_identifier,
        ))),
    ))(input)?;

    let raw_sel = RawSelectCommand {
        table: table.to_string(),
        columns,
    };

    Ok((input, ParseTree::Select(raw_sel)))
}

pub(super) fn match_select<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
    input: &'a str,
) -> IResult<&'a str, (), E> {
    let (input, (_, _)) = tuple((tag_no_case("select"), take_whitespace))(input)?;
    Ok((input, ()))
}

pub(super) fn match_from<'a, E: ParseError<&'a str> + ContextError<&'a str>>(
    input: &'a str,
) -> IResult<&'a str, (), E> {
    let (input, (_, _)) = tuple((tag_no_case("from"), take_whitespace))(input)?;
    Ok((input, ()))
}

#[cfg(test)]
mod tests {
    use nom::error::VerboseError;

    use crate::engine::objects::RawSelectCommand;

    use super::*;

    #[test]
    fn test_select_parser() -> Result<(), Box<dyn std::error::Error>> {
        let test = "select foo, bar from baz";

        let (output, value) = parse_select::<VerboseError<&str>>(test)?;

        let value = match value {
            ParseTree::Select(s) => s,
            _ => panic!("Wrong type"),
        };
        assert_eq!(output.len(), 0);

        let expected = RawSelectCommand {
            table: "baz".to_string(),
            columns: vec!["foo".to_string(), "bar".to_string()],
        };
        assert_eq!(expected, value);

        Ok(())
    }
}