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> { separated_list0(terminated(char(','), multispace0), map(parse_identifier, |name|name.to_string()))(input) } pub fn parse_values(input: &str) -> IResult<&str, Vec> { 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!() } } } }