Now interpreter returns an iterator

This commit is contained in:
Yuriy Dupyn 2024-01-20 15:08:18 +01:00
parent 430d092def
commit ddf17ae0a5
2 changed files with 88 additions and 59 deletions

View file

@ -18,15 +18,35 @@ pub struct State {
tables: Tables,
}
#[derive(Debug)]
pub enum Response {
Selected(Vec<Row>),
// #[derive(Debug)]
pub enum Response<'a> {
Selected(Box<dyn Iterator<Item=Row> + '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<Response> {
pub fn interpret<'a>(&'a mut self, operation: Operation) -> DbResult<Response<'a>> {
// 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<dyn Iterator<Item=Row> + '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<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)]
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(),