use super::{ common::{parse_identifier, parse_table_name}, literal::{parse_literal, Literal}, }; use crate::syntax::RawQuerySyntax; 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> { 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_literal)(input) } #[cfg(test)] mod tests { use super::parse_insert; use crate::{parsing::literal::Literal, 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(), Literal::Int(1)), ( "data".to_string(), Literal::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(), Literal::Int(1)), ( "data".to_string(), Literal::String("Text".to_string()) ) ] ); } _ => { unreachable!() } } } #[test] fn test_parse_insert_option() { let sql = r#"INSERT INTO games (id, name, year, price) VALUES (u12345, "Doom", Some(1993), 6.5);"#; let syntax = parse_insert(sql).expect("should parse"); match syntax { (";", RawQuerySyntax::Insert(table_name, insertion_values)) => { assert_eq!(table_name, "games"); assert_eq!( insertion_values, vec![ ("id".to_string(), Literal::Uuid(12345)), ( "name".to_string(), Literal::String("Doom".to_string()) ), ( "year".to_string(), Literal::Some(Box::new(Literal::Int(1993))) ), ( "price".to_string(), Literal::Number(6.5) ) ] ); } _ => { panic!() } } } }