diff --git a/minisql/src/error.rs b/minisql/src/error.rs index 126a855..be6bfd8 100644 --- a/minisql/src/error.rs +++ b/minisql/src/error.rs @@ -1,5 +1,6 @@ -use crate::base::{ColumnName, TableName, ColumnPosition}; -use crate::type_system::{DbType, DbValue, UUID}; +use crate::internals::schema::{ColumnName, TableName}; +use crate::internals::row::ColumnPosition; +use crate::type_system::{DbType, Value, UUID}; use crate::operation::InsertionValues; #[derive(Debug)] @@ -7,7 +8,7 @@ pub enum Error { TableDoesNotExist(TableName), ColumnDoesNotExist(TableName, ColumnName), ColumnPositionDoesNotExist(TableName, ColumnPosition), - ValueDoesNotMatchExpectedType(TableName, ColumnName, DbType, DbValue), + ValueDoesNotMatchExpectedType(TableName, ColumnName, DbType, Value), AttemptingToInsertAlreadyPresentId(TableName, UUID), MissingTypeAnnotationOfColumn(TableName, ColumnPosition), MissingColumnInInsertValues(TableName, ColumnName, InsertionValues), diff --git a/minisql/src/column_index.rs b/minisql/src/internals/column_index.rs similarity index 78% rename from minisql/src/column_index.rs rename to minisql/src/internals/column_index.rs index 7be8671..c9184c3 100644 --- a/minisql/src/column_index.rs +++ b/minisql/src/internals/column_index.rs @@ -1,12 +1,13 @@ use std::collections::{BTreeMap, HashSet}; -use crate::base::{ColumnPosition, ColumnName, DbResult}; -use crate::type_system::{UUID, DbValue, IndexableDbValue}; -use crate::table::Table; +use crate::type_system::{UUID, Value, IndexableValue}; +use crate::internals::schema::{ColumnName, DbResult}; +use crate::internals::table::Table; +use crate::internals::row::ColumnPosition; use crate::error::Error; #[derive(Debug)] pub struct ColumnIndex { - index: BTreeMap> + index: BTreeMap> } impl ColumnIndex { @@ -15,14 +16,14 @@ impl ColumnIndex { Self { index } } - pub fn get(&self, value: &IndexableDbValue) -> 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: IndexableDbValue, id: UUID) { + pub fn add(&mut self, value: IndexableValue, id: UUID) { match self.index.get_mut(&value) { Some(ids) => { ids.insert(id); @@ -40,7 +41,7 @@ impl ColumnIndex { pub fn update_from_table(&mut self, table: &Table, column_position: ColumnPosition) -> DbResult<()> { for (id, row) in &table.rows { let value = match row.get(column_position) { - Some(DbValue::Indexable(value)) => { + Some(Value::Indexable(value)) => { value.clone() }, Some(_) => { @@ -56,7 +57,7 @@ impl ColumnIndex { Ok(()) } - pub fn remove(&mut self, value: &IndexableDbValue, 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); diff --git a/minisql/src/internals/mod.rs b/minisql/src/internals/mod.rs new file mode 100644 index 0000000..0817ee8 --- /dev/null +++ b/minisql/src/internals/mod.rs @@ -0,0 +1,4 @@ +pub mod table; +pub mod row; +pub mod column_index; +pub mod schema; diff --git a/minisql/src/internals/row.rs b/minisql/src/internals/row.rs new file mode 100644 index 0000000..430a26f --- /dev/null +++ b/minisql/src/internals/row.rs @@ -0,0 +1,74 @@ +use std::slice::SliceIndex; +use std::ops::{Index, IndexMut}; +use crate::type_system::Value; + +pub type ColumnPosition = usize; + +#[derive(Debug, Clone)] +pub struct Row(Vec); + +impl Index for Row +where + Idx: SliceIndex<[Value]>, +{ + type Output = Idx::Output; + + fn index(&self, index: Idx) -> &Self::Output { + &self.0[index] + } +} + +impl IndexMut for Row +where + Idx: SliceIndex<[Value]>, +{ + fn index_mut(&mut self, index: Idx) -> &mut Self::Output { + &mut self.0[index] + } +} + +impl FromIterator for Row { + fn from_iter>(iter: I) -> Self { + let mut v = vec![]; + for x in iter { + v.push(x) + } + Row(v) + } +} + +impl Row { + pub fn new() -> Self { + Row(vec![]) + } + + pub fn with_number_of_columns(number_of_columns: usize) -> Self { + Row(Vec::with_capacity(number_of_columns)) + } + + pub fn push(&mut self, value: Value) { + self.0.push(value) + } + + pub fn len(&self) -> usize { + self.0.len() + } + + pub fn get(&self, column_position: ColumnPosition) -> Option<&Value> { + self.0.get(column_position) + } + + pub fn restrict_columns(&self, columns: &Vec) -> 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 => {} + } + } + subrow + } +} diff --git a/minisql/src/base.rs b/minisql/src/internals/schema.rs similarity index 93% rename from minisql/src/base.rs rename to minisql/src/internals/schema.rs index 7163840..eb65451 100644 --- a/minisql/src/base.rs +++ b/minisql/src/internals/schema.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; use bimap::BiMap; use crate::operation::{InsertionValues, ColumnSelection}; -use crate::table::Row; -use crate::type_system::{DbType, DbValue, IndexableDbValue, UUID}; +use crate::internals::row::{Row, ColumnPosition}; +use crate::type_system::{DbType, Value, IndexableValue, UUID}; use crate::error::Error; // Note that it is nice to split metadata from the data because @@ -18,7 +18,6 @@ pub struct TableSchema { pub type TableName = String; pub type ColumnName = String; -pub type ColumnPosition = usize; pub type DbResult = Result; @@ -81,7 +80,6 @@ impl TableSchema { self.column_name_position_mapping.len() } - // TODO: IS THIS THE RIGHT PLACE? 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. @@ -95,7 +93,7 @@ impl TableSchema { let mut row: Row = Row::with_number_of_columns(number_of_columns); - let mut values: HashMap = HashMap::new(); + let mut values: HashMap = HashMap::new(); for (column_name, db_value) in &insertion_values { values.insert(column_name.clone(), db_value.clone()); } @@ -115,7 +113,7 @@ impl TableSchema { let id: UUID = match row.get(self.primary_key) { Some(val) => { match val { - DbValue::Indexable(IndexableDbValue::UUID(id)) => { + Value::Indexable(IndexableValue::UUID(id)) => { *id }, _ => diff --git a/minisql/src/table.rs b/minisql/src/internals/table.rs similarity index 66% rename from minisql/src/table.rs rename to minisql/src/internals/table.rs index 01e11ec..33dc5cd 100644 --- a/minisql/src/table.rs +++ b/minisql/src/internals/table.rs @@ -1,92 +1,12 @@ use std::collections::{BTreeMap, HashMap, HashSet}; -use std::slice::SliceIndex; -use std::ops::{Index, IndexMut}; -use crate::base::{TableSchema, ColumnPosition, ColumnName, DbResult}; -use crate::type_system::{UUID, DbValue, IndexableDbValue}; -use crate::column_index::ColumnIndex; +use crate::type_system::{UUID, Value, IndexableValue}; use crate::error::Error; +use crate::internals::schema::{TableSchema, ColumnName, DbResult}; +use crate::internals::row::{Row, ColumnPosition}; +use crate::internals::column_index::ColumnIndex; -// ======Table Row====== -pub type Rows = - // TODO: This should be some sort of an interface to a dictionary - // s.t. in the background it may modify stuff in memory or talk to the disk - BTreeMap; - -// Use `ColumnPosition` as index -#[derive(Debug, Clone)] -pub struct Row(Vec); - -impl Index for Row -where - Idx: SliceIndex<[DbValue]>, -{ - type Output = Idx::Output; - - fn index(&self, index: Idx) -> &Self::Output { - &self.0[index] - } -} - -impl IndexMut for Row -where - Idx: SliceIndex<[DbValue]>, -{ - fn index_mut(&mut self, index: Idx) -> &mut Self::Output { - &mut self.0[index] - } -} - -impl FromIterator for Row { - fn from_iter>(iter: I) -> Self { - let mut v = vec![]; - for x in iter { - v.push(x) - } - Row(v) - } -} - -impl Row { - pub fn new() -> Self { - Row(vec![]) - } - - pub fn with_number_of_columns(number_of_columns: usize) -> Self { - Row(Vec::with_capacity(number_of_columns)) - } - - pub fn push(&mut self, value: DbValue) { - self.0.push(value) - } - - pub fn len(&self) -> usize { - self.0.len() - } - - pub fn get(&self, column_position: ColumnPosition) -> Option<&DbValue> { - self.0.get(column_position) - } - - pub fn restrict_columns(&self, columns: &Vec) -> 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 => {} - } - } - subrow - } - -} - - -// ======Table====== #[derive(Debug)] pub struct Table { pub schema: TableSchema, @@ -96,6 +16,9 @@ pub struct Table { HashMap } +pub type Rows = + BTreeMap; + impl Table { pub fn new(table_schema: TableSchema) -> Self { @@ -117,7 +40,7 @@ impl Table { .collect() } - fn get_rows_by_value(&self, column_position: ColumnPosition, value: &DbValue) -> Vec { + 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 }) @@ -128,14 +51,14 @@ impl Table { 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: DbValue) -> DbResult> { + pub fn select_rows_where_eq(&self, selected_column_positions: &Vec, column_position: ColumnPosition, value: Value) -> DbResult> { match value { - DbValue::Indexable(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, &DbValue::Indexable(value)).iter().map(|row| row.restrict_columns(&selected_column_positions)).collect()) + Ok(self.get_rows_by_value(column_position, &Value::Indexable(value)).iter().map(|row| row.restrict_columns(&selected_column_positions)).collect()) } }, _ => { @@ -152,7 +75,7 @@ impl Table { for (column_position, column_index) in &mut self.indexes { match row.get(*column_position) { - Some(DbValue::Indexable(val)) => { + Some(Value::Indexable(val)) => { column_index.add(val.clone(), id) }, Some(_) => {}, @@ -169,7 +92,7 @@ impl Table { match self.rows.remove(&id) { Some(row) => { for (column_position, column_index) in &mut self.indexes { - if let DbValue::Indexable(value) = &row[*column_position] { + if let Value::Indexable(value) = &row[*column_position] { let _ = column_index.remove(value, id); }; } @@ -187,7 +110,7 @@ impl Table { total_count } - fn delete_rows_by_value(&mut self, column_position: ColumnPosition, value: &DbValue) -> usize { + 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 }) .collect(); @@ -201,14 +124,14 @@ impl Table { number_of_rows } - pub fn delete_rows_where_eq(&mut self, column_position: ColumnPosition, value: DbValue) -> DbResult { + pub fn delete_rows_where_eq(&mut self, column_position: ColumnPosition, value: Value) -> DbResult { match value { - DbValue::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, &DbValue::Indexable(value))) + Ok(self.delete_rows_by_value(column_position, &Value::Indexable(value))) } }, _ => @@ -221,15 +144,15 @@ impl Table { self.indexes.insert(column_position, column_index); } - fn fetch_ids_from_index(&self, column_position: ColumnPosition, value: &IndexableDbValue) -> DbResult>> { + fn fetch_ids_from_index(&self, column_position: ColumnPosition, value: &IndexableValue) -> DbResult>> { if self.schema.is_primary(column_position) { match value { - IndexableDbValue::UUID(id) => + IndexableValue::UUID(id) => Ok(Some(HashSet::from([*id]))), _ => { 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_, DbValue::Indexable(value.clone()))) + Err(Error::ValueDoesNotMatchExpectedType(self.schema.table_name.clone(), column_name, type_, Value::Indexable(value.clone()))) } } } else { diff --git a/minisql/src/interpreter.rs b/minisql/src/interpreter.rs index 3037d82..4e4ce35 100644 --- a/minisql/src/interpreter.rs +++ b/minisql/src/interpreter.rs @@ -1,10 +1,11 @@ use bimap::BiMap; -use crate::type_system::{DbValue, DbType, IndexableDbValue}; -use crate::base::{TableName, TableSchema, ColumnPosition, ColumnName, DbResult}; -use crate::table::{Table, Row}; +use crate::type_system::{Value, DbType, IndexableValue}; +use crate::internals::schema::{TableName, TableSchema, ColumnName, DbResult}; +use crate::internals::table::Table; +use crate::internals::row::{Row, ColumnPosition}; use crate::error::Error; use crate::operation::{Operation, Condition, ColumnSelection}; -use crate::column_index::ColumnIndex; +use crate::internals::column_index::ColumnIndex; // Use `TablePosition` as index @@ -196,8 +197,8 @@ mod tests { #[test] fn test_insert_select_basic1() { - use DbValue::*; - use IndexableDbValue::*; + use Value::*; + use IndexableValue::*; let mut state = State::new(); let users_schema = users_schema(); @@ -231,8 +232,8 @@ mod tests { #[test] fn test_insert_select_basic2() { - use DbValue::*; - use IndexableDbValue::*; + use Value::*; + use IndexableValue::*; use Operation::*; use ColumnSelection::*; use Condition::*; @@ -313,8 +314,8 @@ mod tests { #[test] fn test_delete() { - use DbValue::*; - use IndexableDbValue::*; + use Value::*; + use IndexableValue::*; use Operation::*; use ColumnSelection::*; use Condition::*; @@ -369,8 +370,8 @@ mod tests { pub fn example() { - use DbValue::*; - use IndexableDbValue::*; + use Value::*; + use IndexableValue::*; use Operation::*; use ColumnSelection::*; use Condition::*; diff --git a/minisql/src/main.rs b/minisql/src/main.rs index 0a9fd94..f3c39ae 100644 --- a/minisql/src/main.rs +++ b/minisql/src/main.rs @@ -1,6 +1,4 @@ -mod base; -mod table; -mod column_index; +mod internals; mod operation; mod interpreter; mod error; diff --git a/minisql/src/operation.rs b/minisql/src/operation.rs index 7235fed..8e49477 100644 --- a/minisql/src/operation.rs +++ b/minisql/src/operation.rs @@ -1,6 +1,5 @@ -use crate::base::{TableName, ColumnName}; -use crate::type_system::DbValue; -use crate::base::TableSchema; +use crate::type_system::Value; +use crate::internals::schema::{TableSchema, TableName, ColumnName}; // ==============SQL operations================ // TODO: Note that every operation has a table name. @@ -17,7 +16,7 @@ pub enum Operation { // DropTable(TableName), } -pub type InsertionValues = Vec<(ColumnName, DbValue)>; +pub type InsertionValues = Vec<(ColumnName, Value)>; pub enum ColumnSelection { All, @@ -29,7 +28,7 @@ pub enum Condition { // Or(Box, Box), // Not(Box), - Eq(ColumnName, DbValue), + Eq(ColumnName, Value), // LessOrEqual(ColumnName, DbValue), // Less(ColumnName, DbValue), diff --git a/minisql/src/type_system.rs b/minisql/src/type_system.rs index a6b1ce5..7674c16 100644 --- a/minisql/src/type_system.rs +++ b/minisql/src/type_system.rs @@ -14,29 +14,29 @@ pub type UUID = u64; // I would rather have non-nullable values by default, // and something like an explicit Option type for nulls. #[derive(Debug, Clone, PartialEq)] -pub enum DbValue { +pub enum Value { Number(f64), // TODO: Can't put floats as keys in maps, since they don't implement Eq. What to // do? - Indexable(IndexableDbValue), + Indexable(IndexableValue), } #[derive(Debug, Ord, Eq, Clone, PartialOrd, PartialEq)] -pub enum IndexableDbValue { +pub enum IndexableValue { String(String), Int(u64), UUID(UUID), // TODO: what about null? } -impl DbValue { +impl Value { pub fn to_type(self) -> DbType { match self { Self::Number(_) => DbType::Number, Self::Indexable(val) => match val { - IndexableDbValue::String(_) => DbType::String, - IndexableDbValue::Int(_) => DbType::Int, - IndexableDbValue::UUID(_) => DbType::UUID, + IndexableValue::String(_) => DbType::String, + IndexableValue::Int(_) => DbType::Int, + IndexableValue::UUID(_) => DbType::UUID, } } }