From 0e2d408d686397a6924b0e2a48d16cb762a3a5bf Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 1 Sep 2024 22:42:43 -0300 Subject: [PATCH 01/23] query struct + WIP procesar query --- src/main.rs | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index e7a11a9..be04baf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,70 @@ +use std::{collections::HashMap, io::Empty, iter::Enumerate}; + fn main() { - println!("Hello, world!"); + let args: Vec = std::env::args().collect(); + if args.len() < 3 { + println!("Uso: cargo run -- ruta/a/tablas \"query\""); + } else { + let path: &String = &args[1]; + let text_query: &String = &args[2]; + let query_result = build_query(text_query, path); + } +} + +fn build_query(text_query: &String, path: &String) -> Result{ + let args = text_to_vec(text_query); + match full_check_query(&args) { + Ok(x) => Ok(0), + Err(x) => Err(x) + } + +} + +fn text_to_vec(text_query: &String) -> Vec { + let mut resultado: Vec = Vec::new(); + let mut split = text_query.split(' '); + + let mut element_opt = split.next(); + while element_opt.is_some() { + match element_opt { + Some(x) => resultado.push(x.to_string()), // TODO: Check si esto esta bien + None => continue + } + element_opt = split.next(); + } + + resultado +} + +fn full_check_query(args: &Vec) -> Result { + let mut result :u32 = 0; + match check_operation(&args[0]) { + Ok(x) => result += x, + Err(x) => result += x + } + match +} + +fn check_operation(operation: &String) -> Result { + if operation.eq("DELETE") || operation.eq("INSERT") || operation.eq("SELECT") || operation.eq("UPDATE") { + Ok(0) + } else { + Err(1) + } +} + +enum queryType { + DELETE, + INSERT, + SELECT, + UPDATE +} + +struct query { + operation: queryType, + tabla: String, // DELETE, INSERT, SELECT, UPDATE + selectores: Option>, // INSERT, SELECT, UPDATE + where_condition: Option, // DELETE (siempre), SELECT (a veces), UPDATE (siempre) + order_by: Option, // SELECT (a veces) + values: Option // INSERT y UPDATE (en update es set) } From c13aecafcfb61f8974712a54608cc42c5bd37541 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Wed, 4 Sep 2024 20:12:27 -0300 Subject: [PATCH 02/23] WIP: validacion formato y exec --- src/main.rs | 97 +++++++++++++++++++++++++++++++++++++--------------- src/query.rs | 31 +++++++++++++++++ 2 files changed, 101 insertions(+), 27 deletions(-) create mode 100644 src/query.rs diff --git a/src/main.rs b/src/main.rs index be04baf..f82b570 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ -use std::{collections::HashMap, io::Empty, iter::Enumerate}; +use core::fmt; +use std::{collections::HashMap, error, io::Empty, iter::Enumerate, path::Display}; fn main() { let args: Vec = std::env::args().collect(); @@ -7,15 +8,23 @@ fn main() { } else { let path: &String = &args[1]; let text_query: &String = &args[2]; - let query_result = build_query(text_query, path); + match build_query(text_query, path) { + Ok(x) => exec_query(&path, x), + Err(x) => print_err(x) + } } } +fn exec_query(path: &String, query: query) { + let mut file = std::fs::File::open(format!("{}/{}",path,query.operation)); + +} + fn build_query(text_query: &String, path: &String) -> Result{ + // Crea query valida o devuelve codigo de error. let args = text_to_vec(text_query); - match full_check_query(&args) { - Ok(x) => Ok(0), - Err(x) => Err(x) + match full_check_query(&arg, &path) { + Ok(x) => } } @@ -35,36 +44,70 @@ fn text_to_vec(text_query: &String) -> Vec { resultado } +fn full_check_query(args: &Vec, path: &String) -> Result { + let mut error_code :u32 = 0; + let mut codigo_query: queryType; + match check_operation(&args) { + Ok(x) => codigo_query = x, + Err(x) => return Err(x) + } + match check_table_exist(path, &args, codigo_query){ + Ok(x) => error_code = x, + Err(x) => return Err(x) + } + match +} -fn full_check_query(args: &Vec) -> Result { - let mut result :u32 = 0; - match check_operation(&args[0]) { - Ok(x) => result += x, - Err(x) => result += x +fn check_operation(args: &Vec) -> Result { + let operation = &args[0]; + if operation.eq("DELETE") { + check_format_delete(args) + } else if operation.eq("INSERT" ) { + check_format_insert(args) + } else if operation.eq("SELECT") { + check_format_select(args) + } else if operation.eq("UPDATE") { + Ok(queryType::UPDATE) + } else { + Err(1) // Codigo: OPERACION INVALIDA } - match } -fn check_operation(operation: &String) -> Result { - if operation.eq("DELETE") || operation.eq("INSERT") || operation.eq("SELECT") || operation.eq("UPDATE") { - Ok(0) +fn check_format_delete(args: &Vec) -> Result { + if args[1].eq("FROM") && args[3].eq("WHERE"){ + Ok(queryType::DELETE) } else { - Err(1) + Err(3) // Codigo: DELETE MAL FORMATEADO + } +} + +fn check_format_insert(args: &Vec) -> Result { + if args[1].eq("INTO") { + if (args.len() - 3) % 2 != 0 || args.len() - 3 < 0 { + Err(2) + } else{ + let mut counter = 0; + let correct_value_len = (args.len() - 3)/2; // INSERT INTO a b c VALUES x y z. Len = 9. Correct len = 3. + while counter < correct_value_len && ! args[counter].eq("VALUES"){ + counter += 1; + } + + if counter == correct_value_len && args[counter].eq("VALUES") { + Ok(queryType::INSERT) + } else{ + Err(2) // Codigo: INSERT MAL FORMATEADO + } + } + } + else { + Err(2) // Codigo: INSERT MAL FORMATEADO } } -enum queryType { - DELETE, - INSERT, - SELECT, - UPDATE +fn check_format_select(args: &Vec) -> Result { + Ok(0) } -struct query { - operation: queryType, - tabla: String, // DELETE, INSERT, SELECT, UPDATE - selectores: Option>, // INSERT, SELECT, UPDATE - where_condition: Option, // DELETE (siempre), SELECT (a veces), UPDATE (siempre) - order_by: Option, // SELECT (a veces) - values: Option // INSERT y UPDATE (en update es set) +fn check_table_exist(path: &String, args: &Vec, query: queryType) -> Result{ +// std::fs::File } diff --git a/src/query.rs b/src/query.rs new file mode 100644 index 0000000..7b15b2d --- /dev/null +++ b/src/query.rs @@ -0,0 +1,31 @@ +#[derive(Debug)] + +enum queryType { + DELETE, + INSERT, + SELECT, + UPDATE +} + +struct query { + operation: queryType, + tabla: String, // DELETE, INSERT, SELECT, UPDATE + selectores: Option>, // INSERT, SELECT, UPDATE + where_condition: Option, // DELETE (siempre), SELECT (a veces), UPDATE (siempre) + order_by: Option, // SELECT (a veces) + values: Option // INSERT y UPDATE (en update es set) +} + +impl std::fmt::Display for query { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.operation == queryType::DELETE { + write!(f,"{}","DELETE") + } else if self.operation == queryType::INSERT { + write!(f,"{}","INSERT") + } else if self.operation == queryType::SELECT { + write!(f,"{}","SELECT") + } else if self.operation == queryType::UPDATE { + write!(f,"{}","UPDATE") + } + } +} \ No newline at end of file From cd942d655df2cc418528dc4e43c26cc1d48b8a6c Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Fri, 6 Sep 2024 21:05:53 -0300 Subject: [PATCH 03/23] WIP: Por iniciar exec --- src/query/query_type.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/query/query_type.rs diff --git a/src/query/query_type.rs b/src/query/query_type.rs new file mode 100644 index 0000000..9e2eb41 --- /dev/null +++ b/src/query/query_type.rs @@ -0,0 +1,19 @@ +use core::fmt; + +pub enum QueryType { + DELETE, + INSERT, + SELECT, + UPDATE +} + +impl std::fmt::Display for QueryType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + QueryType::DELETE => write!(f,"{}","DELETE"), + QueryType::INSERT => write!(f,"{}","INSERT"), + QueryType::SELECT => write!(f,"{}","SELECT"), + QueryType::UPDATE => write!(f,"{}","UPDATE"), + } + } +} \ No newline at end of file From fb8477539ca8b929becb687c7466afa4a5712fd8 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Fri, 6 Sep 2024 21:06:27 -0300 Subject: [PATCH 04/23] WIP: Por iniciar exec --- src/main.rs | 284 +++++++++++++++++++++++++++++++++++++++++++++------ src/query.rs | 43 +++----- 2 files changed, 271 insertions(+), 56 deletions(-) diff --git a/src/main.rs b/src/main.rs index f82b570..e76463e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,34 +1,204 @@ -use core::fmt; +use std::io::BufReader; +use std::fs::File; +use std::vec; use std::{collections::HashMap, error, io::Empty, iter::Enumerate, path::Display}; +pub mod query; +use query::build_empty_query; + +use crate::query::Query; +use crate::query::query_type::QueryType; + fn main() { let args: Vec = std::env::args().collect(); if args.len() < 3 { println!("Uso: cargo run -- ruta/a/tablas \"query\""); } else { let path: &String = &args[1]; - let text_query: &String = &args[2]; - match build_query(text_query, path) { - Ok(x) => exec_query(&path, x), - Err(x) => print_err(x) + let args = text_to_vec(&args[2]); // Tokenization + match build_query(args, path) { + Ok(x) => exec_query(x), +// Err(x) => print_err(x) + Err(_) => println!("TODO print_err") } } } -fn exec_query(path: &String, query: query) { - let mut file = std::fs::File::open(format!("{}/{}",path,query.operation)); +fn exec_query(query: query::Query) { + match query.table { + Some(f) => { + let mut file = std::fs::File::open(f); + + }, + None => println!("Esto no debería pasar :(") + } } -fn build_query(text_query: &String, path: &String) -> Result{ +/* +fn build_query(text_query: &String, path: &String) -> Result{ // Crea query valida o devuelve codigo de error. let args = text_to_vec(text_query); - match full_check_query(&arg, &path) { - Ok(x) => + let mut resultado = build_empty_query(); + + match full_check_query(&args, &path, &mut resultado) { + Ok(_) => return Ok(resultado), + Err(x) => return Err(x) + } + +} +*/ + +fn build_query(args: Vec, path: &String) -> Result { + // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build + match vec_to_query(&args, path) { + Ok(x) => return validate_query(x), // Sintaxis analysis + Err(x) => return Err(x) + } +} + +fn validate_query(query: Query) -> Result { + // Sintatic analysis + +} + +fn text_to_vec(text_query: &String) -> Vec { + // Text to vector. Tokenization by space, new line & coma + let mut result: Vec = Vec::new(); + let mut split = text_query.split(&[' ', '\n']); + + let mut element_opt = split.next(); + while element_opt.is_some() { + match element_opt { + Some(x) => { + if x.contains(',') { + let mut tmp = String::from(x); + tmp.pop(); + result.push(tmp); + } + else { + result.push(x.to_string()); + } + }, + None => continue + } + + element_opt = split.next(); + } + result +} + +fn vec_to_query(args: &Vec, path: &String) -> Result{ + // Vec to non validated query + let mut result = build_empty_query(); + match check_operation(&args) { + Ok(x) => { + match &x { + QueryType::DELETE => separate_args_delete(args, path, &mut result), + QueryType::INSERT => separate_args_insert(args, path, &mut result), + QueryType::SELECT => separate_args_select(args, path, &mut result), + QueryType::UPDATE => separate_args_update(args, path, &mut result) + } + result.operation = Some(x); + }, + Err(x) => return Err(x) + } + + Ok(result) +} + +fn merge_table_and_path(path: &String, table: &String) -> String { + let mut table_full: String = path.to_string(); + table_full.push('/'); + table_full.push_str(table); + + table_full +} + +fn separate_args_delete(args: &Vec, path: &String, result: &mut Query) { + result.table = Some(merge_table_and_path(path, &args[2])); + + let mut where_condition = args[4].to_string(); + let mut counter = 5; + while counter < args.len() { + where_condition.push_str(&args[counter].to_string()); + counter += 1; } + result.where_condition = Some(where_condition); } +fn separate_args_insert(args: &Vec, path: &String, result: &mut Query) { + result.table = Some(merge_table_and_path(path, &args[2])); + + let mut columns: Vec = Vec::new(); + let mut counter = 3; + while counter < args.len()/2 && ! args[counter].eq("VALUES") { + columns.push(args[counter].to_string()); + counter += 1; + } + + counter += 1; + let mut values: Vec = Vec::new(); + while counter < args.len() { + values.push(args[counter].to_string()); + counter += 1; + } + + result.columns = Some(columns); + result.values = Some(values); +} + +fn separate_args_update(args: &Vec, path: &String, result: &mut Query) { + result.table = Some(merge_table_and_path(path, &args[1])); + + let mut counter = 3; + let mut columns: Vec = Vec::new(); + let mut values: Vec = Vec::new(); + + while counter < args.len() && !args[counter].eq("WHERE") { + if counter % 3 == 0 { + columns.push(args[counter].to_string()); + } else if ( counter % 3 ) == 2 { + values.push(args[counter].to_string()); + } + counter += 1; + } + counter += 1; + + let mut where_condition = String::new(); + while counter < args.len() { + where_condition.push_str(&args[counter].to_string()); + counter += 1; + } + + result.columns = Some(columns); + result.where_condition = Some(where_condition); + result.values = Some(values); +} + +fn separate_args_select(args: &Vec, path: &String, result: &mut Query) { + let mut columns: Vec = Vec::new(); + let mut counter = 1; + while counter < args.len() && !args[counter].eq("FROM") { + columns.push(args[counter].to_string()); + counter += 1; + } + counter += 1; + result.table = Some(merge_table_and_path(path, &args[counter])); + + let mut where_condition = String::new(); + while counter < args.len() && !args[counter].eq("ORDER") { + where_condition.push_str(&args[counter].to_string()); + counter += 1; + } + result.where_condition = Some(where_condition); + + // Last condition returns false on desc, true on asc + result.order_by = Some((args[counter + 2].to_string(),counter + 3 != args.len())); +} + +/* fn text_to_vec(text_query: &String) -> Vec { let mut resultado: Vec = Vec::new(); let mut split = text_query.split(' '); @@ -36,7 +206,20 @@ fn text_to_vec(text_query: &String) -> Vec { let mut element_opt = split.next(); while element_opt.is_some() { match element_opt { - Some(x) => resultado.push(x.to_string()), // TODO: Check si esto esta bien + Some(x) => { + + if x.contains('\n') { + let mut split2 = x.split('\n'); + let mut element_split2 = split2.next(); + resultado.push(element_split2.unwrap().to_string()); + element_split2 = split2.next(); + resultado.push(element_split2.unwrap().to_string()); + } else if x.contains(',') { + + } else { + resultado.push(x.to_string()) + } + }, // TODO: Check si esto esta bien None => continue } element_opt = split.next(); @@ -44,21 +227,26 @@ fn text_to_vec(text_query: &String) -> Vec { resultado } -fn full_check_query(args: &Vec, path: &String) -> Result { + +fn full_check_query(args: &Vec, path: &String) -> Result { let mut error_code :u32 = 0; - let mut codigo_query: queryType; + let mut result = build_empty_query(); match check_operation(&args) { - Ok(x) => codigo_query = x, + Ok(x) => result.operation = Some(x), Err(x) => return Err(x) } - match check_table_exist(path, &args, codigo_query){ - Ok(x) => error_code = x, + match check_table_exist(path, args, &result.operation.unwrap()){ + Ok(x) => result.table = Some(x), Err(x) => return Err(x) } - match + match check_columns_exist(args,&result.table.unwrap()) { + + } } +*/ -fn check_operation(args: &Vec) -> Result { +fn check_operation(args: &Vec) -> Result { + // Check correct operation sintaxis let operation = &args[0]; if operation.eq("DELETE") { check_format_delete(args) @@ -67,21 +255,21 @@ fn check_operation(args: &Vec) -> Result { } else if operation.eq("SELECT") { check_format_select(args) } else if operation.eq("UPDATE") { - Ok(queryType::UPDATE) + Ok(QueryType::UPDATE) } else { - Err(1) // Codigo: OPERACION INVALIDA + Err(1) // Code: OPERACION INVALIDA } } -fn check_format_delete(args: &Vec) -> Result { +fn check_format_delete(args: &Vec) -> Result { if args[1].eq("FROM") && args[3].eq("WHERE"){ - Ok(queryType::DELETE) + Ok(QueryType::DELETE) } else { - Err(3) // Codigo: DELETE MAL FORMATEADO + Err(3) // Code: DELETE MAL FORMATEADO } } -fn check_format_insert(args: &Vec) -> Result { +fn check_format_insert(args: &Vec) -> Result { if args[1].eq("INTO") { if (args.len() - 3) % 2 != 0 || args.len() - 3 < 0 { Err(2) @@ -93,21 +281,57 @@ fn check_format_insert(args: &Vec) -> Result { } if counter == correct_value_len && args[counter].eq("VALUES") { - Ok(queryType::INSERT) + Ok(QueryType::INSERT) } else{ Err(2) // Codigo: INSERT MAL FORMATEADO } } } else { - Err(2) // Codigo: INSERT MAL FORMATEADO + Err(2) // Codigo: INSERT MAL FORMATEADO } } -fn check_format_select(args: &Vec) -> Result { - Ok(0) +fn check_format_select(args: &Vec) -> Result { + Ok(QueryType::SELECT) } -fn check_table_exist(path: &String, args: &Vec, query: queryType) -> Result{ -// std::fs::File +fn check_table_exist(path: &String, args: &Vec, operation: &QueryType) -> Result{ + // Asume query bien formateado + let mut table= String::from(path); + table.push('/'); + match &operation { + QueryType::DELETE => table.push_str(&args[2]), + QueryType::INSERT => table.push_str(&args[2]), + QueryType::SELECT => { + // Debo encontrar cual es la tabla (asumiendo query bien formateado) + let mut counter = 2; + while ! args[counter].eq("FROM"){ + counter += 1; + } + table.push_str(&args[counter + 1]) + }, + QueryType::UPDATE => table.push_str(&args[1]), + } + + match File::open(&table) { // TODO: Path::exist()? + Ok(_) => return Ok(table), + Err(_) => return Err(4) // Código: NO SE PUDO ABRIR ARCHIVO + } } + +fn check_columns_exist(args: &Vec, result: &mut Query) -> Result,u32> { + let file = File::open(&result.table.unwrap() ); + match file { + Ok(_) => { + let mut reader = BufReader::new(file); + + let mut line = String::new(); + match reader.read_line(&mut line) { + + } + } + Err(_) => return Err(5) + } + +} \ No newline at end of file diff --git a/src/query.rs b/src/query.rs index 7b15b2d..913fb22 100644 --- a/src/query.rs +++ b/src/query.rs @@ -1,31 +1,22 @@ -#[derive(Debug)] +pub mod query_type; -enum queryType { - DELETE, - INSERT, - SELECT, - UPDATE +use query_type::QueryType; +pub struct Query { + pub operation: Option, + pub table: Option, // DELETE, INSERT, SELECT, UPDATE + pub columns: Option>, // INSERT, SELECT, UPDATE + pub where_condition: Option, // DELETE (siempre), SELECT (a veces), UPDATE (siempre) + pub order_by: Option<(String,bool)>, // SELECT (a veces) + pub values: Option> // INSERT y UPDATE (en update es set) } -struct query { - operation: queryType, - tabla: String, // DELETE, INSERT, SELECT, UPDATE - selectores: Option>, // INSERT, SELECT, UPDATE - where_condition: Option, // DELETE (siempre), SELECT (a veces), UPDATE (siempre) - order_by: Option, // SELECT (a veces) - values: Option // INSERT y UPDATE (en update es set) -} - -impl std::fmt::Display for query { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if self.operation == queryType::DELETE { - write!(f,"{}","DELETE") - } else if self.operation == queryType::INSERT { - write!(f,"{}","INSERT") - } else if self.operation == queryType::SELECT { - write!(f,"{}","SELECT") - } else if self.operation == queryType::UPDATE { - write!(f,"{}","UPDATE") - } +pub fn build_empty_query() -> Query { + return Query { + operation: None, + table: None, + columns: None, + where_condition: None, + order_by: None, + values: None, } } \ No newline at end of file From fce4e38a818383ccacd40d496788a1470735005f Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sat, 7 Sep 2024 15:11:58 -0300 Subject: [PATCH 05/23] SEPARACION EN LIBS --- src/libs/error.rs | 0 src/libs/exec.rs | 17 +++ src/libs/parsing.rs | 300 ++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 23 ++-- 4 files changed, 333 insertions(+), 7 deletions(-) create mode 100644 src/libs/error.rs create mode 100644 src/libs/exec.rs create mode 100644 src/libs/parsing.rs diff --git a/src/libs/error.rs b/src/libs/error.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/libs/exec.rs b/src/libs/exec.rs new file mode 100644 index 0000000..dbd6ea5 --- /dev/null +++ b/src/libs/exec.rs @@ -0,0 +1,17 @@ +fn exec_query(query: query::Query) -> Result { + match query.table { + Some(f) => match std::fs::File::open(f) { + Ok(x) => { + match query.operation.unwrap() { + QueryType::DELETE => exec_query_delete(x, query), + QueryType::INSERT => exec_query_insert(x, query), + QueryType::SELECT => exec_query_select(x, query), + QueryType::UPDATE => exec_query_update(x, query), + } + }, + Err(_) => return Err(6) + } , + None => return Err(6) + } + +} \ No newline at end of file diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs new file mode 100644 index 0000000..ddadfcb --- /dev/null +++ b/src/libs/parsing.rs @@ -0,0 +1,300 @@ +fn build_query(args: Vec, path: &String) -> Result { + // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build + match vec_to_query(&args, path) { + Ok(x) => return validate_query(x), // Sintaxis analysis + Err(x) => return Err(x) + } +} + +/* +fn build_query(text_query: &String, path: &String) -> Result{ + // Crea query valida o devuelve codigo de error. + let args = text_to_vec(text_query); + let mut resultado = build_empty_query(); + + match full_check_query(&args, &path, &mut resultado) { + Ok(_) => return Ok(resultado), + Err(x) => return Err(x) + } + +} +*/ + +fn validate_query(query: Query) -> Result { + // Sintatic analysis + +} + +fn text_to_vec(text_query: &String) -> Vec { + // Text to vector. Tokenization by space, new line & coma + let mut result: Vec = Vec::new(); + let mut split = text_query.split(&[' ', '\n']); + + let mut element_opt = split.next(); + while element_opt.is_some() { + match element_opt { + Some(x) => { + if x.contains(',') { + let mut tmp = String::from(x); + tmp.pop(); + result.push(tmp); + } + else { + result.push(x.to_string()); + } + }, + None => continue + } + + element_opt = split.next(); + } + result +} + +fn vec_to_query(args: &Vec, path: &String) -> Result{ + // Vec to non validated query + let mut result = build_empty_query(); + match check_operation(&args) { + Ok(x) => { + match &x { + QueryType::DELETE => separate_args_delete(args, path, &mut result), + QueryType::INSERT => separate_args_insert(args, path, &mut result), + QueryType::SELECT => separate_args_select(args, path, &mut result), + QueryType::UPDATE => separate_args_update(args, path, &mut result) + } + result.operation = Some(x); + }, + Err(x) => return Err(x) + } + + Ok(result) +} + +fn merge_table_and_path(path: &String, table: &String) -> String { + let mut table_full: String = path.to_string(); + table_full.push('/'); + table_full.push_str(table); + + table_full +} + +fn separate_args_delete(args: &Vec, path: &String, result: &mut Query) { + result.table = Some(merge_table_and_path(path, &args[2])); + + let mut where_condition = args[4].to_string(); + let mut counter = 5; + while counter < args.len() { + where_condition.push_str(&args[counter].to_string()); + counter += 1; + } + + result.where_condition = Some(where_condition); +} + +fn separate_args_insert(args: &Vec, path: &String, result: &mut Query) { + result.table = Some(merge_table_and_path(path, &args[2])); + + let mut columns: Vec = Vec::new(); + let mut counter = 3; + while counter < args.len()/2 && ! args[counter].eq("VALUES") { + columns.push(args[counter].to_string()); + counter += 1; + } + + counter += 1; + let mut values: Vec = Vec::new(); + while counter < args.len() { + values.push(args[counter].to_string()); + counter += 1; + } + + result.columns = Some(columns); + result.values = Some(values); +} + +fn separate_args_update(args: &Vec, path: &String, result: &mut Query) { + result.table = Some(merge_table_and_path(path, &args[1])); + + let mut counter = 3; + let mut columns: Vec = Vec::new(); + let mut values: Vec = Vec::new(); + + while counter < args.len() && !args[counter].eq("WHERE") { + if counter % 3 == 0 { + columns.push(args[counter].to_string()); + } else if ( counter % 3 ) == 2 { + values.push(args[counter].to_string()); + } + counter += 1; + } + counter += 1; + + let mut where_condition = String::new(); + while counter < args.len() { + where_condition.push_str(&args[counter].to_string()); + counter += 1; + } + + result.columns = Some(columns); + result.where_condition = Some(where_condition); + result.values = Some(values); +} + +fn separate_args_select(args: &Vec, path: &String, result: &mut Query) { + let mut columns: Vec = Vec::new(); + let mut counter = 1; + while counter < args.len() && !args[counter].eq("FROM") { + columns.push(args[counter].to_string()); + counter += 1; + } + counter += 1; + result.table = Some(merge_table_and_path(path, &args[counter])); + + let mut where_condition = String::new(); + while counter < args.len() && !args[counter].eq("ORDER") { + where_condition.push_str(&args[counter].to_string()); + counter += 1; + } + result.where_condition = Some(where_condition); + + // Last condition returns false on desc, true on asc + result.order_by = Some((args[counter + 2].to_string(),counter + 3 != args.len())); +} + +/* +fn text_to_vec(text_query: &String) -> Vec { + let mut resultado: Vec = Vec::new(); + let mut split = text_query.split(' '); + + let mut element_opt = split.next(); + while element_opt.is_some() { + match element_opt { + Some(x) => { + + if x.contains('\n') { + let mut split2 = x.split('\n'); + let mut element_split2 = split2.next(); + resultado.push(element_split2.unwrap().to_string()); + element_split2 = split2.next(); + resultado.push(element_split2.unwrap().to_string()); + } else if x.contains(',') { + + } else { + resultado.push(x.to_string()) + } + }, // TODO: Check si esto esta bien + None => continue + } + element_opt = split.next(); + } + + resultado +} + +fn full_check_query(args: &Vec, path: &String) -> Result { + let mut error_code :u32 = 0; + let mut result = build_empty_query(); + match check_operation(&args) { + Ok(x) => result.operation = Some(x), + Err(x) => return Err(x) + } + match check_table_exist(path, args, &result.operation.unwrap()){ + Ok(x) => result.table = Some(x), + Err(x) => return Err(x) + } + match check_columns_exist(args,&result.table.unwrap()) { + + } +} +*/ + +fn check_operation(args: &Vec) -> Result { + // Check correct operation sintaxis + let operation = &args[0]; + if operation.eq("DELETE") { + check_format_delete(args) + } else if operation.eq("INSERT" ) { + check_format_insert(args) + } else if operation.eq("SELECT") { + check_format_select(args) + } else if operation.eq("UPDATE") { + Ok(QueryType::UPDATE) + } else { + Err(1) // Code: OPERACION INVALIDA + } +} + +fn check_format_delete(args: &Vec) -> Result { + if args[1].eq("FROM") && args[3].eq("WHERE"){ + Ok(QueryType::DELETE) + } else { + Err(3) // Code: DELETE MAL FORMATEADO + } +} + +fn check_format_insert(args: &Vec) -> Result { + if args[1].eq("INTO") { + if (args.len() - 3) % 2 != 0 || args.len() - 3 < 0 { + Err(2) + } else{ + let mut counter = 0; + let correct_value_len = (args.len() - 3)/2; // INSERT INTO a b c VALUES x y z. Len = 9. Correct len = 3. + while counter < correct_value_len && ! args[counter].eq("VALUES"){ + counter += 1; + } + + if counter == correct_value_len && args[counter].eq("VALUES") { + Ok(QueryType::INSERT) + } else{ + Err(2) // Codigo: INSERT MAL FORMATEADO + } + } + } + else { + Err(2) // Codigo: INSERT MAL FORMATEADO + } +} + +fn check_format_select(args: &Vec) -> Result { + Ok(QueryType::SELECT) +} + +fn check_table_exist(path: &String, args: &Vec, operation: &QueryType) -> Result{ + // Asume query bien formateado + let mut table= String::from(path); + table.push('/'); + match &operation { + QueryType::DELETE => table.push_str(&args[2]), + QueryType::INSERT => table.push_str(&args[2]), + QueryType::SELECT => { + // Debo encontrar cual es la tabla (asumiendo query bien formateado) + let mut counter = 2; + while ! args[counter].eq("FROM"){ + counter += 1; + } + table.push_str(&args[counter + 1]) + }, + QueryType::UPDATE => table.push_str(&args[1]), + } + + match File::open(&table) { // TODO: Path::exist()? + Ok(_) => return Ok(table), + Err(_) => return Err(4) // Código: NO SE PUDO ABRIR ARCHIVO + } +} + +fn check_columns_exist(args: &Vec, result: &mut Query) -> Result,u32> { + let file = File::open(&result.table.unwrap() ); + match file { + Ok(_) => { + let mut reader = BufReader::new(file); + + let mut line = String::new(); + match reader.read_line(&mut line) { + + } + } + Err(_) => return Err(5) + } + +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index e76463e..7782e58 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,8 +4,10 @@ use std::vec; use std::{collections::HashMap, error, io::Empty, iter::Enumerate, path::Display}; pub mod query; -use query::build_empty_query; +pub mod libs; +use crate::libs:: +use query::build_empty_query; use crate::query::Query; use crate::query::query_type::QueryType; @@ -24,13 +26,20 @@ fn main() { } } -fn exec_query(query: query::Query) { +fn exec_query(query: query::Query) -> Result { match query.table { - Some(f) => { - let mut file = std::fs::File::open(f); - - }, - None => println!("Esto no debería pasar :(") + Some(f) => match std::fs::File::open(f) { + Ok(x) => { + match query.operation.unwrap() { + QueryType::DELETE => exec_query_delete(x, query), + QueryType::INSERT => exec_query_insert(x, query), + QueryType::SELECT => exec_query_select(x, query), + QueryType::UPDATE => exec_query_update(x, query), + } + }, + Err(_) => return Err(6) + } , + None => return Err(6) } } From 68098288e5d9311e6e3a79399787d37436b13f03 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sat, 7 Sep 2024 17:40:11 -0300 Subject: [PATCH 06/23] WIP: Parse y exec. OK: separacion en libs --- src/libs.rs | 4 + src/libs/error.rs | 11 ++ src/libs/exec.rs | 46 ++++-- src/libs/parsing.rs | 356 +++++++++++++++++++++++++--------------- src/main.rs | 340 +------------------------------------- src/query.rs | 2 +- src/query/query_type.rs | 1 - 7 files changed, 282 insertions(+), 478 deletions(-) create mode 100644 src/libs.rs diff --git a/src/libs.rs b/src/libs.rs new file mode 100644 index 0000000..1bd6d7c --- /dev/null +++ b/src/libs.rs @@ -0,0 +1,4 @@ +// Dumb file for organize everything into libs +pub mod error; +pub mod exec; +pub mod parsing; diff --git a/src/libs/error.rs b/src/libs/error.rs index e69de29..5ffae73 100644 --- a/src/libs/error.rs +++ b/src/libs/error.rs @@ -0,0 +1,11 @@ +pub static OPERACION_INVALIDA: u32 = 1; +pub static DELETE_MAL_FORMATEADO: u32 = 2; +pub static INSERT_MAL_FORMATEADO: u32 = 3; +pub static SELECT_MAL_FORMATEADO: u32 = 4; +pub static UPDATE_MAL_FORMATEADO: u32 = 5; +pub static ARCHIVO_NO_PUDO_SER_ABIERTO: u32 = 6; +pub static ARCHIVO_SIN_COLUMNAS: u32 = 7; + +pub fn print_err(error_code: u32) { + // TODO print error +} \ No newline at end of file diff --git a/src/libs/exec.rs b/src/libs/exec.rs index dbd6ea5..7a751eb 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -1,17 +1,41 @@ -fn exec_query(query: query::Query) -> Result { - match query.table { +use std::fs::File; + +use crate::query::query_type::QueryType; +use crate::query::Query; + +pub fn exec_query(query: Query) { + let table = &query.table; + match table { Some(f) => match std::fs::File::open(f) { - Ok(x) => { - match query.operation.unwrap() { - QueryType::DELETE => exec_query_delete(x, query), - QueryType::INSERT => exec_query_insert(x, query), - QueryType::SELECT => exec_query_select(x, query), - QueryType::UPDATE => exec_query_update(x, query), + Ok(file) => { + match &query.operation { + Some(op) => match op { + QueryType::DELETE => exec_query_delete(file, query), + QueryType::INSERT => exec_query_insert(file, query), + QueryType::SELECT => exec_query_select(file, query), + QueryType::UPDATE => exec_query_update(file, query), + }, + None => println!("Error en el programa") } }, - Err(_) => return Err(6) + Err(_) => println!("Error en el programa") } , - None => return Err(6) + None => println!("Error en el programa") } +} + +fn exec_query_delete(file: File, query: Query) { + // TODO +} + +fn exec_query_insert(file: File, query: Query) { + // TODO +} + +fn exec_query_select(file: File, query: Query) { + // TODO +} -} \ No newline at end of file +fn exec_query_update(file: File, query: Query) { + // TODO +} diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index ddadfcb..b08efe6 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -1,79 +1,25 @@ -fn build_query(args: Vec, path: &String) -> Result { - // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build - match vec_to_query(&args, path) { - Ok(x) => return validate_query(x), // Sintaxis analysis - Err(x) => return Err(x) - } -} +use std::io::{BufRead, BufReader}; +use std::fs::File; -/* -fn build_query(text_query: &String, path: &String) -> Result{ - // Crea query valida o devuelve codigo de error. - let args = text_to_vec(text_query); - let mut resultado = build_empty_query(); +use crate::libs::error; +use crate::query::Query; +use crate::query::query_type::QueryType; +use crate::query::build_empty_query; - match full_check_query(&args, &path, &mut resultado) { - Ok(_) => return Ok(resultado), +pub fn build_query(text_query: &String, path: &String) -> Result { + // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build + let args = text_to_vec(&text_query); + match vec_to_query(&args, path) { // sintactic analysis + Ok(x) => return validate_query(x), // Semantic analysis Err(x) => return Err(x) } - -} -*/ - -fn validate_query(query: Query) -> Result { - // Sintatic analysis - -} - -fn text_to_vec(text_query: &String) -> Vec { - // Text to vector. Tokenization by space, new line & coma - let mut result: Vec = Vec::new(); - let mut split = text_query.split(&[' ', '\n']); - - let mut element_opt = split.next(); - while element_opt.is_some() { - match element_opt { - Some(x) => { - if x.contains(',') { - let mut tmp = String::from(x); - tmp.pop(); - result.push(tmp); - } - else { - result.push(x.to_string()); - } - }, - None => continue - } - - element_opt = split.next(); - } - result -} - -fn vec_to_query(args: &Vec, path: &String) -> Result{ - // Vec to non validated query - let mut result = build_empty_query(); - match check_operation(&args) { - Ok(x) => { - match &x { - QueryType::DELETE => separate_args_delete(args, path, &mut result), - QueryType::INSERT => separate_args_insert(args, path, &mut result), - QueryType::SELECT => separate_args_select(args, path, &mut result), - QueryType::UPDATE => separate_args_update(args, path, &mut result) - } - result.operation = Some(x); - }, - Err(x) => return Err(x) - } - - Ok(result) } fn merge_table_and_path(path: &String, table: &String) -> String { let mut table_full: String = path.to_string(); table_full.push('/'); table_full.push_str(table); + table_full.push_str(".csv"); table_full } @@ -81,10 +27,12 @@ fn merge_table_and_path(path: &String, table: &String) -> String { fn separate_args_delete(args: &Vec, path: &String, result: &mut Query) { result.table = Some(merge_table_and_path(path, &args[2])); - let mut where_condition = args[4].to_string(); + let mut where_condition: Vec = Vec::new(); + where_condition.push(args[4].to_string()); + let mut counter = 5; while counter < args.len() { - where_condition.push_str(&args[counter].to_string()); + where_condition.push(args[counter].to_string()); counter += 1; } @@ -129,9 +77,9 @@ fn separate_args_update(args: &Vec, path: &String, result: &mut Query) { } counter += 1; - let mut where_condition = String::new(); + let mut where_condition = Vec::new(); while counter < args.len() { - where_condition.push_str(&args[counter].to_string()); + where_condition.push(args[counter].to_string()); counter += 1; } @@ -150,9 +98,9 @@ fn separate_args_select(args: &Vec, path: &String, result: &mut Query) { counter += 1; result.table = Some(merge_table_and_path(path, &args[counter])); - let mut where_condition = String::new(); + let mut where_condition = Vec::new(); while counter < args.len() && !args[counter].eq("ORDER") { - where_condition.push_str(&args[counter].to_string()); + where_condition.push(args[counter].to_string()); counter += 1; } result.where_condition = Some(where_condition); @@ -161,78 +109,31 @@ fn separate_args_select(args: &Vec, path: &String, result: &mut Query) { result.order_by = Some((args[counter + 2].to_string(),counter + 3 != args.len())); } -/* -fn text_to_vec(text_query: &String) -> Vec { - let mut resultado: Vec = Vec::new(); - let mut split = text_query.split(' '); - - let mut element_opt = split.next(); - while element_opt.is_some() { - match element_opt { - Some(x) => { - - if x.contains('\n') { - let mut split2 = x.split('\n'); - let mut element_split2 = split2.next(); - resultado.push(element_split2.unwrap().to_string()); - element_split2 = split2.next(); - resultado.push(element_split2.unwrap().to_string()); - } else if x.contains(',') { - - } else { - resultado.push(x.to_string()) - } - }, // TODO: Check si esto esta bien - None => continue - } - element_opt = split.next(); - } - - resultado -} - -fn full_check_query(args: &Vec, path: &String) -> Result { - let mut error_code :u32 = 0; - let mut result = build_empty_query(); - match check_operation(&args) { - Ok(x) => result.operation = Some(x), - Err(x) => return Err(x) - } - match check_table_exist(path, args, &result.operation.unwrap()){ - Ok(x) => result.table = Some(x), - Err(x) => return Err(x) - } - match check_columns_exist(args,&result.table.unwrap()) { - - } -} -*/ - -fn check_operation(args: &Vec) -> Result { +fn check_operation_format(args: &Vec) -> Result { // Check correct operation sintaxis let operation = &args[0]; if operation.eq("DELETE") { - check_format_delete(args) + check_delete_format(args) } else if operation.eq("INSERT" ) { - check_format_insert(args) + check_insert_format(args) } else if operation.eq("SELECT") { - check_format_select(args) + check_select_format(args) } else if operation.eq("UPDATE") { - Ok(QueryType::UPDATE) + check_update_format(args) } else { - Err(1) // Code: OPERACION INVALIDA + Err(error::OPERACION_INVALIDA) } } -fn check_format_delete(args: &Vec) -> Result { +fn check_delete_format(args: &Vec) -> Result { if args[1].eq("FROM") && args[3].eq("WHERE"){ Ok(QueryType::DELETE) } else { - Err(3) // Code: DELETE MAL FORMATEADO + Err(error::DELETE_MAL_FORMATEADO) } } -fn check_format_insert(args: &Vec) -> Result { +fn check_insert_format(args: &Vec) -> Result { if args[1].eq("INTO") { if (args.len() - 3) % 2 != 0 || args.len() - 3 < 0 { Err(2) @@ -246,19 +147,25 @@ fn check_format_insert(args: &Vec) -> Result { if counter == correct_value_len && args[counter].eq("VALUES") { Ok(QueryType::INSERT) } else{ - Err(2) // Codigo: INSERT MAL FORMATEADO + Err(error::INSERT_MAL_FORMATEADO) } } } else { - Err(2) // Codigo: INSERT MAL FORMATEADO + Err(error::INSERT_MAL_FORMATEADO) } } -fn check_format_select(args: &Vec) -> Result { +fn check_select_format(args: &Vec) -> Result { + // TODO format select Ok(QueryType::SELECT) } +fn check_update_format(args: &Vec) -> Result { + // TODO format select + Ok(QueryType::UPDATE) +} + fn check_table_exist(path: &String, args: &Vec, operation: &QueryType) -> Result{ // Asume query bien formateado let mut table= String::from(path); @@ -279,11 +186,137 @@ fn check_table_exist(path: &String, args: &Vec, operation: &QueryType) - match File::open(&table) { // TODO: Path::exist()? Ok(_) => return Ok(table), - Err(_) => return Err(4) // Código: NO SE PUDO ABRIR ARCHIVO + Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) } } + +fn validate_query(query: Query) -> Result { + // Pre: Sintactical query OK + // Post: Valid query for execution + match File::open(&query.table.unwrap()) { + Ok(_) => {}, + Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + } + + match &query.operation.unwrap() { + QueryType::DELETE => validate_delete_query(&query), + QueryType::INSERT => validate_insert_query(query), + QueryType::SELECT => validate_select_query(query), + QueryType::UPDATE => validate_update_query(query), + } +} + +fn validate_delete_query(query: &Query) -> Result { + if query.columns.is_none() && query.values.is_none() && query.columns.is_none() { + match query.table { + Some(table) => { + + }, + Err(_) => Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + } + + match File::open(query.table.unwrap()) { + Ok(x) => { + match get_columns(x) { + Some(x) => check_columns_contains(x, &query), + None => return Err(error::ARCHIVO_SIN_COLUMNAS) + } + }, + Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + } + } else { + Err(error::DELETE_MAL_FORMATEADO) + } +} + +fn get_columns(file: File) -> Option> { + let mut result: Vec = Vec::new(); + let mut reader: BufReader = BufReader::new(file); + let mut line = String::new(); + match reader.read_line(&mut line) { + Ok(_) => { + let mut split = line.split(','); + let mut element_opt = split.next(); + while element_opt.is_some() { + match element_opt { + Some(x) => result.push(x.to_string()), + None => continue + } + element_opt = split.next(); + } + + Some(result) + }, + Err(_) => None + } +} + +fn check_columns_contains(columns: Vec, query: &Query) -> Result { + +} + + +fn text_to_vec(text_query: &String) -> Vec { + // Text to vector. Tokenization by space, new line & coma + let mut result: Vec = Vec::new(); + let mut split = text_query.split(&[' ', '\n']); + + let mut element_opt = split.next(); + while element_opt.is_some() { + match element_opt { + Some(x) => { + if x.contains(',') { + let mut tmp = String::from(x); + tmp.pop(); + result.push(tmp); + } + else { + result.push(x.to_string()); + } + }, + None => continue + } + + element_opt = split.next(); + } + result +} + +fn vec_to_query(args: &Vec, path: &String) -> Result{ + // Vec to non validated query + let mut result: Query = build_empty_query(); + match check_operation_format(&args) { + Ok(x) => { + match &x { + QueryType::DELETE => separate_args_delete(args, path, &mut result), + QueryType::INSERT => separate_args_insert(args, path, &mut result), + QueryType::SELECT => separate_args_select(args, path, &mut result), + QueryType::UPDATE => separate_args_update(args, path, &mut result) + } + result.operation = Some(x); + }, + Err(x) => return Err(x) + } + + Ok(result) +} + +/* +fn build_query(text_query: &String, path: &String) -> Result{ + // Crea query valida o devuelve codigo de error. + let args = text_to_vec(text_query); + let mut resultado = build_empty_query(); + + match full_check_query(&args, &path, &mut resultado) { + Ok(_) => return Ok(resultado), + Err(x) => return Err(x) + } + +} + fn check_columns_exist(args: &Vec, result: &mut Query) -> Result,u32> { + // TODO columns exist let file = File::open(&result.table.unwrap() ); match file { Ok(_) => { @@ -297,4 +330,63 @@ fn check_columns_exist(args: &Vec, result: &mut Query) -> Result return Err(5) } +} + +fn text_to_vec(text_query: &String) -> Vec { + let mut resultado: Vec = Vec::new(); + let mut split = text_query.split(' '); + + let mut element_opt = split.next(); + while element_opt.is_some() { + match element_opt { + Some(x) => { + + if x.contains('\n') { + let mut split2 = x.split('\n'); + let mut element_split2 = split2.next(); + resultado.push(element_split2.unwrap().to_string()); + element_split2 = split2.next(); + resultado.push(element_split2.unwrap().to_string()); + } else if x.contains(',') { + + } else { + resultado.push(x.to_string()) + } + }, // TODO: Check si esto esta bien + None => continue + } + element_opt = split.next(); + } + + resultado +} + +fn full_check_query(args: &Vec, path: &String) -> Result { + let mut error_code :u32 = 0; + let mut result = build_empty_query(); + match check_operation(&args) { + Ok(x) => result.operation = Some(x), + Err(x) => return Err(x) + } + match check_table_exist(path, args, &result.operation.unwrap()){ + Ok(x) => result.table = Some(x), + Err(x) => return Err(x) + } + match check_columns_exist(args,&result.table.unwrap()) { + + } +} +*/ + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_text_to_vec(){ + let rt1 = text_to_vec(&String::from("SELECT * FROM table")); + assert_eq!(rt1, vec!["SELECT","*","FROM","table"]); + let rt2 = text_to_vec(&String::from("SELECT id, producto, id_cliente\nFROM ordenes\nWHERE cantidad > 1")); + assert_eq!(rt2, vec!["SELECT","id","producto","id_cliente","FROM","ordenes","WHERE","cantidad>1"]); + } } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 7782e58..842dfb2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,9 @@ -use std::io::BufReader; -use std::fs::File; -use std::vec; -use std::{collections::HashMap, error, io::Empty, iter::Enumerate, path::Display}; - pub mod query; pub mod libs; -use crate::libs:: -use query::build_empty_query; -use crate::query::Query; -use crate::query::query_type::QueryType; +use libs::error::print_err; +use libs::exec::exec_query; +use libs::parsing::build_query; fn main() { let args: Vec = std::env::args().collect(); @@ -17,330 +11,10 @@ fn main() { println!("Uso: cargo run -- ruta/a/tablas \"query\""); } else { let path: &String = &args[1]; - let args = text_to_vec(&args[2]); // Tokenization - match build_query(args, path) { - Ok(x) => exec_query(x), -// Err(x) => print_err(x) - Err(_) => println!("TODO print_err") + let text_query: &String = &args[2]; + match build_query(text_query, path) { + Ok(x) => exec_query(x), + Err(x) => print_err(x) } } } - -fn exec_query(query: query::Query) -> Result { - match query.table { - Some(f) => match std::fs::File::open(f) { - Ok(x) => { - match query.operation.unwrap() { - QueryType::DELETE => exec_query_delete(x, query), - QueryType::INSERT => exec_query_insert(x, query), - QueryType::SELECT => exec_query_select(x, query), - QueryType::UPDATE => exec_query_update(x, query), - } - }, - Err(_) => return Err(6) - } , - None => return Err(6) - } - -} - -/* -fn build_query(text_query: &String, path: &String) -> Result{ - // Crea query valida o devuelve codigo de error. - let args = text_to_vec(text_query); - let mut resultado = build_empty_query(); - - match full_check_query(&args, &path, &mut resultado) { - Ok(_) => return Ok(resultado), - Err(x) => return Err(x) - } - -} -*/ - -fn build_query(args: Vec, path: &String) -> Result { - // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build - match vec_to_query(&args, path) { - Ok(x) => return validate_query(x), // Sintaxis analysis - Err(x) => return Err(x) - } -} - -fn validate_query(query: Query) -> Result { - // Sintatic analysis - -} - -fn text_to_vec(text_query: &String) -> Vec { - // Text to vector. Tokenization by space, new line & coma - let mut result: Vec = Vec::new(); - let mut split = text_query.split(&[' ', '\n']); - - let mut element_opt = split.next(); - while element_opt.is_some() { - match element_opt { - Some(x) => { - if x.contains(',') { - let mut tmp = String::from(x); - tmp.pop(); - result.push(tmp); - } - else { - result.push(x.to_string()); - } - }, - None => continue - } - - element_opt = split.next(); - } - result -} - -fn vec_to_query(args: &Vec, path: &String) -> Result{ - // Vec to non validated query - let mut result = build_empty_query(); - match check_operation(&args) { - Ok(x) => { - match &x { - QueryType::DELETE => separate_args_delete(args, path, &mut result), - QueryType::INSERT => separate_args_insert(args, path, &mut result), - QueryType::SELECT => separate_args_select(args, path, &mut result), - QueryType::UPDATE => separate_args_update(args, path, &mut result) - } - result.operation = Some(x); - }, - Err(x) => return Err(x) - } - - Ok(result) -} - -fn merge_table_and_path(path: &String, table: &String) -> String { - let mut table_full: String = path.to_string(); - table_full.push('/'); - table_full.push_str(table); - - table_full -} - -fn separate_args_delete(args: &Vec, path: &String, result: &mut Query) { - result.table = Some(merge_table_and_path(path, &args[2])); - - let mut where_condition = args[4].to_string(); - let mut counter = 5; - while counter < args.len() { - where_condition.push_str(&args[counter].to_string()); - counter += 1; - } - - result.where_condition = Some(where_condition); -} - -fn separate_args_insert(args: &Vec, path: &String, result: &mut Query) { - result.table = Some(merge_table_and_path(path, &args[2])); - - let mut columns: Vec = Vec::new(); - let mut counter = 3; - while counter < args.len()/2 && ! args[counter].eq("VALUES") { - columns.push(args[counter].to_string()); - counter += 1; - } - - counter += 1; - let mut values: Vec = Vec::new(); - while counter < args.len() { - values.push(args[counter].to_string()); - counter += 1; - } - - result.columns = Some(columns); - result.values = Some(values); -} - -fn separate_args_update(args: &Vec, path: &String, result: &mut Query) { - result.table = Some(merge_table_and_path(path, &args[1])); - - let mut counter = 3; - let mut columns: Vec = Vec::new(); - let mut values: Vec = Vec::new(); - - while counter < args.len() && !args[counter].eq("WHERE") { - if counter % 3 == 0 { - columns.push(args[counter].to_string()); - } else if ( counter % 3 ) == 2 { - values.push(args[counter].to_string()); - } - counter += 1; - } - counter += 1; - - let mut where_condition = String::new(); - while counter < args.len() { - where_condition.push_str(&args[counter].to_string()); - counter += 1; - } - - result.columns = Some(columns); - result.where_condition = Some(where_condition); - result.values = Some(values); -} - -fn separate_args_select(args: &Vec, path: &String, result: &mut Query) { - let mut columns: Vec = Vec::new(); - let mut counter = 1; - while counter < args.len() && !args[counter].eq("FROM") { - columns.push(args[counter].to_string()); - counter += 1; - } - counter += 1; - result.table = Some(merge_table_and_path(path, &args[counter])); - - let mut where_condition = String::new(); - while counter < args.len() && !args[counter].eq("ORDER") { - where_condition.push_str(&args[counter].to_string()); - counter += 1; - } - result.where_condition = Some(where_condition); - - // Last condition returns false on desc, true on asc - result.order_by = Some((args[counter + 2].to_string(),counter + 3 != args.len())); -} - -/* -fn text_to_vec(text_query: &String) -> Vec { - let mut resultado: Vec = Vec::new(); - let mut split = text_query.split(' '); - - let mut element_opt = split.next(); - while element_opt.is_some() { - match element_opt { - Some(x) => { - - if x.contains('\n') { - let mut split2 = x.split('\n'); - let mut element_split2 = split2.next(); - resultado.push(element_split2.unwrap().to_string()); - element_split2 = split2.next(); - resultado.push(element_split2.unwrap().to_string()); - } else if x.contains(',') { - - } else { - resultado.push(x.to_string()) - } - }, // TODO: Check si esto esta bien - None => continue - } - element_opt = split.next(); - } - - resultado -} - -fn full_check_query(args: &Vec, path: &String) -> Result { - let mut error_code :u32 = 0; - let mut result = build_empty_query(); - match check_operation(&args) { - Ok(x) => result.operation = Some(x), - Err(x) => return Err(x) - } - match check_table_exist(path, args, &result.operation.unwrap()){ - Ok(x) => result.table = Some(x), - Err(x) => return Err(x) - } - match check_columns_exist(args,&result.table.unwrap()) { - - } -} -*/ - -fn check_operation(args: &Vec) -> Result { - // Check correct operation sintaxis - let operation = &args[0]; - if operation.eq("DELETE") { - check_format_delete(args) - } else if operation.eq("INSERT" ) { - check_format_insert(args) - } else if operation.eq("SELECT") { - check_format_select(args) - } else if operation.eq("UPDATE") { - Ok(QueryType::UPDATE) - } else { - Err(1) // Code: OPERACION INVALIDA - } -} - -fn check_format_delete(args: &Vec) -> Result { - if args[1].eq("FROM") && args[3].eq("WHERE"){ - Ok(QueryType::DELETE) - } else { - Err(3) // Code: DELETE MAL FORMATEADO - } -} - -fn check_format_insert(args: &Vec) -> Result { - if args[1].eq("INTO") { - if (args.len() - 3) % 2 != 0 || args.len() - 3 < 0 { - Err(2) - } else{ - let mut counter = 0; - let correct_value_len = (args.len() - 3)/2; // INSERT INTO a b c VALUES x y z. Len = 9. Correct len = 3. - while counter < correct_value_len && ! args[counter].eq("VALUES"){ - counter += 1; - } - - if counter == correct_value_len && args[counter].eq("VALUES") { - Ok(QueryType::INSERT) - } else{ - Err(2) // Codigo: INSERT MAL FORMATEADO - } - } - } - else { - Err(2) // Codigo: INSERT MAL FORMATEADO - } -} - -fn check_format_select(args: &Vec) -> Result { - Ok(QueryType::SELECT) -} - -fn check_table_exist(path: &String, args: &Vec, operation: &QueryType) -> Result{ - // Asume query bien formateado - let mut table= String::from(path); - table.push('/'); - match &operation { - QueryType::DELETE => table.push_str(&args[2]), - QueryType::INSERT => table.push_str(&args[2]), - QueryType::SELECT => { - // Debo encontrar cual es la tabla (asumiendo query bien formateado) - let mut counter = 2; - while ! args[counter].eq("FROM"){ - counter += 1; - } - table.push_str(&args[counter + 1]) - }, - QueryType::UPDATE => table.push_str(&args[1]), - } - - match File::open(&table) { // TODO: Path::exist()? - Ok(_) => return Ok(table), - Err(_) => return Err(4) // Código: NO SE PUDO ABRIR ARCHIVO - } -} - -fn check_columns_exist(args: &Vec, result: &mut Query) -> Result,u32> { - let file = File::open(&result.table.unwrap() ); - match file { - Ok(_) => { - let mut reader = BufReader::new(file); - - let mut line = String::new(); - match reader.read_line(&mut line) { - - } - } - Err(_) => return Err(5) - } - -} \ No newline at end of file diff --git a/src/query.rs b/src/query.rs index 913fb22..0acc4f4 100644 --- a/src/query.rs +++ b/src/query.rs @@ -5,7 +5,7 @@ pub struct Query { pub operation: Option, pub table: Option, // DELETE, INSERT, SELECT, UPDATE pub columns: Option>, // INSERT, SELECT, UPDATE - pub where_condition: Option, // DELETE (siempre), SELECT (a veces), UPDATE (siempre) + pub where_condition: Option>, // DELETE (siempre), SELECT (a veces), UPDATE (siempre) pub order_by: Option<(String,bool)>, // SELECT (a veces) pub values: Option> // INSERT y UPDATE (en update es set) } diff --git a/src/query/query_type.rs b/src/query/query_type.rs index 9e2eb41..d1ddba5 100644 --- a/src/query/query_type.rs +++ b/src/query/query_type.rs @@ -1,5 +1,4 @@ use core::fmt; - pub enum QueryType { DELETE, INSERT, From f5e05ea22667fa0cffbdeb5ecc5799ec304fa813 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sat, 7 Sep 2024 21:42:55 -0300 Subject: [PATCH 07/23] WIP: Dios que complejo --- src/condition.rs | 31 ++++++++ src/condition/condition_type.rs | 13 ++++ src/libs/error.rs | 4 +- src/libs/parsing.rs | 127 ++++++++++++++++++++++++-------- src/main.rs | 1 + src/query.rs | 17 +++-- 6 files changed, 154 insertions(+), 39 deletions(-) create mode 100644 src/condition.rs create mode 100644 src/condition/condition_type.rs diff --git a/src/condition.rs b/src/condition.rs new file mode 100644 index 0000000..3a721ed --- /dev/null +++ b/src/condition.rs @@ -0,0 +1,31 @@ +pub mod condition_type; +use condition_type::BooleanOperator; +use condition_type::ConditionOperator; + +pub struct Condition { + pub condition: ConditionOperator, + pub v1: Option, + pub v2: Option, +} + +pub struct ComplexCondition { + pub operator: BooleanOperator, + pub cond1: Condition, + pub nest_cond: Box // Linked list of complex conditions +} + +pub fn build_condition(v1: String, v2: String, condition: ConditionOperator) -> Condition { + return Condition { + condition: condition, + v1: Some(v1), + v2: Some(v2), + } +} + +pub fn build_complex_condition(op: BooleanOperator,condition: Condition, comp: Box) -> ComplexCondition { + return Condition { + operator: op, + cond1: condition, + nest_cond: comp // Linked list of complex conditions + } +} \ No newline at end of file diff --git a/src/condition/condition_type.rs b/src/condition/condition_type.rs new file mode 100644 index 0000000..68e318b --- /dev/null +++ b/src/condition/condition_type.rs @@ -0,0 +1,13 @@ +pub enum ConditionOperator { + Minor, // Int + MinorEqual, // Int + Equal, // Int and String + Higher, // Int + HigherEqual, // Int +} + +pub enum BooleanOperator { + AND, + OR, + NOT +} \ No newline at end of file diff --git a/src/libs/error.rs b/src/libs/error.rs index 5ffae73..85979bc 100644 --- a/src/libs/error.rs +++ b/src/libs/error.rs @@ -4,7 +4,9 @@ pub static INSERT_MAL_FORMATEADO: u32 = 3; pub static SELECT_MAL_FORMATEADO: u32 = 4; pub static UPDATE_MAL_FORMATEADO: u32 = 5; pub static ARCHIVO_NO_PUDO_SER_ABIERTO: u32 = 6; -pub static ARCHIVO_SIN_COLUMNAS: u32 = 7; +pub static ARCHIVO_VACIO: u32 = 7; +pub static ARCHIVO_NO_CONTIENE_COLUMNAS_SOLICITADAS: u32 = 8; +pub static WHERE_EN_DELETE_MAL_FORMATEADO: u32 = 9; pub fn print_err(error_code: u32) { // TODO print error diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index b08efe6..c568328 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -1,16 +1,18 @@ use std::io::{BufRead, BufReader}; use std::fs::File; +use crate::condition::{build_condition, ComplexCondition, Condition}; use crate::libs::error; use crate::query::Query; use crate::query::query_type::QueryType; use crate::query::build_empty_query; + pub fn build_query(text_query: &String, path: &String) -> Result { // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build let args = text_to_vec(&text_query); - match vec_to_query(&args, path) { // sintactic analysis - Ok(x) => return validate_query(x), // Semantic analysis + match vec_to_query(&args, path) { + Ok(x) => return validate_query(x), Err(x) => return Err(x) } } @@ -27,13 +29,18 @@ fn merge_table_and_path(path: &String, table: &String) -> String { fn separate_args_delete(args: &Vec, path: &String, result: &mut Query) { result.table = Some(merge_table_and_path(path, &args[2])); - let mut where_condition: Vec = Vec::new(); - where_condition.push(args[4].to_string()); - + let mut where_condition: ComplexCondition; + let mut simple_condition_tmp: Condition; + let mut complex_condition_tmp: Condition; let mut counter = 5; + while counter < args.len() { - where_condition.push(args[counter].to_string()); - counter += 1; + if args[counter].eq("AND") || args[counter].eq["OR"] || args[counter].eq("NOT") { + complex_condition_tmp = build_condition(v1, v2, condition) + } + simple_condition = build_condition(args[counter].to_string(), args[counter + 1].to_string(), condition); + + counter += 3; } result.where_condition = Some(where_condition); @@ -126,13 +133,30 @@ fn check_operation_format(args: &Vec) -> Result { } fn check_delete_format(args: &Vec) -> Result { - if args[1].eq("FROM") && args[3].eq("WHERE"){ - Ok(QueryType::DELETE) + if args[1].eq("FROM") && args[3].eq("WHERE") { + non_valid_keywords = vec!["INSERT","INTO",""] + Ok(QueryType::DELETE) } else { Err(error::DELETE_MAL_FORMATEADO) } } +fn check_non_valid_keywords(args: &Vec, non_valid_keywords: Vec<&str>) -> bool { + // Checks if args contains any non valid keyword + let mut result = true; + let mut counter = 0; + + while counter < args.len() && result { + if non_valid_keywords.contains(&&args[counter].as_str()) { + result = false; + } else { + counter += 1; + } + } + + result +} + fn check_insert_format(args: &Vec) -> Result { if args[1].eq("INTO") { if (args.len() - 3) % 2 != 0 || args.len() - 3 < 0 { @@ -166,6 +190,41 @@ fn check_update_format(args: &Vec) -> Result { Ok(QueryType::UPDATE) } +fn check_where_format(args: &Vec, start_position: usize) -> bool { + let mut result = true; + + let mut counter: usize = start_position; + + let mut not_detected: bool = false; + let mut op_detected: bool = false; + + while counter < args.len() && result { + if args[counter].eq("NOT") { + if not_detected || op_detected { + result = false; // NOT NOT. Que estas haciendo ? + } else { + not_detected = true; + counter += 1; + } + } else if args[counter].eq("AND") || args[counter].eq("OR") { + if op_detected { + result = false; // AND OR , OR AND, OR OR, AND AND. Que estas haciendo ? + } else { + op_detected = true; + counter += 1; + } + } else { + if counter + 3 > args.len() { + result = false; + } else { + + } + } + } + + result +} + fn check_table_exist(path: &String, args: &Vec, operation: &QueryType) -> Result{ // Asume query bien formateado let mut table= String::from(path); @@ -199,31 +258,34 @@ fn validate_query(query: Query) -> Result { Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) } - match &query.operation.unwrap() { - QueryType::DELETE => validate_delete_query(&query), - QueryType::INSERT => validate_insert_query(query), - QueryType::SELECT => validate_select_query(query), - QueryType::UPDATE => validate_update_query(query), + match &query.operation { + Some(op) => { + match &query.operation.unwrap() { + QueryType::DELETE => validate_delete_query(query), + QueryType::INSERT => validate_insert_query(query), + QueryType::SELECT => validate_select_query(query), + QueryType::UPDATE => validate_update_query(query), + } + }, + None => return Err(error::OPERACION_INVALIDA) } } -fn validate_delete_query(query: &Query) -> Result { +fn validate_delete_query(query: Query) -> Result { if query.columns.is_none() && query.values.is_none() && query.columns.is_none() { - match query.table { + match &query.table { Some(table) => { - + match File::open(table) { + Ok(file) => { + match get_columns(file) { + Some(columns) => check_columns_contains_condition(columns,query), + None => return Err(error::ARCHIVO_VACIO) + } + }, + Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + } }, - Err(_) => Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) - } - - match File::open(query.table.unwrap()) { - Ok(x) => { - match get_columns(x) { - Some(x) => check_columns_contains(x, &query), - None => return Err(error::ARCHIVO_SIN_COLUMNAS) - } - }, - Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + None => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) } } else { Err(error::DELETE_MAL_FORMATEADO) @@ -252,10 +314,13 @@ fn get_columns(file: File) -> Option> { } } -fn check_columns_contains(columns: Vec, query: &Query) -> Result { +fn get_where_columns(query: &Query) -> Option> { -} +} +fn check_columns_contains_condition(columns: Vec, query: Query) -> Result { + +} fn text_to_vec(text_query: &String) -> Vec { // Text to vector. Tokenization by space, new line & coma @@ -266,7 +331,7 @@ fn text_to_vec(text_query: &String) -> Vec { while element_opt.is_some() { match element_opt { Some(x) => { - if x.contains(',') { + if x.contains(',') || x.contains(";"){ let mut tmp = String::from(x); tmp.pop(); result.push(tmp); diff --git a/src/main.rs b/src/main.rs index 842dfb2..6b8e678 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +pub mod condition; pub mod query; pub mod libs; diff --git a/src/query.rs b/src/query.rs index 0acc4f4..2d2d272 100644 --- a/src/query.rs +++ b/src/query.rs @@ -1,13 +1,16 @@ pub mod query_type; use query_type::QueryType; + +use crate::condition::ComplexCondition; + pub struct Query { - pub operation: Option, - pub table: Option, // DELETE, INSERT, SELECT, UPDATE - pub columns: Option>, // INSERT, SELECT, UPDATE - pub where_condition: Option>, // DELETE (siempre), SELECT (a veces), UPDATE (siempre) - pub order_by: Option<(String,bool)>, // SELECT (a veces) - pub values: Option> // INSERT y UPDATE (en update es set) + pub operation: Option, // DELETE, INSERT, SELECT, UPDATE + pub table: Option, // DELETE, INSERT, SELECT, UPDATE + pub columns: Option>, // INSERT, SELECT, UPDATE + pub where_condition: Option, // DELETE (siempre), SELECT (a veces), UPDATE (siempre) + pub order_by: Option<(String,bool)>, // SELECT (a veces) + pub values: Option> // INSERT y UPDATE (en update es set) } pub fn build_empty_query() -> Query { @@ -19,4 +22,4 @@ pub fn build_empty_query() -> Query { order_by: None, values: None, } -} \ No newline at end of file +} From f81db0ff0f186fff16ef0a8ae9746f3911bceaad Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 8 Sep 2024 01:24:35 -0300 Subject: [PATCH 08/23] WIP: Arbol de expresiones binarias --- src/condition.rs | 63 +++++++++++++++++--- src/libs/error.rs | 1 + src/libs/parsing.rs | 138 ++++++++++++++++++++++++++++---------------- src/query.rs | 6 +- 4 files changed, 147 insertions(+), 61 deletions(-) diff --git a/src/condition.rs b/src/condition.rs index 3a721ed..9264314 100644 --- a/src/condition.rs +++ b/src/condition.rs @@ -1,4 +1,7 @@ pub mod condition_type; +use std::ops::RemAssign; +use std::ptr::null; + use condition_type::BooleanOperator; use condition_type::ConditionOperator; @@ -9,9 +12,12 @@ pub struct Condition { } pub struct ComplexCondition { - pub operator: BooleanOperator, - pub cond1: Condition, - pub nest_cond: Box // Linked list of complex conditions + // Tree of complex conditions + pub operator: Option, + pub condition: Option, + pub left_cond: Option>, // Oldest condition ( first to be found ) + pub parent: Option>, // Newest condition ( last to be found ) + pub right_cond: Option> // Newest condition ( last to be found ) } pub fn build_condition(v1: String, v2: String, condition: ConditionOperator) -> Condition { @@ -22,10 +28,49 @@ pub fn build_condition(v1: String, v2: String, condition: ConditionOperator) -> } } -pub fn build_complex_condition(op: BooleanOperator,condition: Condition, comp: Box) -> ComplexCondition { - return Condition { - operator: op, - cond1: condition, - nest_cond: comp // Linked list of complex conditions +pub fn build_empty_complex_condition() -> ComplexCondition { + return ComplexCondition { + operator: None, + condition: None, + left_cond: None, + right_cond: None, + parent: None, + } +} + +pub fn tree_check(root: ComplexCondition) -> bool { + match &root.operator { + Some(op) => { + match op { + BooleanOperator::OR => tree_check_or_and(root), + BooleanOperator::AND => tree_check_or_and(root), + BooleanOperator::NOT => tree_check_not(root) + } + }, + None => return true + } +} + +fn tree_check_or_and(root: ComplexCondition) -> bool { + match root.left_cond { + Some(left) => { + match root.right_cond { + Some(right) => return tree_check(*left) && tree_check(*right), + None => return false + } + }, + None => return false + } +} + +fn tree_check_not(root: ComplexCondition) -> bool { + match root.left_cond { + Some(left) => { + match root.right_cond { + Some(_) => return false, + None => return tree_check(*left) + } + }, + None => return false } -} \ No newline at end of file +} diff --git a/src/libs/error.rs b/src/libs/error.rs index 85979bc..da794e6 100644 --- a/src/libs/error.rs +++ b/src/libs/error.rs @@ -7,6 +7,7 @@ pub static ARCHIVO_NO_PUDO_SER_ABIERTO: u32 = 6; pub static ARCHIVO_VACIO: u32 = 7; pub static ARCHIVO_NO_CONTIENE_COLUMNAS_SOLICITADAS: u32 = 8; pub static WHERE_EN_DELETE_MAL_FORMATEADO: u32 = 9; +pub static WHERE_MAL_FORMATEADO: u32 = 10; pub fn print_err(error_code: u32) { // TODO print error diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index c568328..e4c8761 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -1,13 +1,12 @@ use std::io::{BufRead, BufReader}; use std::fs::File; -use crate::condition::{build_condition, ComplexCondition, Condition}; +use crate::condition::{build_condition, build_empty_complex_condition, tree_check, ComplexCondition, Condition}; use crate::libs::error; use crate::query::Query; use crate::query::query_type::QueryType; use crate::query::build_empty_query; - pub fn build_query(text_query: &String, path: &String) -> Result { // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build let args = text_to_vec(&text_query); @@ -26,24 +25,55 @@ fn merge_table_and_path(path: &String, table: &String) -> String { table_full } -fn separate_args_delete(args: &Vec, path: &String, result: &mut Query) { +fn separate_args_delete(args: &Vec, path: &String, result: &mut Query) -> Result { result.table = Some(merge_table_and_path(path, &args[2])); + match get_where_condition(args, 4, build_empty_complex_condition()) { + Ok(cond) => result.where_condition = Some(cond), + Err(x) => return Err(x) + } + Ok(0) +} - let mut where_condition: ComplexCondition; - let mut simple_condition_tmp: Condition; - let mut complex_condition_tmp: Condition; - let mut counter = 5; - - while counter < args.len() { - if args[counter].eq("AND") || args[counter].eq["OR"] || args[counter].eq("NOT") { - complex_condition_tmp = build_condition(v1, v2, condition) +fn get_where_condition(args: &Vec, start_position: usize, root: ComplexCondition) -> Result { + if start_position == args.len() || args[start_position].eq("ORDER") { + if tree_check(root) { + Ok(root) + } else { + Err(error::WHERE_MAL_FORMATEADO) } - simple_condition = build_condition(args[counter].to_string(), args[counter + 1].to_string(), condition); + } else if args[start_position].eq("OR") { + + } else if args[start_position].eq("AND") { - counter += 3; + } else if args[start_position].eq("NOT") { + + } else if check_valid_args_for_basic_condition(args, start_position) { + + } else { + Err(error::WHERE_MAL_FORMATEADO) } +} - result.where_condition = Some(where_condition); +fn check_valid_args_for_basic_condition(args: &Vec, start_position: usize) -> bool { + if start_position + 3 > args.len() { + false + } else { + let first = &args[start_position]; + let second = &args[start_position + 1]; + let third = &args[start_position + 2]; + + if first.eq("AND") || first.eq("OR") || first.eq("NOT") { + false + } else if second.eq("AND") || second.eq("OR") || second.eq("NOT") { + false + } else if ! ( second.eq(">") || second.eq(">=") || second.eq("=") || second.eq("<") || second.eq("<=") ) { + false + } else if third.eq("AND") || third.eq("OR") || third.eq("NOT") { + false + } else { + true + } + } } fn separate_args_insert(args: &Vec, path: &String, result: &mut Query) { @@ -121,7 +151,7 @@ fn check_operation_format(args: &Vec) -> Result { let operation = &args[0]; if operation.eq("DELETE") { check_delete_format(args) - } else if operation.eq("INSERT" ) { + } else if operation.eq("INSERT") { check_insert_format(args) } else if operation.eq("SELECT") { check_select_format(args) @@ -133,32 +163,17 @@ fn check_operation_format(args: &Vec) -> Result { } fn check_delete_format(args: &Vec) -> Result { - if args[1].eq("FROM") && args[3].eq("WHERE") { - non_valid_keywords = vec!["INSERT","INTO",""] - Ok(QueryType::DELETE) + let non_valid_keywords = vec!["INSERT","INTO","VALUES","SELECT","ORDER","BY","UPDATE","SET"]; + if args[1].eq("FROM") && args[3].eq("WHERE") && check_non_valid_keywords(args, non_valid_keywords) { + Ok(QueryType::DELETE) } else { Err(error::DELETE_MAL_FORMATEADO) } } -fn check_non_valid_keywords(args: &Vec, non_valid_keywords: Vec<&str>) -> bool { - // Checks if args contains any non valid keyword - let mut result = true; - let mut counter = 0; - - while counter < args.len() && result { - if non_valid_keywords.contains(&&args[counter].as_str()) { - result = false; - } else { - counter += 1; - } - } - - result -} - fn check_insert_format(args: &Vec) -> Result { - if args[1].eq("INTO") { + let non_valid_keywords = vec!["DELETE","FROM","SELECT","ORDER","BY","UPDATE","SET","WHERE","AND","OR","NOT"]; + if args[1].eq("INTO") && check_non_valid_keywords(args, non_valid_keywords){ if (args.len() - 3) % 2 != 0 || args.len() - 3 < 0 { Err(2) } else{ @@ -181,13 +196,38 @@ fn check_insert_format(args: &Vec) -> Result { } fn check_select_format(args: &Vec) -> Result { - // TODO format select - Ok(QueryType::SELECT) + let non_valid_keywords = vec!["DELETE","INSERT","INTO","VALUES","UPDATE","SET"]; + if check_non_valid_keywords(args, non_valid_keywords) { + // TODO format select + Ok(QueryType::SELECT) + } else { + Err(error::SELECT_MAL_FORMATEADO) + } } fn check_update_format(args: &Vec) -> Result { - // TODO format select - Ok(QueryType::UPDATE) + let non_valid_keywords = vec!["DELETE","FROM","INSERT","INTO","SELECT","VALUES","ORDER","BY"]; + if args[2].eq("SET") && args.contains(&"WHERE".to_string()) && check_non_valid_keywords(args, non_valid_keywords) { + Ok(QueryType::UPDATE) + } else{ + Err(error::UPDATE_MAL_FORMATEADO) + } +} + +fn check_non_valid_keywords(args: &Vec, non_valid_keywords: Vec<&str>) -> bool { + // Checks if args contains any non valid keyword + let mut result = true; + let mut counter = 0; + + while counter < args.len() && result { + if non_valid_keywords.contains(&&args[counter].as_str()) { + result = false; + } else { + counter += 1; + } + } + + result } fn check_where_format(args: &Vec, start_position: usize) -> bool { @@ -324,21 +364,18 @@ fn check_columns_contains_condition(columns: Vec, query: Query) -> Resul fn text_to_vec(text_query: &String) -> Vec { // Text to vector. Tokenization by space, new line & coma + let tmp_text_query = text_query; + tmp_text_query.replace('\n', " "); + tmp_text_query.replace(',', " "); + tmp_text_query.replace(';', ""); let mut result: Vec = Vec::new(); - let mut split = text_query.split(&[' ', '\n']); + let mut split = tmp_text_query.split(' '); let mut element_opt = split.next(); while element_opt.is_some() { match element_opt { Some(x) => { - if x.contains(',') || x.contains(";"){ - let mut tmp = String::from(x); - tmp.pop(); - result.push(tmp); - } - else { - result.push(x.to_string()); - } + result.push(x.to_string()); }, None => continue } @@ -354,7 +391,10 @@ fn vec_to_query(args: &Vec, path: &String) -> Result{ match check_operation_format(&args) { Ok(x) => { match &x { - QueryType::DELETE => separate_args_delete(args, path, &mut result), + QueryType::DELETE => match separate_args_delete(args, path, &mut result){ + Ok(_) => , + Err(x) => return Err(x) + }, QueryType::INSERT => separate_args_insert(args, path, &mut result), QueryType::SELECT => separate_args_select(args, path, &mut result), QueryType::UPDATE => separate_args_update(args, path, &mut result) diff --git a/src/query.rs b/src/query.rs index 2d2d272..452e235 100644 --- a/src/query.rs +++ b/src/query.rs @@ -8,9 +8,9 @@ pub struct Query { pub operation: Option, // DELETE, INSERT, SELECT, UPDATE pub table: Option, // DELETE, INSERT, SELECT, UPDATE pub columns: Option>, // INSERT, SELECT, UPDATE - pub where_condition: Option, // DELETE (siempre), SELECT (a veces), UPDATE (siempre) - pub order_by: Option<(String,bool)>, // SELECT (a veces) - pub values: Option> // INSERT y UPDATE (en update es set) + pub where_condition: Option, // DELETE (always), SELECT (sometimes), UPDATE (always) . Tree of conditions + pub order_by: Option<(String,bool)>, // SELECT (sometimes) + pub values: Option> // INSERT, UPDATE (in update is set) } pub fn build_empty_query() -> Query { From d7540f7334b7aa1a6ba0d918f65f3dae8fbaf22c Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 8 Sep 2024 13:21:01 -0300 Subject: [PATCH 09/23] WIP: Nuevo branch para simplificar --- README.md | 8 ++ src/condition.rs | 119 +++++++++++++++++++-- src/libs/error.rs | 1 + src/libs/parsing.rs | 247 +++++++++++++++++++++++--------------------- src/query.rs | 6 ++ 5 files changed, 255 insertions(+), 126 deletions(-) diff --git a/README.md b/README.md index e69de29..76dbff9 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,8 @@ +# Ejercicio individual | (75.42) Taller de programación I + +## Alumno: Testa Santiago Tomas ( 108301 ) + +### Detalles de implementación + +Para la lógica compuesta del WHERE el objetivo era crear un arbol de condiciones formado por las relaciones de precedencia. + diff --git a/src/condition.rs b/src/condition.rs index 9264314..dbbc9cc 100644 --- a/src/condition.rs +++ b/src/condition.rs @@ -1,14 +1,14 @@ pub mod condition_type; -use std::ops::RemAssign; -use std::ptr::null; +use crate::query::Query; +use crate::libs::error; use condition_type::BooleanOperator; use condition_type::ConditionOperator; pub struct Condition { pub condition: ConditionOperator, - pub v1: Option, - pub v2: Option, + pub column: Option, + pub value: Option, } pub struct ComplexCondition { @@ -16,15 +16,14 @@ pub struct ComplexCondition { pub operator: Option, pub condition: Option, pub left_cond: Option>, // Oldest condition ( first to be found ) - pub parent: Option>, // Newest condition ( last to be found ) pub right_cond: Option> // Newest condition ( last to be found ) } -pub fn build_condition(v1: String, v2: String, condition: ConditionOperator) -> Condition { +pub fn build_condition(column: String, value: String, condition: ConditionOperator) -> Condition { return Condition { condition: condition, - v1: Some(v1), - v2: Some(v2), + column: Some(column), + value: Some(value), } } @@ -33,12 +32,21 @@ pub fn build_empty_complex_condition() -> ComplexCondition { operator: None, condition: None, left_cond: None, - right_cond: None, - parent: None, + right_cond: None } } +pub fn build_complex_condition(operator: BooleanOperator, left: Option>, right: Option>) -> ComplexCondition { + return ComplexCondition { + operator: Some(operator), + condition: None, + left_cond: left, + right_cond: right + } +} + pub fn tree_check(root: ComplexCondition) -> bool { + // In Order valid check ( no None leafs ) match &root.operator { Some(op) => { match op { @@ -74,3 +82,94 @@ fn tree_check_not(root: ComplexCondition) -> bool { None => return false } } + +pub fn add_node_to_tree(args: &Vec, start_position: &mut usize, root: ComplexCondition) -> Result { + if *start_position == args.len() || args[*start_position].eq("ORDER") { + if tree_check(root) { + Ok(root) + } else { + Err(error::WHERE_MAL_FORMATEADO) + } + } else if args[*start_position].eq("OR") { + add_node_to_tree_or(args, &mut start_position, root) + } else if args[*start_position].eq("AND") { + add_node_to_tree_and(args, &mut start_position, root) + } else if args[*start_position].eq("NOT") { + add_node_to_tree_not(args, &mut start_position, root) + } else if check_valid_args_for_basic_condition(args, *start_position) { + match root.operator { + Some(op) => {}, + None => {} + } + } else { + Err(error::WHERE_MAL_FORMATEADO) + } +} + +fn add_node_to_tree_or(args: &Vec, start_position: &mut usize, root: ComplexCondition) -> Result { + let new_root = build_complex_condition(BooleanOperator::OR, Some(Box(root)), None ); + *start_position += 1; + add_node_to_tree(args, start_position, new_root) +} + +fn add_node_to_tree_and(args: &Vec, start_position: &mut usize, root: ComplexCondition) -> Result { + match root.operator { + Some(op) => { + match op { + BooleanOperator::OR => {}, + BooleanOperator::AND => { + let new_root = build_complex_condition(BooleanOperator::AND, Some(Box(root)), None ); + *start_position += 1; + add_node_to_tree(args, start_position , new_root) + }, + BooleanOperator::NOT => { + let new_root = build_complex_condition(BooleanOperator::AND, Some(Box(root)), None ); + *start_position += 1; + add_node_to_tree(args, start_position, new_root) + }, + } + }, + None => { + let new_root = build_complex_condition(BooleanOperator::AND, Some(Box(root)), None ); + add_node_to_tree(args, start_position + 1, new_root) + } + } +} + +fn add_node_to_tree_not(args: &Vec, start_position: &mut usize, root: ComplexCondition) -> Result { + +} + +fn check_valid_args_for_basic_condition(args: &Vec, start_position: usize) -> bool { + if start_position + 3 > args.len() { + false + } else { + let first = &args[start_position]; + let second = &args[start_position + 1]; + let third = &args[start_position + 2]; + + if first.eq("AND") || first.eq("OR") || first.eq("NOT") { + false + } else if second.eq("AND") || second.eq("OR") || second.eq("NOT") { + false + } else if ! ( second.eq(">") || second.eq(">=") || second.eq("=") || second.eq("<") || second.eq("<=") ) { + false + } else if third.eq("AND") || third.eq("OR") || third.eq("NOT") { + false + } else { + true + } + } +} + +fn get_where_columns(query: &Query, vec: Vec, node: &ComplexCondition) -> Vec { + match node.operator { + Some(_) => {}, + None => { + match node.condition { + Some(_) => {}, + None => return vec + } + } + } +} \ No newline at end of file diff --git a/src/libs/error.rs b/src/libs/error.rs index da794e6..bbe0641 100644 --- a/src/libs/error.rs +++ b/src/libs/error.rs @@ -8,6 +8,7 @@ pub static ARCHIVO_VACIO: u32 = 7; pub static ARCHIVO_NO_CONTIENE_COLUMNAS_SOLICITADAS: u32 = 8; pub static WHERE_EN_DELETE_MAL_FORMATEADO: u32 = 9; pub static WHERE_MAL_FORMATEADO: u32 = 10; +pub static ORDER_BY_MAL_FORMATEADO: u32 = 11; pub fn print_err(error_code: u32) { // TODO print error diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index e4c8761..26b6b1c 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -1,12 +1,15 @@ use std::io::{BufRead, BufReader}; use std::fs::File; -use crate::condition::{build_condition, build_empty_complex_condition, tree_check, ComplexCondition, Condition}; +use crate::condition::condition_type::BooleanOperator; +use crate::condition::{add_node_to_tree, build_complex_condition, build_condition, build_empty_complex_condition, tree_check, ComplexCondition, Condition}; use crate::libs::error; -use crate::query::Query; +use crate::query::{Query, DELETE_MIN_LEN, INSERT_MIN_LEN, SELECT_MIN_LEN, UPDATE_MIN_LEN}; use crate::query::query_type::QueryType; use crate::query::build_empty_query; +use super::error::DELETE_MAL_FORMATEADO; + pub fn build_query(text_query: &String, path: &String) -> Result { // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build let args = text_to_vec(&text_query); @@ -26,124 +29,117 @@ fn merge_table_and_path(path: &String, table: &String) -> String { } fn separate_args_delete(args: &Vec, path: &String, result: &mut Query) -> Result { - result.table = Some(merge_table_and_path(path, &args[2])); - match get_where_condition(args, 4, build_empty_complex_condition()) { - Ok(cond) => result.where_condition = Some(cond), - Err(x) => return Err(x) - } - Ok(0) -} - -fn get_where_condition(args: &Vec, start_position: usize, root: ComplexCondition) -> Result { - if start_position == args.len() || args[start_position].eq("ORDER") { - if tree_check(root) { - Ok(root) - } else { - Err(error::WHERE_MAL_FORMATEADO) - } - } else if args[start_position].eq("OR") { - - } else if args[start_position].eq("AND") { - - } else if args[start_position].eq("NOT") { - - } else if check_valid_args_for_basic_condition(args, start_position) { - + if args.len() < DELETE_MIN_LEN { + return Err(error::DELETE_MAL_FORMATEADO); } else { - Err(error::WHERE_MAL_FORMATEADO) + result.table = Some(merge_table_and_path(path, &args[2])); + match add_node_to_tree(args, &mut 4, build_empty_complex_condition()) { + Ok(cond) => result.where_condition = Some(cond), + Err(x) => return Err(x) + } + Ok(0) } } -fn check_valid_args_for_basic_condition(args: &Vec, start_position: usize) -> bool { - if start_position + 3 > args.len() { - false +fn separate_args_insert(args: &Vec, path: &String, result: &mut Query) -> Result { + if args.len() < INSERT_MIN_LEN { + return Err(error::INSERT_MAL_FORMATEADO) } else { - let first = &args[start_position]; - let second = &args[start_position + 1]; - let third = &args[start_position + 2]; - - if first.eq("AND") || first.eq("OR") || first.eq("NOT") { - false - } else if second.eq("AND") || second.eq("OR") || second.eq("NOT") { - false - } else if ! ( second.eq(">") || second.eq(">=") || second.eq("=") || second.eq("<") || second.eq("<=") ) { - false - } else if third.eq("AND") || third.eq("OR") || third.eq("NOT") { - false - } else { - true - } - } -} - -fn separate_args_insert(args: &Vec, path: &String, result: &mut Query) { - result.table = Some(merge_table_and_path(path, &args[2])); - - let mut columns: Vec = Vec::new(); - let mut counter = 3; - while counter < args.len()/2 && ! args[counter].eq("VALUES") { - columns.push(args[counter].to_string()); - counter += 1; - } + result.table = Some(merge_table_and_path(path, &args[2])); - counter += 1; - let mut values: Vec = Vec::new(); - while counter < args.len() { - values.push(args[counter].to_string()); + let mut columns: Vec = Vec::new(); + let mut counter = 3; + while counter < args.len()/2 && ! args[counter].eq("VALUES") { + columns.push(args[counter].to_string()); + counter += 1; + } + counter += 1; + let mut values: Vec = Vec::new(); + while counter < args.len() { + values.push(args[counter].to_string()); + counter += 1; + } + + result.columns = Some(columns); + result.values = Some(values); + Ok(0) } - - result.columns = Some(columns); - result.values = Some(values); } -fn separate_args_update(args: &Vec, path: &String, result: &mut Query) { - result.table = Some(merge_table_and_path(path, &args[1])); - - let mut counter = 3; - let mut columns: Vec = Vec::new(); - let mut values: Vec = Vec::new(); +fn separate_args_update(args: &Vec, path: &String, result: &mut Query) -> Result { + if args.len() < UPDATE_MIN_LEN { + result.table = Some(merge_table_and_path(path, &args[1])); - while counter < args.len() && !args[counter].eq("WHERE") { - if counter % 3 == 0 { - columns.push(args[counter].to_string()); - } else if ( counter % 3 ) == 2 { - values.push(args[counter].to_string()); - } - counter += 1; - } - counter += 1; - - let mut where_condition = Vec::new(); - while counter < args.len() { - where_condition.push(args[counter].to_string()); + let mut counter = 3; + let mut columns: Vec = Vec::new(); + let mut values: Vec = Vec::new(); + + while counter < args.len() && !args[counter].eq("WHERE") { + if counter % 3 == 0 { + columns.push(args[counter].to_string()); + } else if ( counter % 3 ) == 2 { + values.push(args[counter].to_string()); + } + counter += 1; + } counter += 1; + + result.columns = Some(columns); + result.values = Some(values); + + match add_node_to_tree(args, &mut counter, build_empty_complex_condition()) { + Ok(cond) => result.where_condition = Some(cond), + Err(x) => return Err(x) + } + Ok(0) + } else { + return Err(error::UPDATE_MAL_FORMATEADO) } - - result.columns = Some(columns); - result.where_condition = Some(where_condition); - result.values = Some(values); } -fn separate_args_select(args: &Vec, path: &String, result: &mut Query) { - let mut columns: Vec = Vec::new(); - let mut counter = 1; - while counter < args.len() && !args[counter].eq("FROM") { - columns.push(args[counter].to_string()); +fn separate_args_select(args: &Vec, path: &String, result: &mut Query) -> Result { + if args.len() < SELECT_MIN_LEN { + return Err(error::SELECT_MAL_FORMATEADO) + } else { + let mut columns: Vec = Vec::new(); + let mut counter = 1; + while counter < args.len() && !args[counter].eq("FROM") { + columns.push(args[counter].to_string()); + counter += 1; + } counter += 1; - } - counter += 1; - result.table = Some(merge_table_and_path(path, &args[counter])); - - let mut where_condition = Vec::new(); - while counter < args.len() && !args[counter].eq("ORDER") { - where_condition.push(args[counter].to_string()); + result.table = Some(merge_table_and_path(path, &args[counter])); counter += 1; + + if counter == args.len() { + Ok(0) + } else { + match add_node_to_tree(args, &mut counter, build_empty_complex_condition()) { + Ok(cond) => result.where_condition = Some(cond), + Err(x) => return Err(x) + } + + if counter < args.len() { + if args[counter + 1].eq("BY") { + if counter + 3 == args.len() { // ORDER BY column + result.order_by = Some((args[counter + 2].to_string(), true)); + } else if counter + 4 == args.len() { // ORDER BY column ASC/DESC + if args[counter + 3].eq("ASC") || args[counter + 3].eq("DESC") { + result.order_by = Some((args[counter + 2].to_string(), args[counter + 2].eq("ASC"))); + } else { + return Err(error::ORDER_BY_MAL_FORMATEADO) + } + } else { + return Err(error::ORDER_BY_MAL_FORMATEADO) + } + } else { + return Err(error::ORDER_BY_MAL_FORMATEADO) + } + } + Ok(0) + } } - result.where_condition = Some(where_condition); - - // Last condition returns false on desc, true on asc - result.order_by = Some((args[counter + 2].to_string(),counter + 3 != args.len())); } fn check_operation_format(args: &Vec) -> Result { @@ -300,7 +296,7 @@ fn validate_query(query: Query) -> Result { match &query.operation { Some(op) => { - match &query.operation.unwrap() { + match op { QueryType::DELETE => validate_delete_query(query), QueryType::INSERT => validate_insert_query(query), QueryType::SELECT => validate_select_query(query), @@ -312,7 +308,7 @@ fn validate_query(query: Query) -> Result { } fn validate_delete_query(query: Query) -> Result { - if query.columns.is_none() && query.values.is_none() && query.columns.is_none() { + if query.columns.is_none() && query.values.is_none() && query.where_condition.is_some() { match &query.table { Some(table) => { match File::open(table) { @@ -332,6 +328,21 @@ fn validate_delete_query(query: Query) -> Result { } } +fn validate_insert_query(query: Query) -> Result { + // TODO + Ok(query) +} + +fn validate_select_query(query: Query) -> Result { + // TODO + Ok(query) +} + +fn validate_update_query(query: Query) -> Result { + // TODO + Ok(query) +} + fn get_columns(file: File) -> Option> { let mut result: Vec = Vec::new(); let mut reader: BufReader = BufReader::new(file); @@ -354,23 +365,19 @@ fn get_columns(file: File) -> Option> { } } -fn get_where_columns(query: &Query) -> Option> { - -} - fn check_columns_contains_condition(columns: Vec, query: Query) -> Result { - + // TODO } fn text_to_vec(text_query: &String) -> Vec { // Text to vector. Tokenization by space, new line & coma let tmp_text_query = text_query; tmp_text_query.replace('\n', " "); - tmp_text_query.replace(',', " "); + tmp_text_query.replace(',', ""); tmp_text_query.replace(';', ""); - let mut result: Vec = Vec::new(); let mut split = tmp_text_query.split(' '); + let mut result: Vec = Vec::new(); let mut element_opt = split.next(); while element_opt.is_some() { match element_opt { @@ -392,14 +399,22 @@ fn vec_to_query(args: &Vec, path: &String) -> Result{ Ok(x) => { match &x { QueryType::DELETE => match separate_args_delete(args, path, &mut result){ - Ok(_) => , + Ok(_) => result.operation = Some(x), Err(x) => return Err(x) }, - QueryType::INSERT => separate_args_insert(args, path, &mut result), - QueryType::SELECT => separate_args_select(args, path, &mut result), - QueryType::UPDATE => separate_args_update(args, path, &mut result) + QueryType::INSERT => match separate_args_insert(args, path, &mut result) { + Ok(_) => result.operation = Some(x), + Err(x) => return Err(x) + }, + QueryType::SELECT => match separate_args_select(args, path, &mut result) { + Ok(_) => result.operation = Some(x), + Err(x) => return Err(x) + }, + QueryType::UPDATE => match separate_args_update(args, path, &mut result) { + Ok(_) => result.operation = Some(x), + Err(x) => return Err(x) + } } - result.operation = Some(x); }, Err(x) => return Err(x) } diff --git a/src/query.rs b/src/query.rs index 452e235..45c2a3e 100644 --- a/src/query.rs +++ b/src/query.rs @@ -4,6 +4,12 @@ use query_type::QueryType; use crate::condition::ComplexCondition; +pub static DELETE_MIN_LEN :usize = 7; // DELETE FROM tabla WHERE a < b +pub static INSERT_MIN_LEN :usize = 6; // INSERT INTO tabla col VALUES val +pub static SELECT_MIN_LEN :usize = 4; // SELECT * FROM tabla +pub static UPDATE_MIN_LEN :usize = 10; // UPDATE tabla SET col = valor WHERE a < b + + pub struct Query { pub operation: Option, // DELETE, INSERT, SELECT, UPDATE pub table: Option, // DELETE, INSERT, SELECT, UPDATE From ef08de54693002bb19d391f8fe2cefe7d37ba4c3 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 8 Sep 2024 13:38:09 -0300 Subject: [PATCH 10/23] WIP: corrigiendo el arbol --- src/condition.rs | 2 +- src/libs/error.rs | 1 + src/libs/parsing.rs | 27 +++++++++++++++++++++++---- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/condition.rs b/src/condition.rs index dbbc9cc..f005c7e 100644 --- a/src/condition.rs +++ b/src/condition.rs @@ -162,7 +162,7 @@ fn check_valid_args_for_basic_condition(args: &Vec, start_position: usiz } } -fn get_where_columns(query: &Query, vec: Vec, node: &ComplexCondition) -> Vec { +pub fn get_where_columns(query: &Query, vec: Vec, node: &ComplexCondition) -> Vec { match node.operator { Some(_) => {}, None => { diff --git a/src/libs/error.rs b/src/libs/error.rs index bbe0641..2e05cd5 100644 --- a/src/libs/error.rs +++ b/src/libs/error.rs @@ -9,6 +9,7 @@ pub static ARCHIVO_NO_CONTIENE_COLUMNAS_SOLICITADAS: u32 = 8; pub static WHERE_EN_DELETE_MAL_FORMATEADO: u32 = 9; pub static WHERE_MAL_FORMATEADO: u32 = 10; pub static ORDER_BY_MAL_FORMATEADO: u32 = 11; +pub static NO_WHERE: u32 = 12; pub fn print_err(error_code: u32) { // TODO print error diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index 26b6b1c..552e358 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -2,7 +2,7 @@ use std::io::{BufRead, BufReader}; use std::fs::File; use crate::condition::condition_type::BooleanOperator; -use crate::condition::{add_node_to_tree, build_complex_condition, build_condition, build_empty_complex_condition, tree_check, ComplexCondition, Condition}; +use crate::condition::{add_node_to_tree, build_complex_condition, build_condition, build_empty_complex_condition, get_where_columns, tree_check, ComplexCondition, Condition}; use crate::libs::error; use crate::query::{Query, DELETE_MIN_LEN, INSERT_MIN_LEN, SELECT_MIN_LEN, UPDATE_MIN_LEN}; use crate::query::query_type::QueryType; @@ -289,9 +289,12 @@ fn check_table_exist(path: &String, args: &Vec, operation: &QueryType) - fn validate_query(query: Query) -> Result { // Pre: Sintactical query OK // Post: Valid query for execution - match File::open(&query.table.unwrap()) { - Ok(_) => {}, - Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + match &query.table { + Some(table) => match File::open(table) { + Ok(_) => {}, + Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + }, + None => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) } match &query.operation { @@ -367,6 +370,22 @@ fn get_columns(file: File) -> Option> { fn check_columns_contains_condition(columns: Vec, query: Query) -> Result { // TODO + match &query.where_condition { + Some(node) => { + let where_columnns = get_where_columns(&query, Vec::new(), node ); + let mut counter = 0; + while counter < columns.len() && where_columnns.contains(&columns[counter]) { + counter += 1; + } + + if counter == columns.len() { + Ok(query) + } else { + Err(error::NO_WHERE) + } + }, + None => return Err(error::NO_WHERE) + } } fn text_to_vec(text_query: &String) -> Vec { From b359e61f74195068e8f7e8c22a60495d44788e7b Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 8 Sep 2024 15:35:47 -0300 Subject: [PATCH 11/23] MOD: where simple sin relaciones complejas. TODO complejas --- README.md | 1 + src/condition.rs | 159 +-------------------------- src/condition/complex_condition.rs | 166 +++++++++++++++++++++++++++++ src/libs/parsing.rs | 47 ++++---- src/query.rs | 6 +- 5 files changed, 204 insertions(+), 175 deletions(-) create mode 100644 src/condition/complex_condition.rs diff --git a/README.md b/README.md index 76dbff9..eadd1c2 100644 --- a/README.md +++ b/README.md @@ -6,3 +6,4 @@ Para la lógica compuesta del WHERE el objetivo era crear un arbol de condiciones formado por las relaciones de precedencia. +Dicho objetivo no pudo ser implementado. Se implementó lógica de condiciones simples ( no compuestas ) diff --git a/src/condition.rs b/src/condition.rs index f005c7e..1ec5875 100644 --- a/src/condition.rs +++ b/src/condition.rs @@ -1,8 +1,12 @@ pub mod condition_type; +/* +pub mod complex_condition; use crate::query::Query; use crate::libs::error; use condition_type::BooleanOperator; +*/ + use condition_type::ConditionOperator; pub struct Condition { @@ -11,14 +15,6 @@ pub struct Condition { pub value: Option, } -pub struct ComplexCondition { - // Tree of complex conditions - pub operator: Option, - pub condition: Option, - pub left_cond: Option>, // Oldest condition ( first to be found ) - pub right_cond: Option> // Newest condition ( last to be found ) -} - pub fn build_condition(column: String, value: String, condition: ConditionOperator) -> Condition { return Condition { condition: condition, @@ -26,150 +22,3 @@ pub fn build_condition(column: String, value: String, condition: ConditionOperat value: Some(value), } } - -pub fn build_empty_complex_condition() -> ComplexCondition { - return ComplexCondition { - operator: None, - condition: None, - left_cond: None, - right_cond: None - } -} - -pub fn build_complex_condition(operator: BooleanOperator, left: Option>, right: Option>) -> ComplexCondition { - return ComplexCondition { - operator: Some(operator), - condition: None, - left_cond: left, - right_cond: right - } -} - -pub fn tree_check(root: ComplexCondition) -> bool { - // In Order valid check ( no None leafs ) - match &root.operator { - Some(op) => { - match op { - BooleanOperator::OR => tree_check_or_and(root), - BooleanOperator::AND => tree_check_or_and(root), - BooleanOperator::NOT => tree_check_not(root) - } - }, - None => return true - } -} - -fn tree_check_or_and(root: ComplexCondition) -> bool { - match root.left_cond { - Some(left) => { - match root.right_cond { - Some(right) => return tree_check(*left) && tree_check(*right), - None => return false - } - }, - None => return false - } -} - -fn tree_check_not(root: ComplexCondition) -> bool { - match root.left_cond { - Some(left) => { - match root.right_cond { - Some(_) => return false, - None => return tree_check(*left) - } - }, - None => return false - } -} - -pub fn add_node_to_tree(args: &Vec, start_position: &mut usize, root: ComplexCondition) -> Result { - if *start_position == args.len() || args[*start_position].eq("ORDER") { - if tree_check(root) { - Ok(root) - } else { - Err(error::WHERE_MAL_FORMATEADO) - } - } else if args[*start_position].eq("OR") { - add_node_to_tree_or(args, &mut start_position, root) - } else if args[*start_position].eq("AND") { - add_node_to_tree_and(args, &mut start_position, root) - } else if args[*start_position].eq("NOT") { - add_node_to_tree_not(args, &mut start_position, root) - } else if check_valid_args_for_basic_condition(args, *start_position) { - match root.operator { - Some(op) => {}, - None => {} - } - } else { - Err(error::WHERE_MAL_FORMATEADO) - } -} - -fn add_node_to_tree_or(args: &Vec, start_position: &mut usize, root: ComplexCondition) -> Result { - let new_root = build_complex_condition(BooleanOperator::OR, Some(Box(root)), None ); - *start_position += 1; - add_node_to_tree(args, start_position, new_root) -} - -fn add_node_to_tree_and(args: &Vec, start_position: &mut usize, root: ComplexCondition) -> Result { - match root.operator { - Some(op) => { - match op { - BooleanOperator::OR => {}, - BooleanOperator::AND => { - let new_root = build_complex_condition(BooleanOperator::AND, Some(Box(root)), None ); - *start_position += 1; - add_node_to_tree(args, start_position , new_root) - }, - BooleanOperator::NOT => { - let new_root = build_complex_condition(BooleanOperator::AND, Some(Box(root)), None ); - *start_position += 1; - add_node_to_tree(args, start_position, new_root) - }, - } - }, - None => { - let new_root = build_complex_condition(BooleanOperator::AND, Some(Box(root)), None ); - add_node_to_tree(args, start_position + 1, new_root) - } - } -} - -fn add_node_to_tree_not(args: &Vec, start_position: &mut usize, root: ComplexCondition) -> Result { - -} - -fn check_valid_args_for_basic_condition(args: &Vec, start_position: usize) -> bool { - if start_position + 3 > args.len() { - false - } else { - let first = &args[start_position]; - let second = &args[start_position + 1]; - let third = &args[start_position + 2]; - - if first.eq("AND") || first.eq("OR") || first.eq("NOT") { - false - } else if second.eq("AND") || second.eq("OR") || second.eq("NOT") { - false - } else if ! ( second.eq(">") || second.eq(">=") || second.eq("=") || second.eq("<") || second.eq("<=") ) { - false - } else if third.eq("AND") || third.eq("OR") || third.eq("NOT") { - false - } else { - true - } - } -} - -pub fn get_where_columns(query: &Query, vec: Vec, node: &ComplexCondition) -> Vec { - match node.operator { - Some(_) => {}, - None => { - match node.condition { - Some(_) => {}, - None => return vec - } - } - } -} \ No newline at end of file diff --git a/src/condition/complex_condition.rs b/src/condition/complex_condition.rs new file mode 100644 index 0000000..0f41a05 --- /dev/null +++ b/src/condition/complex_condition.rs @@ -0,0 +1,166 @@ +use crate::query::Query; +use crate::libs::error; +use super::BooleanOperator; + +pub struct ComplexCondition { + // Tree of complex conditions + pub operator: Option, + pub condition: Option, + pub left_cond: Option>, // Oldest condition ( first to be found ) + pub right_cond: Option> // Newest condition ( last to be found ) +} + +pub fn build_empty_complex_condition() -> ComplexCondition { + return ComplexCondition { + operator: None, + condition: None, + left_cond: None, + right_cond: None + } +} + +pub fn build_complex_condition(operator: BooleanOperator, left: Option>, right: Option>) -> ComplexCondition { + return ComplexCondition { + operator: Some(operator), + condition: None, + left_cond: left, + right_cond: right + } +} + +pub fn tree_check(root: ComplexCondition) -> bool { + // In Order valid check ( no None leafs ) + match &root.operator { + Some(op) => { + match op { + BooleanOperator::OR => tree_check_or_and(root), + BooleanOperator::AND => tree_check_or_and(root), + BooleanOperator::NOT => tree_check_not(root) + } + }, + None => return true + } +} + +fn tree_check_or_and(root: ComplexCondition) -> bool { + match root.left_cond { + Some(left) => { + match root.right_cond { + Some(right) => return tree_check(*left) && tree_check(*right), + None => return false + } + }, + None => return false + } +} + +fn tree_check_not(root: ComplexCondition) -> bool { + match root.left_cond { + Some(left) => { + match root.right_cond { + Some(_) => return false, + None => return tree_check(*left) + } + }, + None => return false + } +} + +pub fn add_node_to_tree(args: &Vec, start_position: &mut usize, root: ComplexCondition) -> Result { + if *start_position == args.len() || args[*start_position].eq("ORDER") { + if tree_check(root) { + Ok(root) + } else { + Err(error::WHERE_MAL_FORMATEADO) + } + } else if args[*start_position].eq("OR") { + add_node_to_tree_or(args, &mut start_position, root) + } else if args[*start_position].eq("AND") { + add_node_to_tree_and(args, &mut start_position, root) + } else if args[*start_position].eq("NOT") { + add_node_to_tree_not(args, &mut start_position, root) + } else if check_valid_args_for_basic_condition(args, *start_position) { + match root.operator { + Some(op) => { + + }, + None => return Err(error::WHERE_MAL_FORMATEADO) // C1 C2 + } + } else { + Err(error::WHERE_MAL_FORMATEADO) + } +} + +fn add_node_to_tree_or(args: &Vec, start_position: &mut usize, root: ComplexCondition) -> Result { + let new_root = build_complex_condition(BooleanOperator::OR, Some(Box::new(root)), None ); + *start_position += 1; + add_node_to_tree(args, start_position, new_root) +} + +fn add_node_to_tree_and(args: &Vec, start_position: &mut usize, root: ComplexCondition) -> Result { + match root.operator { + Some(op) => { + match op { + BooleanOperator::OR => { + match root.left_cond { + Some(x) => {}, + None => return Err(error::WHERE_MAL_FORMATEADO) + } + }, + BooleanOperator::AND => { + let new_root = build_complex_condition(BooleanOperator::AND, Some(Box::new(root)), None ); + *start_position += 1; + add_node_to_tree(args, start_position , new_root) + }, + BooleanOperator::NOT => { + let new_root = build_complex_condition(BooleanOperator::AND, Some(Box::new(root)), None ); + *start_position += 1; + add_node_to_tree(args, start_position, new_root) + }, + } + }, + None => { + let new_root = build_complex_condition(BooleanOperator::AND, Some(Box::new(root)), None ); + *start_position += 1; + add_node_to_tree(args, start_position, new_root) + } + } +} + +fn add_node_to_tree_not(args: &Vec, start_position: &mut usize, root: ComplexCondition) -> Result { + +} + +fn check_valid_args_for_basic_condition(args: &Vec, start_position: usize) -> bool { + if start_position + 3 > args.len() { + false + } else { + let first = &args[start_position]; + let second = &args[start_position + 1]; + let third = &args[start_position + 2]; + + if first.eq("AND") || first.eq("OR") || first.eq("NOT") { + false + } else if second.eq("AND") || second.eq("OR") || second.eq("NOT") { + false + } else if ! ( second.eq(">") || second.eq(">=") || second.eq("=") || second.eq("<") || second.eq("<=") ) { + false + } else if third.eq("AND") || third.eq("OR") || third.eq("NOT") { + false + } else { + true + } + } +} + +pub fn get_where_columns(query: &Query, vec: Vec, node: &ComplexCondition) -> Vec { + match node.operator { + Some(_) => {}, + None => { + match node.condition { + Some(_) => {}, + None => return vec + } + } + } +} \ No newline at end of file diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index 552e358..f8b9012 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -1,15 +1,13 @@ use std::io::{BufRead, BufReader}; use std::fs::File; -use crate::condition::condition_type::BooleanOperator; -use crate::condition::{add_node_to_tree, build_complex_condition, build_condition, build_empty_complex_condition, get_where_columns, tree_check, ComplexCondition, Condition}; +//use crate::condition::{add_node_to_tree, build_complex_condition, build_condition, build_empty_complex_condition, get_where_columns, tree_check, ComplexCondition, Condition}; +// use crate::condition::Condition; use crate::libs::error; use crate::query::{Query, DELETE_MIN_LEN, INSERT_MIN_LEN, SELECT_MIN_LEN, UPDATE_MIN_LEN}; use crate::query::query_type::QueryType; use crate::query::build_empty_query; -use super::error::DELETE_MAL_FORMATEADO; - pub fn build_query(text_query: &String, path: &String) -> Result { // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build let args = text_to_vec(&text_query); @@ -32,11 +30,14 @@ fn separate_args_delete(args: &Vec, path: &String, result: &mut Query) - if args.len() < DELETE_MIN_LEN { return Err(error::DELETE_MAL_FORMATEADO); } else { - result.table = Some(merge_table_and_path(path, &args[2])); + result.table = Some(merge_table_and_path(path, &args[2])); + + /* TODO: Code for complex conditions match add_node_to_tree(args, &mut 4, build_empty_complex_condition()) { Ok(cond) => result.where_condition = Some(cond), Err(x) => return Err(x) } + */ Ok(0) } } @@ -87,11 +88,13 @@ fn separate_args_update(args: &Vec, path: &String, result: &mut Query) - result.columns = Some(columns); result.values = Some(values); - + + /* TODO: Code for complex conditions match add_node_to_tree(args, &mut counter, build_empty_complex_condition()) { Ok(cond) => result.where_condition = Some(cond), Err(x) => return Err(x) } + */ Ok(0) } else { return Err(error::UPDATE_MAL_FORMATEADO) @@ -115,11 +118,13 @@ fn separate_args_select(args: &Vec, path: &String, result: &mut Query) - if counter == args.len() { Ok(0) } else { + /* TODO: Code for complex conditions match add_node_to_tree(args, &mut counter, build_empty_complex_condition()) { Ok(cond) => result.where_condition = Some(cond), Err(x) => return Err(x) } - + */ + if counter < args.len() { if args[counter + 1].eq("BY") { if counter + 3 == args.len() { // ORDER BY column @@ -370,24 +375,30 @@ fn get_columns(file: File) -> Option> { fn check_columns_contains_condition(columns: Vec, query: Query) -> Result { // TODO - match &query.where_condition { - Some(node) => { - let where_columnns = get_where_columns(&query, Vec::new(), node ); - let mut counter = 0; - while counter < columns.len() && where_columnns.contains(&columns[counter]) { - counter += 1; - } - - if counter == columns.len() { - Ok(query) + match get_where_columns(&query) { + Some(column) => { + if columns.contains(&column) { + Ok(query) } else { - Err(error::NO_WHERE) + Err(error::ARCHIVO_NO_CONTIENE_COLUMNAS_SOLICITADAS) } }, None => return Err(error::NO_WHERE) } } +fn get_where_columns(query: &Query) -> Option { + match &query.where_condition { + Some(cond) => { + match &cond.column { + Some(col) => return Some(col.to_string()), + None => return None + } + }, + None => return None + } +} + fn text_to_vec(text_query: &String) -> Vec { // Text to vector. Tokenization by space, new line & coma let tmp_text_query = text_query; diff --git a/src/query.rs b/src/query.rs index 45c2a3e..6fba4ad 100644 --- a/src/query.rs +++ b/src/query.rs @@ -2,7 +2,9 @@ pub mod query_type; use query_type::QueryType; -use crate::condition::ComplexCondition; +use crate::condition::Condition; + +// use crate::condition::ComplexCondition; pub static DELETE_MIN_LEN :usize = 7; // DELETE FROM tabla WHERE a < b pub static INSERT_MIN_LEN :usize = 6; // INSERT INTO tabla col VALUES val @@ -14,7 +16,7 @@ pub struct Query { pub operation: Option, // DELETE, INSERT, SELECT, UPDATE pub table: Option, // DELETE, INSERT, SELECT, UPDATE pub columns: Option>, // INSERT, SELECT, UPDATE - pub where_condition: Option, // DELETE (always), SELECT (sometimes), UPDATE (always) . Tree of conditions + pub where_condition: Option, // DELETE (always), SELECT (sometimes), UPDATE (always) . Tree of conditions pub order_by: Option<(String,bool)>, // SELECT (sometimes) pub values: Option> // INSERT, UPDATE (in update is set) } From 831f56637c2b39e8e4eb7c20c80cf27ba23ba123 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 8 Sep 2024 20:20:47 -0300 Subject: [PATCH 12/23] WIP gdb: SELECT * FROM clientes --- README.md | 10 ++- src/condition.rs | 15 +++- src/libs/error.rs | 1 + src/libs/exec.rs | 204 +++++++++++++++++++++++++++++++++++++++----- src/libs/parsing.rs | 153 +++++++++++++++------------------ src/query.rs | 2 +- 6 files changed, 279 insertions(+), 106 deletions(-) diff --git a/README.md b/README.md index eadd1c2..1081626 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,16 @@ ## Alumno: Testa Santiago Tomas ( 108301 ) +### Detalles de entrega + +El trabajo no se encuentra completo. Las siguientes funcionalidades se encuentran pendientes: + +1. Logica booleana + +2. + ### Detalles de implementación -Para la lógica compuesta del WHERE el objetivo era crear un arbol de condiciones formado por las relaciones de precedencia. +Para la lógica booleana el objetivo era crear un arbol de condiciones formado por las relaciones de precedencia. Dicho objetivo no pudo ser implementado. Se implementó lógica de condiciones simples ( no compuestas ) diff --git a/src/condition.rs b/src/condition.rs index 1ec5875..79cfc34 100644 --- a/src/condition.rs +++ b/src/condition.rs @@ -1,8 +1,8 @@ pub mod condition_type; +use crate::query::Query; /* pub mod complex_condition; -use crate::query::Query; use crate::libs::error; use condition_type::BooleanOperator; */ @@ -22,3 +22,16 @@ pub fn build_condition(column: String, value: String, condition: ConditionOperat value: Some(value), } } + +/* +pub fn operate_condition(filter: (&u32,&ConditionOperator,&String), elements: &Vec) -> bool { + let (column, operator, value) = filter; + match operator { + ConditionOperator::Minor => {}, + ConditionOperator::MinorEqual => {}, + ConditionOperator::Equal => {}, + ConditionOperator::Higher => {}, + ConditionOperator::HigherEqual => {}, + } +} +*/ \ No newline at end of file diff --git a/src/libs/error.rs b/src/libs/error.rs index 2e05cd5..60bc4d5 100644 --- a/src/libs/error.rs +++ b/src/libs/error.rs @@ -13,4 +13,5 @@ pub static NO_WHERE: u32 = 12; pub fn print_err(error_code: u32) { // TODO print error + println!("ERROR. Codigo: {}",error_code) } \ No newline at end of file diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 7a751eb..17d1554 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -1,41 +1,203 @@ +use std::io::{BufRead, BufReader}; use std::fs::File; +//use crate::condition::operate_condition; use crate::query::query_type::QueryType; use crate::query::Query; +use super::parsing::get_file_first_line; + pub fn exec_query(query: Query) { - let table = &query.table; - match table { - Some(f) => match std::fs::File::open(f) { - Ok(file) => { - match &query.operation { - Some(op) => match op { - QueryType::DELETE => exec_query_delete(file, query), - QueryType::INSERT => exec_query_insert(file, query), - QueryType::SELECT => exec_query_select(file, query), - QueryType::UPDATE => exec_query_update(file, query), - }, - None => println!("Error en el programa") - } - }, - Err(_) => println!("Error en el programa") - } , + match &query.operation { + Some(op) => match op { + QueryType::DELETE => exec_query_delete(query), + QueryType::INSERT => exec_query_insert(query), + QueryType::SELECT => exec_query_select(query), + QueryType::UPDATE => exec_query_update(query), + }, None => println!("Error en el programa") } } -fn exec_query_delete(file: File, query: Query) { +fn exec_query_delete(query: Query) { // TODO } -fn exec_query_insert(file: File, query: Query) { +fn exec_query_insert(query: Query) { // TODO } -fn exec_query_select(file: File, query: Query) { - // TODO +fn exec_query_select(query: Query) { + match &query.order_by { + Some(_) => exec_query_select_order_by(query), + None => { + let col_index = find_filter_column(&query); + let print_columns: Vec = find_print_columns(&query); + read_and_print_file(&query, col_index, &print_columns ); + } + } +} + +fn find_print_columns(query: &Query) -> Vec { + let mut result: Vec = Vec::new(); + match &query.columns { + Some(cols) => match get_file_first_line(query) { + Some(line) => { + let table_columns: Vec = line_to_vec(&line); + for element in cols { + let mut counter = 0; + while ! table_columns[counter].eq(element) && counter < table_columns.len() { + counter += 1; + } + if counter < table_columns.len() { + result.push(counter); + } + } + + result + }, + None => result + }, + None => result + } +} + +fn find_filter_column(query: &Query) -> i32 { + let mut col_index_filter = -1; + match &query.where_condition { + Some(x) => { + match &x.column { + Some(column) => { + match &query.table { + Some(table) => match File::open(table){ + Ok(file) => { + let mut reader: BufReader = BufReader::new(file); + let mut line = String::new(); + match reader.read_line(&mut line) { + Ok(_) => { + let mut split = line.split(','); + let mut element_opt = split.next(); + let mut counter = 0; + + while element_opt.is_some() && col_index_filter < 0 { + match element_opt { + Some(x) => { + if x.eq(column) { + col_index_filter = counter; + } + } + None => {} + } + counter += 1; + element_opt = split.next(); + } + }, + Err(_) => col_index_filter = -1, + } + }, + Err(_) => return -1 + }, + None => return -1 + } + }, + None => { col_index_filter = -1; } + } + }, + None => col_index_filter = -1 + } + col_index_filter +} + +fn read_and_print_file(query: &Query, col_filter: i32, columns: &Vec ) { + match &query.table { + Some(table) => match File::open(table) { + Ok(f) => { + let mut reader: BufReader = BufReader::new(f); + let mut line = String::new(); + + // Print header + reader.read_line(&mut line); + println!("{}",line); + + // Print other lines + let mut read = true; + while read { + match reader.read_line(&mut line) { + Ok(x) => { + read = x != 0; + if read { + let elements = line_to_vec(&line); + match &query.where_condition { + Some(condition) => {}, + None => print_file_unconditional(&columns, &elements) + } + } + }, + Err(_) => println!("Error en el programa") + } + } + }, + Err(_) => println!("Error en el programa") + }, + None => println!("Error en el programa ") + } +} + +fn print_file_unconditional(columns: &Vec, elements: &Vec ) { + // Pre: Columns vector sorted incremental && Elements of line content vector + // Post: print to stdout the correct columns + + if columns.is_empty(){ + let mut counter = 0; + for element in elements { + print!("{}",element); + if counter < elements.len() - 1 { + print!(","); + } + + counter += 1; + } + } else { + let mut counter = 0; + let mut found_count = 0; + while counter < elements.len() { + if columns.contains(&counter) { + if found_count == 0 { + print!("{}",elements[counter]); + } else { + print!(",{}",elements[counter]); + } + found_count += 1; + } + + counter += 1; + } + } + println!(); +} + +fn line_to_vec(line: &String) -> Vec { + let mut result: Vec = Vec::new(); + let mut split = line.split(','); + + let mut element_opt = split.next(); + while element_opt.is_some() { + match element_opt { + Some(x) => { + result.push(x.to_string()); + }, + None => continue + } + + element_opt = split.next(); + } + result +} + +fn exec_query_select_order_by(query: Query) { + } -fn exec_query_update(file: File, query: Query) { +fn exec_query_update(query: Query) { // TODO } diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index f8b9012..28de3ba 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -1,6 +1,8 @@ use std::io::{BufRead, BufReader}; use std::fs::File; +use crate::condition::condition_type::ConditionOperator; +use crate::condition::{build_condition, Condition}; //use crate::condition::{add_node_to_tree, build_complex_condition, build_condition, build_empty_complex_condition, get_where_columns, tree_check, ComplexCondition, Condition}; // use crate::condition::Condition; use crate::libs::error; @@ -8,6 +10,8 @@ use crate::query::{Query, DELETE_MIN_LEN, INSERT_MIN_LEN, SELECT_MIN_LEN, UPDATE use crate::query::query_type::QueryType; use crate::query::build_empty_query; +use super::error::SELECT_MAL_FORMATEADO; + pub fn build_query(text_query: &String, path: &String) -> Result { // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build let args = text_to_vec(&text_query); @@ -32,12 +36,30 @@ fn separate_args_delete(args: &Vec, path: &String, result: &mut Query) - } else { result.table = Some(merge_table_and_path(path, &args[2])); - /* TODO: Code for complex conditions - match add_node_to_tree(args, &mut 4, build_empty_complex_condition()) { - Ok(cond) => result.where_condition = Some(cond), - Err(x) => return Err(x) + if args.len() != DELETE_MIN_LEN { + return Err(error::DELETE_MAL_FORMATEADO) + } else { + /* TODO: Code for complex conditions + match add_node_to_tree(args, &mut 4, build_empty_complex_condition()) { + Ok(cond) => result.where_condition = Some(cond), + Err(x) => return Err(x) + } + */ + + if args[5].eq("<") { + result.where_condition = Some(build_condition(args[4].to_string(), args[6].to_string(), ConditionOperator::Minor)) + } else if args[5].eq("<=") { + result.where_condition = Some(build_condition(args[4].to_string(), args[6].to_string(), ConditionOperator::MinorEqual)) + } else if args[5].eq("=") { + result.where_condition = Some(build_condition(args[4].to_string(), args[6].to_string(), ConditionOperator::Equal)) + } else if args[5].eq(">=") { + result.where_condition = Some(build_condition(args[4].to_string(), args[6].to_string(), ConditionOperator::HigherEqual)) + } else if args[5].eq(">") { + result.where_condition = Some(build_condition(args[4].to_string(), args[6].to_string(), ConditionOperator::Higher)) + } else { + return Err(error::WHERE_MAL_FORMATEADO) + } } - */ Ok(0) } } @@ -124,9 +146,27 @@ fn separate_args_select(args: &Vec, path: &String, result: &mut Query) - Err(x) => return Err(x) } */ + if counter + 3 > args.len(){ + return Err(SELECT_MAL_FORMATEADO); + } else if args[counter].eq("WHERE") { + counter += 1; + if args[counter + 1].eq("<") { + result.where_condition = Some(build_condition(args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::Minor)) + } else if args[counter + 1].eq("<=") { + result.where_condition = Some(build_condition(args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::MinorEqual)) + } else if args[counter + 1].eq("=") { + result.where_condition = Some(build_condition(args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::Equal)) + } else if args[counter + 1].eq(">=") { + result.where_condition = Some(build_condition(args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::HigherEqual)) + } else if args[counter + 1].eq(">") { + result.where_condition = Some(build_condition(args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::Higher)) + } else { + return Err(error::WHERE_MAL_FORMATEADO) + } + } if counter < args.len() { - if args[counter + 1].eq("BY") { + if args[counter].eq("ORDER") && args[counter + 1].eq("BY") { if counter + 3 == args.len() { // ORDER BY column result.order_by = Some((args[counter + 2].to_string(), true)); } else if counter + 4 == args.len() { // ORDER BY column ASC/DESC @@ -401,10 +441,10 @@ fn get_where_columns(query: &Query) -> Option { fn text_to_vec(text_query: &String) -> Vec { // Text to vector. Tokenization by space, new line & coma - let tmp_text_query = text_query; - tmp_text_query.replace('\n', " "); - tmp_text_query.replace(',', ""); - tmp_text_query.replace(';', ""); + let mut tmp_text_query = text_query.to_string(); + tmp_text_query = tmp_text_query.replace("\n", " "); + tmp_text_query = tmp_text_query.replace(",", ""); + tmp_text_query = tmp_text_query.replace(";", ""); let mut split = tmp_text_query.split(' '); let mut result: Vec = Vec::new(); @@ -452,91 +492,40 @@ fn vec_to_query(args: &Vec, path: &String) -> Result{ Ok(result) } -/* -fn build_query(text_query: &String, path: &String) -> Result{ - // Crea query valida o devuelve codigo de error. - let args = text_to_vec(text_query); - let mut resultado = build_empty_query(); - - match full_check_query(&args, &path, &mut resultado) { - Ok(_) => return Ok(resultado), - Err(x) => return Err(x) - } - -} - -fn check_columns_exist(args: &Vec, result: &mut Query) -> Result,u32> { - // TODO columns exist - let file = File::open(&result.table.unwrap() ); - match file { - Ok(_) => { - let mut reader = BufReader::new(file); - - let mut line = String::new(); - match reader.read_line(&mut line) { - - } - } - Err(_) => return Err(5) - } - -} - -fn text_to_vec(text_query: &String) -> Vec { - let mut resultado: Vec = Vec::new(); - let mut split = text_query.split(' '); - - let mut element_opt = split.next(); - while element_opt.is_some() { - match element_opt { - Some(x) => { - - if x.contains('\n') { - let mut split2 = x.split('\n'); - let mut element_split2 = split2.next(); - resultado.push(element_split2.unwrap().to_string()); - element_split2 = split2.next(); - resultado.push(element_split2.unwrap().to_string()); - } else if x.contains(',') { +pub fn get_file_first_line(query: &Query) -> Option { + match &query.table { + Some(table) => match File::open(table) { + Ok(f) => { + let mut reader: BufReader = BufReader::new(f); + let mut line = String::new(); - } else { - resultado.push(x.to_string()) + match reader.read_line(&mut line) { + Ok(_) => Some(line), + Err(_) => None } - }, // TODO: Check si esto esta bien - None => continue - } - element_opt = split.next(); + }, + Err(_) => None + }, + None => None } - - resultado } -fn full_check_query(args: &Vec, path: &String) -> Result { - let mut error_code :u32 = 0; - let mut result = build_empty_query(); - match check_operation(&args) { - Ok(x) => result.operation = Some(x), - Err(x) => return Err(x) - } - match check_table_exist(path, args, &result.operation.unwrap()){ - Ok(x) => result.table = Some(x), - Err(x) => return Err(x) - } - match check_columns_exist(args,&result.table.unwrap()) { - - } -} -*/ #[cfg(test)] mod tests { use super::*; #[test] - fn test_text_to_vec(){ + fn test_text_to_vec1(){ let rt1 = text_to_vec(&String::from("SELECT * FROM table")); assert_eq!(rt1, vec!["SELECT","*","FROM","table"]); + } + + #[test] + fn test_text_to_vec2(){ let rt2 = text_to_vec(&String::from("SELECT id, producto, id_cliente\nFROM ordenes\nWHERE cantidad > 1")); - assert_eq!(rt2, vec!["SELECT","id","producto","id_cliente","FROM","ordenes","WHERE","cantidad>1"]); + assert_eq!(rt2, vec!["SELECT","id","producto","id_cliente","FROM","ordenes","WHERE","cantidad",">","1"]); } + + } \ No newline at end of file diff --git a/src/query.rs b/src/query.rs index 6fba4ad..c3ef6aa 100644 --- a/src/query.rs +++ b/src/query.rs @@ -16,7 +16,7 @@ pub struct Query { pub operation: Option, // DELETE, INSERT, SELECT, UPDATE pub table: Option, // DELETE, INSERT, SELECT, UPDATE pub columns: Option>, // INSERT, SELECT, UPDATE - pub where_condition: Option, // DELETE (always), SELECT (sometimes), UPDATE (always) . Tree of conditions + pub where_condition: Option, // DELETE (always), SELECT (sometimes), UPDATE (always) . pub order_by: Option<(String,bool)>, // SELECT (sometimes) pub values: Option> // INSERT, UPDATE (in update is set) } From 2ce7a7917d64f3738d7cdd0c3191c583aaf659d1 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 8 Sep 2024 20:29:57 -0300 Subject: [PATCH 13/23] OK: SELECT * FROM --- src/libs/exec.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 17d1554..bb4530b 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -116,8 +116,13 @@ fn read_and_print_file(query: &Query, col_filter: i32, columns: &Vec ) { let mut line = String::new(); // Print header - reader.read_line(&mut line); - println!("{}",line); + match reader.read_line(&mut line) { + Ok(_) => { + print!("{}",line); + line.clear(); + }, + Err(_) => println!("Error en el programa") // TODO + } // Print other lines let mut read = true; @@ -131,6 +136,7 @@ fn read_and_print_file(query: &Query, col_filter: i32, columns: &Vec ) { Some(condition) => {}, None => print_file_unconditional(&columns, &elements) } + line.clear(); } }, Err(_) => println!("Error en el programa") @@ -173,7 +179,6 @@ fn print_file_unconditional(columns: &Vec, elements: &Vec ) { counter += 1; } } - println!(); } fn line_to_vec(line: &String) -> Vec { From 509a0cf7b5b877224c268bcac33185769a44947c Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 8 Sep 2024 21:13:55 -0300 Subject: [PATCH 14/23] OK: Select columns FROM tabla --- src/libs/exec.rs | 6 +++++- src/libs/parsing.rs | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libs/exec.rs b/src/libs/exec.rs index bb4530b..dd65e73 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -75,6 +75,7 @@ fn find_filter_column(query: &Query) -> i32 { let mut line = String::new(); match reader.read_line(&mut line) { Ok(_) => { + line = line.replace("\n", ""); let mut split = line.split(','); let mut element_opt = split.next(); let mut counter = 0; @@ -118,7 +119,8 @@ fn read_and_print_file(query: &Query, col_filter: i32, columns: &Vec ) { // Print header match reader.read_line(&mut line) { Ok(_) => { - print!("{}",line); + line = line.replace("\n", ""); + println!("{}",line); line.clear(); }, Err(_) => println!("Error en el programa") // TODO @@ -129,6 +131,7 @@ fn read_and_print_file(query: &Query, col_filter: i32, columns: &Vec ) { while read { match reader.read_line(&mut line) { Ok(x) => { + line = line.replace("\n", ""); read = x != 0; if read { let elements = line_to_vec(&line); @@ -179,6 +182,7 @@ fn print_file_unconditional(columns: &Vec, elements: &Vec ) { counter += 1; } } + println!(""); } fn line_to_vec(line: &String) -> Vec { diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index 28de3ba..021341f 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -134,6 +134,7 @@ fn separate_args_select(args: &Vec, path: &String, result: &mut Query) - counter += 1; } counter += 1; + result.columns = Some(columns); result.table = Some(merge_table_and_path(path, &args[counter])); counter += 1; From d0929442776fdb7db460547e4452f7a839ac71df Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 8 Sep 2024 21:37:57 -0300 Subject: [PATCH 15/23] Corregido SELECT * --- src/libs/parsing.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index 021341f..83e1267 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -134,7 +134,12 @@ fn separate_args_select(args: &Vec, path: &String, result: &mut Query) - counter += 1; } counter += 1; - result.columns = Some(columns); + + + if ! &columns[0].eq("*") { + result.columns = Some(columns); + } + result.table = Some(merge_table_and_path(path, &args[counter])); counter += 1; From 166c9cce8d8e5052a66e6c0939ac992891194e48 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 8 Sep 2024 21:42:47 -0300 Subject: [PATCH 16/23] limpiando clippy --- src/condition.rs | 7 +-- src/libs/parsing.rs | 127 ++++++++++++++++++++-------------------- src/query/query_type.rs | 8 +-- 3 files changed, 70 insertions(+), 72 deletions(-) diff --git a/src/condition.rs b/src/condition.rs index 79cfc34..5377d4f 100644 --- a/src/condition.rs +++ b/src/condition.rs @@ -1,5 +1,4 @@ pub mod condition_type; -use crate::query::Query; /* pub mod complex_condition; @@ -15,9 +14,9 @@ pub struct Condition { pub value: Option, } -pub fn build_condition(column: String, value: String, condition: ConditionOperator) -> Condition { - return Condition { - condition: condition, +pub fn build_condition(column: String, value: String, cond: ConditionOperator) -> Condition { + Condition { + condition: cond, column: Some(column), value: Some(value), } diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index 83e1267..7ebe6e7 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -2,7 +2,7 @@ use std::io::{BufRead, BufReader}; use std::fs::File; use crate::condition::condition_type::ConditionOperator; -use crate::condition::{build_condition, Condition}; +use crate::condition::build_condition ; //use crate::condition::{add_node_to_tree, build_complex_condition, build_condition, build_empty_complex_condition, get_where_columns, tree_check, ComplexCondition, Condition}; // use crate::condition::Condition; use crate::libs::error; @@ -106,12 +106,12 @@ fn separate_args_update(args: &Vec, path: &String, result: &mut Query) - } counter += 1; } - counter += 1; result.columns = Some(columns); result.values = Some(values); - /* TODO: Code for complex conditions + /* TODO: Code for complex conditions + counter += 1; match add_node_to_tree(args, &mut counter, build_empty_complex_condition()) { Ok(cond) => result.where_condition = Some(cond), Err(x) => return Err(x) @@ -277,66 +277,6 @@ fn check_non_valid_keywords(args: &Vec, non_valid_keywords: Vec<&str>) result } -fn check_where_format(args: &Vec, start_position: usize) -> bool { - let mut result = true; - - let mut counter: usize = start_position; - - let mut not_detected: bool = false; - let mut op_detected: bool = false; - - while counter < args.len() && result { - if args[counter].eq("NOT") { - if not_detected || op_detected { - result = false; // NOT NOT. Que estas haciendo ? - } else { - not_detected = true; - counter += 1; - } - } else if args[counter].eq("AND") || args[counter].eq("OR") { - if op_detected { - result = false; // AND OR , OR AND, OR OR, AND AND. Que estas haciendo ? - } else { - op_detected = true; - counter += 1; - } - } else { - if counter + 3 > args.len() { - result = false; - } else { - - } - } - } - - result -} - -fn check_table_exist(path: &String, args: &Vec, operation: &QueryType) -> Result{ - // Asume query bien formateado - let mut table= String::from(path); - table.push('/'); - match &operation { - QueryType::DELETE => table.push_str(&args[2]), - QueryType::INSERT => table.push_str(&args[2]), - QueryType::SELECT => { - // Debo encontrar cual es la tabla (asumiendo query bien formateado) - let mut counter = 2; - while ! args[counter].eq("FROM"){ - counter += 1; - } - table.push_str(&args[counter + 1]) - }, - QueryType::UPDATE => table.push_str(&args[1]), - } - - match File::open(&table) { // TODO: Path::exist()? - Ok(_) => return Ok(table), - Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) - } -} - - fn validate_query(query: Query) -> Result { // Pre: Sintactical query OK // Post: Valid query for execution @@ -534,4 +474,63 @@ mod tests { } -} \ No newline at end of file +} + +/* +fn check_where_format(args: &Vec, start_position: usize) -> bool { + let mut result = true; + + let mut counter: usize = start_position; + + let mut not_detected: bool = false; + let mut op_detected: bool = false; + + while counter < args.len() && result { + if args[counter].eq("NOT") { + if not_detected || op_detected { + result = false; // NOT NOT. Que estas haciendo ? + } else { + not_detected = true; + counter += 1; + } + } else if args[counter].eq("AND") || args[counter].eq("OR") { + if op_detected { + result = false; // AND OR , OR AND, OR OR, AND AND. Que estas haciendo ? + } else { + op_detected = true; + counter += 1; + } + } else if counter + 3 > args.len() { + result = false; + } else { + + } + } + + result +} + +fn check_table_exist(path: &String, args: &Vec, operation: &QueryType) -> Result{ + // Asume query bien formateado + let mut table= String::from(path); + table.push('/'); + match &operation { + QueryType::DELETE => table.push_str(&args[2]), + QueryType::INSERT => table.push_str(&args[2]), + QueryType::SELECT => { + // Debo encontrar cual es la tabla (asumiendo query bien formateado) + let mut counter = 2; + while ! args[counter].eq("FROM"){ + counter += 1; + } + table.push_str(&args[counter + 1]) + }, + QueryType::UPDATE => table.push_str(&args[1]), + } + + match File::open(&table) { // TODO: Path::exist()? + Ok(_) => return Ok(table), + Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + } +} +*/ \ No newline at end of file diff --git a/src/query/query_type.rs b/src/query/query_type.rs index d1ddba5..ffd21e2 100644 --- a/src/query/query_type.rs +++ b/src/query/query_type.rs @@ -9,10 +9,10 @@ pub enum QueryType { impl std::fmt::Display for QueryType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - QueryType::DELETE => write!(f,"{}","DELETE"), - QueryType::INSERT => write!(f,"{}","INSERT"), - QueryType::SELECT => write!(f,"{}","SELECT"), - QueryType::UPDATE => write!(f,"{}","UPDATE"), + QueryType::DELETE => write!(f,"DELETE"), + QueryType::INSERT => write!(f,"INSERT"), + QueryType::SELECT => write!(f,"SELECT"), + QueryType::UPDATE => write!(f,"UPDATE"), } } } \ No newline at end of file From 31183a8a5b4fccf974c68e8ce4ab6346d4b55a63 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 8 Sep 2024 22:10:19 -0300 Subject: [PATCH 17/23] SELECT last_column OK --- src/libs/exec.rs | 36 ++++++++++-------------- src/libs/parsing.rs | 67 +++++++++++++++++++++++---------------------- src/query.rs | 2 +- 3 files changed, 51 insertions(+), 54 deletions(-) diff --git a/src/libs/exec.rs b/src/libs/exec.rs index dd65e73..44d7bbb 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -75,19 +75,16 @@ fn find_filter_column(query: &Query) -> i32 { let mut line = String::new(); match reader.read_line(&mut line) { Ok(_) => { - line = line.replace("\n", ""); + line = line.replace('\n', ""); let mut split = line.split(','); let mut element_opt = split.next(); let mut counter = 0; while element_opt.is_some() && col_index_filter < 0 { - match element_opt { - Some(x) => { - if x.eq(column) { - col_index_filter = counter; - } + if let Some(x) = element_opt { + if x.eq(column) { + col_index_filter = counter; } - None => {} } counter += 1; element_opt = split.next(); @@ -109,7 +106,7 @@ fn find_filter_column(query: &Query) -> i32 { col_index_filter } -fn read_and_print_file(query: &Query, col_filter: i32, columns: &Vec ) { +fn read_and_print_file(query: &Query, col_filter: i32, columns: &[usize] ) { match &query.table { Some(table) => match File::open(table) { Ok(f) => { @@ -117,27 +114,27 @@ fn read_and_print_file(query: &Query, col_filter: i32, columns: &Vec ) { let mut line = String::new(); // Print header - match reader.read_line(&mut line) { +/* match reader.read_line(&mut line) { Ok(_) => { - line = line.replace("\n", ""); + line = line.replace('\n', ""); println!("{}",line); line.clear(); }, Err(_) => println!("Error en el programa") // TODO } - +*/ // Print other lines let mut read = true; while read { match reader.read_line(&mut line) { Ok(x) => { - line = line.replace("\n", ""); + line = line.replace('\n', ""); read = x != 0; if read { let elements = line_to_vec(&line); match &query.where_condition { Some(condition) => {}, - None => print_file_unconditional(&columns, &elements) + None => print_file_unconditional(columns, &elements) } line.clear(); } @@ -152,20 +149,17 @@ fn read_and_print_file(query: &Query, col_filter: i32, columns: &Vec ) { } } -fn print_file_unconditional(columns: &Vec, elements: &Vec ) { +fn print_file_unconditional(columns: &[usize], elements: &[String] ) { // Pre: Columns vector sorted incremental && Elements of line content vector // Post: print to stdout the correct columns if columns.is_empty(){ - let mut counter = 0; - for element in elements { + for (counter, element) in elements.iter().enumerate() { print!("{}",element); if counter < elements.len() - 1 { print!(","); } - - counter += 1; - } + } } else { let mut counter = 0; let mut found_count = 0; @@ -182,10 +176,10 @@ fn print_file_unconditional(columns: &Vec, elements: &Vec ) { counter += 1; } } - println!(""); + println!(); } -fn line_to_vec(line: &String) -> Vec { +fn line_to_vec(line: &str) -> Vec { let mut result: Vec = Vec::new(); let mut split = line.split(','); diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index 7ebe6e7..7aa4fa4 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -14,14 +14,14 @@ use super::error::SELECT_MAL_FORMATEADO; pub fn build_query(text_query: &String, path: &String) -> Result { // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build - let args = text_to_vec(&text_query); + let args = text_to_vec(text_query); match vec_to_query(&args, path) { - Ok(x) => return validate_query(x), - Err(x) => return Err(x) + Ok(x) => validate_query(x), + Err(x) => Err(x) } } -fn merge_table_and_path(path: &String, table: &String) -> String { +fn merge_table_and_path(path: &String, table: &str) -> String { let mut table_full: String = path.to_string(); table_full.push('/'); table_full.push_str(table); @@ -30,9 +30,9 @@ fn merge_table_and_path(path: &String, table: &String) -> String { table_full } -fn separate_args_delete(args: &Vec, path: &String, result: &mut Query) -> Result { +fn separate_args_delete(args: &[String], path: &String, result: &mut Query) -> Result { if args.len() < DELETE_MIN_LEN { - return Err(error::DELETE_MAL_FORMATEADO); + Err(error::DELETE_MAL_FORMATEADO) } else { result.table = Some(merge_table_and_path(path, &args[2])); @@ -64,9 +64,9 @@ fn separate_args_delete(args: &Vec, path: &String, result: &mut Query) - } } -fn separate_args_insert(args: &Vec, path: &String, result: &mut Query) -> Result { +fn separate_args_insert(args: &[String], path: &String, result: &mut Query) -> Result { if args.len() < INSERT_MIN_LEN { - return Err(error::INSERT_MAL_FORMATEADO) + Err(error::INSERT_MAL_FORMATEADO) } else { result.table = Some(merge_table_and_path(path, &args[2])); @@ -90,7 +90,7 @@ fn separate_args_insert(args: &Vec, path: &String, result: &mut Query) - } } -fn separate_args_update(args: &Vec, path: &String, result: &mut Query) -> Result { +fn separate_args_update(args: &[String], path: &String, result: &mut Query) -> Result { if args.len() < UPDATE_MIN_LEN { result.table = Some(merge_table_and_path(path, &args[1])); @@ -119,13 +119,13 @@ fn separate_args_update(args: &Vec, path: &String, result: &mut Query) - */ Ok(0) } else { - return Err(error::UPDATE_MAL_FORMATEADO) + Err(error::UPDATE_MAL_FORMATEADO) } } -fn separate_args_select(args: &Vec, path: &String, result: &mut Query) -> Result { +fn separate_args_select(args: &[String], path: &String, result: &mut Query) -> Result { if args.len() < SELECT_MIN_LEN { - return Err(error::SELECT_MAL_FORMATEADO) + Err(error::SELECT_MAL_FORMATEADO) } else { let mut columns: Vec = Vec::new(); let mut counter = 1; @@ -209,7 +209,7 @@ fn check_operation_format(args: &Vec) -> Result { } } -fn check_delete_format(args: &Vec) -> Result { +fn check_delete_format(args: &[String]) -> Result { let non_valid_keywords = vec!["INSERT","INTO","VALUES","SELECT","ORDER","BY","UPDATE","SET"]; if args[1].eq("FROM") && args[3].eq("WHERE") && check_non_valid_keywords(args, non_valid_keywords) { Ok(QueryType::DELETE) @@ -218,10 +218,10 @@ fn check_delete_format(args: &Vec) -> Result { } } -fn check_insert_format(args: &Vec) -> Result { +fn check_insert_format(args: &[String]) -> Result { let non_valid_keywords = vec!["DELETE","FROM","SELECT","ORDER","BY","UPDATE","SET","WHERE","AND","OR","NOT"]; if args[1].eq("INTO") && check_non_valid_keywords(args, non_valid_keywords){ - if (args.len() - 3) % 2 != 0 || args.len() - 3 < 0 { + if (args.len() - 3) % 2 != 0 { Err(2) } else{ let mut counter = 0; @@ -242,7 +242,7 @@ fn check_insert_format(args: &Vec) -> Result { } } -fn check_select_format(args: &Vec) -> Result { +fn check_select_format(args: &[String]) -> Result { let non_valid_keywords = vec!["DELETE","INSERT","INTO","VALUES","UPDATE","SET"]; if check_non_valid_keywords(args, non_valid_keywords) { // TODO format select @@ -252,7 +252,7 @@ fn check_select_format(args: &Vec) -> Result { } } -fn check_update_format(args: &Vec) -> Result { +fn check_update_format(args: &[String]) -> Result { let non_valid_keywords = vec!["DELETE","FROM","INSERT","INTO","SELECT","VALUES","ORDER","BY"]; if args[2].eq("SET") && args.contains(&"WHERE".to_string()) && check_non_valid_keywords(args, non_valid_keywords) { Ok(QueryType::UPDATE) @@ -261,13 +261,13 @@ fn check_update_format(args: &Vec) -> Result { } } -fn check_non_valid_keywords(args: &Vec, non_valid_keywords: Vec<&str>) -> bool { +fn check_non_valid_keywords(args: &[String], non_valid_keywords: Vec<&str>) -> bool { // Checks if args contains any non valid keyword let mut result = true; let mut counter = 0; while counter < args.len() && result { - if non_valid_keywords.contains(&&args[counter].as_str()) { + if non_valid_keywords.contains(&args[counter].as_str()) { result = false; } else { counter += 1; @@ -297,7 +297,7 @@ fn validate_query(query: Query) -> Result { QueryType::UPDATE => validate_update_query(query), } }, - None => return Err(error::OPERACION_INVALIDA) + None => Err(error::OPERACION_INVALIDA) } } @@ -309,13 +309,13 @@ fn validate_delete_query(query: Query) -> Result { Ok(file) => { match get_columns(file) { Some(columns) => check_columns_contains_condition(columns,query), - None => return Err(error::ARCHIVO_VACIO) + None => Err(error::ARCHIVO_VACIO) } }, - Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + Err(_) => Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) } }, - None => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + None => Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) } } else { Err(error::DELETE_MAL_FORMATEADO) @@ -369,7 +369,7 @@ fn check_columns_contains_condition(columns: Vec, query: Query) -> Resul Err(error::ARCHIVO_NO_CONTIENE_COLUMNAS_SOLICITADAS) } }, - None => return Err(error::NO_WHERE) + None => Err(error::NO_WHERE) } } @@ -377,20 +377,20 @@ fn get_where_columns(query: &Query) -> Option { match &query.where_condition { Some(cond) => { match &cond.column { - Some(col) => return Some(col.to_string()), - None => return None + Some(col) => Some(col.to_string()), + None => None } }, - None => return None + None => None } } fn text_to_vec(text_query: &String) -> Vec { // Text to vector. Tokenization by space, new line & coma let mut tmp_text_query = text_query.to_string(); - tmp_text_query = tmp_text_query.replace("\n", " "); - tmp_text_query = tmp_text_query.replace(",", ""); - tmp_text_query = tmp_text_query.replace(";", ""); + tmp_text_query = tmp_text_query.replace('\n', " "); + tmp_text_query = tmp_text_query.replace(',', ""); + tmp_text_query = tmp_text_query.replace(';', ""); let mut split = tmp_text_query.split(' '); let mut result: Vec = Vec::new(); @@ -411,7 +411,7 @@ fn text_to_vec(text_query: &String) -> Vec { fn vec_to_query(args: &Vec, path: &String) -> Result{ // Vec to non validated query let mut result: Query = build_empty_query(); - match check_operation_format(&args) { + match check_operation_format(args) { Ok(x) => { match &x { QueryType::DELETE => match separate_args_delete(args, path, &mut result){ @@ -446,7 +446,10 @@ pub fn get_file_first_line(query: &Query) -> Option { let mut line = String::new(); match reader.read_line(&mut line) { - Ok(_) => Some(line), + Ok(_) => { + line = line.replace('\n', ""); + Some(line) + }, Err(_) => None } }, diff --git a/src/query.rs b/src/query.rs index c3ef6aa..6135fc3 100644 --- a/src/query.rs +++ b/src/query.rs @@ -22,7 +22,7 @@ pub struct Query { } pub fn build_empty_query() -> Query { - return Query { + Query { operation: None, table: None, columns: None, From c19cfa47c6a2abe3c4c8621e91fddd30a1178f0b Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 8 Sep 2024 23:23:29 -0300 Subject: [PATCH 18/23] WIP gdb INSERT INTO --- src/libs/exec.rs | 41 ++++++++++++++++++++++++++++++++++++++--- src/libs/parsing.rs | 8 ++++---- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 44d7bbb..520165a 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -1,5 +1,5 @@ -use std::io::{BufRead, BufReader}; -use std::fs::File; +use std::io::{BufRead, BufReader, Write}; +use std::fs::{File,OpenOptions}; //use crate::condition::operate_condition; use crate::query::query_type::QueryType; @@ -24,7 +24,35 @@ fn exec_query_delete(query: Query) { } fn exec_query_insert(query: Query) { - // TODO + match &query.table { + Some(table) => { + let total_columns = find_total_columns(&query); + let write_columns = find_print_columns(&query); + match &mut OpenOptions::new().append(true).open(table){ + Ok(file) => { + let mut write_line = String::new(); + let mut counter = 0; + let mut writen_elements = 0; + while counter < total_columns { + if write_columns.contains(&counter) { + if let Some(x) = &query.values { + write_line.push_str(&x[writen_elements].to_string()); + writen_elements += 1; + } + } + + counter += 1; + if counter < total_columns { + write_line.push(','); + } } + + file.write(write_line.as_bytes()); + }, + Err(_) => println!("ERROR en el programa") + } + }, + None => println!("ERROR en el programa") + } } fn exec_query_select(query: Query) { @@ -38,6 +66,13 @@ fn exec_query_select(query: Query) { } } +fn find_total_columns(query: &Query) -> usize { + match get_file_first_line(query){ + Some(line) => line_to_vec(&line).len(), + None => 0 + } +} + fn find_print_columns(query: &Query) -> Vec { let mut result: Vec = Vec::new(); match &query.columns { diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index 7aa4fa4..5dc26bf 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -221,16 +221,16 @@ fn check_delete_format(args: &[String]) -> Result { fn check_insert_format(args: &[String]) -> Result { let non_valid_keywords = vec!["DELETE","FROM","SELECT","ORDER","BY","UPDATE","SET","WHERE","AND","OR","NOT"]; if args[1].eq("INTO") && check_non_valid_keywords(args, non_valid_keywords){ - if (args.len() - 3) % 2 != 0 { + if (args.len() - 4) % 2 != 0 { Err(2) } else{ let mut counter = 0; - let correct_value_len = (args.len() - 3)/2; // INSERT INTO a b c VALUES x y z. Len = 9. Correct len = 3. - while counter < correct_value_len && ! args[counter].eq("VALUES"){ + let correct_value_len = (args.len() - 4)/2; // INSERT INTO tabla a b c VALUES x y z. Len = 10. Correct len = 3. + while counter < correct_value_len && ! args[3 + counter].eq("VALUES"){ counter += 1; } - if counter == correct_value_len && args[counter].eq("VALUES") { + if counter == correct_value_len && args[3 + counter].eq("VALUES") { Ok(QueryType::INSERT) } else{ Err(error::INSERT_MAL_FORMATEADO) From d12be3eac0267ab51beb0237d1e7dad7f748dd02 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Sun, 8 Sep 2024 23:31:52 -0300 Subject: [PATCH 19/23] Edit README entrega --- README.md | 26 +++++++++++++++++++++++--- src/libs/exec.rs | 3 ++- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1081626..3c5d265 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,31 @@ ### Detalles de entrega -El trabajo no se encuentra completo. Las siguientes funcionalidades se encuentran pendientes: +El trabajo no se encuentra completo. -1. Logica booleana +Pendientes: -2. +1. Funcionalidad: Logica booleana en WHERE + +2. Funcionalidad: SELECT c/ ORDER BY + +3. Funcionalidad: SELECT c/ WHERE + +4. Funcionalidad: DELETE + +5. Funcionalidad: UPDATE + +6. Testing (mas test unitarios e integración) + +7. Cargo clippy sin warnings + +Funcionalidades probadas OK + +1. SELECT * FROM + +2. SELECT columnas FROM + +3. INSERT INTO ### Detalles de implementación diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 520165a..cb6873f 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -44,7 +44,8 @@ fn exec_query_insert(query: Query) { counter += 1; if counter < total_columns { write_line.push(','); - } } + } + } file.write(write_line.as_bytes()); }, From 4e31d73f8c67fc80d093ad38445cb40a1ebb7997 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Mon, 9 Sep 2024 16:33:45 -0300 Subject: [PATCH 20/23] INSERT INTO DEBUGGED --- README.md | 2 + src/condition.rs | 18 +- src/condition/condition_type.rs | 14 +- src/libs.rs | 2 +- src/libs/error.rs | 30 +-- src/libs/exec.rs | 165 +++++++------ src/libs/parsing.rs | 414 ++++++++++++++++++-------------- src/main.rs | 12 +- src/query.rs | 33 ++- src/query/query_type.rs | 12 +- 10 files changed, 378 insertions(+), 324 deletions(-) diff --git a/README.md b/README.md index 3c5d265..b04eb63 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,8 @@ Pendientes: 7. Cargo clippy sin warnings +8. Documentación de funciones + Funcionalidades probadas OK 1. SELECT * FROM diff --git a/src/condition.rs b/src/condition.rs index 5377d4f..d667cf3 100644 --- a/src/condition.rs +++ b/src/condition.rs @@ -1,5 +1,5 @@ pub mod condition_type; -/* +/* pub mod complex_condition; use crate::libs::error; @@ -9,20 +9,20 @@ use condition_type::BooleanOperator; use condition_type::ConditionOperator; pub struct Condition { - pub condition: ConditionOperator, - pub column: Option, - pub value: Option, + pub condition: ConditionOperator, + pub column: Option, + pub value: Option, } pub fn build_condition(column: String, value: String, cond: ConditionOperator) -> Condition { Condition { - condition: cond, - column: Some(column), - value: Some(value), + condition: cond, + column: Some(column), + value: Some(value), } } -/* +/* pub fn operate_condition(filter: (&u32,&ConditionOperator,&String), elements: &Vec) -> bool { let (column, operator, value) = filter; match operator { @@ -33,4 +33,4 @@ pub fn operate_condition(filter: (&u32,&ConditionOperator,&String), elements: &V ConditionOperator::HigherEqual => {}, } } -*/ \ No newline at end of file +*/ diff --git a/src/condition/condition_type.rs b/src/condition/condition_type.rs index 68e318b..481d3ef 100644 --- a/src/condition/condition_type.rs +++ b/src/condition/condition_type.rs @@ -1,13 +1,13 @@ pub enum ConditionOperator { - Minor, // Int - MinorEqual, // Int - Equal, // Int and String - Higher, // Int - HigherEqual, // Int + Minor, // Int + MinorEqual, // Int + Equal, // Int and String + Higher, // Int + HigherEqual, // Int } pub enum BooleanOperator { AND, OR, - NOT -} \ No newline at end of file + NOT, +} diff --git a/src/libs.rs b/src/libs.rs index 1bd6d7c..93fd982 100644 --- a/src/libs.rs +++ b/src/libs.rs @@ -1,4 +1,4 @@ -// Dumb file for organize everything into libs +// Dumb file for organize everything into libs pub mod error; pub mod exec; pub mod parsing; diff --git a/src/libs/error.rs b/src/libs/error.rs index 60bc4d5..e247048 100644 --- a/src/libs/error.rs +++ b/src/libs/error.rs @@ -1,17 +1,17 @@ -pub static OPERACION_INVALIDA: u32 = 1; -pub static DELETE_MAL_FORMATEADO: u32 = 2; -pub static INSERT_MAL_FORMATEADO: u32 = 3; -pub static SELECT_MAL_FORMATEADO: u32 = 4; -pub static UPDATE_MAL_FORMATEADO: u32 = 5; -pub static ARCHIVO_NO_PUDO_SER_ABIERTO: u32 = 6; -pub static ARCHIVO_VACIO: u32 = 7; -pub static ARCHIVO_NO_CONTIENE_COLUMNAS_SOLICITADAS: u32 = 8; -pub static WHERE_EN_DELETE_MAL_FORMATEADO: u32 = 9; -pub static WHERE_MAL_FORMATEADO: u32 = 10; -pub static ORDER_BY_MAL_FORMATEADO: u32 = 11; -pub static NO_WHERE: u32 = 12; +pub static OPERACION_INVALIDA: u32 = 1; +pub static DELETE_MAL_FORMATEADO: u32 = 2; +pub static INSERT_MAL_FORMATEADO: u32 = 3; +pub static SELECT_MAL_FORMATEADO: u32 = 4; +pub static UPDATE_MAL_FORMATEADO: u32 = 5; +pub static ARCHIVO_NO_PUDO_SER_ABIERTO: u32 = 6; +pub static ARCHIVO_VACIO: u32 = 7; +pub static ARCHIVO_NO_CONTIENE_COLUMNAS_SOLICITADAS: u32 = 8; +pub static WHERE_EN_DELETE_MAL_FORMATEADO: u32 = 9; +pub static WHERE_MAL_FORMATEADO: u32 = 10; +pub static ORDER_BY_MAL_FORMATEADO: u32 = 11; +pub static NO_WHERE: u32 = 12; pub fn print_err(error_code: u32) { - // TODO print error - println!("ERROR. Codigo: {}",error_code) -} \ No newline at end of file + // TODO print error + println!("ERROR. Codigo: {}", error_code) +} diff --git a/src/libs/exec.rs b/src/libs/exec.rs index cb6873f..47970ef 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -1,5 +1,5 @@ +use std::fs::{File, OpenOptions}; use std::io::{BufRead, BufReader, Write}; -use std::fs::{File,OpenOptions}; //use crate::condition::operate_condition; use crate::query::query_type::QueryType; @@ -7,15 +7,15 @@ use crate::query::Query; use super::parsing::get_file_first_line; -pub fn exec_query(query: Query) { +pub fn exec_query(query: Query) { match &query.operation { Some(op) => match op { QueryType::DELETE => exec_query_delete(query), QueryType::INSERT => exec_query_insert(query), QueryType::SELECT => exec_query_select(query), - QueryType::UPDATE => exec_query_update(query), + QueryType::UPDATE => exec_query_update(query), }, - None => println!("Error en el programa") + None => println!("Error en el programa"), } } @@ -28,7 +28,7 @@ fn exec_query_insert(query: Query) { Some(table) => { let total_columns = find_total_columns(&query); let write_columns = find_print_columns(&query); - match &mut OpenOptions::new().append(true).open(table){ + match &mut OpenOptions::new().append(true).open(table) { Ok(file) => { let mut write_line = String::new(); let mut counter = 0; @@ -44,15 +44,16 @@ fn exec_query_insert(query: Query) { counter += 1; if counter < total_columns { write_line.push(','); - } - } + } + } - file.write(write_line.as_bytes()); - }, - Err(_) => println!("ERROR en el programa") + write_line.push('\n'); + let _ = file.write(write_line.as_bytes()); + } + Err(_) => println!("ERROR en el programa"), } - }, - None => println!("ERROR en el programa") + } + None => println!("ERROR en el programa"), } } @@ -62,15 +63,15 @@ fn exec_query_select(query: Query) { None => { let col_index = find_filter_column(&query); let print_columns: Vec = find_print_columns(&query); - read_and_print_file(&query, col_index, &print_columns ); + read_and_print_file(&query, col_index, &print_columns); } } } fn find_total_columns(query: &Query) -> usize { - match get_file_first_line(query){ + match get_file_first_line(query) { Some(line) => line_to_vec(&line).len(), - None => 0 + None => 0, } } @@ -82,83 +83,81 @@ fn find_print_columns(query: &Query) -> Vec { let table_columns: Vec = line_to_vec(&line); for element in cols { let mut counter = 0; - while ! table_columns[counter].eq(element) && counter < table_columns.len() { + while !table_columns[counter].eq(element) && counter < table_columns.len() { counter += 1; } if counter < table_columns.len() { result.push(counter); } } - + result - }, - None => result - }, - None => result + } + None => result, + }, + None => result, } } fn find_filter_column(query: &Query) -> i32 { let mut col_index_filter = -1; match &query.where_condition { - Some(x) => { - match &x.column { - Some(column) => { - match &query.table { - Some(table) => match File::open(table){ - Ok(file) => { - let mut reader: BufReader = BufReader::new(file); - let mut line = String::new(); - match reader.read_line(&mut line) { - Ok(_) => { - line = line.replace('\n', ""); - let mut split = line.split(','); - let mut element_opt = split.next(); - let mut counter = 0; - - while element_opt.is_some() && col_index_filter < 0 { - if let Some(x) = element_opt { - if x.eq(column) { - col_index_filter = counter; - } - } - counter += 1; - element_opt = split.next(); + Some(x) => match &x.column { + Some(column) => match &query.table { + Some(table) => match File::open(table) { + Ok(file) => { + let mut reader: BufReader = BufReader::new(file); + let mut line = String::new(); + match reader.read_line(&mut line) { + Ok(_) => { + line = line.replace('\n', ""); + let mut split = line.split(','); + let mut element_opt = split.next(); + let mut counter = 0; + + while element_opt.is_some() && col_index_filter < 0 { + if let Some(x) = element_opt { + if x.eq(column) { + col_index_filter = counter; } - }, - Err(_) => col_index_filter = -1, - } - }, - Err(_) => return -1 - }, - None => return -1 + } + counter += 1; + element_opt = split.next(); + } + } + Err(_) => col_index_filter = -1, + } } + Err(_) => return -1, }, - None => { col_index_filter = -1; } + None => return -1, + }, + None => { + col_index_filter = -1; } - }, - None => col_index_filter = -1 + }, + None => col_index_filter = -1, } col_index_filter } -fn read_and_print_file(query: &Query, col_filter: i32, columns: &[usize] ) { +fn read_and_print_file(query: &Query, col_filter: i32, columns: &[usize]) { match &query.table { Some(table) => match File::open(table) { Ok(f) => { let mut reader: BufReader = BufReader::new(f); let mut line = String::new(); - // Print header -/* match reader.read_line(&mut line) { - Ok(_) => { - line = line.replace('\n', ""); - println!("{}",line); - line.clear(); - }, - Err(_) => println!("Error en el programa") // TODO - } -*/ + // Print header + /* match reader.read_line(&mut line) { + Ok(_) => { + line = line.replace('\n', ""); + println!("{}",line); + line.clear(); + }, + Err(_) => println!("Error en el programa") // TODO + } + */ // Print other lines let mut read = true; while read { @@ -169,29 +168,29 @@ fn read_and_print_file(query: &Query, col_filter: i32, columns: &[usize] ) { if read { let elements = line_to_vec(&line); match &query.where_condition { - Some(condition) => {}, - None => print_file_unconditional(columns, &elements) + Some(condition) => {} + None => print_file_unconditional(columns, &elements), } line.clear(); } - }, - Err(_) => println!("Error en el programa") + } + Err(_) => println!("Error en el programa"), } } - }, - Err(_) => println!("Error en el programa") + } + Err(_) => println!("Error en el programa"), }, - None => println!("Error en el programa ") + None => println!("Error en el programa "), } } -fn print_file_unconditional(columns: &[usize], elements: &[String] ) { - // Pre: Columns vector sorted incremental && Elements of line content vector - // Post: print to stdout the correct columns +fn print_file_unconditional(columns: &[usize], elements: &[String]) { + // Pre: Columns vector sorted incremental && Elements of line content vector + // Post: print to stdout the correct columns - if columns.is_empty(){ + if columns.is_empty() { for (counter, element) in elements.iter().enumerate() { - print!("{}",element); + print!("{}", element); if counter < elements.len() - 1 { print!(","); } @@ -202,9 +201,9 @@ fn print_file_unconditional(columns: &[usize], elements: &[String] ) { while counter < elements.len() { if columns.contains(&counter) { if found_count == 0 { - print!("{}",elements[counter]); + print!("{}", elements[counter]); } else { - print!(",{}",elements[counter]); + print!(",{}", elements[counter]); } found_count += 1; } @@ -224,8 +223,8 @@ fn line_to_vec(line: &str) -> Vec { match element_opt { Some(x) => { result.push(x.to_string()); - }, - None => continue + } + None => continue, } element_opt = split.next(); @@ -233,9 +232,7 @@ fn line_to_vec(line: &str) -> Vec { result } -fn exec_query_select_order_by(query: Query) { - -} +fn exec_query_select_order_by(query: Query) {} fn exec_query_update(query: Query) { // TODO diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index 5dc26bf..5c9aa02 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -1,43 +1,43 @@ -use std::io::{BufRead, BufReader}; use std::fs::File; +use std::io::{BufRead, BufReader}; +use crate::condition::build_condition; use crate::condition::condition_type::ConditionOperator; -use crate::condition::build_condition ; //use crate::condition::{add_node_to_tree, build_complex_condition, build_condition, build_empty_complex_condition, get_where_columns, tree_check, ComplexCondition, Condition}; // use crate::condition::Condition; use crate::libs::error; -use crate::query::{Query, DELETE_MIN_LEN, INSERT_MIN_LEN, SELECT_MIN_LEN, UPDATE_MIN_LEN}; -use crate::query::query_type::QueryType; use crate::query::build_empty_query; +use crate::query::query_type::QueryType; +use crate::query::{Query, DELETE_MIN_LEN, INSERT_MIN_LEN, SELECT_MIN_LEN, UPDATE_MIN_LEN}; use super::error::SELECT_MAL_FORMATEADO; pub fn build_query(text_query: &String, path: &String) -> Result { - // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build - let args = text_to_vec(text_query); - match vec_to_query(&args, path) { - Ok(x) => validate_query(x), - Err(x) => Err(x) + // Full "Compilation" process of query. Tokenization, sintactic analysis, semantic and build + let args = text_to_vec(text_query); + match vec_to_query(&args, path) { + Ok(x) => validate_query(x), + Err(x) => Err(x), } } fn merge_table_and_path(path: &String, table: &str) -> String { let mut table_full: String = path.to_string(); table_full.push('/'); - table_full.push_str(table); + table_full.push_str(table); table_full.push_str(".csv"); table_full } -fn separate_args_delete(args: &[String], path: &String, result: &mut Query) -> Result { +fn separate_args_delete(args: &[String], path: &String, result: &mut Query) -> Result { if args.len() < DELETE_MIN_LEN { Err(error::DELETE_MAL_FORMATEADO) } else { result.table = Some(merge_table_and_path(path, &args[2])); if args.len() != DELETE_MIN_LEN { - return Err(error::DELETE_MAL_FORMATEADO) + return Err(error::DELETE_MAL_FORMATEADO); } else { /* TODO: Code for complex conditions match add_node_to_tree(args, &mut 4, build_empty_complex_condition()) { @@ -47,102 +47,121 @@ fn separate_args_delete(args: &[String], path: &String, result: &mut Query) -> R */ if args[5].eq("<") { - result.where_condition = Some(build_condition(args[4].to_string(), args[6].to_string(), ConditionOperator::Minor)) + result.where_condition = Some(build_condition( + args[4].to_string(), + args[6].to_string(), + ConditionOperator::Minor, + )) } else if args[5].eq("<=") { - result.where_condition = Some(build_condition(args[4].to_string(), args[6].to_string(), ConditionOperator::MinorEqual)) + result.where_condition = Some(build_condition( + args[4].to_string(), + args[6].to_string(), + ConditionOperator::MinorEqual, + )) } else if args[5].eq("=") { - result.where_condition = Some(build_condition(args[4].to_string(), args[6].to_string(), ConditionOperator::Equal)) + result.where_condition = Some(build_condition( + args[4].to_string(), + args[6].to_string(), + ConditionOperator::Equal, + )) } else if args[5].eq(">=") { - result.where_condition = Some(build_condition(args[4].to_string(), args[6].to_string(), ConditionOperator::HigherEqual)) + result.where_condition = Some(build_condition( + args[4].to_string(), + args[6].to_string(), + ConditionOperator::HigherEqual, + )) } else if args[5].eq(">") { - result.where_condition = Some(build_condition(args[4].to_string(), args[6].to_string(), ConditionOperator::Higher)) + result.where_condition = Some(build_condition( + args[4].to_string(), + args[6].to_string(), + ConditionOperator::Higher, + )) } else { - return Err(error::WHERE_MAL_FORMATEADO) + return Err(error::WHERE_MAL_FORMATEADO); } } - Ok(0) + Ok(0) } } -fn separate_args_insert(args: &[String], path: &String, result: &mut Query) -> Result { +fn separate_args_insert(args: &[String], path: &String, result: &mut Query) -> Result { if args.len() < INSERT_MIN_LEN { Err(error::INSERT_MAL_FORMATEADO) } else { - result.table = Some(merge_table_and_path(path, &args[2])); + result.table = Some(merge_table_and_path(path, &args[2])); let mut columns: Vec = Vec::new(); - let mut counter = 3; - while counter < args.len()/2 && ! args[counter].eq("VALUES") { + let mut counter = 3; + while counter < args.len() && !args[counter].eq("VALUES") { columns.push(args[counter].to_string()); counter += 1; } - + counter += 1; let mut values: Vec = Vec::new(); while counter < args.len() { values.push(args[counter].to_string()); counter += 1; } - + result.columns = Some(columns); result.values = Some(values); - Ok(0) + Ok(0) } } -fn separate_args_update(args: &[String], path: &String, result: &mut Query) -> Result { +fn separate_args_update(args: &[String], path: &String, result: &mut Query) -> Result { if args.len() < UPDATE_MIN_LEN { - result.table = Some(merge_table_and_path(path, &args[1])); + result.table = Some(merge_table_and_path(path, &args[1])); - let mut counter = 3; + let mut counter = 3; let mut columns: Vec = Vec::new(); let mut values: Vec = Vec::new(); - + while counter < args.len() && !args[counter].eq("WHERE") { if counter % 3 == 0 { columns.push(args[counter].to_string()); - } else if ( counter % 3 ) == 2 { + } else if (counter % 3) == 2 { values.push(args[counter].to_string()); - } + } counter += 1; } - + result.columns = Some(columns); result.values = Some(values); - /* TODO: Code for complex conditions - counter += 1; + /* TODO: Code for complex conditions + counter += 1; match add_node_to_tree(args, &mut counter, build_empty_complex_condition()) { Ok(cond) => result.where_condition = Some(cond), Err(x) => return Err(x) } */ - Ok(0) + Ok(0) } else { Err(error::UPDATE_MAL_FORMATEADO) } } -fn separate_args_select(args: &[String], path: &String, result: &mut Query) -> Result { +fn separate_args_select(args: &[String], path: &String, result: &mut Query) -> Result { if args.len() < SELECT_MIN_LEN { Err(error::SELECT_MAL_FORMATEADO) } else { let mut columns: Vec = Vec::new(); - let mut counter = 1; + let mut counter = 1; while counter < args.len() && !args[counter].eq("FROM") { columns.push(args[counter].to_string()); counter += 1; } counter += 1; - - if ! &columns[0].eq("*") { + if !&columns[0].eq("*") { result.columns = Some(columns); } result.table = Some(merge_table_and_path(path, &args[counter])); counter += 1; - + if counter == args.len() { Ok(0) } else { @@ -152,43 +171,66 @@ fn separate_args_select(args: &[String], path: &String, result: &mut Query) -> R Err(x) => return Err(x) } */ - if counter + 3 > args.len(){ + if counter + 3 > args.len() { return Err(SELECT_MAL_FORMATEADO); } else if args[counter].eq("WHERE") { counter += 1; if args[counter + 1].eq("<") { - result.where_condition = Some(build_condition(args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::Minor)) + result.where_condition = Some(build_condition( + args[counter].to_string(), + args[counter + 2].to_string(), + ConditionOperator::Minor, + )) } else if args[counter + 1].eq("<=") { - result.where_condition = Some(build_condition(args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::MinorEqual)) + result.where_condition = Some(build_condition( + args[counter].to_string(), + args[counter + 2].to_string(), + ConditionOperator::MinorEqual, + )) } else if args[counter + 1].eq("=") { - result.where_condition = Some(build_condition(args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::Equal)) + result.where_condition = Some(build_condition( + args[counter].to_string(), + args[counter + 2].to_string(), + ConditionOperator::Equal, + )) } else if args[counter + 1].eq(">=") { - result.where_condition = Some(build_condition(args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::HigherEqual)) + result.where_condition = Some(build_condition( + args[counter].to_string(), + args[counter + 2].to_string(), + ConditionOperator::HigherEqual, + )) } else if args[counter + 1].eq(">") { - result.where_condition = Some(build_condition(args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::Higher)) + result.where_condition = Some(build_condition( + args[counter].to_string(), + args[counter + 2].to_string(), + ConditionOperator::Higher, + )) } else { - return Err(error::WHERE_MAL_FORMATEADO) + return Err(error::WHERE_MAL_FORMATEADO); } } - if counter < args.len() { + if counter < args.len() { if args[counter].eq("ORDER") && args[counter + 1].eq("BY") { - if counter + 3 == args.len() { // ORDER BY column + if counter + 3 == args.len() { + // ORDER BY column result.order_by = Some((args[counter + 2].to_string(), true)); - } else if counter + 4 == args.len() { // ORDER BY column ASC/DESC + } else if counter + 4 == args.len() { + // ORDER BY column ASC/DESC if args[counter + 3].eq("ASC") || args[counter + 3].eq("DESC") { - result.order_by = Some((args[counter + 2].to_string(), args[counter + 2].eq("ASC"))); + result.order_by = + Some((args[counter + 2].to_string(), args[counter + 2].eq("ASC"))); } else { - return Err(error::ORDER_BY_MAL_FORMATEADO) + return Err(error::ORDER_BY_MAL_FORMATEADO); } } else { - return Err(error::ORDER_BY_MAL_FORMATEADO) + return Err(error::ORDER_BY_MAL_FORMATEADO); } } else { - return Err(error::ORDER_BY_MAL_FORMATEADO) + return Err(error::ORDER_BY_MAL_FORMATEADO); } } - Ok(0) + Ok(0) } } } @@ -205,47 +247,53 @@ fn check_operation_format(args: &Vec) -> Result { } else if operation.eq("UPDATE") { check_update_format(args) } else { - Err(error::OPERACION_INVALIDA) + Err(error::OPERACION_INVALIDA) } } fn check_delete_format(args: &[String]) -> Result { - let non_valid_keywords = vec!["INSERT","INTO","VALUES","SELECT","ORDER","BY","UPDATE","SET"]; - if args[1].eq("FROM") && args[3].eq("WHERE") && check_non_valid_keywords(args, non_valid_keywords) { - Ok(QueryType::DELETE) + let non_valid_keywords = vec![ + "INSERT", "INTO", "VALUES", "SELECT", "ORDER", "BY", "UPDATE", "SET", + ]; + if args[1].eq("FROM") + && args[3].eq("WHERE") + && check_non_valid_keywords(args, non_valid_keywords) + { + Ok(QueryType::DELETE) } else { - Err(error::DELETE_MAL_FORMATEADO) + Err(error::DELETE_MAL_FORMATEADO) } } fn check_insert_format(args: &[String]) -> Result { - let non_valid_keywords = vec!["DELETE","FROM","SELECT","ORDER","BY","UPDATE","SET","WHERE","AND","OR","NOT"]; - if args[1].eq("INTO") && check_non_valid_keywords(args, non_valid_keywords){ - if (args.len() - 4) % 2 != 0 { + let non_valid_keywords = vec![ + "DELETE", "FROM", "SELECT", "ORDER", "BY", "UPDATE", "SET", "WHERE", "AND", "OR", "NOT", + ]; + if args[1].eq("INTO") && check_non_valid_keywords(args, non_valid_keywords) { + if (args.len() - 4) % 2 != 0 { Err(2) - } else{ + } else { let mut counter = 0; - let correct_value_len = (args.len() - 4)/2; // INSERT INTO tabla a b c VALUES x y z. Len = 10. Correct len = 3. - while counter < correct_value_len && ! args[3 + counter].eq("VALUES"){ + let correct_value_len = (args.len() - 4) / 2; // INSERT INTO tabla a b c VALUES x y z. Len = 10. Correct len = 3. + while counter < correct_value_len && !args[3 + counter].eq("VALUES") { counter += 1; - } - + } + if counter == correct_value_len && args[3 + counter].eq("VALUES") { Ok(QueryType::INSERT) - } else{ - Err(error::INSERT_MAL_FORMATEADO) - } + } else { + Err(error::INSERT_MAL_FORMATEADO) + } } - } - else { - Err(error::INSERT_MAL_FORMATEADO) + } else { + Err(error::INSERT_MAL_FORMATEADO) } } fn check_select_format(args: &[String]) -> Result { - let non_valid_keywords = vec!["DELETE","INSERT","INTO","VALUES","UPDATE","SET"]; + let non_valid_keywords = vec!["DELETE", "INSERT", "INTO", "VALUES", "UPDATE", "SET"]; if check_non_valid_keywords(args, non_valid_keywords) { - // TODO format select + // TODO format select Ok(QueryType::SELECT) } else { Err(error::SELECT_MAL_FORMATEADO) @@ -253,15 +301,20 @@ fn check_select_format(args: &[String]) -> Result { } fn check_update_format(args: &[String]) -> Result { - let non_valid_keywords = vec!["DELETE","FROM","INSERT","INTO","SELECT","VALUES","ORDER","BY"]; - if args[2].eq("SET") && args.contains(&"WHERE".to_string()) && check_non_valid_keywords(args, non_valid_keywords) { + let non_valid_keywords = vec![ + "DELETE", "FROM", "INSERT", "INTO", "SELECT", "VALUES", "ORDER", "BY", + ]; + if args[2].eq("SET") + && args.contains(&"WHERE".to_string()) + && check_non_valid_keywords(args, non_valid_keywords) + { Ok(QueryType::UPDATE) - } else{ + } else { Err(error::UPDATE_MAL_FORMATEADO) } } -fn check_non_valid_keywords(args: &[String], non_valid_keywords: Vec<&str>) -> bool { +fn check_non_valid_keywords(args: &[String], non_valid_keywords: Vec<&str>) -> bool { // Checks if args contains any non valid keyword let mut result = true; let mut counter = 0; @@ -277,63 +330,57 @@ fn check_non_valid_keywords(args: &[String], non_valid_keywords: Vec<&str>) -> result } -fn validate_query(query: Query) -> Result { - // Pre: Sintactical query OK +fn validate_query(query: Query) -> Result { + // Pre: Sintactical query OK // Post: Valid query for execution match &query.table { Some(table) => match File::open(table) { - Ok(_) => {}, - Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + Ok(_) => {} + Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO), }, - None => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + None => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO), } match &query.operation { - Some(op) => { - match op { - QueryType::DELETE => validate_delete_query(query), - QueryType::INSERT => validate_insert_query(query), - QueryType::SELECT => validate_select_query(query), - QueryType::UPDATE => validate_update_query(query), - } + Some(op) => match op { + QueryType::DELETE => validate_delete_query(query), + QueryType::INSERT => validate_insert_query(query), + QueryType::SELECT => validate_select_query(query), + QueryType::UPDATE => validate_update_query(query), }, - None => Err(error::OPERACION_INVALIDA) + None => Err(error::OPERACION_INVALIDA), } } -fn validate_delete_query(query: Query) -> Result { +fn validate_delete_query(query: Query) -> Result { if query.columns.is_none() && query.values.is_none() && query.where_condition.is_some() { match &query.table { - Some(table) => { - match File::open(table) { - Ok(file) => { - match get_columns(file) { - Some(columns) => check_columns_contains_condition(columns,query), - None => Err(error::ARCHIVO_VACIO) - } - }, - Err(_) => Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) - } + Some(table) => match File::open(table) { + Ok(file) => match get_columns(file) { + Some(columns) => check_columns_contains_condition(columns, query), + None => Err(error::ARCHIVO_VACIO), + }, + Err(_) => Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO), }, - None => Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + None => Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO), } } else { Err(error::DELETE_MAL_FORMATEADO) } } -fn validate_insert_query(query: Query) -> Result { +fn validate_insert_query(query: Query) -> Result { // TODO Ok(query) } -fn validate_select_query(query: Query) -> Result { - // TODO +fn validate_select_query(query: Query) -> Result { + // TODO Ok(query) } -fn validate_update_query(query: Query) -> Result { - // TODO +fn validate_update_query(query: Query) -> Result { + // TODO Ok(query) } @@ -348,46 +395,44 @@ fn get_columns(file: File) -> Option> { while element_opt.is_some() { match element_opt { Some(x) => result.push(x.to_string()), - None => continue + None => continue, } element_opt = split.next(); } - + Some(result) - }, - Err(_) => None + } + Err(_) => None, } } -fn check_columns_contains_condition(columns: Vec, query: Query) -> Result { - // TODO +fn check_columns_contains_condition(columns: Vec, query: Query) -> Result { + // TODO match get_where_columns(&query) { Some(column) => { if columns.contains(&column) { - Ok(query) + Ok(query) } else { Err(error::ARCHIVO_NO_CONTIENE_COLUMNAS_SOLICITADAS) } - }, - None => Err(error::NO_WHERE) + } + None => Err(error::NO_WHERE), } -} +} fn get_where_columns(query: &Query) -> Option { match &query.where_condition { - Some(cond) => { - match &cond.column { - Some(col) => Some(col.to_string()), - None => None - } + Some(cond) => match &cond.column { + Some(col) => Some(col.to_string()), + None => None, }, - None => None + None => None, } } fn text_to_vec(text_query: &String) -> Vec { // Text to vector. Tokenization by space, new line & coma - let mut tmp_text_query = text_query.to_string(); + let mut tmp_text_query = text_query.to_string(); tmp_text_query = tmp_text_query.replace('\n', " "); tmp_text_query = tmp_text_query.replace(',', ""); tmp_text_query = tmp_text_query.replace(';', ""); @@ -399,8 +444,8 @@ fn text_to_vec(text_query: &String) -> Vec { match element_opt { Some(x) => { result.push(x.to_string()); - }, - None => continue + } + None => continue, } element_opt = split.next(); @@ -408,32 +453,30 @@ fn text_to_vec(text_query: &String) -> Vec { result } -fn vec_to_query(args: &Vec, path: &String) -> Result{ - // Vec to non validated query - let mut result: Query = build_empty_query(); - match check_operation_format(args) { - Ok(x) => { - match &x { - QueryType::DELETE => match separate_args_delete(args, path, &mut result){ - Ok(_) => result.operation = Some(x), - Err(x) => return Err(x) - }, - QueryType::INSERT => match separate_args_insert(args, path, &mut result) { - Ok(_) => result.operation = Some(x), - Err(x) => return Err(x) - }, - QueryType::SELECT => match separate_args_select(args, path, &mut result) { - Ok(_) => result.operation = Some(x), - Err(x) => return Err(x) - }, - QueryType::UPDATE => match separate_args_update(args, path, &mut result) { - Ok(_) => result.operation = Some(x), - Err(x) => return Err(x) - } - } +fn vec_to_query(args: &Vec, path: &String) -> Result { + // Vec to non validated query + let mut result: Query = build_empty_query(); + match check_operation_format(args) { + Ok(x) => match &x { + QueryType::DELETE => match separate_args_delete(args, path, &mut result) { + Ok(_) => result.operation = Some(x), + Err(x) => return Err(x), + }, + QueryType::INSERT => match separate_args_insert(args, path, &mut result) { + Ok(_) => result.operation = Some(x), + Err(x) => return Err(x), + }, + QueryType::SELECT => match separate_args_select(args, path, &mut result) { + Ok(_) => result.operation = Some(x), + Err(x) => return Err(x), + }, + QueryType::UPDATE => match separate_args_update(args, path, &mut result) { + Ok(_) => result.operation = Some(x), + Err(x) => return Err(x), + }, }, - Err(x) => return Err(x) - } + Err(x) => return Err(x), + } Ok(result) } @@ -449,34 +492,47 @@ pub fn get_file_first_line(query: &Query) -> Option { Ok(_) => { line = line.replace('\n', ""); Some(line) - }, - Err(_) => None + } + Err(_) => None, } - }, - Err(_) => None + } + Err(_) => None, }, - None => None + None => None, } } - #[cfg(test)] mod tests { use super::*; - #[test] - fn test_text_to_vec1(){ + #[test] + fn test_text_to_vec1() { let rt1 = text_to_vec(&String::from("SELECT * FROM table")); - assert_eq!(rt1, vec!["SELECT","*","FROM","table"]); + assert_eq!(rt1, vec!["SELECT", "*", "FROM", "table"]); } - #[test] - fn test_text_to_vec2(){ - let rt2 = text_to_vec(&String::from("SELECT id, producto, id_cliente\nFROM ordenes\nWHERE cantidad > 1")); - assert_eq!(rt2, vec!["SELECT","id","producto","id_cliente","FROM","ordenes","WHERE","cantidad",">","1"]); + #[test] + fn test_text_to_vec2() { + let rt2 = text_to_vec(&String::from( + "SELECT id, producto, id_cliente\nFROM ordenes\nWHERE cantidad > 1", + )); + assert_eq!( + rt2, + vec![ + "SELECT", + "id", + "producto", + "id_cliente", + "FROM", + "ordenes", + "WHERE", + "cantidad", + ">", + "1" + ] + ); } - - } /* @@ -498,7 +554,7 @@ fn check_where_format(args: &Vec, start_position: usize) -> bool { } } else if args[counter].eq("AND") || args[counter].eq("OR") { if op_detected { - result = false; // AND OR , OR AND, OR OR, AND AND. Que estas haciendo ? + result = false; // AND OR , OR AND, OR OR, AND AND. Que estas haciendo ? } else { op_detected = true; counter += 1; @@ -514,26 +570,26 @@ fn check_where_format(args: &Vec, start_position: usize) -> bool { } fn check_table_exist(path: &String, args: &Vec, operation: &QueryType) -> Result{ - // Asume query bien formateado + // Asume query bien formateado let mut table= String::from(path); table.push('/'); match &operation { QueryType::DELETE => table.push_str(&args[2]), QueryType::INSERT => table.push_str(&args[2]), - QueryType::SELECT => { - // Debo encontrar cual es la tabla (asumiendo query bien formateado) + QueryType::SELECT => { + // Debo encontrar cual es la tabla (asumiendo query bien formateado) let mut counter = 2; - while ! args[counter].eq("FROM"){ + while ! args[counter].eq("FROM"){ counter += 1; } table.push_str(&args[counter + 1]) }, QueryType::UPDATE => table.push_str(&args[1]), } - + match File::open(&table) { // TODO: Path::exist()? - Ok(_) => return Ok(table), - Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) + Ok(_) => return Ok(table), + Err(_) => return Err(error::ARCHIVO_NO_PUDO_SER_ABIERTO) } } -*/ \ No newline at end of file +*/ diff --git a/src/main.rs b/src/main.rs index 6b8e678..97d3f98 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ pub mod condition; -pub mod query; pub mod libs; +pub mod query; use libs::error::print_err; use libs::exec::exec_query; @@ -11,11 +11,11 @@ fn main() { if args.len() < 3 { println!("Uso: cargo run -- ruta/a/tablas \"query\""); } else { - let path: &String = &args[1]; - let text_query: &String = &args[2]; - match build_query(text_query, path) { - Ok(x) => exec_query(x), - Err(x) => print_err(x) + let path: &String = &args[1]; + let text_query: &String = &args[2]; + match build_query(text_query, path) { + Ok(x) => exec_query(x), + Err(x) => print_err(x), } } } diff --git a/src/query.rs b/src/query.rs index 6135fc3..e15545f 100644 --- a/src/query.rs +++ b/src/query.rs @@ -6,28 +6,27 @@ use crate::condition::Condition; // use crate::condition::ComplexCondition; -pub static DELETE_MIN_LEN :usize = 7; // DELETE FROM tabla WHERE a < b -pub static INSERT_MIN_LEN :usize = 6; // INSERT INTO tabla col VALUES val -pub static SELECT_MIN_LEN :usize = 4; // SELECT * FROM tabla -pub static UPDATE_MIN_LEN :usize = 10; // UPDATE tabla SET col = valor WHERE a < b - +pub static DELETE_MIN_LEN: usize = 7; // DELETE FROM tabla WHERE a < b +pub static INSERT_MIN_LEN: usize = 6; // INSERT INTO tabla col VALUES val +pub static SELECT_MIN_LEN: usize = 4; // SELECT * FROM tabla +pub static UPDATE_MIN_LEN: usize = 10; // UPDATE tabla SET col = valor WHERE a < b pub struct Query { - pub operation: Option, // DELETE, INSERT, SELECT, UPDATE - pub table: Option, // DELETE, INSERT, SELECT, UPDATE - pub columns: Option>, // INSERT, SELECT, UPDATE - pub where_condition: Option, // DELETE (always), SELECT (sometimes), UPDATE (always) . - pub order_by: Option<(String,bool)>, // SELECT (sometimes) - pub values: Option> // INSERT, UPDATE (in update is set) + pub operation: Option, // DELETE, INSERT, SELECT, UPDATE + pub table: Option, // DELETE, INSERT, SELECT, UPDATE + pub columns: Option>, // INSERT, SELECT, UPDATE + pub where_condition: Option, // DELETE (always), SELECT (sometimes), UPDATE (always) . + pub order_by: Option<(String, bool)>, // SELECT (sometimes) + pub values: Option>, // INSERT, UPDATE (in update is set) } pub fn build_empty_query() -> Query { Query { - operation: None, - table: None, - columns: None, - where_condition: None, - order_by: None, - values: None, + operation: None, + table: None, + columns: None, + where_condition: None, + order_by: None, + values: None, } } diff --git a/src/query/query_type.rs b/src/query/query_type.rs index ffd21e2..8cfa19b 100644 --- a/src/query/query_type.rs +++ b/src/query/query_type.rs @@ -3,16 +3,16 @@ pub enum QueryType { DELETE, INSERT, SELECT, - UPDATE + UPDATE, } impl std::fmt::Display for QueryType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - QueryType::DELETE => write!(f,"DELETE"), - QueryType::INSERT => write!(f,"INSERT"), - QueryType::SELECT => write!(f,"SELECT"), - QueryType::UPDATE => write!(f,"UPDATE"), + QueryType::DELETE => write!(f, "DELETE"), + QueryType::INSERT => write!(f, "INSERT"), + QueryType::SELECT => write!(f, "SELECT"), + QueryType::UPDATE => write!(f, "UPDATE"), } } -} \ No newline at end of file +} From f8d4b7e7a016edbd502d9c40b70157ca6bab89a5 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Mon, 9 Sep 2024 17:46:44 -0300 Subject: [PATCH 21/23] WIP select WHERE --- src/condition.rs | 28 +++++++++++++++++++--------- src/libs/exec.rs | 26 +++++++++++++++++++------- 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/src/condition.rs b/src/condition.rs index d667cf3..9b4be76 100644 --- a/src/condition.rs +++ b/src/condition.rs @@ -22,15 +22,25 @@ pub fn build_condition(column: String, value: String, cond: ConditionOperator) - } } -/* -pub fn operate_condition(filter: (&u32,&ConditionOperator,&String), elements: &Vec) -> bool { - let (column, operator, value) = filter; +pub fn operate_condition(v1: &String, v2: &String, operator: &ConditionOperator ) -> bool { + if let Ok(x1) = v1.parse::() { + if let Ok(x2) = v2.parse::() { + match operator { + ConditionOperator::Minor => return x1 < x2, + ConditionOperator::MinorEqual => return x1 <= x2, + ConditionOperator::Equal => return x1 == x2, + ConditionOperator::Higher => return x1 > x2, + ConditionOperator::HigherEqual => return x1 >= x2, + } + }; + }; + match operator { - ConditionOperator::Minor => {}, - ConditionOperator::MinorEqual => {}, - ConditionOperator::Equal => {}, - ConditionOperator::Higher => {}, - ConditionOperator::HigherEqual => {}, + ConditionOperator::Minor => true, + ConditionOperator::MinorEqual => true, + ConditionOperator::Equal => v1.eq(v2), + ConditionOperator::Higher => true, + ConditionOperator::HigherEqual => true, } } -*/ + diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 47970ef..aa2afbe 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -1,6 +1,7 @@ use std::fs::{File, OpenOptions}; use std::io::{BufRead, BufReader, Write}; +use crate::condition::{self, operate_condition, Condition}; //use crate::condition::operate_condition; use crate::query::query_type::QueryType; use crate::query::Query; @@ -168,7 +169,7 @@ fn read_and_print_file(query: &Query, col_filter: i32, columns: &[usize]) { if read { let elements = line_to_vec(&line); match &query.where_condition { - Some(condition) => {} + Some(condition) => print_file_conditioned(columns, (col_filter, condition), &elements), None => print_file_unconditional(columns, &elements), } line.clear(); @@ -188,24 +189,24 @@ fn print_file_unconditional(columns: &[usize], elements: &[String]) { // Pre: Columns vector sorted incremental && Elements of line content vector // Post: print to stdout the correct columns - if columns.is_empty() { + if columns.is_empty() { // SELECT * FROM for (counter, element) in elements.iter().enumerate() { print!("{}", element); - if counter < elements.len() - 1 { + if counter < columns.len() - 1 { print!(","); } } - } else { + } else { // SELECT columns FROM let mut counter = 0; - let mut found_count = 0; + let mut first = true; while counter < elements.len() { if columns.contains(&counter) { - if found_count == 0 { + if first { print!("{}", elements[counter]); + first = false; } else { print!(",{}", elements[counter]); } - found_count += 1; } counter += 1; @@ -214,6 +215,17 @@ fn print_file_unconditional(columns: &[usize], elements: &[String]) { println!(); } +fn print_file_conditioned(columns: &[usize], filter: (i32, &Condition), elements: &[String]) { + let (col_filter,condition) = filter; + if let Some(value) = &condition.value { + if operate_condition(value, &elements[col_filter as usize], &condition.condition) { + print_file_unconditional(columns, elements) + } + } else { + print_file_unconditional(columns, elements) + } +} + fn line_to_vec(line: &str) -> Vec { let mut result: Vec = Vec::new(); let mut split = line.split(','); From ee7f6f9a799750cc22e6ad821a892493c76c5b26 Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Mon, 9 Sep 2024 17:55:37 -0300 Subject: [PATCH 22/23] gdb OK SELECT * FROM --- src/libs/exec.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/libs/exec.rs b/src/libs/exec.rs index aa2afbe..8324954 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -189,16 +189,18 @@ fn print_file_unconditional(columns: &[usize], elements: &[String]) { // Pre: Columns vector sorted incremental && Elements of line content vector // Post: print to stdout the correct columns + let mut first = true; if columns.is_empty() { // SELECT * FROM for (counter, element) in elements.iter().enumerate() { - print!("{}", element); - if counter < columns.len() - 1 { - print!(","); + if first { + print!("{}", element); + first = false; + } else { + print!(",{}", element); } } } else { // SELECT columns FROM let mut counter = 0; - let mut first = true; while counter < elements.len() { if columns.contains(&counter) { if first { From 79e92e02290b02b39568bcb09872e178d7c49afd Mon Sep 17 00:00:00 2001 From: sttesta3 Date: Mon, 9 Sep 2024 18:05:09 -0300 Subject: [PATCH 23/23] SELECT c/ WHERE --- README.md | 16 ++++++++-------- src/libs/exec.rs | 2 +- src/libs/parsing.rs | 15 ++++++++++----- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index b04eb63..636d2c7 100644 --- a/README.md +++ b/README.md @@ -12,17 +12,15 @@ Pendientes: 2. Funcionalidad: SELECT c/ ORDER BY -3. Funcionalidad: SELECT c/ WHERE +3. Funcionalidad: DELETE -4. Funcionalidad: DELETE +4. Funcionalidad: UPDATE -5. Funcionalidad: UPDATE +5. Testing (mas test unitarios e integración) -6. Testing (mas test unitarios e integración) +6. Cargo clippy sin warnings -7. Cargo clippy sin warnings - -8. Documentación de funciones +7. Documentación de funciones Funcionalidades probadas OK @@ -30,7 +28,9 @@ Funcionalidades probadas OK 2. SELECT columnas FROM -3. INSERT INTO +3. SELECT c/ WHERE + +4. INSERT INTO ### Detalles de implementación diff --git a/src/libs/exec.rs b/src/libs/exec.rs index 8324954..6d382f4 100644 --- a/src/libs/exec.rs +++ b/src/libs/exec.rs @@ -220,7 +220,7 @@ fn print_file_unconditional(columns: &[usize], elements: &[String]) { fn print_file_conditioned(columns: &[usize], filter: (i32, &Condition), elements: &[String]) { let (col_filter,condition) = filter; if let Some(value) = &condition.value { - if operate_condition(value, &elements[col_filter as usize], &condition.condition) { + if operate_condition(&elements[col_filter as usize], value, &condition.condition) { print_file_unconditional(columns, elements) } } else { diff --git a/src/libs/parsing.rs b/src/libs/parsing.rs index 5c9aa02..df35d39 100644 --- a/src/libs/parsing.rs +++ b/src/libs/parsing.rs @@ -180,31 +180,36 @@ fn separate_args_select(args: &[String], path: &String, result: &mut Query) -> R args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::Minor, - )) + )); + counter += 3; } else if args[counter + 1].eq("<=") { result.where_condition = Some(build_condition( args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::MinorEqual, - )) + )); + counter += 3; } else if args[counter + 1].eq("=") { result.where_condition = Some(build_condition( args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::Equal, - )) + )); + counter += 3; } else if args[counter + 1].eq(">=") { result.where_condition = Some(build_condition( args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::HigherEqual, - )) + )); + counter += 3; } else if args[counter + 1].eq(">") { result.where_condition = Some(build_condition( args[counter].to_string(), args[counter + 2].to_string(), ConditionOperator::Higher, - )) + )); + counter += 3; } else { return Err(error::WHERE_MAL_FORMATEADO); }