Add option type and option value parsers value->literal in parser, implement Option literal
143 lines
4.2 KiB
Rust
143 lines
4.2 KiB
Rust
use minisql::type_system::DbType;
|
|
use nom::{
|
|
branch::alt, bytes::complete::{tag, take_while}, character::{complete::{alphanumeric1, anychar, char, multispace0, multispace1}, is_alphanumeric}, combinator::peek, error::make_error, sequence::{delimited, terminated}, IResult, Parser
|
|
};
|
|
|
|
use crate::syntax::Condition;
|
|
use super::literal::parse_literal;
|
|
|
|
pub fn parse_table_name(input: &str) -> IResult<&str, &str> {
|
|
alt((
|
|
delimited(char('"'), alphanumeric1, char('"')),
|
|
parse_identifier,
|
|
))(input)
|
|
}
|
|
|
|
pub fn parse_identifier(input: &str) -> IResult<&str, &str> {
|
|
let (_, first) = peek(anychar)(input)?;
|
|
if first.is_alphabetic() || first == '_' {
|
|
take_while(|c: char| {
|
|
is_alphanumeric(c as u8) || c == '_'
|
|
})(input)
|
|
} else {
|
|
Err(nom::Err::Error(make_error(
|
|
input,
|
|
nom::error::ErrorKind::Alpha,
|
|
)))
|
|
}
|
|
}
|
|
|
|
pub fn parse_column_name(input: &str) -> IResult<&str, String> {
|
|
terminated(parse_identifier, multispace0)(input).map(|(rest, name)| (rest, name.to_string()))
|
|
}
|
|
|
|
pub fn parse_db_type(input: &str) -> IResult<&str, DbType> {
|
|
let (input, db_type) = alt(
|
|
(
|
|
tag("STRING")
|
|
.map(|_| DbType::String),
|
|
tag("INT")
|
|
.map(|_| DbType::Int),
|
|
tag("NUMBER")
|
|
.map(|_| DbType::Number),
|
|
tag("UUID")
|
|
.map(|_| DbType::Uuid),
|
|
delimited(tag("Option("), parse_db_type, tag(")"))
|
|
.map(|ty| {
|
|
DbType::Option(Box::new(ty))
|
|
})
|
|
)
|
|
)(input)?;
|
|
Ok((input, db_type))
|
|
}
|
|
|
|
pub fn parse_condition(input: &str) -> IResult<&str, Option<Condition>> {
|
|
match tag::<&str, &str, nom::error::Error<&str>>("WHERE")(input) {
|
|
Ok((input, _)) => {
|
|
let (input, _) = multispace1(input)?;
|
|
let (input, condition) = parse_equality(input)?;
|
|
Ok((input, Some(condition)))
|
|
}
|
|
Err(_) => Ok((input, None)),
|
|
}
|
|
}
|
|
|
|
fn parse_equality(input: &str) -> IResult<&str, Condition> {
|
|
let (input, column_name) = parse_column_name(input)?;
|
|
let (input, _) = multispace0(input)?;
|
|
let (input, _) = char('=')(input)?;
|
|
let (input, _) = multispace0(input)?;
|
|
let (input, lit) = parse_literal(input)?;
|
|
Ok((input, Condition::Eq(column_name, lit)))
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use minisql::type_system::DbType;
|
|
|
|
use crate::parsing::common::{parse_db_type, parse_equality, parse_identifier};
|
|
use crate::parsing::literal::Literal;
|
|
use crate::syntax::Condition;
|
|
|
|
#[test]
|
|
fn test_parse_equality() {
|
|
match parse_equality("id = 1") {
|
|
Ok(("", Condition::Eq(column_name, value))) => {
|
|
assert!(column_name.eq("id"));
|
|
assert_eq!(value, Literal::Int(1))
|
|
}
|
|
_ => {
|
|
panic!("should parse");
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_parse_db_type() {
|
|
assert!(matches!(
|
|
parse_db_type("INT").expect("should parse").1,
|
|
DbType::Int
|
|
));
|
|
assert!(matches!(
|
|
parse_db_type("STRING").expect("should parse").1,
|
|
DbType::String
|
|
));
|
|
assert!(matches!(
|
|
parse_db_type("UUID").expect("should parse").1,
|
|
DbType::Uuid
|
|
));
|
|
assert!(matches!(
|
|
parse_db_type("NUMBER").expect("should parse").1,
|
|
DbType::Number
|
|
));
|
|
assert!(matches!(parse_db_type("Unknown"), Err(_)));
|
|
}
|
|
|
|
#[test]
|
|
fn test_parse_identifier() {
|
|
assert_eq!(
|
|
parse_identifier("_variable__Test").expect("should parse").1,
|
|
"_variable__Test"
|
|
);
|
|
assert!(matches!(
|
|
parse_identifier("123_variable__Test"),
|
|
Err(_)
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn test_parse_option_string_type() {
|
|
assert_eq!(
|
|
parse_db_type("Option(STRING)").expect("should parse").1,
|
|
DbType::Option(Box::new(DbType::String))
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_parse_nested_option_int_type() {
|
|
assert_eq!(
|
|
parse_db_type("Option(Option(Option(INT)))").expect("should parse").1,
|
|
DbType::Option(Box::new(DbType::Option(Box::new(DbType::Option(Box::new(DbType::Int))))))
|
|
);
|
|
}
|
|
}
|