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

View file

@ -1,12 +1,13 @@
use std::collections::{BTreeMap, HashSet};
use crate::base::{ColumnPosition, ColumnName, DbResult};
use crate::type_system::{UUID, DbValue, IndexableDbValue};
use crate::table::Table;
use crate::type_system::{UUID, Value, IndexableValue};
use crate::internals::schema::{ColumnName, DbResult};
use crate::internals::table::Table;
use crate::internals::row::ColumnPosition;
use crate::error::Error;
#[derive(Debug)]
pub struct ColumnIndex {
index: BTreeMap<IndexableDbValue, HashSet<UUID>>
index: BTreeMap<IndexableValue, HashSet<UUID>>
}
impl ColumnIndex {
@ -15,14 +16,14 @@ impl ColumnIndex {
Self { index }
}
pub fn get(&self, value: &IndexableDbValue) -> HashSet<UUID> {
pub fn get(&self, value: &IndexableValue) -> HashSet<UUID> {
match self.index.get(value) {
Some(set) => set.clone(),
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) {
Some(ids) => {
ids.insert(id);
@ -40,7 +41,7 @@ impl ColumnIndex {
pub fn update_from_table(&mut self, table: &Table, column_position: ColumnPosition) -> DbResult<()> {
for (id, row) in &table.rows {
let value = match row.get(column_position) {
Some(DbValue::Indexable(value)) => {
Some(Value::Indexable(value)) => {
value.clone()
},
Some(_) => {
@ -56,7 +57,7 @@ impl ColumnIndex {
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) {
Some(ids) => {
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 bimap::BiMap;
use crate::operation::{InsertionValues, ColumnSelection};
use crate::table::Row;
use crate::type_system::{DbType, DbValue, IndexableDbValue, UUID};
use crate::internals::row::{Row, ColumnPosition};
use crate::type_system::{DbType, Value, IndexableValue, UUID};
use crate::error::Error;
// 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 ColumnName = String;
pub type ColumnPosition = usize;
pub type DbResult<A> = Result<A, Error>;
@ -81,7 +80,6 @@ impl TableSchema {
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)> {
// TODO: There should be proper validation of the insertion_values.
// 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 values: HashMap<ColumnName, DbValue> = HashMap::new();
let mut values: HashMap<ColumnName, Value> = HashMap::new();
for (column_name, db_value) in &insertion_values {
values.insert(column_name.clone(), db_value.clone());
}
@ -115,7 +113,7 @@ impl TableSchema {
let id: UUID = match row.get(self.primary_key) {
Some(val) => {
match val {
DbValue::Indexable(IndexableDbValue::UUID(id)) => {
Value::Indexable(IndexableValue::UUID(id)) => {
*id
},
_ =>

View file

@ -1,92 +1,12 @@
use std::collections::{BTreeMap, HashMap, HashSet};
use std::slice::SliceIndex;
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::type_system::{UUID, Value, IndexableValue};
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)]
pub struct Table {
pub schema: TableSchema,
@ -96,6 +16,9 @@ pub struct Table {
HashMap<ColumnPosition, ColumnIndex>
}
pub type Rows =
BTreeMap<UUID, Row>;
impl Table {
pub fn new(table_schema: TableSchema) -> Self {
@ -117,7 +40,7 @@ impl Table {
.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
self.rows.values()
.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()
}
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 {
DbValue::Indexable(value) => {
Value::Indexable(value) => {
match self.fetch_ids_from_index(column_position, &value)? {
Some(ids) =>
Ok(self.get_rows_by_ids(ids).iter().map(|row| row.restrict_columns(&selected_column_positions)).collect()),
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 {
match row.get(*column_position) {
Some(DbValue::Indexable(val)) => {
Some(Value::Indexable(val)) => {
column_index.add(val.clone(), id)
},
Some(_) => {},
@ -169,7 +92,7 @@ impl Table {
match self.rows.remove(&id) {
Some(row) => {
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);
};
}
@ -187,7 +110,7 @@ impl Table {
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()
.filter_map(|(id, row)| if row.get(column_position) == Some(value) { Some(*id) } else { None })
.collect();
@ -201,14 +124,14 @@ impl Table {
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 {
DbValue::Indexable(value) => {
Value::Indexable(value) => {
match self.fetch_ids_from_index(column_position, &value)? {
Some(ids) =>
Ok(self.delete_rows_by_ids(ids)),
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);
}
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) {
match value {
IndexableDbValue::UUID(id) =>
IndexableValue::UUID(id) =>
Ok(Some(HashSet::from([*id]))),
_ => {
let column_name: ColumnName = self.schema.column_name_from_column_position(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 {

View file

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

View file

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

View file

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

View file

@ -14,29 +14,29 @@ pub type UUID = u64;
// I would rather have non-nullable values by default,
// and something like an explicit Option type for nulls.
#[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
// do?
Indexable(IndexableDbValue),
Indexable(IndexableValue),
}
#[derive(Debug, Ord, Eq, Clone, PartialOrd, PartialEq)]
pub enum IndexableDbValue {
pub enum IndexableValue {
String(String),
Int(u64),
UUID(UUID),
// TODO: what about null?
}
impl DbValue {
impl Value {
pub fn to_type(self) -> DbType {
match self {
Self::Number(_) => DbType::Number,
Self::Indexable(val) =>
match val {
IndexableDbValue::String(_) => DbType::String,
IndexableDbValue::Int(_) => DbType::Int,
IndexableDbValue::UUID(_) => DbType::UUID,
IndexableValue::String(_) => DbType::String,
IndexableValue::Int(_) => DbType::Int,
IndexableValue::UUID(_) => DbType::UUID,
}
}
}