Add parsing (incl. validation)
Ensure identifiers start with alphabetical character Rename parse_variable_name -> parse_column_name Add DB value parsers and condition parser placeholder Fix number parser, basic condition parser Move select parser to select module Add create statement parser Move condition parser to common; add delete statement parser Add drop statement parser Add insert parser Add update parser, combine operation parsers into one Add initial validation, fix compiler warnings Validation WIP Allow more spaces in create statement, update TableSchema struct Add create index parser and validator Add todo in parse_identifier Rework the new structure, many other changes
This commit is contained in:
parent
143dc0e5ce
commit
61c0a34253
20 changed files with 1138 additions and 39 deletions
164
parser/src/literal.rs
Normal file
164
parser/src/literal.rs
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
use minisql::type_system::{IndexableValue, Value};
|
||||
use nom::{
|
||||
branch::alt,
|
||||
character::complete::{u64, char, digit1, none_of},
|
||||
combinator::opt,
|
||||
multi::many0,
|
||||
sequence::{delimited, pair, preceded},
|
||||
IResult, error::make_error
|
||||
};
|
||||
|
||||
pub fn parse_db_value(input: &str) -> IResult<&str, Value> {
|
||||
alt((
|
||||
parse_string,
|
||||
parse_number,
|
||||
parse_int,
|
||||
parse_uuid,
|
||||
))(input)
|
||||
}
|
||||
|
||||
pub fn parse_number(input: &str) -> IResult<&str, Value> {
|
||||
// Parse the integer part
|
||||
let (input, (sign, digits)) = pair(opt(char('-')), digit1)(input)?;
|
||||
|
||||
// Parse the fractional part
|
||||
let (input, frac_part) = opt(pair(char('.'), digit1))(input)?;
|
||||
|
||||
match frac_part {
|
||||
Some((_fsign, fdigits)) => {
|
||||
// Combine integer and fractional parts
|
||||
let combined_parts = format!(
|
||||
"{}{}",
|
||||
format!("{}{}", sign.unwrap_or('+'), digits),
|
||||
format!(".{}", fdigits)
|
||||
);
|
||||
// Parse the combined parts as a floating-point number
|
||||
let value = combined_parts.parse::<f64>()
|
||||
.map_err(|_| {
|
||||
nom::Err::Failure(make_error(input, nom::error::ErrorKind::Fail))
|
||||
})?;
|
||||
Ok((input, Value::Number(value)))
|
||||
}
|
||||
None => {
|
||||
let value = format!("{}{}", sign.unwrap_or('+'), digits).parse::<u64>()
|
||||
.map_err(|_| {
|
||||
nom::Err::Failure(make_error(input, nom::error::ErrorKind::Fail))
|
||||
})?;
|
||||
Ok((input, Value::Indexable(IndexableValue::Int(value))))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_int(input: &str) -> IResult<&str, Value> {
|
||||
u64(input).map(|(input, v)| {
|
||||
(input, Value::Indexable(IndexableValue::Int(v)))
|
||||
})
|
||||
}
|
||||
|
||||
fn escape_tab(input:&str) -> IResult<&str, char> {
|
||||
let (input, _) = preceded(char('\\'), char('t'))(input)?;
|
||||
Ok((input, '\t'))
|
||||
}
|
||||
|
||||
fn escape_backslash(input:&str) -> IResult<&str, char> {
|
||||
let (input, _) = preceded(char('\\'), char('\\'))(input)?;
|
||||
Ok((input, '\\'))
|
||||
}
|
||||
|
||||
fn escape_newline(input:&str) -> IResult<&str, char> {
|
||||
let (input, _) = preceded(char('\\'), char('n'))(input)?;
|
||||
Ok((input, '\n'))
|
||||
}
|
||||
|
||||
fn escape_carriegereturn(input:&str) -> IResult<&str, char> {
|
||||
let (input, _) = preceded(char('\\'), char('r'))(input)?;
|
||||
Ok((input, '\r'))
|
||||
}
|
||||
|
||||
fn escape_doublequote(input:&str) -> IResult<&str, char> {
|
||||
preceded(char('\\'), char('"'))(input)
|
||||
}
|
||||
|
||||
pub fn parse_string(input: &str) -> IResult<&str, Value> {
|
||||
// Parse the content inside the double quotes
|
||||
let (input, content) = delimited(
|
||||
char('"'),
|
||||
many0(alt((
|
||||
escape_backslash,
|
||||
escape_carriegereturn,
|
||||
escape_newline,
|
||||
escape_doublequote,
|
||||
escape_tab,
|
||||
none_of(r#"\""#)
|
||||
))),
|
||||
char('"'),
|
||||
)(input)?;
|
||||
|
||||
// Combine the characters into a string
|
||||
let value: String = content.into_iter().collect();
|
||||
|
||||
Ok((input, Value::Indexable(IndexableValue::String(value))))
|
||||
}
|
||||
|
||||
fn parse_uuid(input: &str) -> IResult<&str, Value> {
|
||||
// TODO: make it actually uuid
|
||||
u64(input).map(|(input, v)| {
|
||||
(input, Value::Indexable(IndexableValue::Uuid(v)))
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use minisql::type_system::{IndexableValue, Value};
|
||||
use crate::literal::{parse_db_value, parse_string};
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_string_parser() {
|
||||
assert_eq!(parse_string(r#""simple""#), Ok(("", Value::Indexable(IndexableValue::String(String::from("simple"))))));
|
||||
assert_eq!(parse_string(r#""\"\t\r\n\\""#), Ok(("", Value::Indexable(IndexableValue::String(String::from("\"\t\r\n\\"))))));
|
||||
assert_eq!(parse_string(r#""name is \"John\".""#), Ok(("", Value::Indexable(IndexableValue::String(String::from("name is \"John\"."))))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_db_value() {
|
||||
let (input, value) = parse_db_value("5").expect("should parse");
|
||||
assert_eq!(input, "");
|
||||
assert_eq!(value, Value::Indexable(IndexableValue::Int(5)));
|
||||
|
||||
let (input, value) = parse_db_value("5.5").expect("should parse");
|
||||
assert_eq!(input, "");
|
||||
assert_eq!(value, Value::Number(5.5));
|
||||
|
||||
let (_, _) = parse_db_value("\"STRING\"").expect("should parse");
|
||||
let (input, value) = parse_db_value("\"abcdefghkjklmnopqrstuvwxyz!@#$%^&*()_+ \"").expect("should parse");
|
||||
assert_eq!(input, "");
|
||||
assert_eq!(value, Value::Indexable(IndexableValue::String("abcdefghkjklmnopqrstuvwxyz!@#$%^&*()_+ ".to_string())));
|
||||
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_parse_positive_float() {
|
||||
assert_eq!(parse_db_value("23.213313"), Ok(("", Value::Number(23.213313))));
|
||||
assert_eq!(parse_db_value("2241.9734"), Ok(("", Value::Number(2241.9734))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_negative_float() {
|
||||
assert_eq!(parse_db_value("-9241.873654"), Ok(("", Value::Number(-9241.873654))));
|
||||
assert_eq!(parse_db_value("-62625.0"), Ok(("", Value::Number(-62625.0))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_float_between_0_and_1() {
|
||||
assert_eq!(parse_db_value("0.873654"), Ok(("", Value::Number(0.873654))));
|
||||
assert_eq!(parse_db_value("0.62625"), Ok(("", Value::Number(0.62625))));
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_parse_int() {
|
||||
assert_eq!(parse_db_value("5134616"), Ok(("", Value::Indexable(IndexableValue::Int(5134616)))));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue