From 25b26acde09420a9fff575185a234385e3165d46 Mon Sep 17 00:00:00 2001 From: Yuriy Dupyn <2153100+omedusyo@users.noreply.github.com> Date: Fri, 29 Dec 2023 07:58:35 +0100 Subject: [PATCH] format & clippy --- minisql/src/error.rs | 6 +- minisql/src/internals/column_index.rs | 20 +- minisql/src/internals/mod.rs | 4 +- minisql/src/internals/row.rs | 13 +- minisql/src/internals/schema.rs | 111 +++++--- minisql/src/internals/table.rs | 154 +++++++---- minisql/src/interpreter.rs | 375 +++++++++++++++++--------- minisql/src/main.rs | 8 +- minisql/src/operation.rs | 3 +- minisql/src/type_system.rs | 21 +- 10 files changed, 444 insertions(+), 271 deletions(-) diff --git a/minisql/src/error.rs b/minisql/src/error.rs index be6bfd8..51ca0cf 100644 --- a/minisql/src/error.rs +++ b/minisql/src/error.rs @@ -1,7 +1,7 @@ -use crate::internals::schema::{ColumnName, TableName}; use crate::internals::row::ColumnPosition; -use crate::type_system::{DbType, Value, UUID}; +use crate::internals::schema::{ColumnName, TableName}; use crate::operation::InsertionValues; +use crate::type_system::{DbType, Uuid, Value}; #[derive(Debug)] pub enum Error { @@ -9,7 +9,7 @@ pub enum Error { ColumnDoesNotExist(TableName, ColumnName), ColumnPositionDoesNotExist(TableName, ColumnPosition), ValueDoesNotMatchExpectedType(TableName, ColumnName, DbType, Value), - AttemptingToInsertAlreadyPresentId(TableName, UUID), + AttemptingToInsertAlreadyPresentId(TableName, Uuid), MissingTypeAnnotationOfColumn(TableName, ColumnPosition), MissingColumnInInsertValues(TableName, ColumnName, InsertionValues), MismatchBetweenInsertValuesAndColumns(TableName, InsertionValues), diff --git a/minisql/src/internals/column_index.rs b/minisql/src/internals/column_index.rs index f02e8ce..d69f615 100644 --- a/minisql/src/internals/column_index.rs +++ b/minisql/src/internals/column_index.rs @@ -1,9 +1,9 @@ +use crate::type_system::{IndexableValue, Uuid}; use std::collections::{BTreeMap, HashSet}; -use crate::type_system::{UUID, IndexableValue}; #[derive(Debug)] pub struct ColumnIndex { - index: BTreeMap> + index: BTreeMap>, } impl ColumnIndex { @@ -12,34 +12,30 @@ impl ColumnIndex { Self { index } } - pub fn get(&self, value: &IndexableValue) -> HashSet { + pub fn get(&self, value: &IndexableValue) -> HashSet { match self.index.get(value) { Some(set) => set.clone(), None => HashSet::new(), } } - pub fn add(&mut self, value: IndexableValue, id: UUID) { + pub fn add(&mut self, value: IndexableValue, id: Uuid) { match self.index.get_mut(&value) { Some(ids) => { ids.insert(id); - }, + } None => { self.index.insert(value, HashSet::from([id])); } } } - pub fn remove(&mut self, value: &IndexableValue, id_to_be_removed: UUID) -> bool { + pub fn remove(&mut self, value: &IndexableValue, id_to_be_removed: Uuid) -> bool { match self.index.get_mut(value) { Some(ids) => { - let was_present = ids.remove(&id_to_be_removed); - was_present - }, - None => { - false + ids.remove(&id_to_be_removed) // true iff was present } + None => false, } } } - diff --git a/minisql/src/internals/mod.rs b/minisql/src/internals/mod.rs index 0817ee8..864d9d7 100644 --- a/minisql/src/internals/mod.rs +++ b/minisql/src/internals/mod.rs @@ -1,4 +1,4 @@ -pub mod table; -pub mod row; pub mod column_index; +pub mod row; pub mod schema; +pub mod table; diff --git a/minisql/src/internals/row.rs b/minisql/src/internals/row.rs index 430a26f..ad8dc1e 100644 --- a/minisql/src/internals/row.rs +++ b/minisql/src/internals/row.rs @@ -1,6 +1,6 @@ -use std::slice::SliceIndex; -use std::ops::{Index, IndexMut}; use crate::type_system::Value; +use std::ops::{Index, IndexMut}; +use std::slice::SliceIndex; pub type ColumnPosition = usize; @@ -28,7 +28,7 @@ where } impl FromIterator for Row { - fn from_iter>(iter: I) -> Self { + fn from_iter>(iter: I) -> Self { let mut v = vec![]; for x in iter { v.push(x) @@ -62,11 +62,8 @@ impl Row { // If the index from `columns` is non-existant in `row`, it will just ignore it. let mut subrow: Row = Row::new(); for column_position in columns { - match self.get(*column_position) { - Some(value) => { - subrow.0.push(value.clone()) - }, - None => {} + if let Some(value) = self.get(*column_position) { + subrow.0.push(value.clone()) } } subrow diff --git a/minisql/src/internals/schema.rs b/minisql/src/internals/schema.rs index afda2c3..d174215 100644 --- a/minisql/src/internals/schema.rs +++ b/minisql/src/internals/schema.rs @@ -1,10 +1,10 @@ -use std::collections::HashMap; -use bimap::BiMap; -use crate::result::DbResult; -use crate::operation::{InsertionValues, ColumnSelection}; -use crate::internals::row::{Row, ColumnPosition}; -use crate::type_system::{DbType, Value, IndexableValue, UUID}; use crate::error::Error; +use crate::internals::row::{ColumnPosition, Row}; +use crate::operation::{ColumnSelection, InsertionValues}; +use crate::result::DbResult; +use crate::type_system::{DbType, IndexableValue, Uuid, Value}; +use bimap::BiMap; +use std::collections::HashMap; // Note that it is nice to split metadata from the data because // then you can give the metadata to the parser without giving it the data. @@ -22,29 +22,36 @@ pub type ColumnName = String; impl TableSchema { fn get_column(&self, column_name: &ColumnName) -> DbResult<(DbType, ColumnPosition)> { match self.column_name_position_mapping.get_by_left(column_name) { - Some(column_position) => { - match self.types.get(*column_position) { - Some(type_) => { - Ok((*type_, *column_position)) - }, - None => { - Err(Error::MissingTypeAnnotationOfColumn(self.table_name.clone(), *column_position)) - } - } + Some(column_position) => match self.types.get(*column_position) { + Some(type_) => Ok((*type_, *column_position)), + None => Err(Error::MissingTypeAnnotationOfColumn( + self.table_name.clone(), + *column_position, + )), }, - None => Err(Error::ColumnDoesNotExist(self.table_name.clone(), column_name.clone())) + None => Err(Error::ColumnDoesNotExist( + self.table_name.clone(), + column_name.clone(), + )), } } - pub fn column_position_from_column_name(&self, column_name: &ColumnName) -> DbResult { - self.get_column(column_name).map(|(_, column_position)| column_position) + pub fn column_position_from_column_name( + &self, + column_name: &ColumnName, + ) -> DbResult { + self.get_column(column_name) + .map(|(_, column_position)| column_position) } pub fn is_primary(&self, column_position: ColumnPosition) -> bool { self.primary_key == column_position } - fn column_positions_from_column_names(&self, column_names: &[ColumnName]) -> DbResult> { + fn column_positions_from_column_names( + &self, + column_names: &[ColumnName], + ) -> DbResult> { let mut positions: Vec = Vec::with_capacity(column_names.len()); for column_name in column_names { let column_position = self.column_position_from_column_name(column_name)?; @@ -53,24 +60,40 @@ impl TableSchema { Ok(positions) } - pub fn column_name_from_column_position(&self, column_position: ColumnPosition) -> DbResult { - match self.column_name_position_mapping.get_by_right(&column_position) { + pub fn column_name_from_column_position( + &self, + column_position: ColumnPosition, + ) -> DbResult { + match self + .column_name_position_mapping + .get_by_right(&column_position) + { Some(column_name) => Ok(column_name.clone()), - None => Err(Error::ColumnPositionDoesNotExist(self.table_name.clone(), column_position)) + None => Err(Error::ColumnPositionDoesNotExist( + self.table_name.clone(), + column_position, + )), } } - pub fn column_positions_from_column_selection(&self, column_selection: &ColumnSelection) -> DbResult> { + pub fn column_positions_from_column_selection( + &self, + column_selection: &ColumnSelection, + ) -> DbResult> { match column_selection { ColumnSelection::All => { - let mut column_positions: Vec = self.column_name_position_mapping.iter().map(|(_, column_position)| *column_position).collect(); + let mut column_positions: Vec = self + .column_name_position_mapping + .iter() + .map(|(_, column_position)| *column_position) + .collect(); column_positions.sort(); Ok(column_positions) - }, + } ColumnSelection::Columns(column_names) => { self.column_positions_from_column_names(column_names) - }, + } } } @@ -78,7 +101,10 @@ impl TableSchema { self.column_name_position_mapping.len() } - pub fn row_from_insertion_values(&self, insertion_values: InsertionValues) -> DbResult<(UUID, Row)> { + pub fn row_from_insertion_values( + &self, + insertion_values: InsertionValues, + ) -> DbResult<(Uuid, Row)> { // TODO: There should be proper validation of the insertion_values. // And it shouldn't really be done here. // @@ -86,7 +112,10 @@ impl TableSchema { // let number_of_columns = self.number_of_columns(); if number_of_columns != insertion_values.len() { - return Err(Error::MismatchBetweenInsertValuesAndColumns(self.table_name.clone(), insertion_values)) + return Err(Error::MismatchBetweenInsertValuesAndColumns( + self.table_name.clone(), + insertion_values, + )); } let mut row: Row = Row::with_number_of_columns(number_of_columns); @@ -99,27 +128,21 @@ impl TableSchema { for column_position in 0..number_of_columns { let column_name: ColumnName = self.column_name_from_column_position(column_position)?; match values.get(&column_name) { - Some(db_value) => { - row.push(db_value.clone()) - }, + Some(db_value) => row.push(db_value.clone()), None => { - return Err(Error::MissingColumnInInsertValues(self.table_name.clone(), column_name, insertion_values)) + return Err(Error::MissingColumnInInsertValues( + self.table_name.clone(), + column_name, + insertion_values, + )) } } } - let id: UUID = match row.get(self.primary_key) { - Some(val) => { - match val { - Value::Indexable(IndexableValue::UUID(id)) => { - *id - }, - _ => - unreachable!() - } - }, - None => - unreachable!() + let id: Uuid = match row.get(self.primary_key) { + Some(Value::Indexable(IndexableValue::Uuid(id))) => *id, + Some(_) => unreachable!(), + None => unreachable!(), }; Ok((id, row)) diff --git a/minisql/src/internals/table.rs b/minisql/src/internals/table.rs index f2e4ab6..9cf0cac 100644 --- a/minisql/src/internals/table.rs +++ b/minisql/src/internals/table.rs @@ -1,25 +1,21 @@ use std::collections::{BTreeMap, HashMap, HashSet}; -use crate::result::DbResult; -use crate::type_system::{UUID, Value, IndexableValue}; use crate::error::Error; -use crate::internals::schema::{TableSchema, ColumnName}; -use crate::internals::row::{Row, ColumnPosition}; use crate::internals::column_index::ColumnIndex; - +use crate::internals::row::{ColumnPosition, Row}; +use crate::internals::schema::{ColumnName, TableSchema}; +use crate::result::DbResult; +use crate::type_system::{IndexableValue, Uuid, Value}; #[derive(Debug)] pub struct Table { pub schema: TableSchema, pub rows: Rows, // TODO: Consider wrapping this in a lock. Also consider if we need to have the - // same lock for both rows and indexes - pub indexes: - HashMap + // same lock for both rows and indexes + pub indexes: HashMap, } -pub type Rows = - BTreeMap; - +pub type Rows = BTreeMap; impl Table { pub fn new(table_schema: TableSchema) -> Self { @@ -31,11 +27,11 @@ impl Table { } // ======Selection====== - fn get_row_by_id(&self, id: UUID) -> Option { + fn get_row_by_id(&self, id: Uuid) -> Option { self.rows.get(&id).cloned() } - fn get_rows_by_ids(&self, ids: HashSet) -> Vec { + fn get_rows_by_ids(&self, ids: HashSet) -> Vec { ids.into_iter() .filter_map(|id| self.get_row_by_id(id)) .collect() @@ -43,44 +39,71 @@ impl Table { fn get_rows_by_value(&self, column_position: ColumnPosition, value: &Value) -> Vec { // brute-force search - self.rows.values() - .filter_map(|row| if row.get(column_position) == Some(value) { Some(row.clone()) } else { None }) + self.rows + .values() + .filter_map(|row| { + if row.get(column_position) == Some(value) { + Some(row.clone()) + } else { + None + } + }) .collect() } pub fn select_all_rows(&self, selected_column_positions: &Vec) -> Vec { - self.rows.values().map(|row| row.restrict_columns(&selected_column_positions)).collect() + self.rows + .values() + .map(|row| row.restrict_columns(selected_column_positions)) + .collect() } - pub fn select_rows_where_eq(&self, selected_column_positions: &Vec, column_position: ColumnPosition, value: Value) -> DbResult> { + pub fn select_rows_where_eq( + &self, + selected_column_positions: &Vec, + column_position: ColumnPosition, + value: Value, + ) -> DbResult> { match value { - Value::Indexable(value) => { - match self.fetch_ids_from_index(column_position, &value)? { - Some(ids) => - Ok(self.get_rows_by_ids(ids).iter().map(|row| row.restrict_columns(&selected_column_positions)).collect()), - None => - Ok(self.get_rows_by_value(column_position, &Value::Indexable(value)).iter().map(|row| row.restrict_columns(&selected_column_positions)).collect()) - } + Value::Indexable(value) => match self.fetch_ids_from_index(column_position, &value)? { + Some(ids) => Ok(self + .get_rows_by_ids(ids) + .iter() + .map(|row| row.restrict_columns(selected_column_positions)) + .collect()), + None => Ok(self + .get_rows_by_value(column_position, &Value::Indexable(value)) + .iter() + .map(|row| row.restrict_columns(selected_column_positions)) + .collect()), }, - _ => { - Ok(self.get_rows_by_value(column_position, &value).iter().map(|row| row.restrict_columns(&selected_column_positions)).collect()) - } + _ => Ok(self + .get_rows_by_value(column_position, &value) + .iter() + .map(|row| row.restrict_columns(selected_column_positions)) + .collect()), } } // ======Insertion====== - pub fn insert_row_at(&mut self, id: UUID, row: Row) -> DbResult<()> { + pub fn insert_row_at(&mut self, id: Uuid, row: Row) -> DbResult<()> { if self.rows.get(&id).is_some() { - return Err(Error::AttemptingToInsertAlreadyPresentId(self.schema.table_name.clone(), id)) + return Err(Error::AttemptingToInsertAlreadyPresentId( + self.schema.table_name.clone(), + id, + )); } for (column_position, column_index) in &mut self.indexes { match row.get(*column_position) { - Some(Value::Indexable(val)) => { - column_index.add(val.clone(), id) - }, - Some(_) => {}, - None => return Err(Error::ColumnPositionDoesNotExist(self.schema.table_name.clone(), *column_position)) + Some(Value::Indexable(val)) => column_index.add(val.clone(), id), + Some(_) => {} + None => { + return Err(Error::ColumnPositionDoesNotExist( + self.schema.table_name.clone(), + *column_position, + )) + } } } @@ -89,7 +112,7 @@ impl Table { } // ======Deletion====== - fn delete_row_by_id(&mut self, id: UUID) -> usize { + fn delete_row_by_id(&mut self, id: Uuid) -> usize { match self.rows.remove(&id) { Some(row) => { for (column_position, column_index) in &mut self.indexes { @@ -98,12 +121,12 @@ impl Table { }; } 1 - }, - None => 0 + } + None => 0, } } - fn delete_rows_by_ids(&mut self, ids: HashSet) -> usize { + fn delete_rows_by_ids(&mut self, ids: HashSet) -> usize { let mut total_count = 0; for id in ids { total_count += self.delete_row_by_id(id) @@ -112,8 +135,16 @@ impl Table { } fn delete_rows_by_value(&mut self, column_position: ColumnPosition, value: &Value) -> usize { - let matched_ids: HashSet = self.rows.iter() - .filter_map(|(id, row)| if row.get(column_position) == Some(value) { Some(*id) } else { None }) + let matched_ids: HashSet = self + .rows + .iter() + .filter_map(|(id, row)| { + if row.get(column_position) == Some(value) { + Some(*id) + } else { + None + } + }) .collect(); self.delete_rows_by_ids(matched_ids) } @@ -125,18 +156,17 @@ impl Table { number_of_rows } - pub fn delete_rows_where_eq(&mut self, column_position: ColumnPosition, value: Value) -> DbResult { + pub fn delete_rows_where_eq( + &mut self, + column_position: ColumnPosition, + value: Value, + ) -> DbResult { match value { - Value::Indexable(value) => { - match self.fetch_ids_from_index(column_position, &value)? { - Some(ids) => - Ok(self.delete_rows_by_ids(ids)), - None => - Ok(self.delete_rows_by_value(column_position, &Value::Indexable(value))) - } + Value::Indexable(value) => match self.fetch_ids_from_index(column_position, &value)? { + Some(ids) => Ok(self.delete_rows_by_ids(ids)), + None => Ok(self.delete_rows_by_value(column_position, &Value::Indexable(value))), }, - _ => - Ok(self.delete_rows_by_value(column_position, &value)) + _ => Ok(self.delete_rows_by_value(column_position, &value)), } } @@ -145,15 +175,25 @@ impl Table { self.indexes.insert(column_position, column_index); } - fn fetch_ids_from_index(&self, column_position: ColumnPosition, value: &IndexableValue) -> DbResult>> { + fn fetch_ids_from_index( + &self, + column_position: ColumnPosition, + value: &IndexableValue, + ) -> DbResult>> { if self.schema.is_primary(column_position) { match value { - IndexableValue::UUID(id) => - Ok(Some(HashSet::from([*id]))), + IndexableValue::Uuid(id) => Ok(Some(HashSet::from([*id]))), _ => { - let column_name: ColumnName = self.schema.column_name_from_column_position(column_position)?; + let column_name: ColumnName = self + .schema + .column_name_from_column_position(column_position)?; let type_ = self.schema.types[column_position]; - Err(Error::ValueDoesNotMatchExpectedType(self.schema.table_name.clone(), column_name, type_, Value::Indexable(value.clone()))) + Err(Error::ValueDoesNotMatchExpectedType( + self.schema.table_name.clone(), + column_name, + type_, + Value::Indexable(value.clone()), + )) } } } else { @@ -161,10 +201,8 @@ impl Table { Some(index) => { let ids = index.get(value); Ok(Some(ids)) - }, - None => { - Ok(None) } + None => Ok(None), } } } diff --git a/minisql/src/interpreter.rs b/minisql/src/interpreter.rs index 20d803c..b5a98b5 100644 --- a/minisql/src/interpreter.rs +++ b/minisql/src/interpreter.rs @@ -1,13 +1,12 @@ -use bimap::BiMap; -use crate::result::DbResult; -use crate::type_system::{Value, DbType, IndexableValue}; -use crate::internals::schema::{TableName, TableSchema, ColumnName}; -use crate::internals::table::Table; -use crate::internals::row::{Row, ColumnPosition}; use crate::error::Error; -use crate::operation::{Operation, Condition, ColumnSelection}; use crate::internals::column_index::ColumnIndex; - +use crate::internals::row::{ColumnPosition, Row}; +use crate::internals::schema::{ColumnName, TableName, TableSchema}; +use crate::internals::table::Table; +use crate::operation::{ColumnSelection, Condition, Operation}; +use crate::result::DbResult; +use crate::type_system::{DbType, IndexableValue, Value}; +use bimap::BiMap; // Use `TablePosition` as index pub type Tables = Vec; @@ -27,8 +26,7 @@ pub enum Response { Deleted(usize), // how many were deleted TableCreated, IndexCreated, -} - +} impl State { fn new() -> Self { @@ -43,24 +41,28 @@ impl State { Some(table_position) => { let table = &self.tables[*table_position]; Ok(table) - }, - None => Err(Error::TableDoesNotExist(table_name.clone())) + } + None => Err(Error::TableDoesNotExist(table_name.clone())), } } - fn table_from_name_mut<'b: 'a, 'a>(&'b mut self, table_name: &TableName) -> DbResult<&'a mut Table> { + fn table_from_name_mut<'b: 'a, 'a>( + &'b mut self, + table_name: &TableName, + ) -> DbResult<&'a mut Table> { match self.table_name_position_mapping.get_by_left(table_name) { Some(table_position) => { let table = &mut self.tables[*table_position]; Ok(table) - }, - None => Err(Error::TableDoesNotExist(table_name.clone())) + } + None => Err(Error::TableDoesNotExist(table_name.clone())), } } fn attach_table(&mut self, table_name: TableName, table: Table) { let new_table_position: TablePosition = self.tables.len(); - self.table_name_position_mapping.insert(table_name, new_table_position); + self.table_name_position_mapping + .insert(table_name, new_table_position); self.tables.push(table); } @@ -78,72 +80,94 @@ impl State { Select(table_name, column_selection, maybe_condition) => { let table: &Table = self.table_from_name(&table_name)?; - let selected_column_positions: Vec = table.schema.column_positions_from_column_selection(&column_selection)?; + let selected_column_positions: Vec = table + .schema + .column_positions_from_column_selection(&column_selection)?; let selected_rows = match maybe_condition { None => table.select_all_rows(&selected_column_positions), Some(Condition::Eq(eq_column_name, value)) => { - let eq_column_position = table.schema.column_position_from_column_name(&eq_column_name)?; - table.select_rows_where_eq(&selected_column_positions, eq_column_position, value)? + let eq_column_position = table + .schema + .column_position_from_column_name(&eq_column_name)?; + table.select_rows_where_eq( + &selected_column_positions, + eq_column_position, + value, + )? } }; Ok(Response::Selected(selected_rows)) - }, + } Insert(table_name, values) => { let table: &mut Table = self.table_from_name_mut(&table_name)?; let (id, row) = table.schema.row_from_insertion_values(values)?; - let _ = table.insert_row_at(id, row)?; + table.insert_row_at(id, row)?; Ok(Response::Inserted) - }, + } Delete(table_name, maybe_condition) => { let table: &mut Table = self.table_from_name_mut(&table_name)?; let rows_affected = match maybe_condition { None => table.delete_all_rows(), Some(Condition::Eq(eq_column_name, value)) => { - let eq_column_position = table.schema.column_position_from_column_name(&eq_column_name)?; + let eq_column_position = table + .schema + .column_position_from_column_name(&eq_column_name)?; table.delete_rows_where_eq(eq_column_position, value)? } }; Ok(Response::Deleted(rows_affected)) - }, + } CreateTable(table_name, table_schema) => { let table = Table::new(table_schema); self.attach_table(table_name, table); Ok(Response::TableCreated) - }, + } CreateIndex(table_name, column_name) => { let table: &mut Table = self.table_from_name_mut(&table_name)?; - let column_position: ColumnPosition = table.schema.column_position_from_column_name(&column_name)?; + let column_position: ColumnPosition = table + .schema + .column_position_from_column_name(&column_name)?; let mut index: ColumnIndex = ColumnIndex::new(); - let _ = update_index_from_table(&mut index, &table, column_position)?; + update_index_from_table(&mut index, table, column_position)?; - table.attach_index(column_position, index); + table.attach_index(column_position, index); Ok(Response::IndexCreated) - }, + } } } } // Should be used in the case when an indexed is created after the table has existed for a // while. In such a case you need to build the index from the already existing rows. -fn update_index_from_table(column_index: &mut ColumnIndex, table: &Table, column_position: ColumnPosition) -> DbResult<()> { +fn update_index_from_table( + column_index: &mut ColumnIndex, + table: &Table, + column_position: ColumnPosition, +) -> DbResult<()> { for (id, row) in &table.rows { let value = match row.get(column_position) { - Some(Value::Indexable(value)) => { - value.clone() - }, + Some(Value::Indexable(value)) => value.clone(), Some(_) => { - let column_name: ColumnName = table.schema.column_name_from_column_position(column_position)?; - return Err(Error::AttemptToIndexNonIndexableColumn(table.schema.table_name.to_string(), column_name)) - }, + let column_name: ColumnName = table + .schema + .column_name_from_column_position(column_position)?; + return Err(Error::AttemptToIndexNonIndexableColumn( + table.schema.table_name.to_string(), + column_name, + )); + } None => { - return Err(Error::ColumnPositionDoesNotExist(table.schema.table_name.to_string(), column_position)) + return Err(Error::ColumnPositionDoesNotExist( + table.schema.table_name.to_string(), + column_position, + )) } }; column_index.add(value, *id) @@ -153,10 +177,9 @@ fn update_index_from_table(column_index: &mut ColumnIndex, table: &Table, column // TODO: Give a better name to something that you can respond to with rows trait SqlResponseConsumer { - // TODO: + // TODO: } - #[cfg(test)] mod tests { use super::*; @@ -176,7 +199,7 @@ mod tests { mapping.insert("age".to_string(), age); mapping }, - types: vec![DbType::UUID, DbType::String, DbType::Int], + types: vec![DbType::Uuid, DbType::String, DbType::Int], } } @@ -186,7 +209,9 @@ mod tests { let users_schema = users_schema(); let users = users_schema.table_name.clone(); - state.interpret(Operation::CreateTable(users.clone(), users_schema)).unwrap(); + state + .interpret(Operation::CreateTable(users.clone(), users_schema)) + .unwrap(); assert!(state.tables.len() == 1); let table = &state.tables[0]; @@ -201,48 +226,68 @@ mod tests { let users_schema = users_schema(); let users = users_schema.table_name.clone(); - state.interpret(Operation::CreateTable(users.clone(), users_schema)).unwrap(); - let response: Response = state.interpret(Operation::Select(users.clone(), ColumnSelection::All, None)).unwrap(); + state + .interpret(Operation::CreateTable(users.clone(), users_schema)) + .unwrap(); + let response: Response = state + .interpret(Operation::Select(users.clone(), ColumnSelection::All, None)) + .unwrap(); assert!(matches!(response, Response::Selected(_))); - let Response::Selected(rows) = response else { todo!() }; + let Response::Selected(rows) = response else { + todo!() + }; assert!(rows.len() == 0); - } #[test] fn test_select_nonexistant_table() { let mut state = State::new(); - let response: DbResult = state.interpret(Operation::Select("table_that_doesnt_exist".to_string(), ColumnSelection::All, None)); + let response: DbResult = state.interpret(Operation::Select( + "table_that_doesnt_exist".to_string(), + ColumnSelection::All, + None, + )); assert!(matches!(response, Err(Error::TableDoesNotExist(_)))); } #[test] fn test_insert_select_basic1() { - use Value::*; use IndexableValue::*; + use Value::*; let mut state = State::new(); let users_schema = users_schema(); let users = users_schema.table_name.clone(); - state.interpret(Operation::CreateTable(users.clone(), users_schema)).unwrap(); + state + .interpret(Operation::CreateTable(users.clone(), users_schema)) + .unwrap(); let (id, name, age) = ( - Indexable(UUID(0)), + Indexable(Uuid(0)), Indexable(String("Plato".to_string())), - Indexable(Int(64)) + Indexable(Int(64)), ); - state.interpret(Operation::Insert(users.clone(), vec![ - ("id".to_string(), id.clone()), - ("name".to_string(), name.clone()), - ("age".to_string(), age.clone()), - ])).unwrap(); + state + .interpret(Operation::Insert( + users.clone(), + vec![ + ("id".to_string(), id.clone()), + ("name".to_string(), name.clone()), + ("age".to_string(), age.clone()), + ], + )) + .unwrap(); - let response: Response = state.interpret(Operation::Select(users.clone(), ColumnSelection::All, None)).unwrap(); + let response: Response = state + .interpret(Operation::Select(users.clone(), ColumnSelection::All, None)) + .unwrap(); assert!(matches!(response, Response::Selected(_))); - let Response::Selected(rows) = response else { todo!() }; + let Response::Selected(rows) = response else { + todo!() + }; assert!(rows.len() == 1); let row = &rows[0]; @@ -254,45 +299,59 @@ mod tests { #[test] fn test_insert_select_basic2() { - use Value::*; - use IndexableValue::*; - use Operation::*; use ColumnSelection::*; use Condition::*; + use IndexableValue::*; + use Operation::*; + use Value::*; let mut state = State::new(); let users_schema = users_schema(); let users = users_schema.table_name.clone(); - state.interpret(CreateTable(users.clone(), users_schema)).unwrap(); + state + .interpret(CreateTable(users.clone(), users_schema)) + .unwrap(); let (id0, name0, age0) = ( - Indexable(UUID(0)), + Indexable(Uuid(0)), Indexable(String("Plato".to_string())), - Indexable(Int(64)) + Indexable(Int(64)), ); - state.interpret(Insert(users.clone(), vec![ - ("id".to_string(), id0.clone()), - ("name".to_string(), name0.clone()), - ("age".to_string(), age0.clone()), - ])).unwrap(); + state + .interpret(Insert( + users.clone(), + vec![ + ("id".to_string(), id0.clone()), + ("name".to_string(), name0.clone()), + ("age".to_string(), age0.clone()), + ], + )) + .unwrap(); let (id1, name1, age1) = ( - Indexable(UUID(1)), + Indexable(Uuid(1)), Indexable(String("Aristotle".to_string())), - Indexable(Int(20)) + Indexable(Int(20)), ); - state.interpret(Insert(users.clone(), vec![ - ("id".to_string(), id1.clone()), - ("name".to_string(), name1.clone()), - ("age".to_string(), age1.clone()), - ])).unwrap(); + state + .interpret(Insert( + users.clone(), + vec![ + ("id".to_string(), id1.clone()), + ("name".to_string(), name1.clone()), + ("age".to_string(), age1.clone()), + ], + )) + .unwrap(); { let response: Response = state.interpret(Select(users.clone(), All, None)).unwrap(); assert!(matches!(response, Response::Selected(_))); - let Response::Selected(rows) = response else { todo!() }; + let Response::Selected(rows) = response else { + todo!() + }; assert!(rows.len() == 2); let row0 = &rows[0]; let row1 = &rows[1]; @@ -309,9 +368,17 @@ mod tests { } { - let response: Response = state.interpret(Select(users.clone(), All, Some(Eq("id".to_string(), id0.clone())))).unwrap(); + let response: Response = state + .interpret(Select( + users.clone(), + All, + Some(Eq("id".to_string(), id0.clone())), + )) + .unwrap(); assert!(matches!(response, Response::Selected(_))); - let Response::Selected(rows) = response else { todo!() }; + let Response::Selected(rows) = response else { + todo!() + }; assert!(rows.len() == 1); let row0 = &rows[0]; @@ -322,9 +389,17 @@ mod tests { } { - let response: Response = state.interpret(Select(users.clone(), Columns(vec!["name".to_string(), "id".to_string()]), Some(Eq("id".to_string(), id0.clone())))).unwrap(); + let response: Response = state + .interpret(Select( + users.clone(), + Columns(vec!["name".to_string(), "id".to_string()]), + Some(Eq("id".to_string(), id0.clone())), + )) + .unwrap(); assert!(matches!(response, Response::Selected(_))); - let Response::Selected(rows) = response else { todo!() }; + let Response::Selected(rows) = response else { + todo!() + }; assert!(rows.len() == 1); let row0 = &rows[0]; @@ -336,48 +411,66 @@ mod tests { #[test] fn test_delete() { - use Value::*; - use IndexableValue::*; - use Operation::*; use ColumnSelection::*; use Condition::*; + use IndexableValue::*; + use Operation::*; + use Value::*; let mut state = State::new(); let users_schema = users_schema(); let users = users_schema.table_name.clone(); - state.interpret(CreateTable(users.clone(), users_schema)).unwrap(); + state + .interpret(CreateTable(users.clone(), users_schema)) + .unwrap(); let (id0, name0, age0) = ( - Indexable(UUID(0)), + Indexable(Uuid(0)), Indexable(String("Plato".to_string())), - Indexable(Int(64)) + Indexable(Int(64)), ); - state.interpret(Insert(users.clone(), vec![ - ("id".to_string(), id0.clone()), - ("name".to_string(), name0.clone()), - ("age".to_string(), age0.clone()), - ])).unwrap(); + state + .interpret(Insert( + users.clone(), + vec![ + ("id".to_string(), id0.clone()), + ("name".to_string(), name0.clone()), + ("age".to_string(), age0.clone()), + ], + )) + .unwrap(); let (id1, name1, age1) = ( - Indexable(UUID(1)), + Indexable(Uuid(1)), Indexable(String("Aristotle".to_string())), - Indexable(Int(20)) + Indexable(Int(20)), ); - state.interpret(Insert(users.clone(), vec![ - ("id".to_string(), id1.clone()), - ("name".to_string(), name1.clone()), - ("age".to_string(), age1.clone()), - ])).unwrap(); + state + .interpret(Insert( + users.clone(), + vec![ + ("id".to_string(), id1.clone()), + ("name".to_string(), name1.clone()), + ("age".to_string(), age1.clone()), + ], + )) + .unwrap(); - - let delete_response: Response = state.interpret(Delete(users.clone(), Some(Eq("id".to_string(), id0.clone())))).unwrap(); + let delete_response: Response = state + .interpret(Delete( + users.clone(), + Some(Eq("id".to_string(), id0.clone())), + )) + .unwrap(); assert!(matches!(delete_response, Response::Deleted(1))); let response: Response = state.interpret(Select(users.clone(), All, None)).unwrap(); assert!(matches!(response, Response::Selected(_))); - let Response::Selected(rows) = response else { todo!() }; + let Response::Selected(rows) = response else { + todo!() + }; assert!(rows.len() == 1); let row = &rows[0]; @@ -390,13 +483,12 @@ mod tests { // TODO: Test CreateIndex } - pub fn example() { - use Value::*; - use IndexableValue::*; - use Operation::*; use ColumnSelection::*; use Condition::*; + use IndexableValue::*; + use Operation::*; + use Value::*; let users_schema = { let id: ColumnPosition = 0; @@ -413,60 +505,89 @@ pub fn example() { mapping.insert("age".to_string(), age); mapping }, - types: vec![DbType::UUID, DbType::String, DbType::Int], + types: vec![DbType::Uuid, DbType::String, DbType::Int], } }; let users = users_schema.table_name.clone(); - let mut state = State::new(); - state.interpret(Operation::CreateTable(users.clone(), users_schema)).unwrap(); + state + .interpret(Operation::CreateTable(users.clone(), users_schema)) + .unwrap(); let (id0, name0, age0) = ( - Indexable(UUID(0)), + Indexable(Uuid(0)), Indexable(String("Plato".to_string())), - Indexable(Int(64)) + Indexable(Int(64)), ); println!("==INSERT Plato=="); - state.interpret(Insert(users.clone(), vec![ - ("id".to_string(), id0.clone()), - ("name".to_string(), name0.clone()), - ("age".to_string(), age0.clone()), - ])).unwrap(); + state + .interpret(Insert( + users.clone(), + vec![ + ("id".to_string(), id0.clone()), + ("name".to_string(), name0.clone()), + ("age".to_string(), age0.clone()), + ], + )) + .unwrap(); let (id1, name1, age1) = ( - Indexable(UUID(1)), + Indexable(Uuid(1)), Indexable(String("Aristotle".to_string())), - Indexable(Int(20)) + Indexable(Int(20)), ); println!("==INSERT Aristotle=="); - state.interpret(Insert(users.clone(), vec![ - ("id".to_string(), id1.clone()), - ("name".to_string(), name1.clone()), - ("age".to_string(), age1.clone()), - ])).unwrap(); + state + .interpret(Insert( + users.clone(), + vec![ + ("id".to_string(), id1.clone()), + ("name".to_string(), name1.clone()), + ("age".to_string(), age1.clone()), + ], + )) + .unwrap(); println!(); { - let response: Response = state.interpret(Operation::Select(users.clone(), ColumnSelection::All, None)).unwrap(); + let response: Response = state + .interpret(Operation::Select(users.clone(), ColumnSelection::All, None)) + .unwrap(); println!("==SELECT ALL=="); println!("{:?}", response); println!(); } { - let response: Response = state.interpret(Select(users.clone(), All, Some(Eq("id".to_string(), id0.clone())))).unwrap(); + let response: Response = state + .interpret(Select( + users.clone(), + All, + Some(Eq("id".to_string(), id0.clone())), + )) + .unwrap(); println!("==SELECT Plato=="); println!("{:?}", response); println!(); } { - let _delete_response: Response = state.interpret(Delete(users.clone(), Some(Eq("id".to_string(), id0.clone())))).unwrap(); + let _delete_response: Response = state + .interpret(Delete( + users.clone(), + Some(Eq("id".to_string(), id0.clone())), + )) + .unwrap(); println!("==DELETE Plato=="); - let response: Response = state.interpret(Select(users.clone(), Columns(vec!["name".to_string(), "id".to_string()]), None)).unwrap(); + let response: Response = state + .interpret(Select( + users.clone(), + Columns(vec!["name".to_string(), "id".to_string()]), + None, + )) + .unwrap(); println!("==SELECT All=="); println!("{:?}", response); println!(); } - } diff --git a/minisql/src/main.rs b/minisql/src/main.rs index ec3dd18..9a4f292 100644 --- a/minisql/src/main.rs +++ b/minisql/src/main.rs @@ -1,8 +1,8 @@ -mod result; -mod internals; -mod operation; -mod interpreter; mod error; +mod internals; +mod interpreter; +mod operation; +mod result; mod type_system; fn main() { diff --git a/minisql/src/operation.rs b/minisql/src/operation.rs index 8e49477..a5fd0b7 100644 --- a/minisql/src/operation.rs +++ b/minisql/src/operation.rs @@ -1,5 +1,5 @@ +use crate::internals::schema::{ColumnName, TableName, TableSchema}; use crate::type_system::Value; -use crate::internals::schema::{TableSchema, TableName, ColumnName}; // ==============SQL operations================ // TODO: Note that every operation has a table name. @@ -27,7 +27,6 @@ pub enum Condition { // And(Box, Box), // Or(Box, Box), // Not(Box), - Eq(ColumnName, Value), // LessOrEqual(ColumnName, DbValue), // Less(ColumnName, DbValue), diff --git a/minisql/src/type_system.rs b/minisql/src/type_system.rs index 7674c16..4edc3ec 100644 --- a/minisql/src/type_system.rs +++ b/minisql/src/type_system.rs @@ -4,11 +4,11 @@ pub enum DbType { String, Int, Number, - UUID, + Uuid, } // ==============Values================ -pub type UUID = u64; +pub type Uuid = u64; // TODO: What about nulls? I would rather not have that in SQL, it sucks. // I would rather have non-nullable values by default, @@ -16,7 +16,7 @@ pub type UUID = u64; #[derive(Debug, Clone, PartialEq)] pub enum Value { Number(f64), // TODO: Can't put floats as keys in maps, since they don't implement Eq. What to - // do? + // do? Indexable(IndexableValue), } @@ -24,20 +24,19 @@ pub enum Value { pub enum IndexableValue { String(String), Int(u64), - UUID(UUID), + Uuid(Uuid), // TODO: what about null? } impl Value { - pub fn to_type(self) -> DbType { + pub fn to_type(&self) -> DbType { match self { Self::Number(_) => DbType::Number, - Self::Indexable(val) => - match val { - IndexableValue::String(_) => DbType::String, - IndexableValue::Int(_) => DbType::Int, - IndexableValue::UUID(_) => DbType::UUID, - } + Self::Indexable(val) => match val { + IndexableValue::String(_) => DbType::String, + IndexableValue::Int(_) => DbType::Int, + IndexableValue::Uuid(_) => DbType::Uuid, + }, } } }