Put parsing details into one module

This commit is contained in:
Yuriy Dupyn 2024-01-26 19:45:15 +01:00
parent 61c0a34253
commit 6000b1f242
10 changed files with 30 additions and 29 deletions

View file

@ -0,0 +1,94 @@
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!()
}
}
}
}