Validation now outputs a Validated Interpreter Operation
This commit is contained in:
parent
935d9814ae
commit
562e732138
6 changed files with 133 additions and 120 deletions
|
|
@ -18,25 +18,13 @@ pub enum Operation {
|
||||||
// DropTable(TableName),
|
// DropTable(TableName),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum OperationForInterpreter {
|
|
||||||
Select(TablePosition, ColumnSelectionForInterpreter, Option<ConditionForInterpreter>),
|
|
||||||
Insert(TablePosition, InsertionValuesForInterpreter),
|
|
||||||
Delete(TablePosition, Option<ConditionForInterpreter>),
|
|
||||||
CreateTable(TableName, TableSchema),
|
|
||||||
CreateIndex(TablePosition, ColumnPosition),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type InsertionValues = Vec<(ColumnName, Value)>;
|
pub type InsertionValues = Vec<(ColumnName, Value)>;
|
||||||
|
|
||||||
pub type InsertionValuesForInterpreter = Vec<Value>;
|
|
||||||
|
|
||||||
pub enum ColumnSelection {
|
pub enum ColumnSelection {
|
||||||
All,
|
All,
|
||||||
Columns(Vec<ColumnName>),
|
Columns(Vec<ColumnName>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type ColumnSelectionForInterpreter = Vec<ColumnPosition>;
|
|
||||||
|
|
||||||
pub enum Condition {
|
pub enum Condition {
|
||||||
// And(Box<Condition>, Box<Condition>),
|
// And(Box<Condition>, Box<Condition>),
|
||||||
// Or(Box<Condition>, Box<Condition>),
|
// Or(Box<Condition>, Box<Condition>),
|
||||||
|
|
@ -48,11 +36,23 @@ pub enum Condition {
|
||||||
// StringCondition(StringCondition),
|
// StringCondition(StringCondition),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ConditionForInterpreter {
|
|
||||||
Eq(ColumnPosition, Value),
|
|
||||||
}
|
|
||||||
|
|
||||||
// enum StringCondition {
|
// enum StringCondition {
|
||||||
// Prefix(ColumnName, String),
|
// Prefix(ColumnName, String),
|
||||||
// Substring(ColumnName, String),
|
// Substring(ColumnName, String),
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
pub enum OperationForInterpreter {
|
||||||
|
Select(TablePosition, ColumnSelectionForInterpreter, Option<ConditionForInterpreter>),
|
||||||
|
Insert(TablePosition, InsertionValuesForInterpreter),
|
||||||
|
Delete(TablePosition, Option<ConditionForInterpreter>),
|
||||||
|
CreateTable(TableName, TableSchema),
|
||||||
|
CreateIndex(TablePosition, ColumnPosition),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type InsertionValuesForInterpreter = Vec<Value>;
|
||||||
|
|
||||||
|
pub type ColumnSelectionForInterpreter = Vec<ColumnPosition>;
|
||||||
|
|
||||||
|
pub enum ConditionForInterpreter {
|
||||||
|
Eq(ColumnPosition, Value),
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,16 @@ impl TableSchema {
|
||||||
self.column_name_position_mapping.get_by_left(column_name).copied()
|
self.column_name_position_mapping.get_by_left(column_name).copied()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn all_selection(&self) -> ColumnSelectionForInterpreter {
|
||||||
|
self.column_name_position_mapping.iter().map(|(_, column)| *column).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Rename to get_column
|
||||||
|
pub fn get_column0(&self, column_name: &ColumnName) -> Option<(ColumnPosition, DbType)> {
|
||||||
|
let column = self.get_column_position(column_name)?;
|
||||||
|
Some((column, self.column_type(column)))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_type_at(&self, column_name: &ColumnName) -> Option<DbType> {
|
pub fn get_type_at(&self, column_name: &ColumnName) -> Option<DbType> {
|
||||||
let position = self.get_column_position(column_name)?;
|
let position = self.get_column_position(column_name)?;
|
||||||
self.types.get(position).copied()
|
self.types.get(position).copied()
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use minisql::{operation::Operation, schema::TableSchema};
|
use minisql::{operation::Operation, schema::TableSchema};
|
||||||
|
use crate::syntax::RawQuerySyntax;
|
||||||
use nom::{branch::alt, multi::many0, IResult};
|
use nom::{branch::alt, multi::many0, IResult};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
|
@ -34,7 +35,9 @@ pub fn parse_and_validate(query: String, db_metadata: &Vec<(String, &TableSchema
|
||||||
Error::ParsingError(err.to_string())
|
Error::ParsingError(err.to_string())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
validate_operation(&op, db_metadata)?;
|
// TODO
|
||||||
|
// validate_operation(&op, db_metadata)?;
|
||||||
|
todo!();
|
||||||
Ok(op)
|
Ok(op)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
mod parsing;
|
mod parsing;
|
||||||
mod validation;
|
mod validation;
|
||||||
mod core;
|
mod core;
|
||||||
|
mod syntax;
|
||||||
|
|
||||||
pub use core::parse_and_validate;
|
pub use core::parse_and_validate;
|
||||||
pub use core::Error;
|
pub use core::Error;
|
||||||
|
|
|
||||||
36
parser/src/syntax.rs
Normal file
36
parser/src/syntax.rs
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
use minisql::{type_system::Value, schema::{TableSchema, ColumnName, TableName}};
|
||||||
|
|
||||||
|
// TODO: Move this out into separate file and rename to something like Syntax, SyntaxTree,
|
||||||
|
// OperationSyntax, RawOperationSyntax
|
||||||
|
pub enum RawQuerySyntax {
|
||||||
|
Select(TableName, ColumnSelection, Option<Condition>),
|
||||||
|
Insert(TableName, InsertionValues),
|
||||||
|
Delete(TableName, Option<Condition>),
|
||||||
|
// Update(...),
|
||||||
|
CreateTable(TableName, TableSchema),
|
||||||
|
CreateIndex(TableName, ColumnName),
|
||||||
|
// DropTable(TableName),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type InsertionValues = Vec<(ColumnName, Value)>;
|
||||||
|
|
||||||
|
pub enum ColumnSelection {
|
||||||
|
All,
|
||||||
|
Columns(Vec<ColumnName>),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Condition {
|
||||||
|
// And(Box<Condition>, Box<Condition>),
|
||||||
|
// Or(Box<Condition>, Box<Condition>),
|
||||||
|
// Not(Box<Condition>),
|
||||||
|
Eq(ColumnName, Value),
|
||||||
|
// LessOrEqual(ColumnName, DbValue),
|
||||||
|
// Less(ColumnName, DbValue),
|
||||||
|
|
||||||
|
// StringCondition(StringCondition),
|
||||||
|
}
|
||||||
|
|
||||||
|
// enum StringCondition {
|
||||||
|
// Prefix(ColumnName, String),
|
||||||
|
// Substring(ColumnName, String),
|
||||||
|
// }
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
use std::collections::HashMap;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use minisql::{operation::{ColumnSelection, Condition, InsertionValues, Operation}, schema::{TableSchema, ColumnName, TableName}, type_system::DbType};
|
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};
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum ValidationError {
|
pub enum ValidationError {
|
||||||
|
|
@ -25,69 +25,55 @@ pub enum ValidationError {
|
||||||
RequiredColumnsAreMissing(Vec<ColumnName>)
|
RequiredColumnsAreMissing(Vec<ColumnName>)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type DbSchema<'a> = Vec<(TableName, &'a TableSchema)>;
|
pub type DbSchema<'a> = Vec<(TableName, TablePosition, &'a TableSchema)>;
|
||||||
|
|
||||||
/// Validates the operation based on db_metadata
|
/// Validates and converts the raw syntax into a proper interpreter operation based on db schema.
|
||||||
pub fn validate_operation(operation: &Operation, db_schema: &DbSchema) -> Result<(), ValidationError> {
|
pub fn validate_operation(query: RawQuerySyntax, db_schema: &DbSchema) -> Result<OperationForInterpreter, ValidationError> {
|
||||||
match operation {
|
match query {
|
||||||
Operation::Select(table_name, column_selection, condition) => {
|
RawQuerySyntax::Select(table_name, column_selection, condition) => {
|
||||||
validate_select(table_name, column_selection, condition, db_schema)?;
|
validate_select(table_name, column_selection, condition, db_schema)
|
||||||
},
|
},
|
||||||
Operation::Insert(table_name, insertion_values) => {
|
RawQuerySyntax::Insert(table_name, insertion_values) => {
|
||||||
validate_insert(&table_name, insertion_values, db_schema)?;
|
validate_insert(table_name, insertion_values, db_schema)
|
||||||
},
|
},
|
||||||
Operation::Delete(table_name, condition) => {
|
RawQuerySyntax::Delete(table_name, condition) => {
|
||||||
validate_delete(table_name, condition, db_schema)?;
|
validate_delete(table_name, condition, db_schema)
|
||||||
},
|
},
|
||||||
// Operation::Update(table_name, insertion_values, condition) => {
|
RawQuerySyntax::CreateTable(table_name, schema) => {
|
||||||
// validate_update(table_name, insertion_values, db_metadata)?;
|
validate_create(table_name, schema, db_schema)
|
||||||
// },
|
|
||||||
Operation::CreateTable(table_name, schema) => {
|
|
||||||
validate_create(table_name, schema, db_schema)?;
|
|
||||||
},
|
},
|
||||||
Operation::CreateIndex(table_name, column_name) => {
|
RawQuerySyntax::CreateIndex(table_name, column_name) => {
|
||||||
validate_create_index(table_name, column_name, db_schema)?;
|
validate_create_index(table_name, column_name, db_schema)
|
||||||
},
|
},
|
||||||
// Operation::DropTable(table_name) => {
|
|
||||||
// validate_drop(table_name, db_schema)?;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_table_exists<'a>(db_schema: &DbSchema<'a>, table_name: &'a TableName) -> Result<&'a TableSchema, ValidationError> {
|
fn validate_table_exists<'a>(db_schema: &DbSchema<'a>, table_name: &'a TableName) -> Result<(TablePosition, &'a TableSchema), ValidationError> {
|
||||||
db_schema.iter().find(|(tname, _)| table_name.eq(tname))
|
db_schema.iter().find(|(tname, _, _)| table_name.eq(tname))
|
||||||
.ok_or(ValidationError::TableDoesNotExist(table_name.to_string()))
|
.ok_or(ValidationError::TableDoesNotExist(table_name.to_string()))
|
||||||
.map(|(_, table_schema)| table_schema).copied()
|
.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_drop(table_name: &str, db_metadata: &Vec<(String, TableSchema)>) -> Result<(), ValidationError> {
|
if let Some(_) = get_table_schema(db_schema, &table_name) {
|
||||||
// db_metadata.iter().find(|(tname, _)| table_name.eq(tname))
|
|
||||||
// .ok_or(ValidationError::TableDoesNotExist(table_name.to_string()))?;
|
|
||||||
// Ok(())
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub fn validate_create(table_name: &TableName, schema: &TableSchema, db_schema: &DbSchema) -> Result<(), ValidationError> {
|
|
||||||
if let Some(_) = get_table_schema(db_schema, table_name) {
|
|
||||||
return Err(ValidationError::TableAlreadyExists(table_name.to_string()));
|
return Err(ValidationError::TableAlreadyExists(table_name.to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
find_first_duplicate(&schema.get_columns())
|
find_first_duplicate(&table_schema.get_columns())
|
||||||
.map_or_else(
|
.map_or_else(
|
||||||
|| Ok(()),
|
|| Ok(()),
|
||||||
|duplicate_column| Err(ValidationError::DuplicateColumn(duplicate_column.to_string()))
|
|duplicate_column| Err(ValidationError::DuplicateColumn(duplicate_column.to_string()))
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// TODO: Ensure it has a primary key??
|
// TODO: Ensure it has a primary key??
|
||||||
Ok(())
|
Ok(OperationForInterpreter::CreateTable(table_name, table_schema))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validate_select(table_name: &TableName, column_selection: &ColumnSelection, condition: &Option<Condition>, db_schema: &Vec<(TableName, &TableSchema)>) -> Result<(), ValidationError> {
|
pub fn validate_select(table_name: TableName, column_selection: ColumnSelection, condition: Option<Condition>, db_schema: &DbSchema) -> Result<OperationForInterpreter, ValidationError> {
|
||||||
let schema = validate_table_exists(db_schema, table_name)?;
|
let (table_position, schema) = validate_table_exists(db_schema, &table_name)?;
|
||||||
match column_selection {
|
match column_selection {
|
||||||
ColumnSelection::Columns(columns) => {
|
ColumnSelection::Columns(columns) => {
|
||||||
let non_existant_columns: Vec<String> =
|
let non_existant_columns: Vec<ColumnName> =
|
||||||
columns.iter().filter_map(|column|
|
columns.iter().filter_map(|column|
|
||||||
if schema.does_column_exist(&column) {
|
if schema.does_column_exist(&column) {
|
||||||
Some(column.clone())
|
Some(column.clone())
|
||||||
|
|
@ -97,52 +83,21 @@ pub fn validate_select(table_name: &TableName, column_selection: &ColumnSelectio
|
||||||
if non_existant_columns.len() > 0 {
|
if non_existant_columns.len() > 0 {
|
||||||
Err(ValidationError::ColumnsDoNotExist(non_existant_columns))
|
Err(ValidationError::ColumnsDoNotExist(non_existant_columns))
|
||||||
} else {
|
} else {
|
||||||
validate_condition(condition, schema)
|
let selection: ColumnSelectionForInterpreter =
|
||||||
|
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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ColumnSelection::All => Ok(())
|
ColumnSelection::All => {
|
||||||
|
let validated_condition = validate_condition(condition, schema)?;
|
||||||
|
Ok(OperationForInterpreter::Select(table_position, schema.all_selection(), validated_condition))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn validate_update(table_name: &str, insertion_values: &InsertionValues, db_metadata: &Vec<(String, TableSchema)>) -> Result<(), ValidationError> {
|
pub fn validate_insert(table_name: TableName, insertion_values: InsertionValues, db_schema: &DbSchema) -> Result<OperationForInterpreter, ValidationError> {
|
||||||
// let schema = validate_table_exists(db_schema, table_name)?;
|
let (table_position, schema) = validate_table_exists(db_schema, &table_name)?;
|
||||||
// let mut column_names = HashSet::new();
|
|
||||||
// // Find duplicate columns
|
|
||||||
// for (name, _) in insertion_values {
|
|
||||||
// if column_names.contains(name) {
|
|
||||||
// return Err(ValidationError::DuplicateColumn(name.clone()));
|
|
||||||
// } else {
|
|
||||||
// column_names.insert(name.clone());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// // Ensure columns exist in schema
|
|
||||||
// let column_value_type: Vec<_> = insertion_values.iter().map(|(column, value)| {
|
|
||||||
// (column, value, schema.column_name_position_mapping.iter().find(|(name, _) | {
|
|
||||||
// (*name).eq(column)
|
|
||||||
// }).map(|(_, t)| schema.types.get(*t as usize)))
|
|
||||||
// }).collect();
|
|
||||||
// if let Some((name, _, _)) = column_value_type.iter().find(|(_, _, t)| {
|
|
||||||
// t.is_none()
|
|
||||||
// }) {
|
|
||||||
// return Err(ValidationError::ColumnsDoNotExist(vec![(*name).clone())]);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Check types
|
|
||||||
// if let Some((_, _, _)) = column_value_type.iter().find(|(_, value, t)| {
|
|
||||||
// if let Some(Some(column_type)) = t {
|
|
||||||
// !type_of(value).eq(column_type)
|
|
||||||
// } else {
|
|
||||||
// false
|
|
||||||
// }
|
|
||||||
// }) {
|
|
||||||
// // TODO: Add column name information
|
|
||||||
// return Err(ValidationError::TypeMismatch);
|
|
||||||
// }
|
|
||||||
// Ok(())
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub fn validate_insert(table_name: &TableName, insertion_values: &InsertionValues, db_schema: &DbSchema) -> Result<(), ValidationError> {
|
|
||||||
let schema = validate_table_exists(db_schema, table_name)?;
|
|
||||||
|
|
||||||
// Check for duplicate columns in insertion_values.
|
// Check for duplicate columns in insertion_values.
|
||||||
let columns_in_query_vec: Vec<&ColumnName> = insertion_values.iter().map(|(column_name, _)| column_name).collect();
|
let columns_in_query_vec: Vec<&ColumnName> = insertion_values.iter().map(|(column_name, _)| column_name).collect();
|
||||||
|
|
@ -157,56 +112,64 @@ pub fn validate_insert(table_name: &TableName, insertion_values: &InsertionValue
|
||||||
let columns_in_schema: HashSet<&ColumnName> = HashSet::from_iter(schema.get_columns());
|
let columns_in_schema: HashSet<&ColumnName> = HashSet::from_iter(schema.get_columns());
|
||||||
let non_existant_columns = Vec::from_iter(columns_in_query.difference(&columns_in_schema));
|
let non_existant_columns = Vec::from_iter(columns_in_query.difference(&columns_in_schema));
|
||||||
if non_existant_columns.len() > 0 {
|
if non_existant_columns.len() > 0 {
|
||||||
return Err(ValidationError::ColumnsDoNotExist(non_existant_columns.iter().map(|str| str.to_string()).collect()));
|
return Err(ValidationError::ColumnsDoNotExist(non_existant_columns.iter().map(|column_name| column_name.to_string()).collect()));
|
||||||
}
|
}
|
||||||
let missing_required_columns = Vec::from_iter(columns_in_schema.difference(&columns_in_query));
|
let missing_required_columns = Vec::from_iter(columns_in_schema.difference(&columns_in_query));
|
||||||
if missing_required_columns.len() > 0 {
|
if missing_required_columns.len() > 0 {
|
||||||
return Err(ValidationError::RequiredColumnsAreMissing(missing_required_columns.iter().map(|str| str.to_string()).collect()));
|
return Err(ValidationError::RequiredColumnsAreMissing(missing_required_columns.iter().map(|str| str.to_string()).collect()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check types
|
// 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 {
|
for (column_name, value) in insertion_values {
|
||||||
let expected_type = schema.get_type_at(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_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 value_type = value.to_type();
|
let value_type = value.to_type();
|
||||||
if value_type != expected_type {
|
if value_type != expected_type {
|
||||||
return Err(ValidationError::TypeMismatch { column_name: column_name.to_string(), received_type: value_type, expected_type });
|
return Err(ValidationError::TypeMismatch { column_name: column_name.to_string(), received_type: value_type, expected_type });
|
||||||
}
|
}
|
||||||
|
values_map.insert(column, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
// These are values ordered by the column position
|
||||||
|
let values: InsertionValuesForInterpreter = values_map.into_values().collect();
|
||||||
|
|
||||||
|
Ok(OperationForInterpreter::Insert(table_position, values))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validate_delete(table_name: &TableName, condition: &Option<Condition>, db_schema: &DbSchema) -> Result<(), ValidationError> {
|
pub fn validate_delete(table_name: TableName, condition: Option<Condition>, db_schema: &DbSchema) -> Result<OperationForInterpreter, ValidationError> {
|
||||||
let schema = validate_table_exists(db_schema, table_name)?;
|
let (table_position, schema) = validate_table_exists(db_schema, &table_name)?;
|
||||||
validate_condition(condition, schema)?;
|
let validated_condition = validate_condition(condition, schema)?;
|
||||||
Ok(())
|
Ok(OperationForInterpreter::Delete(table_position, validated_condition))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_condition(condition: &Option<Condition>, schema: &TableSchema) -> Result<(), ValidationError> {
|
fn validate_condition(condition: Option<Condition>, schema: &TableSchema) -> Result<Option<ConditionForInterpreter>, ValidationError> {
|
||||||
match condition {
|
match condition {
|
||||||
Some(condition) => {
|
Some(condition) => {
|
||||||
match condition {
|
match condition {
|
||||||
Condition::Eq(column_name, value) => {
|
Condition::Eq(column_name, value) => {
|
||||||
let expected_type: DbType = schema.get_type_at(column_name).ok_or(ValidationError::ColumnsDoNotExist(vec![column_name.to_string()]))?;
|
let (column, expected_type) = schema.get_column0(&column_name).ok_or(ValidationError::ColumnsDoNotExist(vec![column_name.to_string()]))?;
|
||||||
let value_type: DbType = value.to_type();
|
let value_type: DbType = value.to_type();
|
||||||
if !expected_type.eq(&value_type) {
|
if expected_type.eq(&value_type) {
|
||||||
|
Ok(Some(ConditionForInterpreter::Eq(column, value)))
|
||||||
|
} else {
|
||||||
return Err(ValidationError::TypeMismatch { column_name: column_name.to_string(), received_type: value_type, expected_type });
|
return Err(ValidationError::TypeMismatch { column_name: column_name.to_string(), received_type: value_type, expected_type });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {}
|
None => Ok(None)
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_create_index(table_name: &TableName, column_name: &ColumnName, db_schema: &DbSchema) -> Result<(), ValidationError> {
|
fn validate_create_index(table_name: TableName, column_name: ColumnName, db_schema: &DbSchema) -> Result<OperationForInterpreter, ValidationError> {
|
||||||
let schema = validate_table_exists(db_schema, table_name)?;
|
// TODO: You should disallow indexing of Number columns.
|
||||||
if schema.does_column_exist(column_name) {
|
let (table_position, schema) = validate_table_exists(db_schema, &table_name)?;
|
||||||
Ok(())
|
schema
|
||||||
} else {
|
.get_column_position(&column_name)
|
||||||
Err(ValidationError::ColumnsDoNotExist(vec![column_name.to_string()]))
|
.map_or_else(
|
||||||
}
|
|| Err(ValidationError::ColumnsDoNotExist(vec![column_name.to_string()])),
|
||||||
|
|column| Ok(OperationForInterpreter::CreateIndex(table_position, column))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===Helpers===
|
// ===Helpers===
|
||||||
|
|
@ -225,6 +188,6 @@ where A: Eq + std::hash::Hash
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_table_schema<'a>(db_schema: &DbSchema<'a>, table_name: &'a TableName) -> Option<&'a TableSchema> {
|
fn get_table_schema<'a>(db_schema: &DbSchema<'a>, table_name: &'a TableName) -> Option<&'a TableSchema> {
|
||||||
let (_, table_schema) = db_schema.iter().find(|(tname, _)| table_name.eq(tname))?;
|
let (_, _, table_schema) = db_schema.iter().find(|(tname, _, _)| table_name.eq(tname))?;
|
||||||
Some(table_schema)
|
Some(table_schema)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue