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> { many1(terminated(parse_statement, delimited(multispace0, char(';'), multispace0)))(input) } pub fn parse_and_validate(str_query: String, db_schema: &DbSchema) -> Result { 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, ""); } }