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
111 lines
3.4 KiB
Rust
111 lines
3.4 KiB
Rust
use super::{
|
|
common::{parse_identifier, parse_table_name},
|
|
literal::parse_db_value,
|
|
};
|
|
use crate::syntax::RawQuerySyntax;
|
|
use minisql::type_system::Value;
|
|
use nom::{
|
|
bytes::complete::tag,
|
|
character::complete::{char, multispace0, multispace1},
|
|
combinator::map,
|
|
multi::separated_list0,
|
|
sequence::terminated,
|
|
IResult,
|
|
};
|
|
|
|
pub fn parse_insert(input: &str) -> IResult<&str, RawQuerySyntax> {
|
|
let (input, _) = tag("INSERT")(input)?;
|
|
let (input, _) = multispace1(input)?;
|
|
let (input, _) = tag("INTO")(input)?;
|
|
let (input, _) = multispace1(input)?;
|
|
let (input, table_name) = parse_table_name(input)?;
|
|
let (input, _) = multispace1(input)?;
|
|
let (input, _) = char('(')(input)?;
|
|
let (input, _) = multispace0(input)?;
|
|
let (input, column_names) = parse_columns(input)?;
|
|
let (input, _) = multispace0(input)?;
|
|
let (input, _) = char(')')(input)?;
|
|
let (input, _) = multispace1(input)?;
|
|
let (input, _) = tag("VALUES")(input)?;
|
|
let (input, _) = multispace0(input)?;
|
|
let (input, _) = char('(')(input)?;
|
|
let (input, _) = multispace0(input)?;
|
|
let (input, values) = parse_values(input)?;
|
|
let (input, _) = multispace0(input)?;
|
|
let (input, _) = char(')')(input)?;
|
|
Ok((
|
|
input,
|
|
RawQuerySyntax::Insert(
|
|
table_name.to_string(),
|
|
column_names.into_iter().zip(values).collect(),
|
|
),
|
|
))
|
|
}
|
|
|
|
pub fn parse_columns(input: &str) -> IResult<&str, Vec<String>> {
|
|
separated_list0(
|
|
terminated(char(','), multispace0),
|
|
map(parse_identifier, |name| name.to_string()),
|
|
)(input)
|
|
}
|
|
|
|
pub fn parse_values(input: &str) -> IResult<&str, Vec<Value>> {
|
|
separated_list0(terminated(char(','), multispace0), parse_db_value)(input)
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use minisql::type_system::Value;
|
|
|
|
use super::parse_insert;
|
|
use crate::syntax::RawQuerySyntax;
|
|
|
|
#[test]
|
|
fn test_parse_insert() {
|
|
let sql = "INSERT INTO \"MyTable\" (id, data) VALUES(1, \"Text\")";
|
|
let syntax = parse_insert(sql).expect("should parse");
|
|
match syntax {
|
|
("", RawQuerySyntax::Insert(table_name, insertion_values)) => {
|
|
assert_eq!(table_name, "MyTable");
|
|
assert_eq!(
|
|
insertion_values,
|
|
vec![
|
|
("id".to_string(), Value::Int(1)),
|
|
(
|
|
"data".to_string(),
|
|
Value::String("Text".to_string())
|
|
)
|
|
]
|
|
);
|
|
}
|
|
_ => {
|
|
unreachable!()
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_parse_insert_with_spaces() {
|
|
let sql =
|
|
"INSERT INTO \"MyTable\" ( id, data ) VALUES ( 1, \"Text\" )";
|
|
let operation = parse_insert(sql).expect("should parse");
|
|
match operation {
|
|
("", RawQuerySyntax::Insert(table_name, insertion_values)) => {
|
|
assert_eq!(table_name, "MyTable");
|
|
assert_eq!(
|
|
insertion_values,
|
|
vec![
|
|
("id".to_string(), Value::Int(1)),
|
|
(
|
|
"data".to_string(),
|
|
Value::String("Text".to_string())
|
|
)
|
|
]
|
|
);
|
|
}
|
|
_ => {
|
|
unreachable!()
|
|
}
|
|
}
|
|
}
|
|
}
|