format & clippy

This commit is contained in:
Yuriy Dupyn 2023-12-29 07:58:35 +01:00
parent 4f2c864d7a
commit 25b26acde0
10 changed files with 444 additions and 271 deletions

View file

@ -1,13 +1,12 @@
use bimap::BiMap;
use crate::result::DbResult;
use crate::type_system::{Value, DbType, IndexableValue};
use crate::internals::schema::{TableName, TableSchema, ColumnName};
use crate::internals::table::Table;
use crate::internals::row::{Row, ColumnPosition};
use crate::error::Error;
use crate::operation::{Operation, Condition, ColumnSelection};
use crate::internals::column_index::ColumnIndex;
use crate::internals::row::{ColumnPosition, Row};
use crate::internals::schema::{ColumnName, 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 `TablePosition` as index
pub type Tables = Vec<Table>;
@ -27,8 +26,7 @@ pub enum Response {
Deleted(usize), // how many were deleted
TableCreated,
IndexCreated,
}
}
impl State {
fn new() -> Self {
@ -43,24 +41,28 @@ impl State {
Some(table_position) => {
let table = &self.tables[*table_position];
Ok(table)
},
None => Err(Error::TableDoesNotExist(table_name.clone()))
}
None => Err(Error::TableDoesNotExist(table_name.clone())),
}
}
fn table_from_name_mut<'b: 'a, 'a>(&'b mut self, table_name: &TableName) -> DbResult<&'a mut Table> {
fn table_from_name_mut<'b: 'a, 'a>(
&'b mut self,
table_name: &TableName,
) -> DbResult<&'a mut Table> {
match self.table_name_position_mapping.get_by_left(table_name) {
Some(table_position) => {
let table = &mut self.tables[*table_position];
Ok(table)
},
None => Err(Error::TableDoesNotExist(table_name.clone()))
}
None => Err(Error::TableDoesNotExist(table_name.clone())),
}
}
fn attach_table(&mut self, table_name: TableName, table: Table) {
let new_table_position: TablePosition = self.tables.len();
self.table_name_position_mapping.insert(table_name, new_table_position);
self.table_name_position_mapping
.insert(table_name, new_table_position);
self.tables.push(table);
}
@ -78,72 +80,94 @@ impl State {
Select(table_name, column_selection, maybe_condition) => {
let table: &Table = self.table_from_name(&table_name)?;
let selected_column_positions: Vec<ColumnPosition> = table.schema.column_positions_from_column_selection(&column_selection)?;
let selected_column_positions: Vec<ColumnPosition> = table
.schema
.column_positions_from_column_selection(&column_selection)?;
let selected_rows = match maybe_condition {
None => table.select_all_rows(&selected_column_positions),
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 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,
)?
}
};
Ok(Response::Selected(selected_rows))
},
}
Insert(table_name, values) => {
let table: &mut Table = self.table_from_name_mut(&table_name)?;
let (id, row) = table.schema.row_from_insertion_values(values)?;
let _ = table.insert_row_at(id, row)?;
table.insert_row_at(id, row)?;
Ok(Response::Inserted)
},
}
Delete(table_name, maybe_condition) => {
let table: &mut Table = self.table_from_name_mut(&table_name)?;
let rows_affected = match maybe_condition {
None => table.delete_all_rows(),
Some(Condition::Eq(eq_column_name, value)) => {
let eq_column_position = table.schema.column_position_from_column_name(&eq_column_name)?;
let eq_column_position = table
.schema
.column_position_from_column_name(&eq_column_name)?;
table.delete_rows_where_eq(eq_column_position, value)?
}
};
Ok(Response::Deleted(rows_affected))
},
}
CreateTable(table_name, table_schema) => {
let table = Table::new(table_schema);
self.attach_table(table_name, table);
Ok(Response::TableCreated)
},
}
CreateIndex(table_name, column_name) => {
let table: &mut Table = self.table_from_name_mut(&table_name)?;
let column_position: ColumnPosition = table.schema.column_position_from_column_name(&column_name)?;
let column_position: ColumnPosition = table
.schema
.column_position_from_column_name(&column_name)?;
let mut index: ColumnIndex = ColumnIndex::new();
let _ = update_index_from_table(&mut index, &table, column_position)?;
update_index_from_table(&mut index, table, column_position)?;
table.attach_index(column_position, index);
table.attach_index(column_position, index);
Ok(Response::IndexCreated)
},
}
}
}
}
// Should be used in the case when an indexed is created after the table has existed for a
// while. In such a case you need to build the index from the already existing rows.
fn update_index_from_table(column_index: &mut ColumnIndex, table: &Table, column_position: ColumnPosition) -> DbResult<()> {
fn update_index_from_table(
column_index: &mut ColumnIndex,
table: &Table,
column_position: ColumnPosition,
) -> DbResult<()> {
for (id, row) in &table.rows {
let value = match row.get(column_position) {
Some(Value::Indexable(value)) => {
value.clone()
},
Some(Value::Indexable(value)) => value.clone(),
Some(_) => {
let column_name: ColumnName = table.schema.column_name_from_column_position(column_position)?;
return Err(Error::AttemptToIndexNonIndexableColumn(table.schema.table_name.to_string(), column_name))
},
let column_name: ColumnName = table
.schema
.column_name_from_column_position(column_position)?;
return Err(Error::AttemptToIndexNonIndexableColumn(
table.schema.table_name.to_string(),
column_name,
));
}
None => {
return Err(Error::ColumnPositionDoesNotExist(table.schema.table_name.to_string(), column_position))
return Err(Error::ColumnPositionDoesNotExist(
table.schema.table_name.to_string(),
column_position,
))
}
};
column_index.add(value, *id)
@ -153,10 +177,9 @@ fn update_index_from_table(column_index: &mut ColumnIndex, table: &Table, column
// TODO: Give a better name to something that you can respond to with rows
trait SqlResponseConsumer {
// TODO:
// TODO:
}
#[cfg(test)]
mod tests {
use super::*;
@ -176,7 +199,7 @@ mod tests {
mapping.insert("age".to_string(), age);
mapping
},
types: vec![DbType::UUID, DbType::String, DbType::Int],
types: vec![DbType::Uuid, DbType::String, DbType::Int],
}
}
@ -186,7 +209,9 @@ mod tests {
let users_schema = users_schema();
let users = users_schema.table_name.clone();
state.interpret(Operation::CreateTable(users.clone(), users_schema)).unwrap();
state
.interpret(Operation::CreateTable(users.clone(), users_schema))
.unwrap();
assert!(state.tables.len() == 1);
let table = &state.tables[0];
@ -201,48 +226,68 @@ mod tests {
let users_schema = users_schema();
let users = users_schema.table_name.clone();
state.interpret(Operation::CreateTable(users.clone(), users_schema)).unwrap();
let response: Response = state.interpret(Operation::Select(users.clone(), ColumnSelection::All, None)).unwrap();
state
.interpret(Operation::CreateTable(users.clone(), users_schema))
.unwrap();
let response: Response = state
.interpret(Operation::Select(users.clone(), ColumnSelection::All, None))
.unwrap();
assert!(matches!(response, Response::Selected(_)));
let Response::Selected(rows) = response else { todo!() };
let Response::Selected(rows) = response else {
todo!()
};
assert!(rows.len() == 0);
}
#[test]
fn test_select_nonexistant_table() {
let mut state = State::new();
let response: DbResult<Response> = state.interpret(Operation::Select("table_that_doesnt_exist".to_string(), ColumnSelection::All, None));
let response: DbResult<Response> = state.interpret(Operation::Select(
"table_that_doesnt_exist".to_string(),
ColumnSelection::All,
None,
));
assert!(matches!(response, Err(Error::TableDoesNotExist(_))));
}
#[test]
fn test_insert_select_basic1() {
use Value::*;
use IndexableValue::*;
use Value::*;
let mut state = State::new();
let users_schema = users_schema();
let users = users_schema.table_name.clone();
state.interpret(Operation::CreateTable(users.clone(), users_schema)).unwrap();
state
.interpret(Operation::CreateTable(users.clone(), users_schema))
.unwrap();
let (id, name, age) = (
Indexable(UUID(0)),
Indexable(Uuid(0)),
Indexable(String("Plato".to_string())),
Indexable(Int(64))
Indexable(Int(64)),
);
state.interpret(Operation::Insert(users.clone(), vec![
("id".to_string(), id.clone()),
("name".to_string(), name.clone()),
("age".to_string(), age.clone()),
])).unwrap();
state
.interpret(Operation::Insert(
users.clone(),
vec![
("id".to_string(), id.clone()),
("name".to_string(), name.clone()),
("age".to_string(), age.clone()),
],
))
.unwrap();
let response: Response = state.interpret(Operation::Select(users.clone(), ColumnSelection::All, None)).unwrap();
let response: Response = state
.interpret(Operation::Select(users.clone(), ColumnSelection::All, None))
.unwrap();
assert!(matches!(response, Response::Selected(_)));
let Response::Selected(rows) = response else { todo!() };
let Response::Selected(rows) = response else {
todo!()
};
assert!(rows.len() == 1);
let row = &rows[0];
@ -254,45 +299,59 @@ mod tests {
#[test]
fn test_insert_select_basic2() {
use Value::*;
use IndexableValue::*;
use Operation::*;
use ColumnSelection::*;
use Condition::*;
use IndexableValue::*;
use Operation::*;
use Value::*;
let mut state = State::new();
let users_schema = users_schema();
let users = users_schema.table_name.clone();
state.interpret(CreateTable(users.clone(), users_schema)).unwrap();
state
.interpret(CreateTable(users.clone(), users_schema))
.unwrap();
let (id0, name0, age0) = (
Indexable(UUID(0)),
Indexable(Uuid(0)),
Indexable(String("Plato".to_string())),
Indexable(Int(64))
Indexable(Int(64)),
);
state.interpret(Insert(users.clone(), vec![
("id".to_string(), id0.clone()),
("name".to_string(), name0.clone()),
("age".to_string(), age0.clone()),
])).unwrap();
state
.interpret(Insert(
users.clone(),
vec![
("id".to_string(), id0.clone()),
("name".to_string(), name0.clone()),
("age".to_string(), age0.clone()),
],
))
.unwrap();
let (id1, name1, age1) = (
Indexable(UUID(1)),
Indexable(Uuid(1)),
Indexable(String("Aristotle".to_string())),
Indexable(Int(20))
Indexable(Int(20)),
);
state.interpret(Insert(users.clone(), vec![
("id".to_string(), id1.clone()),
("name".to_string(), name1.clone()),
("age".to_string(), age1.clone()),
])).unwrap();
state
.interpret(Insert(
users.clone(),
vec![
("id".to_string(), id1.clone()),
("name".to_string(), name1.clone()),
("age".to_string(), age1.clone()),
],
))
.unwrap();
{
let response: Response = state.interpret(Select(users.clone(), All, None)).unwrap();
assert!(matches!(response, Response::Selected(_)));
let Response::Selected(rows) = response else { todo!() };
let Response::Selected(rows) = response else {
todo!()
};
assert!(rows.len() == 2);
let row0 = &rows[0];
let row1 = &rows[1];
@ -309,9 +368,17 @@ mod tests {
}
{
let response: Response = state.interpret(Select(users.clone(), All, Some(Eq("id".to_string(), id0.clone())))).unwrap();
let response: Response = state
.interpret(Select(
users.clone(),
All,
Some(Eq("id".to_string(), id0.clone())),
))
.unwrap();
assert!(matches!(response, Response::Selected(_)));
let Response::Selected(rows) = response else { todo!() };
let Response::Selected(rows) = response else {
todo!()
};
assert!(rows.len() == 1);
let row0 = &rows[0];
@ -322,9 +389,17 @@ mod tests {
}
{
let response: Response = state.interpret(Select(users.clone(), Columns(vec!["name".to_string(), "id".to_string()]), Some(Eq("id".to_string(), id0.clone())))).unwrap();
let response: Response = state
.interpret(Select(
users.clone(),
Columns(vec!["name".to_string(), "id".to_string()]),
Some(Eq("id".to_string(), id0.clone())),
))
.unwrap();
assert!(matches!(response, Response::Selected(_)));
let Response::Selected(rows) = response else { todo!() };
let Response::Selected(rows) = response else {
todo!()
};
assert!(rows.len() == 1);
let row0 = &rows[0];
@ -336,48 +411,66 @@ mod tests {
#[test]
fn test_delete() {
use Value::*;
use IndexableValue::*;
use Operation::*;
use ColumnSelection::*;
use Condition::*;
use IndexableValue::*;
use Operation::*;
use Value::*;
let mut state = State::new();
let users_schema = users_schema();
let users = users_schema.table_name.clone();
state.interpret(CreateTable(users.clone(), users_schema)).unwrap();
state
.interpret(CreateTable(users.clone(), users_schema))
.unwrap();
let (id0, name0, age0) = (
Indexable(UUID(0)),
Indexable(Uuid(0)),
Indexable(String("Plato".to_string())),
Indexable(Int(64))
Indexable(Int(64)),
);
state.interpret(Insert(users.clone(), vec![
("id".to_string(), id0.clone()),
("name".to_string(), name0.clone()),
("age".to_string(), age0.clone()),
])).unwrap();
state
.interpret(Insert(
users.clone(),
vec![
("id".to_string(), id0.clone()),
("name".to_string(), name0.clone()),
("age".to_string(), age0.clone()),
],
))
.unwrap();
let (id1, name1, age1) = (
Indexable(UUID(1)),
Indexable(Uuid(1)),
Indexable(String("Aristotle".to_string())),
Indexable(Int(20))
Indexable(Int(20)),
);
state.interpret(Insert(users.clone(), vec![
("id".to_string(), id1.clone()),
("name".to_string(), name1.clone()),
("age".to_string(), age1.clone()),
])).unwrap();
state
.interpret(Insert(
users.clone(),
vec![
("id".to_string(), id1.clone()),
("name".to_string(), name1.clone()),
("age".to_string(), age1.clone()),
],
))
.unwrap();
let delete_response: Response = state.interpret(Delete(users.clone(), Some(Eq("id".to_string(), id0.clone())))).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 response: Response = state.interpret(Select(users.clone(), All, None)).unwrap();
assert!(matches!(response, Response::Selected(_)));
let Response::Selected(rows) = response else { todo!() };
let Response::Selected(rows) = response else {
todo!()
};
assert!(rows.len() == 1);
let row = &rows[0];
@ -390,13 +483,12 @@ mod tests {
// TODO: Test CreateIndex
}
pub fn example() {
use Value::*;
use IndexableValue::*;
use Operation::*;
use ColumnSelection::*;
use Condition::*;
use IndexableValue::*;
use Operation::*;
use Value::*;
let users_schema = {
let id: ColumnPosition = 0;
@ -413,60 +505,89 @@ pub fn example() {
mapping.insert("age".to_string(), age);
mapping
},
types: vec![DbType::UUID, DbType::String, DbType::Int],
types: vec![DbType::Uuid, DbType::String, DbType::Int],
}
};
let users = users_schema.table_name.clone();
let mut state = State::new();
state.interpret(Operation::CreateTable(users.clone(), users_schema)).unwrap();
state
.interpret(Operation::CreateTable(users.clone(), users_schema))
.unwrap();
let (id0, name0, age0) = (
Indexable(UUID(0)),
Indexable(Uuid(0)),
Indexable(String("Plato".to_string())),
Indexable(Int(64))
Indexable(Int(64)),
);
println!("==INSERT Plato==");
state.interpret(Insert(users.clone(), vec![
("id".to_string(), id0.clone()),
("name".to_string(), name0.clone()),
("age".to_string(), age0.clone()),
])).unwrap();
state
.interpret(Insert(
users.clone(),
vec![
("id".to_string(), id0.clone()),
("name".to_string(), name0.clone()),
("age".to_string(), age0.clone()),
],
))
.unwrap();
let (id1, name1, age1) = (
Indexable(UUID(1)),
Indexable(Uuid(1)),
Indexable(String("Aristotle".to_string())),
Indexable(Int(20))
Indexable(Int(20)),
);
println!("==INSERT Aristotle==");
state.interpret(Insert(users.clone(), vec![
("id".to_string(), id1.clone()),
("name".to_string(), name1.clone()),
("age".to_string(), age1.clone()),
])).unwrap();
state
.interpret(Insert(
users.clone(),
vec![
("id".to_string(), id1.clone()),
("name".to_string(), name1.clone()),
("age".to_string(), age1.clone()),
],
))
.unwrap();
println!();
{
let response: Response = state.interpret(Operation::Select(users.clone(), ColumnSelection::All, None)).unwrap();
let response: Response = state
.interpret(Operation::Select(users.clone(), ColumnSelection::All, None))
.unwrap();
println!("==SELECT ALL==");
println!("{:?}", response);
println!();
}
{
let response: Response = state.interpret(Select(users.clone(), All, Some(Eq("id".to_string(), id0.clone())))).unwrap();
let response: Response = state
.interpret(Select(
users.clone(),
All,
Some(Eq("id".to_string(), id0.clone())),
))
.unwrap();
println!("==SELECT Plato==");
println!("{:?}", response);
println!();
}
{
let _delete_response: Response = state.interpret(Delete(users.clone(), Some(Eq("id".to_string(), id0.clone())))).unwrap();
let _delete_response: Response = state
.interpret(Delete(
users.clone(),
Some(Eq("id".to_string(), id0.clone())),
))
.unwrap();
println!("==DELETE Plato==");
let response: Response = state.interpret(Select(users.clone(), Columns(vec!["name".to_string(), "id".to_string()]), None)).unwrap();
let response: Response = state
.interpret(Select(
users.clone(),
Columns(vec!["name".to_string(), "id".to_string()]),
None,
))
.unwrap();
println!("==SELECT All==");
println!("{:?}", response);
println!();
}
}