logic exprs
This commit is contained in:
parent
a26ea16f55
commit
824a5cdb43
6 changed files with 474 additions and 26 deletions
|
@ -4,12 +4,13 @@ use std::io::{BufRead, BufReader, Read, Write};
|
|||
use std::net::{Shutdown, TcpListener, TcpStream};
|
||||
use std::thread;
|
||||
use std::collections::HashMap;
|
||||
use std::cmp;
|
||||
|
||||
mod parser;
|
||||
pub use parser::command::Command;
|
||||
|
||||
mod table;
|
||||
use parser::command::{CreateCommand, InsertCommand, SelectCommand, DeleteCommand};
|
||||
use parser::command::{CreateCommand, InsertCommand, SelectCommand, DeleteCommand, LogicExpression, InsertItem, LogicValue};
|
||||
pub use table::datatypes::Datatype;
|
||||
pub use table::table_definition::{ColumnDefinition, TableDefinition};
|
||||
|
||||
|
@ -93,17 +94,40 @@ fn handle_delete(command: DeleteCommand) -> ::anyhow::Result<String> {
|
|||
let mut buf: Vec<u8> = vec![0; tabledef.get_byte_size()];
|
||||
let mut row_count: usize = 0;
|
||||
|
||||
while file.read_exact(buf.as_mut_slice()).is_ok() {
|
||||
row_count += 1;
|
||||
}
|
||||
|
||||
let _ = fs::remove_file(format!("./data/blobs/{}", command.table_name));
|
||||
|
||||
let _ = fs::OpenOptions::new()
|
||||
let mut new_file = fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.append(true)
|
||||
.open(format!("./data/blobs/{}", command.table_name))?;
|
||||
.open(format!("./data/blobs/{}_new", command.table_name))?;
|
||||
|
||||
while file.read_exact(buf.as_mut_slice()).is_ok() {
|
||||
let mut row_data: HashMap<String, LogicValue> = HashMap::new();
|
||||
let mut idx: usize = 0;
|
||||
if let Some(ref le) = command.logic_expression {
|
||||
let mut logic_expr = le.clone();
|
||||
for col_def in &tabledef.column_defs {
|
||||
let len = if col_def.length > 0 {
|
||||
col_def.length
|
||||
} else {
|
||||
1
|
||||
};
|
||||
let str_val = col_def.data_type.from_bytes(&buf[idx..(idx + len)])?;
|
||||
idx += len;
|
||||
row_data.insert(col_def.name.clone(), LogicValue::from_string(str_val)?);
|
||||
}
|
||||
idx = 0;
|
||||
logic_expr.fill_values(row_data);
|
||||
if !logic_expr.evaluate()? {
|
||||
new_file.write_all(&buf)?;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
row_count += 1;
|
||||
}
|
||||
new_file.flush()?;
|
||||
|
||||
let _ = fs::remove_file(format!("./data/blobs/{}", command.table_name))?;
|
||||
let _ = fs::rename(format!("./data/blobs/{}_new", command.table_name), format!("./data/blobs/{}", command.table_name))?;
|
||||
|
||||
return Ok(format!("{} Rows Deleted", row_count));
|
||||
}
|
||||
|
@ -124,15 +148,10 @@ fn handle_select(command: SelectCommand) -> ::anyhow::Result<String> {
|
|||
}
|
||||
}
|
||||
|
||||
response += "| ";
|
||||
for col_name in &column_names {
|
||||
response += format!("{} | ", col_name).as_str();
|
||||
}
|
||||
response += "\n";
|
||||
response += "-----------\n";
|
||||
let mut buf: Vec<u8> = vec![0; tabledef.get_byte_size()];
|
||||
|
||||
let mut table: HashMap<String, Vec<String>> = HashMap::new();
|
||||
let mut longest_cols: HashMap<String, usize> = HashMap::new();
|
||||
let mut num_rows: usize = 0;
|
||||
|
||||
for col_name in &column_names {
|
||||
|
@ -141,6 +160,26 @@ fn handle_select(command: SelectCommand) -> ::anyhow::Result<String> {
|
|||
|
||||
while file.read_exact(buf.as_mut_slice()).is_ok() {
|
||||
let mut idx: usize = 0;
|
||||
let mut row_data: HashMap<String, LogicValue> = HashMap::new();
|
||||
if let Some(ref le) = command.logic_expression {
|
||||
let mut logic_expr = le.clone();
|
||||
for col_def in &tabledef.column_defs {
|
||||
let len = if col_def.length > 0 {
|
||||
col_def.length
|
||||
} else {
|
||||
1
|
||||
};
|
||||
let str_val = col_def.data_type.from_bytes(&buf[idx..(idx + len)])?;
|
||||
idx += len;
|
||||
row_data.insert(col_def.name.clone(), LogicValue::from_string(str_val)?);
|
||||
}
|
||||
idx = 0;
|
||||
logic_expr.fill_values(row_data);
|
||||
if !logic_expr.evaluate()? {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
for col_def in &tabledef.column_defs {
|
||||
let len = if col_def.length > 0 {
|
||||
col_def.length
|
||||
|
@ -148,18 +187,36 @@ fn handle_select(command: SelectCommand) -> ::anyhow::Result<String> {
|
|||
1
|
||||
};
|
||||
if column_names.iter().any(|col_name| &col_def.name == col_name) {
|
||||
let str_val = col_def.data_type.from_bytes(&buf[idx..(idx + len)])?;
|
||||
table.get_mut(&col_def.name).unwrap().push(str_val);
|
||||
let str_val = col_def.data_type.from_bytes(&buf[idx..(idx + len)])?.trim_matches(char::from(0)).to_string();
|
||||
table.get_mut(&col_def.name).unwrap().push(str_val.clone());
|
||||
longest_cols.entry(col_def.name.clone()).and_modify(|val| *val = cmp::max(*val, str_val.len())).or_insert(str_val.len());
|
||||
}
|
||||
idx += len;
|
||||
}
|
||||
num_rows += 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// construct table string
|
||||
response += "| ";
|
||||
for col_name in &column_names {
|
||||
longest_cols.entry(col_name.clone()).and_modify(|val| *val = cmp::max(*val, col_name.len())).or_insert(col_name.len());
|
||||
response += format!("{:0width$} | ", col_name, width = longest_cols.get(col_name).unwrap()).as_str();
|
||||
}
|
||||
let mut total_length: usize = 1;
|
||||
for (col_name, max_len) in longest_cols.clone() {
|
||||
total_length += max_len + 3;
|
||||
}
|
||||
response += "\n";
|
||||
for i in 0..total_length {
|
||||
response += "-";
|
||||
}
|
||||
response += "\n";
|
||||
for i in 0..num_rows {
|
||||
response += "| ";
|
||||
for col_name in &column_names {
|
||||
response += format!("{} | ", table.get(col_name).unwrap()[i]).as_str();
|
||||
response += format!("{:0width$} | ", table.get(col_name).unwrap()[i], width = longest_cols.get(col_name).unwrap()).as_str();
|
||||
}
|
||||
response += "\n";
|
||||
}
|
||||
|
@ -261,6 +318,40 @@ fn main() -> std::io::Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn logical_expression() -> anyhow::Result<()> {
|
||||
assert_eq!(Command::le_from_string(String::from("1 < 5")).unwrap().evaluate().unwrap(), true);
|
||||
assert_eq!(Command::le_from_string(String::from("1 > 5")).unwrap().evaluate().unwrap(), false);
|
||||
assert_eq!(Command::le_from_string(String::from("1 <= 5")).unwrap().evaluate().unwrap(), true);
|
||||
assert_eq!(Command::le_from_string(String::from("1 >= 5")).unwrap().evaluate().unwrap(), false);
|
||||
assert_eq!(Command::le_from_string(String::from("5 >= 5")).unwrap().evaluate().unwrap(), true);
|
||||
assert_eq!(Command::le_from_string(String::from("5 <= 5")).unwrap().evaluate().unwrap(), true);
|
||||
assert_eq!(Command::le_from_string(String::from("5 = 5")).unwrap().evaluate().unwrap(), true);
|
||||
assert_eq!(Command::le_from_string(String::from("5 AND 5")).unwrap().evaluate().is_ok(), false);
|
||||
assert_eq!(Command::le_from_string(String::from("5 OR 5")).unwrap().evaluate().is_ok(), false);
|
||||
|
||||
assert_eq!(Command::le_from_string(String::from("'Test' = 'Test'")).unwrap().evaluate().unwrap(), true);
|
||||
assert_eq!(Command::le_from_string(String::from("'Test' = 'Text'")).unwrap().evaluate().unwrap(), false);
|
||||
assert_eq!(Command::le_from_string(String::from("'Test' <= 'Test'")).unwrap().evaluate().is_ok(), false);
|
||||
assert_eq!(Command::le_from_string(String::from("'Test' >= 'Test'")).unwrap().evaluate().is_ok(), false);
|
||||
assert_eq!(Command::le_from_string(String::from("'Test' < 'Test'")).unwrap().evaluate().is_ok(), false);
|
||||
assert_eq!(Command::le_from_string(String::from("'Test' > 'Test'")).unwrap().evaluate().is_ok(), false);
|
||||
assert_eq!(Command::le_from_string(String::from("'Test' AND 'Test'")).unwrap().evaluate().is_ok(), false);
|
||||
assert_eq!(Command::le_from_string(String::from("'Test' OR 'Test'")).unwrap().evaluate().is_ok(), false);
|
||||
|
||||
assert_eq!(Command::le_from_string(String::from("'Test' < 5")).unwrap().evaluate().is_ok(), false);
|
||||
assert_eq!(Command::le_from_string(String::from("'Test' > 5")).unwrap().evaluate().is_ok(), false);
|
||||
assert_eq!(Command::le_from_string(String::from("'Test' <= 5")).unwrap().evaluate().is_ok(), false);
|
||||
assert_eq!(Command::le_from_string(String::from("'Test' >= 5")).unwrap().evaluate().is_ok(), false);
|
||||
assert_eq!(Command::le_from_string(String::from("'Test' >= 5")).unwrap().evaluate().is_ok(), false);
|
||||
assert_eq!(Command::le_from_string(String::from("'Test' <= 5")).unwrap().evaluate().is_ok(), false);
|
||||
assert_eq!(Command::le_from_string(String::from("'Test' = 5")).unwrap().evaluate().is_ok(), false);
|
||||
assert_eq!(Command::le_from_string(String::from("'Test' AND 5")).unwrap().evaluate().is_ok(), false);
|
||||
assert_eq!(Command::le_from_string(String::from("'Test' OR 5")).unwrap().evaluate().is_ok(), false);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_statement() -> anyhow::Result<()> {
|
||||
let empty_statement = "";
|
||||
|
@ -335,5 +426,6 @@ fn insert_statement() -> anyhow::Result<()> {
|
|||
expected_output_comma
|
||||
);
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use std::collections::{HashMap, HashSet};
|
||||
use std::mem;
|
||||
|
||||
use crate::table::table_definition::ColumnDefinition;
|
||||
use crate::{Datatype, TableDefinition};
|
||||
|
@ -20,6 +21,7 @@ pub struct CreateCommand {
|
|||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct DeleteCommand {
|
||||
pub table_name: String,
|
||||
pub logic_expression: Option<LogicExpression>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
|
@ -32,6 +34,7 @@ pub struct InsertCommand {
|
|||
pub struct SelectCommand {
|
||||
pub table_name: String,
|
||||
pub column_names: Vec<String>,
|
||||
pub logic_expression: Option<LogicExpression>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
|
@ -40,6 +43,38 @@ pub struct InsertItem {
|
|||
pub column_value: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||
enum LogicalOperator {
|
||||
Equal,
|
||||
GreaterThan,
|
||||
LessThan,
|
||||
GreaterThanEqualTo,
|
||||
LessThanEqualTo,
|
||||
And,
|
||||
Or,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||
pub enum LogicValue {
|
||||
StringValue(String),
|
||||
U8Value(u8),
|
||||
BoolValue(bool),
|
||||
ColumnName(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub enum LogicSide {
|
||||
// pub expression: LogicExpression,
|
||||
Value(LogicValue)
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||
pub struct LogicExpression {
|
||||
pub left_hand: LogicValue,
|
||||
pub right_hand: LogicValue,
|
||||
pub operator: LogicalOperator
|
||||
}
|
||||
|
||||
enum CreateParserState {
|
||||
Object,
|
||||
TableName,
|
||||
|
@ -55,12 +90,14 @@ enum SelectParserState {
|
|||
ColumnName,
|
||||
ColumnNameCommaOrFrom,
|
||||
TableName,
|
||||
WhereKeywordOrSemicolon,
|
||||
Semicolon,
|
||||
}
|
||||
|
||||
enum DeleteParserState {
|
||||
FromKeyword,
|
||||
TableName,
|
||||
WhereKeywordOrSemicolon,
|
||||
Semicolon,
|
||||
}
|
||||
|
||||
|
@ -77,8 +114,17 @@ enum InsertParserState {
|
|||
Semicolon,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum LogicExpressionParserState {
|
||||
NumberOrQuoteOrColname,
|
||||
StringValue,
|
||||
EndQuote,
|
||||
Operator,
|
||||
}
|
||||
|
||||
|
||||
pub fn tokenizer(text: String) -> Vec<String> {
|
||||
let parts = HashSet::from([' ', ',', ';', '(', ')']);
|
||||
let parts = HashSet::from([' ', ',', ';', '(', ')', '\'']);
|
||||
let mut tokens: Vec<String> = vec![];
|
||||
let mut cur_str = String::new();
|
||||
let mut in_quotes = false;
|
||||
|
@ -100,10 +146,154 @@ pub fn tokenizer(text: String) -> Vec<String> {
|
|||
cur_str.push(cur_char);
|
||||
}
|
||||
}
|
||||
tokens.push(cur_str);
|
||||
|
||||
tokens
|
||||
}
|
||||
|
||||
impl LogicValue {
|
||||
pub fn from_string(string: String) -> ::anyhow::Result<LogicValue> {
|
||||
let test = string.parse::<u8>();
|
||||
match test {
|
||||
Ok(u8_val) => {
|
||||
return Ok(LogicValue::U8Value(u8_val));
|
||||
},
|
||||
Err(_) => {
|
||||
let res = string.trim_matches(char::from(0));
|
||||
return Ok(LogicValue::StringValue(res.to_string()));
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LogicExpression {
|
||||
pub fn is_valid(&self) -> bool {
|
||||
return mem::discriminant(&self.left_hand) == mem::discriminant(&self.right_hand);
|
||||
}
|
||||
|
||||
pub fn is_evaluatable(&self) -> bool {
|
||||
return mem::discriminant(&self.left_hand) != mem::discriminant(&LogicValue::ColumnName(String::from(""))) &&
|
||||
mem::discriminant(&self.right_hand) != mem::discriminant(&LogicValue::ColumnName(String::from("")));
|
||||
}
|
||||
|
||||
pub fn fill_values(&mut self, hmap: HashMap<String, LogicValue>) -> ::anyhow::Result<()> {
|
||||
for (name, value) in hmap {
|
||||
if self.left_hand == LogicValue::ColumnName(name.clone()) {
|
||||
self.left_hand = value.clone();
|
||||
}
|
||||
if self.right_hand == LogicValue::ColumnName(name.clone()) {
|
||||
self.right_hand = value.clone();
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn evaluate(&self) -> ::anyhow::Result<bool> {
|
||||
if !self.is_evaluatable() {
|
||||
return Err(anyhow!("Logical expression has not been properly filled. (Do you have a typo in a column name?)"));
|
||||
}
|
||||
if !self.is_valid() {
|
||||
return Err(anyhow!("Logical expression is comparing 2 differing datatypes"));
|
||||
}
|
||||
println!("{:?}", self);
|
||||
match self.left_hand {
|
||||
LogicValue::StringValue(_) => {
|
||||
return self.evaluate_string();
|
||||
}
|
||||
LogicValue::BoolValue(_) => {
|
||||
return self.evaluate_bool();
|
||||
}
|
||||
LogicValue::U8Value(_) => {
|
||||
return self.evaluate_u8();
|
||||
}
|
||||
LogicValue::ColumnName(_) => {
|
||||
return Err(anyhow!("Cannot compare names of 2 columns, only values"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn evaluate_string(&self) -> ::anyhow::Result<bool> {
|
||||
match self.operator {
|
||||
LogicalOperator::Equal => {
|
||||
return Ok(self.left_hand == self.right_hand);
|
||||
}
|
||||
_ => {
|
||||
return Err(anyhow!("Invalid operator for datatype varchar"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn evaluate_bool(&self) -> ::anyhow::Result<bool>{
|
||||
match self.operator {
|
||||
LogicalOperator::Equal => {
|
||||
return Ok(self.left_hand == self.right_hand);
|
||||
}
|
||||
LogicalOperator::And => {
|
||||
if let LogicValue::BoolValue(left) = self.left_hand {
|
||||
if let LogicValue::BoolValue(right) = self.right_hand {
|
||||
return Ok(left && right);
|
||||
}
|
||||
}
|
||||
return Err(anyhow!("Mismatched datatypes"));
|
||||
}
|
||||
LogicalOperator::Or => {
|
||||
if let LogicValue::BoolValue(left) = self.left_hand {
|
||||
if let LogicValue::BoolValue(right) = self.right_hand {
|
||||
return Ok(left || right);
|
||||
}
|
||||
}
|
||||
return Err(anyhow!("Mismatched datatypes"));
|
||||
}
|
||||
_ => {
|
||||
return Err(anyhow!("Invalid operator for datatype bool"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn evaluate_u8(&self) -> ::anyhow::Result<bool>{
|
||||
match self.operator {
|
||||
LogicalOperator::Equal => {
|
||||
return Ok(self.left_hand == self.right_hand);
|
||||
}
|
||||
LogicalOperator::GreaterThan => {
|
||||
if let LogicValue::U8Value(left) = self.left_hand {
|
||||
if let LogicValue::U8Value(right) = self.right_hand {
|
||||
return Ok(left > right);
|
||||
}
|
||||
}
|
||||
return Err(anyhow!("Mismatched datatypes"));
|
||||
}
|
||||
LogicalOperator::LessThan => {
|
||||
if let LogicValue::U8Value(left) = self.left_hand {
|
||||
if let LogicValue::U8Value(right) = self.right_hand {
|
||||
return Ok(left < right);
|
||||
}
|
||||
}
|
||||
return Err(anyhow!("Mismatched datatypes"));
|
||||
}
|
||||
LogicalOperator::GreaterThanEqualTo => {
|
||||
if let LogicValue::U8Value(left) = self.left_hand {
|
||||
if let LogicValue::U8Value(right) = self.right_hand {
|
||||
return Ok(left >= right);
|
||||
}
|
||||
}
|
||||
return Err(anyhow!("Mismatched datatypes"));
|
||||
}
|
||||
LogicalOperator::LessThanEqualTo => {
|
||||
if let LogicValue::U8Value(left) = self.left_hand {
|
||||
if let LogicValue::U8Value(right) = self.right_hand {
|
||||
return Ok(left <= right);
|
||||
}
|
||||
}
|
||||
return Err(anyhow!("Mismatched datatypes"));
|
||||
}
|
||||
_ => {
|
||||
return Err(anyhow!("Invalid operator for datatype integer"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Command {
|
||||
fn parse_insert_command(tokens: &mut Vec<String>) -> ::anyhow::Result<Command> {
|
||||
let mut state: InsertParserState = InsertParserState::IntoKeyword;
|
||||
|
@ -218,12 +408,93 @@ impl Command {
|
|||
Err(anyhow!("Unexpected end of input"))
|
||||
}
|
||||
|
||||
fn parse_logic_expression(tokens: &mut Vec<String>) -> ::anyhow::Result<LogicExpression> {
|
||||
let mut state: LogicExpressionParserState = LogicExpressionParserState::NumberOrQuoteOrColname;
|
||||
let mut left_hand: Option<LogicValue> = None;
|
||||
let mut right_hand: Option<LogicValue> = None;
|
||||
let mut operator: Option<LogicalOperator> = None;
|
||||
|
||||
while let Some(token) = &tokens.pop() {
|
||||
match state {
|
||||
LogicExpressionParserState::NumberOrQuoteOrColname => {
|
||||
if token == "'" {
|
||||
state = LogicExpressionParserState::StringValue;
|
||||
} else {
|
||||
let test = token.parse::<u8>();
|
||||
match test {
|
||||
Ok(u8_val) => {
|
||||
if left_hand.is_none() {
|
||||
left_hand = Some(LogicValue::U8Value(u8_val));
|
||||
state = LogicExpressionParserState::Operator;
|
||||
} else {
|
||||
right_hand = Some(LogicValue::U8Value(u8_val));
|
||||
return Ok(LogicExpression {left_hand: left_hand.unwrap(), right_hand: right_hand.unwrap(), operator: operator.unwrap()});
|
||||
}
|
||||
},
|
||||
Err(_) => {
|
||||
if left_hand.is_none() {
|
||||
left_hand = Some(LogicValue::ColumnName(token.to_string()));
|
||||
state = LogicExpressionParserState::Operator;
|
||||
} else {
|
||||
right_hand = Some(LogicValue::ColumnName(token.to_string()));
|
||||
return Ok(LogicExpression {left_hand: left_hand.unwrap(), right_hand: right_hand.unwrap(), operator: operator.unwrap()});
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
LogicExpressionParserState::StringValue => {
|
||||
let mut value: Option<LogicValue> = None;
|
||||
if token == "'" {
|
||||
value = Some(LogicValue::StringValue("".to_string()));
|
||||
} else {
|
||||
value = Some(LogicValue::StringValue(token.to_string()));
|
||||
}
|
||||
if left_hand.is_none() {
|
||||
left_hand = value;
|
||||
} else {
|
||||
right_hand = value;
|
||||
}
|
||||
state = LogicExpressionParserState::EndQuote;
|
||||
}
|
||||
LogicExpressionParserState::EndQuote => {
|
||||
if token == "'" {
|
||||
if right_hand.is_none() {
|
||||
state = LogicExpressionParserState::Operator;
|
||||
} else {
|
||||
return Ok(LogicExpression {left_hand: left_hand.unwrap(), right_hand: right_hand.unwrap(), operator: operator.unwrap()});
|
||||
}
|
||||
} else {
|
||||
return Err(anyhow!("Expected end quote at or near {}", token));
|
||||
}
|
||||
}
|
||||
LogicExpressionParserState::Operator => {
|
||||
operator = match token.as_str() {
|
||||
"OR" => Some(LogicalOperator::Or),
|
||||
"AND" => Some(LogicalOperator::And),
|
||||
"=" => Some(LogicalOperator::Equal),
|
||||
">" => Some(LogicalOperator::GreaterThan),
|
||||
"<" => Some(LogicalOperator::LessThan),
|
||||
">=" => Some(LogicalOperator::GreaterThanEqualTo),
|
||||
"<=" => Some(LogicalOperator::LessThanEqualTo),
|
||||
_ => return Err(anyhow!("Unknown operator {}", token))
|
||||
};
|
||||
state = LogicExpressionParserState::NumberOrQuoteOrColname;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(anyhow!("Unexpected end of input"))
|
||||
}
|
||||
|
||||
fn parse_select_command(tokens: &mut Vec<String>) -> ::anyhow::Result<Command> {
|
||||
let mut state: SelectParserState = SelectParserState::ColumnName;
|
||||
|
||||
// intermediate tmp vars
|
||||
let mut table_name = String::new();
|
||||
let mut column_names: Vec<String> = vec![];
|
||||
let mut logic_expression: Option<LogicExpression> = None;
|
||||
|
||||
while let Some(token) = &tokens.pop() {
|
||||
match state {
|
||||
|
@ -246,13 +517,24 @@ impl Command {
|
|||
}
|
||||
SelectParserState::TableName => {
|
||||
table_name = token.to_string();
|
||||
state = SelectParserState::Semicolon;
|
||||
state = SelectParserState::WhereKeywordOrSemicolon;
|
||||
}
|
||||
SelectParserState::WhereKeywordOrSemicolon => {
|
||||
if token == ";" {
|
||||
return Ok(Command::Select(SelectCommand { table_name, column_names, logic_expression: None }));
|
||||
} else if token == "WHERE" {
|
||||
logic_expression = Some(Self::parse_logic_expression(tokens)?);
|
||||
state = SelectParserState::Semicolon;
|
||||
} else {
|
||||
return Err(anyhow!("Expected semicolon at or near '{}'", token));
|
||||
|
||||
}
|
||||
}
|
||||
SelectParserState::Semicolon => {
|
||||
if token != ";" {
|
||||
return Err(anyhow!("Expected semicolon at or near '{}'", token));
|
||||
} else {
|
||||
return Ok(Command::Select(SelectCommand { table_name, column_names }));
|
||||
return Ok(Command::Select(SelectCommand { table_name, column_names, logic_expression }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -267,6 +549,7 @@ impl Command {
|
|||
|
||||
// intermediate tmp vars
|
||||
let mut table_name = String::new();
|
||||
let mut logic_expression: Option<LogicExpression> = None;
|
||||
|
||||
while let Some(token) = &tokens.pop() {
|
||||
match state {
|
||||
|
@ -279,13 +562,23 @@ impl Command {
|
|||
}
|
||||
DeleteParserState::TableName => {
|
||||
table_name = token.to_string();
|
||||
state = DeleteParserState::Semicolon;
|
||||
state = DeleteParserState::WhereKeywordOrSemicolon;
|
||||
}
|
||||
DeleteParserState::WhereKeywordOrSemicolon => {
|
||||
if token == ";" {
|
||||
return Ok(Command::Delete(DeleteCommand { table_name, logic_expression: None }));
|
||||
} else if token == "WHERE" {
|
||||
logic_expression = Some(Self::parse_logic_expression(tokens)?);
|
||||
state = DeleteParserState::Semicolon;
|
||||
} else {
|
||||
return Err(anyhow!("Expected semicolon at or near '{}'", token));
|
||||
}
|
||||
}
|
||||
DeleteParserState::Semicolon => {
|
||||
if token != ";" {
|
||||
return Err(anyhow!("Expected semicolon at or near '{}'", token));
|
||||
} else {
|
||||
return Ok(Command::Delete(DeleteCommand { table_name }));
|
||||
return Ok(Command::Delete(DeleteCommand { table_name, logic_expression }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -400,4 +693,12 @@ impl Command {
|
|||
|
||||
Err(anyhow!("Unexpected end of statement"))
|
||||
}
|
||||
|
||||
pub fn le_from_string(command_str: String) -> ::anyhow::Result<LogicExpression> {
|
||||
let mut tokens: Vec<String> = tokenizer(command_str.clone());
|
||||
println!("{}", command_str);
|
||||
println!("{:?}", tokens);
|
||||
tokens.reverse();
|
||||
return Ok(Self::parse_logic_expression(&mut tokens)?);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue