mod reader;
mod table;
use std::collections::HashMap;
use wasm_dbms_api::prelude::{ColumnDef, DbmsError, DbmsResult, QueryError, TableSchema, Value};
use wasm_dbms_memory::prelude::{MemoryAccess, TableReader};
pub use self::reader::DatabaseOverlayReader;
pub use self::table::IndexOverlay;
pub(crate) use self::table::TableOverlay;
#[derive(Debug, Default, Clone)]
pub struct DatabaseOverlay {
tables: HashMap<String, TableOverlay>,
}
impl DatabaseOverlay {
pub fn reader<'a, T, MA>(
&'a mut self,
table_reader: TableReader<'a, T, MA>,
) -> DatabaseOverlayReader<'a, T, MA>
where
T: TableSchema,
MA: MemoryAccess,
{
let table_name = T::table_name();
let table_overlay = self
.tables
.entry(table_name.to_string())
.or_insert_with(|| TableOverlay::new(T::indexes()));
DatabaseOverlayReader::new(table_overlay, table_reader)
}
pub fn insert<T>(&mut self, values: Vec<(ColumnDef, Value)>) -> DbmsResult<()>
where
T: TableSchema,
{
let table_name = T::table_name();
let pk = T::primary_key();
let pk = Self::primary_key(pk, &values)?;
let overlay = self
.tables
.entry(table_name.to_string())
.or_insert_with(|| TableOverlay::new(T::indexes()));
overlay.insert(pk, values);
Ok(())
}
pub fn update<T>(
&mut self,
pk: Value,
updates: Vec<(&'static str, Value)>,
current_row: &[(ColumnDef, Value)],
) where
T: TableSchema,
{
let table_name = T::table_name();
let overlay = self
.tables
.entry(table_name.to_string())
.or_insert_with(|| TableOverlay::new(T::indexes()));
overlay.update(pk, updates, current_row);
}
pub fn delete<T>(&mut self, pk: Value, current_row: &[(ColumnDef, Value)])
where
T: TableSchema,
{
let table_name = T::table_name();
let overlay = self
.tables
.entry(table_name.to_string())
.or_insert_with(|| TableOverlay::new(T::indexes()));
overlay.delete(pk, current_row);
}
pub fn index_overlay(&self, table: &str) -> Option<&IndexOverlay> {
self.tables.get(table).map(|t| &t.index_overlay)
}
pub(crate) fn table_overlay(&self, table: &str) -> Option<&TableOverlay> {
self.tables.get(table)
}
fn primary_key(pk: &'static str, values: &[(ColumnDef, Value)]) -> DbmsResult<Value> {
for (col_def, value) in values {
if col_def.name == pk {
return Ok(value.clone());
}
}
Err(DbmsError::Query(QueryError::MissingNonNullableField(
pk.to_string(),
)))
}
}