Reorganization

This commit is contained in:
Yuriy Dupyn 2023-12-29 07:39:59 +01:00
parent f7a6cc2549
commit e9d3df7a22
10 changed files with 140 additions and 141 deletions

View file

@ -1,5 +1,6 @@
use crate::base::{ColumnName, TableName, ColumnPosition}; use crate::internals::schema::{ColumnName, TableName};
use crate::type_system::{DbType, DbValue, UUID}; use crate::internals::row::ColumnPosition;
use crate::type_system::{DbType, Value, UUID};
use crate::operation::InsertionValues; use crate::operation::InsertionValues;
#[derive(Debug)] #[derive(Debug)]
@ -7,7 +8,7 @@ pub enum Error {
TableDoesNotExist(TableName), TableDoesNotExist(TableName),
ColumnDoesNotExist(TableName, ColumnName), ColumnDoesNotExist(TableName, ColumnName),
ColumnPositionDoesNotExist(TableName, ColumnPosition), ColumnPositionDoesNotExist(TableName, ColumnPosition),
ValueDoesNotMatchExpectedType(TableName, ColumnName, DbType, DbValue), ValueDoesNotMatchExpectedType(TableName, ColumnName, DbType, Value),
AttemptingToInsertAlreadyPresentId(TableName, UUID), AttemptingToInsertAlreadyPresentId(TableName, UUID),
MissingTypeAnnotationOfColumn(TableName, ColumnPosition), MissingTypeAnnotationOfColumn(TableName, ColumnPosition),
MissingColumnInInsertValues(TableName, ColumnName, InsertionValues), MissingColumnInInsertValues(TableName, ColumnName, InsertionValues),

View file

@ -1,12 +1,13 @@
use std::collections::{BTreeMap, HashSet}; use std::collections::{BTreeMap, HashSet};
use crate::base::{ColumnPosition, ColumnName, DbResult}; use crate::type_system::{UUID, Value, IndexableValue};
use crate::type_system::{UUID, DbValue, IndexableDbValue}; use crate::internals::schema::{ColumnName, DbResult};
use crate::table::Table; use crate::internals::table::Table;
use crate::internals::row::ColumnPosition;
use crate::error::Error; use crate::error::Error;
#[derive(Debug)] #[derive(Debug)]
pub struct ColumnIndex { pub struct ColumnIndex {
index: BTreeMap<IndexableDbValue, HashSet<UUID>> index: BTreeMap<IndexableValue, HashSet<UUID>>
} }
impl ColumnIndex { impl ColumnIndex {
@ -15,14 +16,14 @@ impl ColumnIndex {
Self { index } Self { index }
} }
pub fn get(&self, value: &IndexableDbValue) -> HashSet<UUID> { pub fn get(&self, value: &IndexableValue) -> HashSet<UUID> {
match self.index.get(value) { match self.index.get(value) {
Some(set) => set.clone(), Some(set) => set.clone(),
None => HashSet::new(), None => HashSet::new(),
} }
} }
pub fn add(&mut self, value: IndexableDbValue, id: UUID) { pub fn add(&mut self, value: IndexableValue, id: UUID) {
match self.index.get_mut(&value) { match self.index.get_mut(&value) {
Some(ids) => { Some(ids) => {
ids.insert(id); ids.insert(id);
@ -40,7 +41,7 @@ impl ColumnIndex {
pub fn update_from_table(&mut self, table: &Table, column_position: ColumnPosition) -> DbResult<()> { pub fn update_from_table(&mut self, table: &Table, column_position: ColumnPosition) -> DbResult<()> {
for (id, row) in &table.rows { for (id, row) in &table.rows {
let value = match row.get(column_position) { let value = match row.get(column_position) {
Some(DbValue::Indexable(value)) => { Some(Value::Indexable(value)) => {
value.clone() value.clone()
}, },
Some(_) => { Some(_) => {
@ -56,7 +57,7 @@ impl ColumnIndex {
Ok(()) Ok(())
} }
pub fn remove(&mut self, value: &IndexableDbValue, id_to_be_removed: UUID) -> bool { pub fn remove(&mut self, value: &IndexableValue, id_to_be_removed: UUID) -> bool {
match self.index.get_mut(value) { match self.index.get_mut(value) {
Some(ids) => { Some(ids) => {
let was_present = ids.remove(&id_to_be_removed); let was_present = ids.remove(&id_to_be_removed);

View file

@ -0,0 +1,4 @@
pub mod table;
pub mod row;
pub mod column_index;
pub mod schema;

View file

@ -0,0 +1,74 @@
use std::slice::SliceIndex;
use std::ops::{Index, IndexMut};
use crate::type_system::Value;
pub type ColumnPosition = usize;
#[derive(Debug, Clone)]
pub struct Row(Vec<Value>);
impl<Idx> Index<Idx> for Row
where
Idx: SliceIndex<[Value]>,
{
type Output = Idx::Output;
fn index(&self, index: Idx) -> &Self::Output {
&self.0[index]
}
}
impl<Idx> IndexMut<Idx> for Row
where
Idx: SliceIndex<[Value]>,
{
fn index_mut(&mut self, index: Idx) -> &mut Self::Output {
&mut self.0[index]
}
}
impl FromIterator<Value> for Row {
fn from_iter<I: IntoIterator<Item=Value>>(iter: I) -> Self {
let mut v = vec![];
for x in iter {
v.push(x)
}
Row(v)
}
}
impl Row {
pub fn new() -> Self {
Row(vec![])
}
pub fn with_number_of_columns(number_of_columns: usize) -> Self {
Row(Vec::with_capacity(number_of_columns))
}
pub fn push(&mut self, value: Value) {
self.0.push(value)
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn get(&self, column_position: ColumnPosition) -> Option<&Value> {
self.0.get(column_position)
}
pub fn restrict_columns(&self, columns: &Vec<ColumnPosition>) -> Row {
// If the index from `columns` is non-existant in `row`, it will just ignore it.
let mut subrow: Row = Row::new();
for column_position in columns {
match self.get(*column_position) {
Some(value) => {
subrow.0.push(value.clone())
},
None => {}
}
}
subrow
}
}

View file

@ -1,8 +1,8 @@
use std::collections::HashMap; use std::collections::HashMap;
use bimap::BiMap; use bimap::BiMap;
use crate::operation::{InsertionValues, ColumnSelection}; use crate::operation::{InsertionValues, ColumnSelection};
use crate::table::Row; use crate::internals::row::{Row, ColumnPosition};
use crate::type_system::{DbType, DbValue, IndexableDbValue, UUID}; use crate::type_system::{DbType, Value, IndexableValue, UUID};
use crate::error::Error; use crate::error::Error;
// Note that it is nice to split metadata from the data because // Note that it is nice to split metadata from the data because
@ -18,7 +18,6 @@ pub struct TableSchema {
pub type TableName = String; pub type TableName = String;
pub type ColumnName = String; pub type ColumnName = String;
pub type ColumnPosition = usize;
pub type DbResult<A> = Result<A, Error>; pub type DbResult<A> = Result<A, Error>;
@ -81,7 +80,6 @@ impl TableSchema {
self.column_name_position_mapping.len() self.column_name_position_mapping.len()
} }
// TODO: IS THIS THE RIGHT PLACE?
pub fn row_from_insertion_values(&self, insertion_values: InsertionValues) -> DbResult<(UUID, Row)> { pub fn row_from_insertion_values(&self, insertion_values: InsertionValues) -> DbResult<(UUID, Row)> {
// TODO: There should be proper validation of the insertion_values. // TODO: There should be proper validation of the insertion_values.
// And it shouldn't really be done here. // And it shouldn't really be done here.
@ -95,7 +93,7 @@ impl TableSchema {
let mut row: Row = Row::with_number_of_columns(number_of_columns); let mut row: Row = Row::with_number_of_columns(number_of_columns);
let mut values: HashMap<ColumnName, DbValue> = HashMap::new(); let mut values: HashMap<ColumnName, Value> = HashMap::new();
for (column_name, db_value) in &insertion_values { for (column_name, db_value) in &insertion_values {
values.insert(column_name.clone(), db_value.clone()); values.insert(column_name.clone(), db_value.clone());
} }
@ -115,7 +113,7 @@ impl TableSchema {
let id: UUID = match row.get(self.primary_key) { let id: UUID = match row.get(self.primary_key) {
Some(val) => { Some(val) => {
match val { match val {
DbValue::Indexable(IndexableDbValue::UUID(id)) => { Value::Indexable(IndexableValue::UUID(id)) => {
*id *id
}, },
_ => _ =>

View file

@ -1,92 +1,12 @@
use std::collections::{BTreeMap, HashMap, HashSet}; use std::collections::{BTreeMap, HashMap, HashSet};
use std::slice::SliceIndex; use crate::type_system::{UUID, Value, IndexableValue};
use std::ops::{Index, IndexMut};
use crate::base::{TableSchema, ColumnPosition, ColumnName, DbResult};
use crate::type_system::{UUID, DbValue, IndexableDbValue};
use crate::column_index::ColumnIndex;
use crate::error::Error; use crate::error::Error;
use crate::internals::schema::{TableSchema, ColumnName, DbResult};
use crate::internals::row::{Row, ColumnPosition};
use crate::internals::column_index::ColumnIndex;
// ======Table Row======
pub type Rows =
// TODO: This should be some sort of an interface to a dictionary
// s.t. in the background it may modify stuff in memory or talk to the disk
BTreeMap<UUID, Row>;
// Use `ColumnPosition` as index
#[derive(Debug, Clone)]
pub struct Row(Vec<DbValue>);
impl<Idx> Index<Idx> for Row
where
Idx: SliceIndex<[DbValue]>,
{
type Output = Idx::Output;
fn index(&self, index: Idx) -> &Self::Output {
&self.0[index]
}
}
impl<Idx> IndexMut<Idx> for Row
where
Idx: SliceIndex<[DbValue]>,
{
fn index_mut(&mut self, index: Idx) -> &mut Self::Output {
&mut self.0[index]
}
}
impl FromIterator<DbValue> for Row {
fn from_iter<I: IntoIterator<Item=DbValue>>(iter: I) -> Self {
let mut v = vec![];
for x in iter {
v.push(x)
}
Row(v)
}
}
impl Row {
pub fn new() -> Self {
Row(vec![])
}
pub fn with_number_of_columns(number_of_columns: usize) -> Self {
Row(Vec::with_capacity(number_of_columns))
}
pub fn push(&mut self, value: DbValue) {
self.0.push(value)
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn get(&self, column_position: ColumnPosition) -> Option<&DbValue> {
self.0.get(column_position)
}
pub fn restrict_columns(&self, columns: &Vec<ColumnPosition>) -> Row {
// If the index from `columns` is non-existant in `row`, it will just ignore it.
let mut subrow: Row = Row::new();
for column_position in columns {
match self.get(*column_position) {
Some(value) => {
subrow.0.push(value.clone())
},
None => {}
}
}
subrow
}
}
// ======Table======
#[derive(Debug)] #[derive(Debug)]
pub struct Table { pub struct Table {
pub schema: TableSchema, pub schema: TableSchema,
@ -96,6 +16,9 @@ pub struct Table {
HashMap<ColumnPosition, ColumnIndex> HashMap<ColumnPosition, ColumnIndex>
} }
pub type Rows =
BTreeMap<UUID, Row>;
impl Table { impl Table {
pub fn new(table_schema: TableSchema) -> Self { pub fn new(table_schema: TableSchema) -> Self {
@ -117,7 +40,7 @@ impl Table {
.collect() .collect()
} }
fn get_rows_by_value(&self, column_position: ColumnPosition, value: &DbValue) -> Vec<Row> { fn get_rows_by_value(&self, column_position: ColumnPosition, value: &Value) -> Vec<Row> {
// brute-force search // brute-force search
self.rows.values() self.rows.values()
.filter_map(|row| if row.get(column_position) == Some(value) { Some(row.clone()) } else { None }) .filter_map(|row| if row.get(column_position) == Some(value) { Some(row.clone()) } else { None })
@ -128,14 +51,14 @@ impl Table {
self.rows.values().map(|row| row.restrict_columns(&selected_column_positions)).collect() self.rows.values().map(|row| row.restrict_columns(&selected_column_positions)).collect()
} }
pub fn select_rows_where_eq(&self, selected_column_positions: &Vec<ColumnPosition>, column_position: ColumnPosition, value: DbValue) -> DbResult<Vec<Row>> { pub fn select_rows_where_eq(&self, selected_column_positions: &Vec<ColumnPosition>, column_position: ColumnPosition, value: Value) -> DbResult<Vec<Row>> {
match value { match value {
DbValue::Indexable(value) => { Value::Indexable(value) => {
match self.fetch_ids_from_index(column_position, &value)? { match self.fetch_ids_from_index(column_position, &value)? {
Some(ids) => Some(ids) =>
Ok(self.get_rows_by_ids(ids).iter().map(|row| row.restrict_columns(&selected_column_positions)).collect()), Ok(self.get_rows_by_ids(ids).iter().map(|row| row.restrict_columns(&selected_column_positions)).collect()),
None => None =>
Ok(self.get_rows_by_value(column_position, &DbValue::Indexable(value)).iter().map(|row| row.restrict_columns(&selected_column_positions)).collect()) Ok(self.get_rows_by_value(column_position, &Value::Indexable(value)).iter().map(|row| row.restrict_columns(&selected_column_positions)).collect())
} }
}, },
_ => { _ => {
@ -152,7 +75,7 @@ impl Table {
for (column_position, column_index) in &mut self.indexes { for (column_position, column_index) in &mut self.indexes {
match row.get(*column_position) { match row.get(*column_position) {
Some(DbValue::Indexable(val)) => { Some(Value::Indexable(val)) => {
column_index.add(val.clone(), id) column_index.add(val.clone(), id)
}, },
Some(_) => {}, Some(_) => {},
@ -169,7 +92,7 @@ impl Table {
match self.rows.remove(&id) { match self.rows.remove(&id) {
Some(row) => { Some(row) => {
for (column_position, column_index) in &mut self.indexes { for (column_position, column_index) in &mut self.indexes {
if let DbValue::Indexable(value) = &row[*column_position] { if let Value::Indexable(value) = &row[*column_position] {
let _ = column_index.remove(value, id); let _ = column_index.remove(value, id);
}; };
} }
@ -187,7 +110,7 @@ impl Table {
total_count total_count
} }
fn delete_rows_by_value(&mut self, column_position: ColumnPosition, value: &DbValue) -> usize { fn delete_rows_by_value(&mut self, column_position: ColumnPosition, value: &Value) -> usize {
let matched_ids: HashSet<UUID> = self.rows.iter() let matched_ids: HashSet<UUID> = self.rows.iter()
.filter_map(|(id, row)| if row.get(column_position) == Some(value) { Some(*id) } else { None }) .filter_map(|(id, row)| if row.get(column_position) == Some(value) { Some(*id) } else { None })
.collect(); .collect();
@ -201,14 +124,14 @@ impl Table {
number_of_rows number_of_rows
} }
pub fn delete_rows_where_eq(&mut self, column_position: ColumnPosition, value: DbValue) -> DbResult<usize> { pub fn delete_rows_where_eq(&mut self, column_position: ColumnPosition, value: Value) -> DbResult<usize> {
match value { match value {
DbValue::Indexable(value) => { Value::Indexable(value) => {
match self.fetch_ids_from_index(column_position, &value)? { match self.fetch_ids_from_index(column_position, &value)? {
Some(ids) => Some(ids) =>
Ok(self.delete_rows_by_ids(ids)), Ok(self.delete_rows_by_ids(ids)),
None => None =>
Ok(self.delete_rows_by_value(column_position, &DbValue::Indexable(value))) Ok(self.delete_rows_by_value(column_position, &Value::Indexable(value)))
} }
}, },
_ => _ =>
@ -221,15 +144,15 @@ impl Table {
self.indexes.insert(column_position, column_index); self.indexes.insert(column_position, column_index);
} }
fn fetch_ids_from_index(&self, column_position: ColumnPosition, value: &IndexableDbValue) -> DbResult<Option<HashSet<UUID>>> { fn fetch_ids_from_index(&self, column_position: ColumnPosition, value: &IndexableValue) -> DbResult<Option<HashSet<UUID>>> {
if self.schema.is_primary(column_position) { if self.schema.is_primary(column_position) {
match value { match value {
IndexableDbValue::UUID(id) => IndexableValue::UUID(id) =>
Ok(Some(HashSet::from([*id]))), Ok(Some(HashSet::from([*id]))),
_ => { _ => {
let column_name: ColumnName = self.schema.column_name_from_column_position(column_position)?; let column_name: ColumnName = self.schema.column_name_from_column_position(column_position)?;
let type_ = self.schema.types[column_position]; let type_ = self.schema.types[column_position];
Err(Error::ValueDoesNotMatchExpectedType(self.schema.table_name.clone(), column_name, type_, DbValue::Indexable(value.clone()))) Err(Error::ValueDoesNotMatchExpectedType(self.schema.table_name.clone(), column_name, type_, Value::Indexable(value.clone())))
} }
} }
} else { } else {

View file

@ -1,10 +1,11 @@
use bimap::BiMap; use bimap::BiMap;
use crate::type_system::{DbValue, DbType, IndexableDbValue}; use crate::type_system::{Value, DbType, IndexableValue};
use crate::base::{TableName, TableSchema, ColumnPosition, ColumnName, DbResult}; use crate::internals::schema::{TableName, TableSchema, ColumnName, DbResult};
use crate::table::{Table, Row}; use crate::internals::table::Table;
use crate::internals::row::{Row, ColumnPosition};
use crate::error::Error; use crate::error::Error;
use crate::operation::{Operation, Condition, ColumnSelection}; use crate::operation::{Operation, Condition, ColumnSelection};
use crate::column_index::ColumnIndex; use crate::internals::column_index::ColumnIndex;
// Use `TablePosition` as index // Use `TablePosition` as index
@ -196,8 +197,8 @@ mod tests {
#[test] #[test]
fn test_insert_select_basic1() { fn test_insert_select_basic1() {
use DbValue::*; use Value::*;
use IndexableDbValue::*; use IndexableValue::*;
let mut state = State::new(); let mut state = State::new();
let users_schema = users_schema(); let users_schema = users_schema();
@ -231,8 +232,8 @@ mod tests {
#[test] #[test]
fn test_insert_select_basic2() { fn test_insert_select_basic2() {
use DbValue::*; use Value::*;
use IndexableDbValue::*; use IndexableValue::*;
use Operation::*; use Operation::*;
use ColumnSelection::*; use ColumnSelection::*;
use Condition::*; use Condition::*;
@ -313,8 +314,8 @@ mod tests {
#[test] #[test]
fn test_delete() { fn test_delete() {
use DbValue::*; use Value::*;
use IndexableDbValue::*; use IndexableValue::*;
use Operation::*; use Operation::*;
use ColumnSelection::*; use ColumnSelection::*;
use Condition::*; use Condition::*;
@ -369,8 +370,8 @@ mod tests {
pub fn example() { pub fn example() {
use DbValue::*; use Value::*;
use IndexableDbValue::*; use IndexableValue::*;
use Operation::*; use Operation::*;
use ColumnSelection::*; use ColumnSelection::*;
use Condition::*; use Condition::*;

View file

@ -1,6 +1,4 @@
mod base; mod internals;
mod table;
mod column_index;
mod operation; mod operation;
mod interpreter; mod interpreter;
mod error; mod error;

View file

@ -1,6 +1,5 @@
use crate::base::{TableName, ColumnName}; use crate::type_system::Value;
use crate::type_system::DbValue; use crate::internals::schema::{TableSchema, TableName, ColumnName};
use crate::base::TableSchema;
// ==============SQL operations================ // ==============SQL operations================
// TODO: Note that every operation has a table name. // TODO: Note that every operation has a table name.
@ -17,7 +16,7 @@ pub enum Operation {
// DropTable(TableName), // DropTable(TableName),
} }
pub type InsertionValues = Vec<(ColumnName, DbValue)>; pub type InsertionValues = Vec<(ColumnName, Value)>;
pub enum ColumnSelection { pub enum ColumnSelection {
All, All,
@ -29,7 +28,7 @@ pub enum Condition {
// Or(Box<Condition>, Box<Condition>), // Or(Box<Condition>, Box<Condition>),
// Not(Box<Condition>), // Not(Box<Condition>),
Eq(ColumnName, DbValue), Eq(ColumnName, Value),
// LessOrEqual(ColumnName, DbValue), // LessOrEqual(ColumnName, DbValue),
// Less(ColumnName, DbValue), // Less(ColumnName, DbValue),

View file

@ -14,29 +14,29 @@ pub type UUID = u64;
// I would rather have non-nullable values by default, // I would rather have non-nullable values by default,
// and something like an explicit Option type for nulls. // and something like an explicit Option type for nulls.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum DbValue { pub enum Value {
Number(f64), // TODO: Can't put floats as keys in maps, since they don't implement Eq. What to Number(f64), // TODO: Can't put floats as keys in maps, since they don't implement Eq. What to
// do? // do?
Indexable(IndexableDbValue), Indexable(IndexableValue),
} }
#[derive(Debug, Ord, Eq, Clone, PartialOrd, PartialEq)] #[derive(Debug, Ord, Eq, Clone, PartialOrd, PartialEq)]
pub enum IndexableDbValue { pub enum IndexableValue {
String(String), String(String),
Int(u64), Int(u64),
UUID(UUID), UUID(UUID),
// TODO: what about null? // TODO: what about null?
} }
impl DbValue { impl Value {
pub fn to_type(self) -> DbType { pub fn to_type(self) -> DbType {
match self { match self {
Self::Number(_) => DbType::Number, Self::Number(_) => DbType::Number,
Self::Indexable(val) => Self::Indexable(val) =>
match val { match val {
IndexableDbValue::String(_) => DbType::String, IndexableValue::String(_) => DbType::String,
IndexableDbValue::Int(_) => DbType::Int, IndexableValue::Int(_) => DbType::Int,
IndexableDbValue::UUID(_) => DbType::UUID, IndexableValue::UUID(_) => DbType::UUID,
} }
} }
} }