94 lines
3.3 KiB
Rust
94 lines
3.3 KiB
Rust
use super::{literal::parse_db_value, common::{parse_table_name, parse_identifier}};
|
|
use minisql::{operation::Operation, type_system::Value};
|
|
use nom::{
|
|
bytes::complete::tag,
|
|
character::complete::{multispace0, multispace1, char},
|
|
combinator::map,
|
|
multi::separated_list0,
|
|
sequence::terminated,
|
|
IResult,
|
|
};
|
|
|
|
pub fn parse_insert(input: &str) -> IResult<&str, Operation> {
|
|
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)?;
|
|
let (input, _) = multispace0(input)?;
|
|
let (input, _) = char(';')(input)?;
|
|
Ok((
|
|
input,
|
|
Operation::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::{operation::Operation, type_system::{IndexableValue, Value}};
|
|
|
|
use super::parse_insert;
|
|
|
|
|
|
#[test]
|
|
fn test_parse_insert() {
|
|
let sql = "INSERT INTO \"MyTable\" (id, data) VALUES(1, \"Text\");";
|
|
let operation = parse_insert(sql).expect("should parse");
|
|
match operation {
|
|
("", Operation::Insert(table_name, insertion_values)) => {
|
|
assert_eq!(table_name, "MyTable");
|
|
assert_eq!(
|
|
insertion_values,
|
|
vec![
|
|
("id".to_string(), Value::Indexable(IndexableValue::Int(1))),
|
|
("data".to_string(), Value::Indexable(IndexableValue::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 {
|
|
("", Operation::Insert(table_name, insertion_values)) => {
|
|
assert_eq!(table_name, "MyTable");
|
|
assert_eq!(insertion_values,
|
|
vec![
|
|
("id".to_string(), Value::Indexable(IndexableValue::Int(1))),
|
|
("data".to_string(), Value::Indexable(IndexableValue::String("Text".to_string())))
|
|
]);
|
|
}
|
|
_ => {
|
|
unreachable!()
|
|
}
|
|
}
|
|
}
|
|
}
|