diff --git a/squirrel-server/src/main.rs b/squirrel-server/src/main.rs index 6adaf7b..6cd4f66 100644 --- a/squirrel-server/src/main.rs +++ b/squirrel-server/src/main.rs @@ -10,7 +10,7 @@ pub use parser::command::Command; mod table; use parser::command::{CreateCommand, InsertCommand, SelectCommand}; pub use table::datatypes::Datatype; -pub use table::table::{ColumnDefinition, TableDefinition}; +pub use table::table_definition::{ColumnDefinition, TableDefinition}; const BUFFER_SIZE: usize = 500; @@ -27,7 +27,7 @@ fn handle_create(command: CreateCommand) -> ::anyhow::Result { column.data_type.as_str(), column.length ); - file.write_all(line.as_bytes()).unwrap(); + file.write_all(line.as_bytes())?; } Ok(command.table_definition) @@ -43,7 +43,7 @@ fn read_tabledef(table_name: String) -> ::anyhow::Result { let parts: Vec<&str> = line_str.split(' ').collect(); let col_def = ColumnDefinition { name: parts[0].to_string(), - data_type: Datatype::from_str(parts[1]).unwrap(), + data_type: Datatype::parse_from_str(parts[1])?, length: parts[2].parse::()?.into(), }; column_defs.push(col_def); @@ -60,10 +60,9 @@ fn handle_insert(command: InsertCommand) -> ::anyhow::Result<()> { .create(true) .write(true) .append(true) - .open(format!("./data/blobs/{}", command.table_name)) - .unwrap(); + .open(format!("./data/blobs/{}", command.table_name))?; - let tabledef = read_tabledef(command.table_name).unwrap(); + let tabledef = read_tabledef(command.table_name)?; for col_def in &tabledef.column_defs { if let Some(insert_item) = command.items.get(&col_def.name) { @@ -89,7 +88,7 @@ fn handle_insert(command: InsertCommand) -> ::anyhow::Result<()> { fn handle_select(command: SelectCommand) -> ::anyhow::Result { let mut file = fs::File::open(format!("./data/blobs/{}", command.table_name))?; - let tabledef = read_tabledef(command.table_name).unwrap(); + let tabledef = read_tabledef(command.table_name)?; let mut response = String::new(); response += "| "; diff --git a/squirrel-server/src/parser/command.rs b/squirrel-server/src/parser/command.rs index 7753a44..3a224f8 100644 --- a/squirrel-server/src/parser/command.rs +++ b/squirrel-server/src/parser/command.rs @@ -1,6 +1,6 @@ use std::collections::{HashMap, HashSet}; -use crate::table::table::ColumnDefinition; +use crate::table::table_definition::ColumnDefinition; use crate::{Datatype, TableDefinition}; use anyhow::anyhow; @@ -36,34 +36,34 @@ pub struct InsertItem { } enum CreateParserState { - FindObject, - FindTableName, - FindColumnName, - FindColumnDefinitions, - FindColumnDatatype, - FindColumnDefinitionEnd, - FindColumnLength, - FindSemicolon, + Object, + TableName, + ColumnName, + ColumnDefinitions, + ColumnDatatype, + ColumnDefinitionEnd, + ColumnLength, + Semicolon, } enum SelectParserState { - FindWildcard, // Temporary, col selection coming soon - FindFrom, - FindTableName, - FindSemicolon, + Wildcard, // Temporary, col selection coming soon + FromKeyword, + TableName, + Semicolon, } enum InsertParserState { - FindIntoKeyword, - FindTableName, - FindColumnListBegin, - FindColumnName, - FindColumnNameEnd, - FindValuesKeyword, - FindValuesListBegin, - FindValue, - FindValueEnd, - FindSemicolon, + IntoKeyword, + TableName, + ColumnListBegin, + ColumnName, + ColumnNameEnd, + ValuesKeyword, + ValuesListBegin, + Value, + ValueEnd, + Semicolon, } pub fn tokenizer(text: String) -> Vec { @@ -95,7 +95,7 @@ pub fn tokenizer(text: String) -> Vec { impl Command { fn parse_insert_command(tokens: &mut Vec) -> ::anyhow::Result { - let mut state: InsertParserState = InsertParserState::FindIntoKeyword; + let mut state: InsertParserState = InsertParserState::IntoKeyword; let mut table_name = String::new(); let mut column_name = String::new(); @@ -106,35 +106,35 @@ impl Command { while let Some(token) = &tokens.pop() { match state { - InsertParserState::FindIntoKeyword => { + InsertParserState::IntoKeyword => { if !token.eq_ignore_ascii_case("INTO") { return Err(anyhow!("Expected to find INTO at or near '{}'", token)); } else { - state = InsertParserState::FindTableName; + state = InsertParserState::TableName; } } - InsertParserState::FindTableName => { + InsertParserState::TableName => { table_name = token.to_string(); - state = InsertParserState::FindColumnListBegin; + state = InsertParserState::ColumnListBegin; } - InsertParserState::FindColumnListBegin => { + InsertParserState::ColumnListBegin => { if token != "(" { return Err(anyhow!( "Unexpected token at or near '{}'. Expected start of column list", token )); } - state = InsertParserState::FindColumnName; + state = InsertParserState::ColumnName; } - InsertParserState::FindColumnName => { + InsertParserState::ColumnName => { column_name = token.to_string(); - state = InsertParserState::FindColumnNameEnd; + state = InsertParserState::ColumnNameEnd; } - InsertParserState::FindColumnNameEnd => { + InsertParserState::ColumnNameEnd => { if token == "," { - state = InsertParserState::FindColumnName; + state = InsertParserState::ColumnName; } else if token == ")" { - state = InsertParserState::FindValuesKeyword; + state = InsertParserState::ValuesKeyword; } else { return Err(anyhow!( "Unexpected token at or near '{}'. Expected comma or rparen.", @@ -143,33 +143,33 @@ impl Command { } column_list.push(column_name.clone()); } - InsertParserState::FindValuesKeyword => { + InsertParserState::ValuesKeyword => { if token != "VALUES" { return Err(anyhow!( "Unexpected token at or near '{}'. Expected 'VALUES'.", token )); } - state = InsertParserState::FindValuesListBegin; + state = InsertParserState::ValuesListBegin; } - InsertParserState::FindValuesListBegin => { + InsertParserState::ValuesListBegin => { if token != "(" { return Err(anyhow!( "Unexpected token at or near '{}'. Expected start of values list", token )); } - state = InsertParserState::FindValue; + state = InsertParserState::Value; } - InsertParserState::FindValue => { + InsertParserState::Value => { column_val = token.to_string(); - state = InsertParserState::FindValueEnd; + state = InsertParserState::ValueEnd; } - InsertParserState::FindValueEnd => { + InsertParserState::ValueEnd => { if token == "," { - state = InsertParserState::FindValue; + state = InsertParserState::Value; } else if token == ")" { - state = InsertParserState::FindSemicolon; + state = InsertParserState::Semicolon; } else { return Err(anyhow!( "Unexpected token at or near '{}'. Expected comma or rparen.", @@ -179,7 +179,7 @@ impl Command { value_list.push(column_val.clone()); } - InsertParserState::FindSemicolon => { + InsertParserState::Semicolon => { if token != ";" { return Err(anyhow!("Expected semicolon at or near '{}'", token)); } else { @@ -208,32 +208,32 @@ impl Command { } fn parse_select_command(tokens: &mut Vec) -> ::anyhow::Result { - let mut state: SelectParserState = SelectParserState::FindWildcard; + let mut state: SelectParserState = SelectParserState::Wildcard; // intermediate tmp vars let mut table_name = String::new(); while let Some(token) = &tokens.pop() { match state { - SelectParserState::FindWildcard => { + SelectParserState::Wildcard => { if token != "*" { return Err(anyhow!("Expected to find selection at or near '{}' (SQUIRREL does not support column seletion)", token)); } else { - state = SelectParserState::FindFrom; + state = SelectParserState::FromKeyword; } } - SelectParserState::FindFrom => { + SelectParserState::FromKeyword => { if !token.eq_ignore_ascii_case("FROM") { return Err(anyhow!("Expected to find FROM at or near '{}'", token)); } else { - state = SelectParserState::FindTableName; + state = SelectParserState::TableName; } } - SelectParserState::FindTableName => { + SelectParserState::TableName => { table_name = token.to_string(); - state = SelectParserState::FindSemicolon; + state = SelectParserState::Semicolon; } - SelectParserState::FindSemicolon => { + SelectParserState::Semicolon => { if token != ";" { return Err(anyhow!("Expected semicolon at or near '{}'", token)); } else { @@ -247,7 +247,7 @@ impl Command { } fn parse_create_command(tokens: &mut Vec) -> ::anyhow::Result { - let mut state: CreateParserState = CreateParserState::FindObject; + let mut state: CreateParserState = CreateParserState::Object; let mut col_defs: Vec = vec![]; // intermediate tmp vars @@ -258,41 +258,41 @@ impl Command { while let Some(token) = &tokens.pop() { match state { - CreateParserState::FindObject => match token.to_uppercase().as_str() { + CreateParserState::Object => match token.to_uppercase().as_str() { "TABLE" => { - state = CreateParserState::FindTableName; + state = CreateParserState::TableName; } _ => return Err(anyhow!("Can't create object of type '{}'", token.as_str())), }, - CreateParserState::FindTableName => { - state = CreateParserState::FindColumnDefinitions; + CreateParserState::TableName => { + state = CreateParserState::ColumnDefinitions; table_name = token.to_string(); } - CreateParserState::FindColumnDefinitions => { + CreateParserState::ColumnDefinitions => { if token != "(" { return Err(anyhow!("Could not find column list")); } else { - state = CreateParserState::FindColumnName; + state = CreateParserState::ColumnName; } } - CreateParserState::FindColumnName => { + CreateParserState::ColumnName => { col_name = token.to_string(); - state = CreateParserState::FindColumnDatatype; + state = CreateParserState::ColumnDatatype; } - CreateParserState::FindColumnDatatype => { - let dtype = Datatype::from_str(token).unwrap(); + CreateParserState::ColumnDatatype => { + let dtype = Datatype::parse_from_str(token).unwrap(); if dtype.has_len() { - state = CreateParserState::FindColumnLength; + state = CreateParserState::ColumnLength; } else { - state = CreateParserState::FindColumnDefinitionEnd; + state = CreateParserState::ColumnDefinitionEnd; } data_type = Some(dtype); } - CreateParserState::FindColumnLength => { + CreateParserState::ColumnLength => { length = token.parse()?; - state = CreateParserState::FindColumnDefinitionEnd; + state = CreateParserState::ColumnDefinitionEnd; } - CreateParserState::FindColumnDefinitionEnd => { + CreateParserState::ColumnDefinitionEnd => { let column_def = ColumnDefinition { data_type: data_type.unwrap(), length, @@ -307,15 +307,15 @@ impl Command { match token.as_str() { "," => { - state = CreateParserState::FindColumnName; + state = CreateParserState::ColumnName; } ")" => { - state = CreateParserState::FindSemicolon; + state = CreateParserState::Semicolon; } _ => return Err(anyhow!("Expected end")), } } - CreateParserState::FindSemicolon => { + CreateParserState::Semicolon => { if token != ";" { return Err(anyhow!("Expected semicolon at or near '{}'", token)); } else { diff --git a/squirrel-server/src/table/datatypes.rs b/squirrel-server/src/table/datatypes.rs index 006654b..20f9fc9 100644 --- a/squirrel-server/src/table/datatypes.rs +++ b/squirrel-server/src/table/datatypes.rs @@ -1,3 +1,5 @@ +use anyhow::anyhow; + #[derive(Debug, Eq, PartialEq)] pub enum Datatype { Integer, @@ -54,14 +56,15 @@ impl Datatype { } } } - pub fn from_str(string: &str) -> Result { + + pub fn parse_from_str(string: &str) -> ::anyhow::Result { match string { - "varchar" => return Ok(Datatype::CharacterVarying), - "character varying" => return Ok(Datatype::CharacterVarying), - "integer" => return Ok(Datatype::Integer), - "int" => return Ok(Datatype::Integer), - "int8" => return Ok(Datatype::Integer), - _ => return Err(String::from("Undefined data type")), + "varchar" => Ok(Datatype::CharacterVarying), + "character varying" => Ok(Datatype::CharacterVarying), + "integer" => Ok(Datatype::Integer), + "int" => Ok(Datatype::Integer), + "int8" => Ok(Datatype::Integer), + _ => Err(anyhow!("Undefined data type")), } } } diff --git a/squirrel-server/src/table/mod.rs b/squirrel-server/src/table/mod.rs index 83c9111..e3ffa22 100644 --- a/squirrel-server/src/table/mod.rs +++ b/squirrel-server/src/table/mod.rs @@ -1,2 +1,2 @@ pub mod datatypes; -pub mod table; +pub mod table_definition; diff --git a/squirrel-server/src/table/table.rs b/squirrel-server/src/table/table.rs deleted file mode 100644 index 463aa96..0000000 --- a/squirrel-server/src/table/table.rs +++ /dev/null @@ -1,31 +0,0 @@ -use crate::Datatype; - -#[derive(Debug, Eq, PartialEq)] -pub struct ColumnDefinition { - pub name: String, - pub data_type: Datatype, - pub length: usize, // used for char(n), varchar(n) -} - -#[derive(Debug, Eq, PartialEq)] -pub struct TableDefinition { - pub name: String, - pub column_defs: Vec, -} - -impl TableDefinition { - pub fn get_byte_size(&self) -> usize { - let mut sum: usize = 0; - for col_def in self.column_defs.iter() { - // TODO HACK FIXME - // We should keep track of length - // even for built-in datatypes. - sum += if col_def.length > 0 { - col_def.length - } else { - 1 - }; - } - sum - } -}