Add option type and option value parsers value->literal in parser, implement Option literal
158 lines
5.6 KiB
Rust
158 lines
5.6 KiB
Rust
use nom::{
|
|
bytes::complete::tag,
|
|
character::complete::{char, multispace0, multispace1},
|
|
combinator::opt,
|
|
multi::separated_list0,
|
|
sequence::terminated,
|
|
IResult,
|
|
};
|
|
|
|
use super::common::{parse_db_type, parse_identifier, parse_table_name};
|
|
use crate::syntax::{ColumnSchema, RawQuerySyntax, RawTableSchema};
|
|
|
|
pub fn parse_create(input: &str) -> IResult<&str, RawQuerySyntax> {
|
|
let (input, _) = tag("CREATE")(input)?;
|
|
let (input, _) = multispace1(input)?;
|
|
let (input, _) = tag("TABLE")(input)?;
|
|
let (input, _) = multispace1(input)?;
|
|
let (input, table_name) = parse_table_name(input)?;
|
|
let (input, _) = multispace0(input)?;
|
|
let (input, _) = char('(')(input)?;
|
|
let (input, _) = multispace0(input)?;
|
|
let (input, column_definitions) = parse_column_definitions(input)?;
|
|
|
|
let (input, _) = char(')')(input)?;
|
|
let schema = RawTableSchema {
|
|
table_name: table_name.to_string(),
|
|
columns: column_definitions,
|
|
};
|
|
Ok((input, RawQuerySyntax::CreateTable(schema)))
|
|
}
|
|
|
|
fn parse_column_definitions(input: &str) -> IResult<&str, Vec<ColumnSchema>> {
|
|
separated_list0(terminated(char(','), multispace0), parse_column_definition)(input)
|
|
}
|
|
|
|
fn parse_primary_key(input: &str) -> IResult<&str, &str> {
|
|
let (input, _) = multispace1(input)?;
|
|
let (input, _) = tag("PRIMARY")(input)?;
|
|
let (input, _) = multispace1(input)?;
|
|
let (input, _) = tag("KEY")(input)?;
|
|
Ok((input, "PRIMARY KEY"))
|
|
}
|
|
|
|
fn parse_column_definition(input: &str) -> IResult<&str, ColumnSchema> {
|
|
let (input, identifier) = parse_identifier(input)?;
|
|
let (input, _) = multispace1(input)?;
|
|
let (input, db_type) = parse_db_type(input)?;
|
|
let (input, pk) = opt(parse_primary_key)(input).map(|(input, pk)| (input, pk.is_some()))?;
|
|
let (input, _) = multispace0(input)?;
|
|
Ok((
|
|
input,
|
|
ColumnSchema {
|
|
column_name: identifier.to_string(),
|
|
type_: db_type,
|
|
is_primary: pk,
|
|
},
|
|
))
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use minisql::type_system::DbType;
|
|
|
|
use crate::parsing::create::parse_create;
|
|
use crate::syntax::RawQuerySyntax;
|
|
|
|
#[test]
|
|
fn test_parse_create_no_spaces() {
|
|
parse_create("CREATE TABLE \"Table1\"(id UUID ,column1 INT)").expect("should parse");
|
|
}
|
|
|
|
#[test]
|
|
fn test_parse_create_primary_key() {
|
|
parse_create("CREATE TABLE \"Table1\"(id UUID PRIMARY KEY,column1 INT)")
|
|
.expect("should parse");
|
|
}
|
|
|
|
#[test]
|
|
fn test_parse_create_no_quotes_table_name() {
|
|
parse_create("CREATE TABLE Table1(id UUID PRIMARY KEY,column1 INT)")
|
|
.expect("should parse");
|
|
}
|
|
|
|
#[test]
|
|
fn test_parse_create_primary_key_with_spaces() {
|
|
parse_create(
|
|
"CREATE TABLE \"Table1\" ( id UUID PRIMARY KEY , column1 INT )",
|
|
)
|
|
.expect("should parse");
|
|
}
|
|
|
|
#[test]
|
|
fn test_parse_create() {
|
|
let (_, create) = parse_create("CREATE TABLE \"Table1\"( id UUID , column1 INT )")
|
|
.expect("should parse");
|
|
assert!(matches!(create, RawQuerySyntax::CreateTable(_)));
|
|
match create {
|
|
RawQuerySyntax::CreateTable(schema) => {
|
|
assert_eq!(schema.table_name, "Table1");
|
|
assert_eq!(schema.number_of_columns(), 2);
|
|
|
|
let result_id = schema.get_column(&"id".to_string());
|
|
assert!(matches!(result_id, Some(_)));
|
|
let Some(id_column) = result_id else { panic!() };
|
|
assert_eq!(id_column.column_name, "id".to_string());
|
|
|
|
let result_column1 = schema.get_column(&"column1".to_string());
|
|
assert!(matches!(result_column1, Some(_)));
|
|
let Some(column1_column) = result_column1 else {
|
|
panic!()
|
|
};
|
|
assert_eq!(column1_column.column_name, "column1".to_string());
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_parse_create_option() {
|
|
let (_, create) = parse_create("CREATE TABLE games (id UUID PRIMARY KEY, name STRING, year Option(INT), price NUMBER)")
|
|
.expect("should parse");
|
|
assert!(matches!(create, RawQuerySyntax::CreateTable(_)));
|
|
match create {
|
|
RawQuerySyntax::CreateTable(schema) => {
|
|
assert_eq!(schema.table_name, "games");
|
|
assert_eq!(schema.number_of_columns(), 4);
|
|
|
|
let result_id = schema.get_column(&"id".to_string());
|
|
assert!(matches!(result_id, Some(_)));
|
|
let Some(id_column) = result_id else { panic!() };
|
|
assert_eq!(id_column.column_name, "id".to_string());
|
|
|
|
let result_column1 = schema.get_column(&"name".to_string());
|
|
assert!(matches!(result_column1, Some(_)));
|
|
let Some(column1_column) = result_column1 else {
|
|
panic!()
|
|
};
|
|
assert_eq!(column1_column.column_name, "name".to_string());
|
|
assert_eq!(column1_column.type_, DbType::String);
|
|
|
|
let column = schema.get_column(&"year".to_string());
|
|
let Some(column) = column else {
|
|
panic!()
|
|
};
|
|
assert_eq!(column.column_name, "year".to_string());
|
|
assert_eq!(column.type_, DbType::Option(Box::new(DbType::Int)));
|
|
|
|
let column = schema.get_column(&"price".to_string());
|
|
let Some(column) = column else {
|
|
panic!()
|
|
};
|
|
assert_eq!(column.column_name, "price".to_string());
|
|
assert_eq!(column.type_, DbType::Number);
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|