Cleanup
This commit is contained in:
parent
9771a89716
commit
11dc992476
10 changed files with 157 additions and 403 deletions
|
|
@ -1,4 +1,4 @@
|
|||
use minisql::{operation::OperationForInterpreter, interpreter::DbSchema};
|
||||
use minisql::{operation::Operation, interpreter::DbSchema};
|
||||
use crate::syntax::RawQuerySyntax;
|
||||
use nom::{branch::alt, multi::many0, IResult};
|
||||
use thiserror::Error;
|
||||
|
|
@ -29,7 +29,7 @@ pub fn parse_statements<'a>(input: &'a str) -> IResult<&str, Vec<RawQuerySyntax>
|
|||
many0(parse_statement)(input)
|
||||
}
|
||||
|
||||
pub fn parse_and_validate(query: String, db_schema: &DbSchema) -> Result<OperationForInterpreter, Error> {
|
||||
pub fn parse_and_validate(query: String, db_schema: &DbSchema) -> Result<Operation, Error> {
|
||||
let (_, op) = parse_statement(query.as_str())
|
||||
.map_err(|err| {
|
||||
Error::ParsingError(err.to_string())
|
||||
|
|
|
|||
|
|
@ -100,8 +100,8 @@ mod tests {
|
|||
RawQuerySyntax::CreateTable(name, schema) => {
|
||||
assert_eq!(name, "Table1");
|
||||
assert_eq!(schema.number_of_columns(), 2);
|
||||
assert_eq!(schema.column_position_from_column_name(&"id".to_string()).unwrap(), 0);
|
||||
assert_eq!(schema.column_position_from_column_name(&"column1".to_string()).unwrap(), 1);
|
||||
assert_eq!(schema.get_column_position(&"id".to_string()).unwrap(), 0);
|
||||
assert_eq!(schema.get_column_position(&"column1".to_string()).unwrap(), 1);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@ use std::collections::HashSet;
|
|||
use std::collections::HashMap;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::syntax::{ColumnSelection, Condition, InsertionValues, RawQuerySyntax};
|
||||
use minisql::{operation::{ColumnSelectionForInterpreter, ConditionForInterpreter, InsertionValuesForInterpreter, OperationForInterpreter}, type_system::Value, schema::{TableSchema, ColumnName, TableName}, type_system::DbType, interpreter::{TablePosition, DbSchema}};
|
||||
use crate::syntax;
|
||||
use crate::syntax::RawQuerySyntax;
|
||||
use minisql::operation;
|
||||
use minisql::{operation::Operation, type_system::Value, schema::{TableSchema, ColumnName, TableName}, type_system::DbType, interpreter::{TablePosition, DbSchema}};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ValidationError {
|
||||
|
|
@ -26,7 +28,7 @@ pub enum ValidationError {
|
|||
}
|
||||
|
||||
/// Validates and converts the raw syntax into a proper interpreter operation based on db schema.
|
||||
pub fn validate_operation(query: RawQuerySyntax, db_schema: &DbSchema) -> Result<OperationForInterpreter, ValidationError> {
|
||||
pub fn validate_operation(query: RawQuerySyntax, db_schema: &DbSchema) -> Result<Operation, ValidationError> {
|
||||
match query {
|
||||
RawQuerySyntax::Select(table_name, column_selection, condition) => {
|
||||
validate_select(table_name, column_selection, condition, db_schema)
|
||||
|
|
@ -52,7 +54,7 @@ fn validate_table_exists<'a>(db_schema: &DbSchema<'a>, table_name: &'a TableName
|
|||
.map(|(_, table_position, table_schema)| (*table_position, *table_schema))
|
||||
}
|
||||
|
||||
pub fn validate_create(table_name: TableName, table_schema: TableSchema, db_schema: &DbSchema) -> Result<OperationForInterpreter, ValidationError> {
|
||||
pub fn validate_create(table_name: TableName, table_schema: TableSchema, db_schema: &DbSchema) -> Result<Operation, ValidationError> {
|
||||
if let Some(_) = get_table_schema(db_schema, &table_name) {
|
||||
return Err(ValidationError::TableAlreadyExists(table_name.to_string()));
|
||||
}
|
||||
|
|
@ -64,13 +66,13 @@ pub fn validate_create(table_name: TableName, table_schema: TableSchema, db_sche
|
|||
)?;
|
||||
|
||||
// TODO: Ensure it has a primary key??
|
||||
Ok(OperationForInterpreter::CreateTable(table_name, table_schema))
|
||||
Ok(Operation::CreateTable(table_name, table_schema))
|
||||
}
|
||||
|
||||
pub fn validate_select(table_name: TableName, column_selection: ColumnSelection, condition: Option<Condition>, db_schema: &DbSchema) -> Result<OperationForInterpreter, ValidationError> {
|
||||
pub fn validate_select(table_name: TableName, column_selection: syntax::ColumnSelection, condition: Option<syntax::Condition>, db_schema: &DbSchema) -> Result<Operation, ValidationError> {
|
||||
let (table_position, schema) = validate_table_exists(db_schema, &table_name)?;
|
||||
match column_selection {
|
||||
ColumnSelection::Columns(columns) => {
|
||||
syntax::ColumnSelection::Columns(columns) => {
|
||||
let non_existant_columns: Vec<ColumnName> =
|
||||
columns.iter().filter_map(|column|
|
||||
if schema.does_column_exist(&column) {
|
||||
|
|
@ -81,20 +83,20 @@ pub fn validate_select(table_name: TableName, column_selection: ColumnSelection,
|
|||
if non_existant_columns.len() > 0 {
|
||||
Err(ValidationError::ColumnsDoNotExist(non_existant_columns))
|
||||
} else {
|
||||
let selection: ColumnSelectionForInterpreter =
|
||||
let selection: operation::ColumnSelection =
|
||||
columns.iter().filter_map(|column_name| schema.get_column_position(column_name)).collect();
|
||||
let validated_condition = validate_condition(condition, schema)?;
|
||||
Ok(OperationForInterpreter::Select(table_position, selection, validated_condition))
|
||||
Ok(Operation::Select(table_position, selection, validated_condition))
|
||||
}
|
||||
}
|
||||
ColumnSelection::All => {
|
||||
syntax::ColumnSelection::All => {
|
||||
let validated_condition = validate_condition(condition, schema)?;
|
||||
Ok(OperationForInterpreter::Select(table_position, schema.all_selection(), validated_condition))
|
||||
Ok(Operation::Select(table_position, schema.all_selection(), validated_condition))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate_insert(table_name: TableName, insertion_values: InsertionValues, db_schema: &DbSchema) -> Result<OperationForInterpreter, ValidationError> {
|
||||
pub fn validate_insert(table_name: TableName, insertion_values: syntax::InsertionValues, db_schema: &DbSchema) -> Result<Operation, ValidationError> {
|
||||
let (table_position, schema) = validate_table_exists(db_schema, &table_name)?;
|
||||
|
||||
// Check for duplicate columns in insertion_values.
|
||||
|
|
@ -120,7 +122,7 @@ pub fn validate_insert(table_name: TableName, insertion_values: InsertionValues,
|
|||
// Check types and prepare for creation of InsertionValues for the interpreter
|
||||
let mut values_map: HashMap<_, Value> = HashMap::new();
|
||||
for (column_name, value) in insertion_values {
|
||||
let (column, expected_type) = schema.get_column0(&column_name).ok_or(ValidationError::ColumnsDoNotExist(vec![column_name.to_string()]))?; // By the previous validation steps this is never gonna trigger an error.
|
||||
let (column, expected_type) = schema.get_column(&column_name).ok_or(ValidationError::ColumnsDoNotExist(vec![column_name.to_string()]))?; // By the previous validation steps this is never gonna trigger an error.
|
||||
let value_type = value.to_type();
|
||||
if value_type != expected_type {
|
||||
return Err(ValidationError::TypeMismatch { column_name: column_name.to_string(), received_type: value_type, expected_type });
|
||||
|
|
@ -129,26 +131,26 @@ pub fn validate_insert(table_name: TableName, insertion_values: InsertionValues,
|
|||
}
|
||||
|
||||
// These are values ordered by the column position
|
||||
let values: InsertionValuesForInterpreter = values_map.into_values().collect();
|
||||
let values: operation::InsertionValues = values_map.into_values().collect();
|
||||
|
||||
Ok(OperationForInterpreter::Insert(table_position, values))
|
||||
Ok(Operation::Insert(table_position, values))
|
||||
}
|
||||
|
||||
pub fn validate_delete(table_name: TableName, condition: Option<Condition>, db_schema: &DbSchema) -> Result<OperationForInterpreter, ValidationError> {
|
||||
pub fn validate_delete(table_name: TableName, condition: Option<syntax::Condition>, db_schema: &DbSchema) -> Result<Operation, ValidationError> {
|
||||
let (table_position, schema) = validate_table_exists(db_schema, &table_name)?;
|
||||
let validated_condition = validate_condition(condition, schema)?;
|
||||
Ok(OperationForInterpreter::Delete(table_position, validated_condition))
|
||||
Ok(Operation::Delete(table_position, validated_condition))
|
||||
}
|
||||
|
||||
fn validate_condition(condition: Option<Condition>, schema: &TableSchema) -> Result<Option<ConditionForInterpreter>, ValidationError> {
|
||||
fn validate_condition(condition: Option<syntax::Condition>, schema: &TableSchema) -> Result<Option<operation::Condition>, ValidationError> {
|
||||
match condition {
|
||||
Some(condition) => {
|
||||
match condition {
|
||||
Condition::Eq(column_name, value) => {
|
||||
let (column, expected_type) = schema.get_column0(&column_name).ok_or(ValidationError::ColumnsDoNotExist(vec![column_name.to_string()]))?;
|
||||
syntax::Condition::Eq(column_name, value) => {
|
||||
let (column, expected_type) = schema.get_column(&column_name).ok_or(ValidationError::ColumnsDoNotExist(vec![column_name.to_string()]))?;
|
||||
let value_type: DbType = value.to_type();
|
||||
if expected_type.eq(&value_type) {
|
||||
Ok(Some(ConditionForInterpreter::Eq(column, value)))
|
||||
Ok(Some(operation::Condition::Eq(column, value)))
|
||||
} else {
|
||||
return Err(ValidationError::TypeMismatch { column_name: column_name.to_string(), received_type: value_type, expected_type });
|
||||
}
|
||||
|
|
@ -159,27 +161,27 @@ fn validate_condition(condition: Option<Condition>, schema: &TableSchema) -> Res
|
|||
}
|
||||
}
|
||||
|
||||
fn validate_create_index(table_name: TableName, column_name: ColumnName, db_schema: &DbSchema) -> Result<OperationForInterpreter, ValidationError> {
|
||||
fn validate_create_index(table_name: TableName, column_name: ColumnName, db_schema: &DbSchema) -> Result<Operation, ValidationError> {
|
||||
// TODO: You should disallow indexing of Number columns.
|
||||
let (table_position, schema) = validate_table_exists(db_schema, &table_name)?;
|
||||
schema
|
||||
.get_column_position(&column_name)
|
||||
.map_or_else(
|
||||
|| Err(ValidationError::ColumnsDoNotExist(vec![column_name.to_string()])),
|
||||
|column| Ok(OperationForInterpreter::CreateIndex(table_position, column))
|
||||
|column| Ok(Operation::CreateIndex(table_position, column))
|
||||
)
|
||||
}
|
||||
|
||||
// ===Helpers===
|
||||
fn find_first_duplicate<A>(xs: &[A]) -> Option<&A>
|
||||
where A: Eq + std::hash::Hash
|
||||
fn find_first_duplicate<T>(ts: &[T]) -> Option<&T>
|
||||
where T: Eq + std::hash::Hash
|
||||
{
|
||||
let mut already_seen_elements: HashSet<&A> = HashSet::new();
|
||||
for x in xs {
|
||||
if already_seen_elements.contains(x) {
|
||||
return Some(x);
|
||||
let mut already_seen_elements: HashSet<&T> = HashSet::new();
|
||||
for t in ts {
|
||||
if already_seen_elements.contains(t) {
|
||||
return Some(t);
|
||||
} else {
|
||||
already_seen_elements.insert(&x);
|
||||
already_seen_elements.insert(&t);
|
||||
}
|
||||
}
|
||||
None
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue