Return error for queries containing non-ASCII characters Allow underscores in identifiers Add a delete statement test with spaces Remove trailing spaces and semicolons from tests and parsers Complete the multiple statement parser TODO
90 lines
2.8 KiB
Rust
90 lines
2.8 KiB
Rust
use crate::syntax::RawQuerySyntax;
|
|
use minisql::{interpreter::DbSchema, operation::Operation};
|
|
use nom::{branch::alt, character::complete::{multispace0, char}, multi::many1, sequence::{delimited, terminated}, IResult};
|
|
use thiserror::Error;
|
|
|
|
use crate::{
|
|
parsing::{
|
|
create::parse_create, delete::parse_delete, index::parse_create_index,
|
|
insert::parse_insert, select::parse_select,
|
|
},
|
|
validation::{validate_operation, ValidationError},
|
|
};
|
|
|
|
#[derive(Debug, Error)]
|
|
pub enum Error {
|
|
#[error("parsing error: {0}")]
|
|
ParsingError(String),
|
|
#[error("validation error: {0}")]
|
|
ValidationError(#[from] ValidationError),
|
|
}
|
|
|
|
/// Parse single statement
|
|
fn parse_statement(input: &str) -> IResult<&str, RawQuerySyntax> {
|
|
alt((
|
|
parse_insert,
|
|
parse_create,
|
|
parse_delete,
|
|
//parse_drop,
|
|
parse_select,
|
|
// parse_update,
|
|
parse_create_index,
|
|
))(input)
|
|
}
|
|
|
|
/// Parse one or more statements
|
|
fn parse_statement1(input: &str) -> IResult<&str, Vec<RawQuerySyntax>> {
|
|
many1(terminated(parse_statement, delimited(multispace0, char(';'), multispace0)))(input)
|
|
}
|
|
|
|
pub fn parse_and_validate(str_query: String, db_schema: &DbSchema) -> Result<Operation, Error> {
|
|
if let Some(non_ascii) = str_query.chars().find(|c| c.len_utf8() > 1) {
|
|
return Err(Error::ParsingError(
|
|
format!("Non ASCII character found: {}", non_ascii)
|
|
));
|
|
}
|
|
let (_, op) =
|
|
parse_statement(str_query.as_str()).map_err(|err| Error::ParsingError(err.to_string()))?;
|
|
|
|
Ok(validate_operation(op, db_schema)?)
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use crate::core::parse_statement1;
|
|
use crate::parse_and_validate;
|
|
use crate::Error;
|
|
#[test]
|
|
fn test_non_unicode() {
|
|
let result = parse_and_validate(format!("SELECT * FROM users WHERE name = \"京\""), &Default::default());
|
|
assert!(matches!(result, Err(Error::ParsingError(_))));
|
|
if let Err(Error::ParsingError(err)) = result {
|
|
assert_eq!(err, format!("Non ASCII character found: {}", '京'));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_parse_two_select() {
|
|
let (rest, sntx) = parse_statement1("SELECT * FROM users ; SELECT * FROM cities ; ").expect("should parse");
|
|
assert_eq!(
|
|
sntx.len(),
|
|
2
|
|
);
|
|
assert_eq!(rest, "");
|
|
}
|
|
|
|
#[test]
|
|
fn test_parse_three_insert_one_select() {
|
|
let (rest, sntx) = parse_statement1(
|
|
r#"INSERT INTO table1 (id, data) VALUES (u1, 2);
|
|
SELECT * FROM users ;
|
|
INSERT INTO table1 (id, data) VALUES (u4, 30) ;
|
|
INSERT INTO table1 (id, data) VALUES (u5, 40) ;
|
|
"#).expect("should parse");
|
|
assert_eq!(
|
|
sntx.len(),
|
|
4
|
|
);
|
|
assert_eq!(rest, "");
|
|
}
|
|
}
|