Put parsing details into one module
This commit is contained in:
parent
61c0a34253
commit
6000b1f242
10 changed files with 30 additions and 29 deletions
|
|
@ -1,122 +0,0 @@
|
|||
use crate::common::{parse_table_name, parse_column_name, parse_condition};
|
||||
use minisql::operation::{ColumnSelection, Operation};
|
||||
use nom::{
|
||||
branch::alt,
|
||||
bytes::complete::tag,
|
||||
character::complete::{multispace0, multispace1, char},
|
||||
combinator::map,
|
||||
error::Error,
|
||||
multi::separated_list0,
|
||||
sequence::terminated,
|
||||
IResult,
|
||||
};
|
||||
|
||||
pub fn parse_select(input: &str) -> IResult<&str, Operation> {
|
||||
let (input, _) = tag("SELECT")(input)?;
|
||||
let (input, _) = multispace1(input)?;
|
||||
|
||||
let (input, column_selection) = try_parse_column_selection(input)?;
|
||||
let (input, _) = multispace0(input)?;
|
||||
let (input, _) = tag("FROM")(input)?;
|
||||
let (input, _) = multispace1(input)?;
|
||||
let (input, table_name) = parse_table_name(input)?;
|
||||
let (input, _) = multispace0(input)?;
|
||||
let (input, condition) = parse_condition(input)?;
|
||||
let (input, _) = multispace0(input)?;
|
||||
// TODO: make it optional?
|
||||
let (input, _) = tag(";")(input)?;
|
||||
Ok((
|
||||
input,
|
||||
Operation::Select(table_name.to_string(), column_selection, condition),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn try_parse_column_selection(input: &str) -> IResult<&str, ColumnSelection> {
|
||||
let all_parser = map(tag::<&str, &str, Error<&str>>("*"), |_| {
|
||||
ColumnSelection::All
|
||||
});
|
||||
let columns_parser = map(
|
||||
separated_list0(terminated(char(','), multispace0), parse_column_name),
|
||||
|names| ColumnSelection::Columns(names),
|
||||
);
|
||||
alt((all_parser, columns_parser))(input)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use minisql::operation::{ColumnSelection, Operation};
|
||||
use crate::{common::{parse_column_name, parse_table_name}, select::parse_select};
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_parse_select_all() {
|
||||
let sql = "SELECT * FROM \"MyTable\";";
|
||||
let operation = parse_select(sql).expect("should parse");
|
||||
match operation {
|
||||
("", Operation::Select(table_name, column_selection, maybe_condition)) => {
|
||||
assert_eq!(table_name, "MyTable");
|
||||
assert!(matches!(column_selection, ColumnSelection::All));
|
||||
assert!(matches!(maybe_condition, None));
|
||||
}
|
||||
(input, _) => {
|
||||
println!("Input to be parsed: {}", input);
|
||||
panic!("expected select operation")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_column_name() {
|
||||
parse_column_name("1abc").expect_err("variable names should not start with number");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_table_name() {
|
||||
parse_table_name("\"\"").expect_err("Empty table names are not allowed");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_select_columns() {
|
||||
let sql = "SELECT name , email FROM \"AddressBook\" ;";
|
||||
let operation = parse_select(sql).expect("should parse");
|
||||
match operation {
|
||||
("", Operation::Select(table_name, column_selection, maybe_condition)) => {
|
||||
assert_eq!(table_name, "AddressBook");
|
||||
assert!(matches!(column_selection, ColumnSelection::Columns(_)));
|
||||
match column_selection {
|
||||
ColumnSelection::Columns(column_names) => {
|
||||
assert_eq!(column_names, vec!["name", "email"]);
|
||||
}
|
||||
_ => {
|
||||
panic!("should select columns")
|
||||
}
|
||||
}
|
||||
assert!(matches!(maybe_condition, None));
|
||||
}
|
||||
(input, _) => {
|
||||
println!("Input to be parsed: {}", input);
|
||||
panic!("expected select operation")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_select_where() {
|
||||
use minisql::operation::Condition;
|
||||
let sql = "SELECT * FROM \"AddressBook\" WHERE id = 5 ;";
|
||||
let operation = parse_select(sql).expect("should parse");
|
||||
match operation {
|
||||
("", Operation::Select(table_name, column_selection, maybe_condition)) => {
|
||||
assert_eq!(table_name, "AddressBook");
|
||||
assert!(matches!(column_selection, ColumnSelection::All));
|
||||
assert!(matches!(maybe_condition, Some(Condition::Eq(_, _))));
|
||||
}
|
||||
(input, _) => {
|
||||
println!("Input to be parsed: {}", input);
|
||||
panic!("expected select operation")
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: a test with multiple statements
|
||||
// TODO: allow underscores in identifiers
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue