diff --git a/src/db/table/select/mod.rs b/src/db/table/select/mod.rs index 1b1ad64..50015eb 100644 --- a/src/db/table/select/mod.rs +++ b/src/db/table/select/mod.rs @@ -1,8 +1,8 @@ -pub mod where_clause; +pub mod where_stack; pub mod limit_clause; pub mod order_by_clause; use crate::db::table::{Table, Value}; -use crate::cli::ast::{Operand, SelectStatement, SelectStatementColumns, WhereStackElement}; +use crate::cli::ast::{SelectStatement, SelectStatementColumns}; use crate::db::table::common::validate_and_clone_row; @@ -23,24 +23,8 @@ pub fn select(table: &Table, statement: SelectStatement) -> Result Result>, String> { let mut rows: Vec> = vec![]; if let Some(where_stack) = &statement.where_clause { - // This will need to be updated once we have multiple conditions working properly - let where_clause = match where_stack.first() { - Some(WhereStackElement::Condition(where_clause)) => where_clause, - _ => return Err(format!("Found nothing when expected edge")), - }; - - // Will need to update once the where clause supports multiple conditions - let l_side = match &where_clause.l_side { - Operand::Identifier(column) => column, - _ => return Err(format!("Found invalid left side of where clause: {:?}", where_clause.l_side)), - }; - - if !table.has_column(&l_side) { - return Err(format!("Column {} does not exist in table {}", l_side, table.name)); - - } for row in table.rows.iter() { - if where_clause::matches_where_clause(table, &row, &where_clause) { + if where_stack::matches_where_stack(table, &row, &where_stack)? { rows.push(get_columns_from_row(table, &row, &statement.columns)?); } } diff --git a/src/db/table/select/where_clause.rs b/src/db/table/select/where_stack.rs similarity index 60% rename from src/db/table/select/where_clause.rs rename to src/db/table/select/where_stack.rs index 0e3afa6..060d4a0 100644 --- a/src/db/table/select/where_clause.rs +++ b/src/db/table/select/where_stack.rs @@ -1,51 +1,73 @@ -use crate::cli::ast::{Operator, WhereCondition, Operand}; +use crate::cli::ast::{Operator, WhereCondition, Operand, WhereStackElement}; use crate::db::table::{Table, Value, DataType}; // For now this function only supports one column = value where clause -pub fn matches_where_clause(table: &Table, row: &Vec, where_clause: &WhereCondition) -> bool { + +pub fn matches_where_stack(table: &Table, row: &Vec, where_stack: &Vec) -> Result { + let where_condition = match where_stack.first() { + Some(WhereStackElement::Condition(where_condition)) => where_condition, + _ => return Err(format!("Found nothing when expected edge")), + }; + + if let Operand::Identifier(column_name) = &where_condition.l_side { + if !table.has_column(column_name) { + return Err(format!("Column {} does not exist in table {}", column_name, table.name)); + } + } + + matches_where_clause(table, row, where_condition) +} + +pub fn matches_where_clause(table: &Table, row: &Vec, where_clause: &WhereCondition) -> Result { let l_side = match &where_clause.l_side { Operand::Identifier(column) => column, - _ => return false, + _ => return Err(format!("Found invalid left side of condition: {:?}", where_clause.l_side)), }; let r_side = match &where_clause.r_side { Operand::Value(value) => value, - _ => return false, + _ => return Err(format!("Found invalid right side of condition: {:?}", where_clause.r_side)), }; let column_value = table.get_column_from_row(row, &l_side); + if column_value.get_type() == DataType::Null && r_side.get_type() == DataType::Null { + return Ok(true); + } + else if column_value.get_type() == DataType::Null || r_side.get_type() == DataType::Null { + return Ok(false); + } if column_value.get_type() != r_side.get_type() { - return false; + return Err(format!("Found different data types for column and value: {:?} and {:?}", column_value.get_type(), r_side.get_type())); } match where_clause.operator { Operator::Equals => { - return *column_value == *r_side; + return Ok(*column_value == *r_side); }, Operator::NotEquals => { - return *column_value != *r_side; + return Ok(*column_value != *r_side); }, _ => { match column_value.get_type() { DataType::Integer | DataType::Real | DataType::Text => { match where_clause.operator { Operator::LessThan => { - return *column_value < *r_side; + return Ok(*column_value < *r_side); }, Operator::GreaterThan => { - return *column_value > *r_side; + return Ok(*column_value > *r_side); }, Operator::LessEquals => { - return *column_value <= *r_side; + return Ok(*column_value <= *r_side); }, Operator::GreaterEquals => { - return *column_value >= *r_side; + return Ok(*column_value >= *r_side); }, _ => { - return false; + return Err(format!("Found invalid operator: {:?}", where_clause.operator)); }, } }, _ => { - return false; + return Err(format!("Found invalid operator: {:?} for data type: {:?}", where_clause.operator, column_value.get_type())); }, } } @@ -68,7 +90,8 @@ mod tests { ]); let row = vec![Value::Integer(1)]; let where_clause = WhereCondition {l_side: Operand::Identifier("id".to_string()),operator:Operator::Equals,r_side: Operand::Value(Value::Integer(1))}; - assert!(matches_where_clause(&table, &row, &where_clause)); + let result = matches_where_clause(&table, &row, &where_clause); + assert!(result.is_ok() && result.unwrap()); } #[test] @@ -78,7 +101,8 @@ mod tests { ]); let row = vec![Value::Integer(2)]; let where_clause = WhereCondition {l_side: Operand::Identifier("id".to_string()),operator:Operator::Equals,r_side: Operand::Value(Value::Integer(1))}; - assert!(!matches_where_clause(&table, &row, &where_clause)); + let result = matches_where_clause(&table, &row, &where_clause); + assert!(result.is_ok() && !result.unwrap()); } #[test] @@ -92,7 +116,10 @@ mod tests { ]); let row = vec![Value::Integer(1)]; let where_clause = WhereCondition {l_side: Operand::Identifier("id".to_string()),operator:Operator::Equals,r_side: Operand::Value(Value::Text("Fletcher".to_string()))}; - assert!(!matches_where_clause(&table, &row, &where_clause)); + let result = matches_where_clause(&table, &row, &where_clause); + assert!(result.is_err()); + let expected_error = "Found different data types for column and value: Integer and Text"; + assert_eq!(expected_error, result.err().unwrap()); } #[test] @@ -102,15 +129,20 @@ mod tests { ]); let row = vec![Value::Integer(10)]; let where_clause = WhereCondition {l_side: Operand::Identifier("id".to_string()),operator:Operator::GreaterThan,r_side: Operand::Value(Value::Integer(0))}; - assert!(matches_where_clause(&table, &row, &where_clause)); + let result = matches_where_clause(&table, &row, &where_clause); + assert!(result.is_ok() && result.unwrap()); let where_clause = WhereCondition {l_side: Operand::Identifier("id".to_string()),operator:Operator::GreaterEquals,r_side: Operand::Value(Value::Integer(0))}; - assert!(matches_where_clause(&table, &row, &where_clause)); + let result = matches_where_clause(&table, &row, &where_clause); + assert!(result.is_ok() && result.unwrap()); let where_clause = WhereCondition {l_side: Operand::Identifier("id".to_string()),operator:Operator::LessThan,r_side: Operand::Value(Value::Integer(20))}; - assert!(matches_where_clause(&table, &row, &where_clause)); + let result = matches_where_clause(&table, &row, &where_clause); + assert!(result.is_ok() && result.unwrap()); let where_clause = WhereCondition {l_side: Operand::Identifier("id".to_string()),operator:Operator::LessEquals,r_side: Operand::Value(Value::Integer(20))}; - assert!(matches_where_clause(&table, &row, &where_clause)); + let result = matches_where_clause(&table, &row, &where_clause); + assert!(result.is_ok() && result.unwrap()); let where_clause = WhereCondition {l_side: Operand::Identifier("id".to_string()),operator:Operator::NotEquals,r_side: Operand::Value(Value::Integer(10))}; - assert!(!matches_where_clause(&table, &row, &where_clause)); + let result = matches_where_clause(&table, &row, &where_clause); + assert!(result.is_ok() && !result.unwrap()); } #[test] @@ -120,17 +152,23 @@ mod tests { ]); let row = vec![Value::Text("lop".to_string())]; let where_clause = WhereCondition {l_side: Operand::Identifier("name".to_string()),operator:Operator::GreaterEquals,r_side: Operand::Value(Value::Text("abc".to_string()))}; - assert!(matches_where_clause(&table, &row, &where_clause)); + let result = matches_where_clause(&table, &row, &where_clause); + assert!(result.is_ok() && result.unwrap()); let where_clause = WhereCondition {l_side: Operand::Identifier("name".to_string()),operator:Operator::LessEquals,r_side: Operand::Value(Value::Text("lop".to_string()))}; - assert!(matches_where_clause(&table, &row, &where_clause)); + let result = matches_where_clause(&table, &row, &where_clause); + assert!(result.is_ok() && result.unwrap()); let where_clause = WhereCondition {l_side: Operand::Identifier("name".to_string()),operator:Operator::GreaterThan,r_side: Operand::Value(Value::Text("xyz".to_string()))}; - assert!(!matches_where_clause(&table, &row, &where_clause)); + let result = matches_where_clause(&table, &row, &where_clause); + assert!(result.is_ok() && !result.unwrap()); let where_clause = WhereCondition {l_side: Operand::Identifier("name".to_string()),operator:Operator::LessThan,r_side: Operand::Value(Value::Text("abc".to_string()))}; - assert!(!matches_where_clause(&table, &row, &where_clause)); + let result = matches_where_clause(&table, &row, &where_clause); + assert!(result.is_ok() && !result.unwrap()); let where_clause = WhereCondition {l_side: Operand::Identifier("name".to_string()),operator:Operator::NotEquals,r_side: Operand::Value(Value::Text("abc".to_string()))}; - assert!(matches_where_clause(&table, &row, &where_clause)); + let result = matches_where_clause(&table, &row, &where_clause); + assert!(result.is_ok() && result.unwrap()); let where_clause = WhereCondition {l_side: Operand::Identifier("name".to_string()),operator:Operator::Equals,r_side: Operand::Value(Value::Text("lop".to_string()))}; - assert!(matches_where_clause(&table, &row, &where_clause)); + let result = matches_where_clause(&table, &row, &where_clause); + assert!(result.is_ok() && result.unwrap()); } #[test] @@ -140,7 +178,8 @@ mod tests { ]); let row = vec![Value::Null]; let where_clause = WhereCondition {l_side: Operand::Identifier("id".to_string()),operator:Operator::GreaterEquals,r_side: Operand::Value(Value::Integer(1))}; - assert!(!matches_where_clause(&table, &row, &where_clause)); + let result = matches_where_clause(&table, &row, &where_clause); + assert!(result.is_ok() && !result.unwrap()); } #[test] @@ -150,6 +189,9 @@ mod tests { ]); let row = vec![Value::Blob(vec![1, 2, 3])]; let where_clause = WhereCondition {l_side: Operand::Identifier("id".to_string()),operator:Operator::GreaterEquals,r_side: Operand::Value(Value::Blob(vec![1, 2, 3]))}; - assert!(!matches_where_clause(&table, &row, &where_clause)); + let result = matches_where_clause(&table, &row, &where_clause); + assert!(result.is_err()); + let expected_error = "Found invalid operator: GreaterEquals for data type: Blob"; + assert_eq!(expected_error, result.err().unwrap()); } } \ No newline at end of file