diff --git a/minisql/src/internals/table.rs b/minisql/src/internals/table.rs index 914d1ef..2b5a5bc 100644 --- a/minisql/src/internals/table.rs +++ b/minisql/src/internals/table.rs @@ -67,37 +67,40 @@ impl Table { .collect() } - pub fn select_all_rows(&self, selected_column_positions: &Vec) -> Vec { + pub fn select_all_rows<'a>(&'a self, selected_column_positions: Vec) -> impl Iterator + 'a { self.rows .values() - .map(|row| row.restrict_columns(selected_column_positions)) - .collect() + .map(move |row| row.restrict_columns(&selected_column_positions)) } - pub fn select_rows_where_eq( - &self, - selected_column_positions: &Vec, + pub fn select_rows_where_eq<'a>( + &'a self, + selected_column_positions: Vec, column_position: ColumnPosition, value: Value, - ) -> DbResult> { + ) -> 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)? { - 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()), + Some(ids) => + Ok(self + .get_rows_by_ids(ids) + .into_iter() + .map(restrict_columns_of_row) + ), + None => + Ok(self + .get_rows_by_value(column_position, &Value::Indexable(value)) + .into_iter() + .map(restrict_columns_of_row) + ), }, - _ => 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) + .into_iter() + .map(restrict_columns_of_row) + ), } } diff --git a/minisql/src/interpreter.rs b/minisql/src/interpreter.rs index 7a3bad3..84f2494 100644 --- a/minisql/src/interpreter.rs +++ b/minisql/src/interpreter.rs @@ -18,15 +18,35 @@ pub struct State { tables: Tables, } -#[derive(Debug)] -pub enum Response { - Selected(Vec), +// #[derive(Debug)] +pub enum Response<'a> { + Selected(Box + 'a>), Inserted, Deleted(usize), // how many were deleted TableCreated, IndexCreated, } +impl std::fmt::Debug for Response<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + use Response::*; + match self { + Selected(_rows) => + // TODO: How can we iterate through the rows without having to take ownership of + // them? + f.write_str("Some rows... trust me"), + Inserted => + f.write_str("Inserted"), + Deleted(usize) => + f.write_fmt(format_args!("Deleted({})", usize)), + TableCreated => + f.write_str("TableCreated"), + IndexCreated => + f.write_str("IndexCreated"), + } + } +} + impl State { fn new() -> Self { Self { @@ -35,7 +55,7 @@ impl State { } } - fn table_from_name<'b: 'a, 'a>(&'b self, table_name: &TableName) -> DbResult<&'a Table> { + fn table_from_name<'a>(&'a self, table_name: &TableName) -> DbResult<&'a Table> { match self.table_name_position_mapping.get_by_left(table_name) { Some(table_position) => { let table = &self.tables[*table_position]; @@ -65,13 +85,7 @@ impl State { self.tables.push(table); } - // TODO: Decide if we want for this to return a response (but then you have to deal with lifetimes, - // because you'll be forced to put an iterator/slice into the Response data-structure. - // Alternative is to pass a row-consumer to the functionas that knows how to communicate with - // the client, but the details of communication are hidden behind an interface - // - // writer: impl SqlResponseConsumer - pub fn interpret(&mut self, operation: Operation) -> DbResult { + pub fn interpret<'a>(&'a mut self, operation: Operation) -> DbResult> { // TODO: lock stuff use Operation::*; @@ -83,17 +97,22 @@ impl State { .schema() .column_positions_from_column_selection(&column_selection)?; let selected_rows = match maybe_condition { - None => table.select_all_rows(&selected_column_positions), + None => { + let x = table.select_all_rows(selected_column_positions); + Box::new(x) as Box + 'a> + }, 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 x = + table.select_rows_where_eq( + selected_column_positions, + eq_column_position, + value, + )?; + Box::new(x) as Box + 'a> } }; @@ -140,11 +159,6 @@ impl State { } } -// TODO: Give a better name to something that you can respond to with rows -trait SqlResponseConsumer { - // TODO: -} - #[cfg(test)] mod tests { use super::*; @@ -198,8 +212,9 @@ mod tests { .unwrap(); assert!(matches!(response, Response::Selected(_))); let Response::Selected(rows) = response else { - todo!() + panic!() }; + let rows: Vec<_> = rows.collect(); assert!(rows.len() == 0); } @@ -250,8 +265,9 @@ mod tests { assert!(matches!(response, Response::Selected(_))); let Response::Selected(rows) = response else { - todo!() + panic!() }; + let rows: Vec<_> = rows.collect(); assert!(rows.len() == 1); let row = &rows[0]; @@ -314,8 +330,9 @@ mod tests { assert!(matches!(response, Response::Selected(_))); let Response::Selected(rows) = response else { - todo!() + panic!() }; + let rows: Vec<_> = rows.collect(); assert!(rows.len() == 2); let row0 = &rows[0]; let row1 = &rows[1]; @@ -341,8 +358,9 @@ mod tests { .unwrap(); assert!(matches!(response, Response::Selected(_))); let Response::Selected(rows) = response else { - todo!() + panic!() }; + let rows: Vec<_> = rows.collect(); assert!(rows.len() == 1); let row0 = &rows[0]; @@ -362,8 +380,9 @@ mod tests { .unwrap(); assert!(matches!(response, Response::Selected(_))); let Response::Selected(rows) = response else { - todo!() + panic!() }; + let rows: Vec<_> = rows.collect(); assert!(rows.len() == 1); let row0 = &rows[0]; @@ -421,20 +440,23 @@ mod tests { )) .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 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!() + panic!() }; + let rows: Vec<_> = rows.collect(); assert!(rows.len() == 1); let row = &rows[0]; @@ -600,13 +622,17 @@ pub fn example() { } { - let _delete_response: Response = state + { + // TODO: Why do I have to write these braces explicitely? Why doesn't Rust compiler + // "infer" them? + let _delete_response: Response = state .interpret(Delete( users.clone(), Some(Eq("id".to_string(), id0.clone())), )) .unwrap(); - println!("==DELETE Plato=="); + println!("==DELETE Plato=="); + } let response: Response = state .interpret(Select( users.clone(),