From 1d746430d236c032225eaaa0e45aaa88af0d5c8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jind=C5=99ich=20Moravec?= Date: Tue, 23 Jan 2024 20:56:07 +0100 Subject: [PATCH] feat: return schema and column positions with select --- minisql/src/internals/row.rs | 10 +++-- minisql/src/internals/table.rs | 5 ++- minisql/src/interpreter.rs | 76 +++++++++++++++++----------------- minisql/src/lib.rs | 1 + minisql/src/restricted_row.rs | 35 ++++++++++++++++ 5 files changed, 84 insertions(+), 43 deletions(-) create mode 100644 minisql/src/restricted_row.rs diff --git a/minisql/src/internals/row.rs b/minisql/src/internals/row.rs index ad8dc1e..e46dac9 100644 --- a/minisql/src/internals/row.rs +++ b/minisql/src/internals/row.rs @@ -1,6 +1,7 @@ use crate::type_system::Value; use std::ops::{Index, IndexMut}; use std::slice::SliceIndex; +use crate::restricted_row::RestrictedRow; pub type ColumnPosition = usize; @@ -58,14 +59,15 @@ impl Row { self.0.get(column_position) } - pub fn restrict_columns(&self, columns: &Vec) -> Row { + pub fn restrict_columns(&self, columns: &Vec) -> RestrictedRow { // If the index from `columns` is non-existant in `row`, it will just ignore it. - let mut subrow: Row = Row::new(); + let mut subrow: Vec<(ColumnPosition, Value)> = vec![]; for column_position in columns { if let Some(value) = self.get(*column_position) { - subrow.0.push(value.clone()) + subrow.push((*column_position, value.clone())); } } - subrow + + subrow.into() } } diff --git a/minisql/src/internals/table.rs b/minisql/src/internals/table.rs index 2b5a5bc..c9f366c 100644 --- a/minisql/src/internals/table.rs +++ b/minisql/src/internals/table.rs @@ -3,6 +3,7 @@ use std::collections::{BTreeMap, HashMap, HashSet}; use crate::error::Error; use crate::internals::column_index::ColumnIndex; use crate::internals::row::{ColumnPosition, Row}; +use crate::restricted_row::RestrictedRow; use crate::schema::{ColumnName, TableSchema, TableName}; use crate::result::DbResult; use crate::type_system::{IndexableValue, Uuid, Value}; @@ -67,7 +68,7 @@ impl Table { .collect() } - pub fn select_all_rows<'a>(&'a self, selected_column_positions: Vec) -> impl Iterator + 'a { + pub fn select_all_rows<'a>(&'a self, selected_column_positions: Vec) -> impl Iterator + 'a { self.rows .values() .map(move |row| row.restrict_columns(&selected_column_positions)) @@ -78,7 +79,7 @@ impl Table { selected_column_positions: Vec, column_position: ColumnPosition, value: Value, - ) -> DbResult + 'a> { + ) -> DbResult + 'a> { let restrict_columns_of_row = move |row: Row| row.restrict_columns(&selected_column_positions); match value { Value::Indexable(value) => match self.fetch_ids_from_index(column_position, &value)? { diff --git a/minisql/src/interpreter.rs b/minisql/src/interpreter.rs index 84f2494..805923e 100644 --- a/minisql/src/interpreter.rs +++ b/minisql/src/interpreter.rs @@ -1,11 +1,12 @@ use crate::error::Error; -use crate::internals::row::{ColumnPosition, Row}; +use crate::internals::row::ColumnPosition; use crate::schema::{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 crate::restricted_row::RestrictedRow; // Use `TablePosition` as index pub type Tables = Vec; @@ -20,7 +21,7 @@ pub struct State { // #[derive(Debug)] pub enum Response<'a> { - Selected(Box + 'a>), + Selected(&'a TableSchema, Box + 'a>), Inserted, Deleted(usize), // how many were deleted TableCreated, @@ -31,7 +32,7 @@ impl std::fmt::Debug for Response<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { use Response::*; match self { - Selected(_rows) => + Selected(_schema, _rows) => // TODO: How can we iterate through the rows without having to take ownership of // them? f.write_str("Some rows... trust me"), @@ -99,7 +100,7 @@ impl State { let selected_rows = match maybe_condition { None => { let x = table.select_all_rows(selected_column_positions); - Box::new(x) as Box + 'a> + Box::new(x) as Box + 'a> }, Some(Condition::Eq(eq_column_name, value)) => { @@ -112,11 +113,11 @@ impl State { eq_column_position, value, )?; - Box::new(x) as Box + 'a> + Box::new(x) as Box + 'a> } }; - Ok(Response::Selected(selected_rows)) + Ok(Response::Selected(table.schema(), selected_rows)) } Insert(table_name, values) => { let table: &mut Table = self.table_from_name_mut(&table_name)?; @@ -210,8 +211,8 @@ mod tests { let response: Response = state .interpret(Operation::Select(users.clone(), ColumnSelection::All, None)) .unwrap(); - assert!(matches!(response, Response::Selected(_))); - let Response::Selected(rows) = response else { + assert!(matches!(response, Response::Selected(_, _))); + let Response::Selected(schema, rows) = response else { panic!() }; let rows: Vec<_> = rows.collect(); @@ -263,8 +264,8 @@ mod tests { .interpret(Operation::Select(users.clone(), ColumnSelection::All, None)) .unwrap(); - assert!(matches!(response, Response::Selected(_))); - let Response::Selected(rows) = response else { + assert!(matches!(response, Response::Selected(_, _))); + let Response::Selected(schema, rows) = response else { panic!() }; let rows: Vec<_> = rows.collect(); @@ -272,9 +273,9 @@ mod tests { let row = &rows[0]; assert!(row.len() == 3); - assert!(row[0] == id); - assert!(row[1] == name); - assert!(row[2] == age); + assert!(row[0].1 == id); + assert!(row[1].1 == name); + assert!(row[2].1 == age); } #[test] @@ -328,24 +329,25 @@ mod tests { { let response: Response = state.interpret(Select(users.clone(), All, None)).unwrap(); - assert!(matches!(response, Response::Selected(_))); - let Response::Selected(rows) = response else { + assert!(matches!(response, Response::Selected(_, _))); + let Response::Selected(_, rows) = response else { panic!() }; - let rows: Vec<_> = rows.collect(); + + let rows: Vec<_> = rows.collect(); assert!(rows.len() == 2); let row0 = &rows[0]; let row1 = &rows[1]; assert!(row0.len() == 3); - assert!(row0[0] == id0); - assert!(row0[1] == name0); - assert!(row0[2] == age0); + assert!(row0[0].1 == id0); + assert!(row0[1].1 == name0); + assert!(row0[2].1 == age0); assert!(row1.len() == 3); - assert!(row1[0] == id1); - assert!(row1[1] == name1); - assert!(row1[2] == age1); + assert!(row1[0].1 == id1); + assert!(row1[1].1 == name1); + assert!(row1[2].1 == age1); } { @@ -356,8 +358,8 @@ mod tests { Some(Eq("id".to_string(), id0.clone())), )) .unwrap(); - assert!(matches!(response, Response::Selected(_))); - let Response::Selected(rows) = response else { + assert!(matches!(response, Response::Selected(_, _))); + let Response::Selected(_, rows) = response else { panic!() }; let rows: Vec<_> = rows.collect(); @@ -365,9 +367,9 @@ mod tests { let row0 = &rows[0]; assert!(row0.len() == 3); - assert!(row0[0] == id0); - assert!(row0[1] == name0); - assert!(row0[2] == age0); + assert!(row0[0].1 == id0); + assert!(row0[1].1 == name0); + assert!(row0[2].1 == age0); } { @@ -378,8 +380,8 @@ mod tests { Some(Eq("id".to_string(), id0.clone())), )) .unwrap(); - assert!(matches!(response, Response::Selected(_))); - let Response::Selected(rows) = response else { + assert!(matches!(response, Response::Selected(_, _))); + let Response::Selected(_, rows) = response else { panic!() }; let rows: Vec<_> = rows.collect(); @@ -387,8 +389,8 @@ mod tests { let row0 = &rows[0]; assert!(row0.len() == 2); - assert!(row0[0] == name0); - assert!(row0[1] == id0); + assert!(row0[0].1 == name0); + assert!(row0[1].1 == id0); } } @@ -452,8 +454,8 @@ mod tests { let response: Response = state.interpret(Select(users.clone(), All, None)).unwrap(); - assert!(matches!(response, Response::Selected(_))); - let Response::Selected(rows) = response else { + assert!(matches!(response, Response::Selected(_, _))); + let Response::Selected(_, rows) = response else { panic!() }; let rows: Vec<_> = rows.collect(); @@ -461,9 +463,9 @@ mod tests { let row = &rows[0]; assert!(row.len() == 3); - assert!(row[0] == id1); - assert!(row[1] == name1); - assert!(row[2] == age1); + assert!(row[0].1 == id1); + assert!(row[1].1 == name1); + assert!(row[2].1 == age1); } #[test] @@ -644,4 +646,4 @@ pub fn example() { println!("{:?}", response); println!(); } -} +} \ No newline at end of file diff --git a/minisql/src/lib.rs b/minisql/src/lib.rs index b8e95c3..f9a0b09 100644 --- a/minisql/src/lib.rs +++ b/minisql/src/lib.rs @@ -5,3 +5,4 @@ pub mod type_system; mod error; mod internals; mod result; +pub mod restricted_row; diff --git a/minisql/src/restricted_row.rs b/minisql/src/restricted_row.rs new file mode 100644 index 0000000..26be188 --- /dev/null +++ b/minisql/src/restricted_row.rs @@ -0,0 +1,35 @@ +use std::ops::Index; +use std::slice::SliceIndex; +use crate::internals::row::ColumnPosition; +use crate::type_system::Value; + +#[derive(Debug, Clone)] +pub struct RestrictedRow(Vec<(ColumnPosition, Value)>); + +impl Index for RestrictedRow +where + Idx: SliceIndex<[(ColumnPosition, Value)]>, +{ + type Output = Idx::Output; + + fn index(&self, index: Idx) -> &Self::Output { + &self.0[index] + } +} + +impl From> for RestrictedRow { + fn from(v: Vec<(ColumnPosition, Value)>) -> Self { + RestrictedRow(v) + } +} + +impl RestrictedRow { + pub fn len(&self) -> usize { + self.0.len() + } + + pub fn iter(&self) -> impl Iterator { + self.0.iter() + } +} +