Merge branch 'interpreter-iterator' into 'main'

Make interpreter return an iterator of rows

See merge request x433485/minisql!7
This commit is contained in:
Yuriy Dupyn 2024-01-21 08:39:39 +01:00
commit 143dc0e5ce
2 changed files with 88 additions and 59 deletions

View file

@ -67,37 +67,40 @@ impl Table {
.collect() .collect()
} }
pub fn select_all_rows(&self, selected_column_positions: &Vec<ColumnPosition>) -> Vec<Row> { pub fn select_all_rows<'a>(&'a self, selected_column_positions: Vec<ColumnPosition>) -> impl Iterator<Item=Row> + 'a {
self.rows self.rows
.values() .values()
.map(|row| row.restrict_columns(selected_column_positions)) .map(move |row| row.restrict_columns(&selected_column_positions))
.collect()
} }
pub fn select_rows_where_eq( pub fn select_rows_where_eq<'a>(
&self, &'a self,
selected_column_positions: &Vec<ColumnPosition>, selected_column_positions: Vec<ColumnPosition>,
column_position: ColumnPosition, column_position: ColumnPosition,
value: Value, value: Value,
) -> DbResult<Vec<Row>> { ) -> DbResult<impl Iterator<Item=Row> + 'a> {
let restrict_columns_of_row = move |row: Row| row.restrict_columns(&selected_column_positions);
match value { match value {
Value::Indexable(value) => match self.fetch_ids_from_index(column_position, &value)? { Value::Indexable(value) => match self.fetch_ids_from_index(column_position, &value)? {
Some(ids) => Ok(self Some(ids) =>
.get_rows_by_ids(ids) Ok(self
.iter() .get_rows_by_ids(ids)
.map(|row| row.restrict_columns(selected_column_positions)) .into_iter()
.collect()), .map(restrict_columns_of_row)
None => Ok(self ),
.get_rows_by_value(column_position, &Value::Indexable(value)) None =>
.iter() Ok(self
.map(|row| row.restrict_columns(selected_column_positions)) .get_rows_by_value(column_position, &Value::Indexable(value))
.collect()), .into_iter()
.map(restrict_columns_of_row)
),
}, },
_ => Ok(self _ =>
.get_rows_by_value(column_position, &value) Ok(self
.iter() .get_rows_by_value(column_position, &value)
.map(|row| row.restrict_columns(selected_column_positions)) .into_iter()
.collect()), .map(restrict_columns_of_row)
),
} }
} }

View file

