First attempt at UPDATE

This commit is contained in:
Yuriy Dupyn 2023-12-11 20:07:04 +01:00
parent 20615508a2
commit e0876bb0f1
3 changed files with 124 additions and 9 deletions

9
Cargo.lock generated
View file

@ -2,6 +2,15 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "bimap"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "230c5f1ca6a325a32553f8640d31ac9b49f2411e901e427570154868b46da4f7"
[[package]] [[package]]
name = "minisql" name = "minisql"
version = "0.1.0" version = "0.1.0"
dependencies = [
"bimap",
]

View file

@ -6,3 +6,4 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
bimap = "0.6.3"

View file

@ -1,4 +1,5 @@
use std::collections::{BTreeMap, HashMap, HashSet}; use std::collections::{BTreeMap, HashMap, HashSet};
use bimap::BiMap;
// ==============SQL operations================ // ==============SQL operations================
// TODO: Note that every operation has a table name. // TODO: Note that every operation has a table name.
@ -112,7 +113,8 @@ struct ColumnIndex {
struct TableSchema { struct TableSchema {
table_name: TableName, // used for descriptive errors table_name: TableName, // used for descriptive errors
primary_key: ColumnPosition, primary_key: ColumnPosition,
columns: HashMap<ColumnName, (DbType, ColumnPosition)> column_name_position_mapping: BiMap<ColumnName, ColumnPosition>,
types: Vec<DbType>,
} }
// TODO // TODO
@ -219,8 +221,17 @@ impl ColumnIndex {
impl TableSchema { impl TableSchema {
fn get_column(&self, column_name: &ColumnName) -> DbResult<(DbType, ColumnPosition)> { fn get_column(&self, column_name: &ColumnName) -> DbResult<(DbType, ColumnPosition)> {
match self.columns.get(column_name) { match self.column_name_position_mapping.get_by_left(column_name) {
Some((type_, column_position)) => Ok((*type_, *column_position)), Some(column_position) => {
match self.types.get(*column_position) {
Some(type_) => {
Ok((*type_, *column_position))
},
None => {
Err(Error::MissingTypeAnnotationOfColumn(self.table_name.clone(), *column_position))
}
}
},
None => Err(Error::ColumnDoesNotExist(self.table_name.clone(), column_name.clone())) None => Err(Error::ColumnDoesNotExist(self.table_name.clone(), column_name.clone()))
} }
} }
@ -238,10 +249,17 @@ impl TableSchema {
Ok(positions) Ok(positions)
} }
fn column_name_from_column_position(&self, column_position: ColumnPosition) -> DbResult<ColumnName> {
match self.column_name_position_mapping.get_by_right(&column_position) {
Some(column_name) => Ok(column_name.clone()),
None => Err(Error::ColumnPositionDoesNotExist(self.table_name.clone(), column_position))
}
}
fn column_positions_from_column_selection(&self, column_selection: &ColumnSelection) -> DbResult<Vec<ColumnPosition>> { fn column_positions_from_column_selection(&self, column_selection: &ColumnSelection) -> DbResult<Vec<ColumnPosition>> {
match column_selection { match column_selection {
ColumnSelection::All => { ColumnSelection::All => {
let mut column_positions: Vec<ColumnPosition> = self.columns.values().map(|(_, column_position)| *column_position).collect(); let mut column_positions: Vec<ColumnPosition> = self.column_name_position_mapping.iter().map(|(_, column_position)| *column_position).collect();
column_positions.sort(); column_positions.sort();
Ok(column_positions) Ok(column_positions)
}, },
@ -252,6 +270,57 @@ impl TableSchema {
} }
} }
fn number_of_columns(&self) -> usize {
self.column_name_position_mapping.len()
}
fn row_from_insertion_values(&self, insertion_values: InsertionValues) -> DbResult<(UUID, Row)> {
// TODO: There should be proper validation of the insertion_values.
// And it shouldn't really be done here.
//
// In the below we don't check for duplicate column names
//
let number_of_columns = self.number_of_columns();
if number_of_columns != insertion_values.len() {
return Err(Error::MismatchBetweenInsertValuesAndColumns(self.table_name.clone(), insertion_values))
}
let mut row: Vec<DbValue> = Vec::with_capacity(number_of_columns);
let mut values: HashMap<ColumnName, DbValue> = HashMap::new();
for (column_name, db_value) in &insertion_values {
values.insert(column_name.clone(), db_value.clone());
}
for column_position in 0..number_of_columns {
let column_name: ColumnName = self.column_name_from_column_position(column_position)?;
match values.get(&column_name) {
Some(db_value) => {
row.push(db_value.clone())
},
None => {
return Err(Error::MissingColumnInInsertValues(self.table_name.clone(), column_name, insertion_values))
}
}
}
let id = match row.get(self.primary_key) {
Some(val) => {
match val {
DbValue::Indexable(IndexableDbValue::UUID(id)) => {
id
},
_ =>
unreachable!()
}
},
None =>
unreachable!()
};
Ok((*id, row))
}
} }
impl Table { impl Table {
@ -324,10 +393,25 @@ impl Table {
} }
} }
fn insert(&mut self, values: InsertionValues) { fn insert(&mut self, values: InsertionValues) -> DbResult<()> {
// 1. You need to update indices let (id, row) = self.schema.row_from_insertion_values(values)?;
// 2. you simply insert the data
todo!() if self.rows.get(&id).is_some() {
return Err(Error::AttemptingToInsertAlreadyPresentId(self.schema.table_name.clone(), id))
}
for (column_position, column_index) in &mut self.indexes {
match row.get(*column_position) {
Some(DbValue::Indexable(val)) => {
column_index.add(val.clone(), id)
},
Some(_) => {},
None => return Err(Error::ColumnPositionDoesNotExist(self.schema.table_name.clone(), *column_position))
}
}
let _ = self.rows.insert(id, row);
Ok(())
} }
fn delete_where(&mut self, maybe_condition: Option<Condition>) { fn delete_where(&mut self, maybe_condition: Option<Condition>) {
@ -344,6 +428,21 @@ impl ColumnIndex {
None => HashSet::new(), None => HashSet::new(),
} }
} }
fn add(&mut self, value: IndexableDbValue, id: UUID) {
match self.index.get_mut(&value) {
Some(ids) => {
ids.insert(id);
},
None => {
self.index.insert(value, HashSet::from([id]));
}
}
}
fn remove(&mut self, id: UUID) {
todo!()
}
} }
enum Response { enum Response {
@ -354,9 +453,15 @@ enum Response {
type DbResult<A> = Result<A, Error>; type DbResult<A> = Result<A, Error>;
// #[derive(Debug)]
enum Error { enum Error {
ColumnDoesNotExist(TableName, ColumnName), ColumnDoesNotExist(TableName, ColumnName),
ValueDoesNotMatchExpectedType(TableName, ColumnName, DbType, DbValue) ColumnPositionDoesNotExist(TableName, ColumnPosition),
ValueDoesNotMatchExpectedType(TableName, ColumnName, DbType, DbValue),
AttemptingToInsertAlreadyPresentId(TableName, UUID),
MissingTypeAnnotationOfColumn(TableName, ColumnPosition),
MissingColumnInInsertValues(TableName, ColumnName, InsertionValues),
MismatchBetweenInsertValuesAndColumns(TableName, InsertionValues),
} }
fn main() { fn main() {