@ -18,15 +18,35 @@ pub struct State {
tables: Tables, tables: Tables,
} }
#[derive(Debug)] // #[derive(Debug)]
pub enum Response { pub enum Response<'a> {
Selected(Vec<Row>), Selected(Box<dyn Iterator<Item=Row> + 'a>),
Inserted, Inserted,
Deleted(usize), // how many were deleted Deleted(usize), // how many were deleted
TableCreated, TableCreated,
IndexCreated, 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 { impl State {
fn new() -> Self { fn new() -> Self {
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) { match self.table_name_position_mapping.get_by_left(table_name) {
Some(table_position) => { Some(table_position) => {
let table = &self.tables[*table_position]; let table = &self.tables[*table_position];
@ -65,13 +85,7 @@ impl State {
self.tables.push(table); self.tables.push(table);
} }
// TODO: Decide if we want for this to return a response (but then you have to deal with lifetimes, pub fn interpret<'a>(&'a mut self, operation: Operation) -> DbResult<Response<'a>> {
// 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<Response> {
// TODO: lock stuff // TODO: lock stuff
use Operation::*; use Operation::*;
@ -83,17 +97,22 @@ impl State {
.schema() .schema()
.column_positions_from_column_selection(&column_selection)?; .column_positions_from_column_selection(&column_selection)?;
let selected_rows = match maybe_condition { 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<dyn Iterator<Item=Row> + 'a>
},
Some(Condition::Eq(eq_column_name, value)) => { Some(Condition::Eq(eq_column_name, value)) => {
let eq_column_position = table let eq_column_position = table
.schema() .schema()
.column_position_from_column_name(&eq_column_name)?; .column_position_from_column_name(&eq_column_name)?;
table.select_rows_where_eq( let x =
&selected_column_positions, table.select_rows_where_eq(
eq_column_position, selected_column_positions,
value, eq_column_position,
)? value,
)?;
Box::new(x) as Box<dyn Iterator<Item=Row> + '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)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -198,8 +212,9 @@ mod tests {
.unwrap(); .unwrap();
assert!(matches!(response, Response::Selected(_))); assert!(matches!(response, Response::Selected(_)));
let Response::Selected(rows) = response else { let Response::Selected(rows) = response else {
todo!() panic!()
}; };
let rows: Vec<_> = rows.collect();
assert!(rows.len() == 0); assert!(rows.len() == 0);
} }
@ -250,8 +265,9 @@ mod tests {
assert!(matches!(response, Response::Selected(_))); assert!(matches!(response, Response::Selected(_)));
let Response::Selected(rows) = response else { let Response::Selected(rows) = response else {
todo!() panic!()
}; };
let rows: Vec<_> = rows.collect();
assert!(rows.len() == 1); assert!(rows.len() == 1);
let row = &rows[0]; let row = &rows[0];
@ -314,8 +330,9 @@ mod tests {
assert!(matches!(response, Response::Selected(_))); assert!(matches!(response, Response::Selected(_)));
let Response::Selected(rows) = response else { let Response::Selected(rows) = response else {
todo!() panic!()
}; };
let rows: Vec<_> = rows.collect();
assert!(rows.len() == 2); assert!(rows.len() == 2);
let row0 = &rows[0]; let row0 = &rows[0];
let row1 = &rows[1]; let row1 = &rows[1];
@ -341,8 +358,9 @@ mod tests {
.unwrap(); .unwrap();
assert!(matches!(response, Response::Selected(_))); assert!(matches!(response, Response::Selected(_)));
let Response::Selected(rows) = response else { let Response::Selected(rows) = response else {
todo!() panic!()
}; };
let rows: Vec<_> = rows.collect();
assert!(rows.len() == 1); assert!(rows.len() == 1);
let row0 = &rows[0]; let row0 = &rows[0];
@ -362,8 +380,9 @@ mod tests {
.unwrap(); .unwrap();
assert!(matches!(response, Response::Selected(_))); assert!(matches!(response, Response::Selected(_)));
let Response::Selected(rows) = response else { let Response::Selected(rows) = response else {
todo!() panic!()
}; };
let rows: Vec<_> = rows.collect();
assert!(rows.len() == 1); assert!(rows.len() == 1);
let row0 = &rows[0]; let row0 = &rows[0];
@ -421,20 +440,23 @@ mod tests {
)) ))
.unwrap(); .unwrap();
let delete_response: Response = state {
.interpret(Delete( let delete_response: Response = state
users.clone(), .interpret(Delete(
Some(Eq("id".to_string(), id0.clone())), users.clone(),
)) Some(Eq("id".to_string(), id0.clone())),
.unwrap(); ))
assert!(matches!(delete_response, Response::Deleted(1))); .unwrap();
assert!(matches!(delete_response, Response::Deleted(1)));
}
let response: Response = state.interpret(Select(users.clone(), All, None)).unwrap(); let response: Response = state.interpret(Select(users.clone(), All, None)).unwrap();
assert!(matches!(response, Response::Selected(_))); assert!(matches!(response, Response::Selected(_)));
let Response::Selected(rows) = response else { let Response::Selected(rows) = response else {
todo!() panic!()
}; };
let rows: Vec<_> = rows.collect();
assert!(rows.len() == 1); assert!(rows.len() == 1);
let row = &rows[0]; 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( .interpret(Delete(
users.clone(), users.clone(),
Some(Eq("id".to_string(), id0.clone())), Some(Eq("id".to_string(), id0.clone())),
)) ))
.unwrap(); .unwrap();
println!("==DELETE Plato=="); println!("==DELETE Plato==");
}
let response: Response = state let response: Response = state
.interpret(Select( .interpret(Select(
users.clone(), users.clone(),