use std::collections::HashMap;
use super::{Catalog, IndexMetadata, TableMetadata};
use crate::planner::PlannerError;
#[derive(Debug, Default)]
pub struct MemoryCatalog {
tables: HashMap<String, TableMetadata>,
indexes: HashMap<String, IndexMetadata>,
table_id_counter: u32,
index_id_counter: u32,
}
impl MemoryCatalog {
pub fn new() -> Self {
Self::default()
}
pub fn table_count(&self) -> usize {
self.tables.len()
}
pub fn index_count(&self) -> usize {
self.indexes.len()
}
pub fn table_names(&self) -> Vec<&str> {
self.tables.keys().map(|s| s.as_str()).collect()
}
pub fn index_names(&self) -> Vec<&str> {
self.indexes.keys().map(|s| s.as_str()).collect()
}
pub fn clear(&mut self) {
self.tables.clear();
self.indexes.clear();
}
pub(crate) fn counters(&self) -> (u32, u32) {
(self.table_id_counter, self.index_id_counter)
}
pub(crate) fn set_counters(&mut self, table_id_counter: u32, index_id_counter: u32) {
self.table_id_counter = table_id_counter;
self.index_id_counter = index_id_counter;
}
pub(crate) fn insert_table_unchecked(&mut self, table: TableMetadata) {
self.tables.insert(table.name.clone(), table);
}
pub(crate) fn remove_table_unchecked(&mut self, name: &str) {
self.tables.remove(name);
self.indexes.retain(|_, idx| idx.table != name);
}
pub(crate) fn insert_index_unchecked(&mut self, index: IndexMetadata) {
self.indexes.insert(index.name.clone(), index);
}
pub(crate) fn remove_index_unchecked(&mut self, name: &str) {
self.indexes.remove(name);
}
}
impl Catalog for MemoryCatalog {
fn create_table(&mut self, table: TableMetadata) -> Result<(), PlannerError> {
if self.tables.contains_key(&table.name) {
return Err(PlannerError::table_already_exists(&table.name));
}
self.tables.insert(table.name.clone(), table);
Ok(())
}
fn get_table(&self, name: &str) -> Option<&TableMetadata> {
self.tables.get(name)
}
fn drop_table(&mut self, name: &str) -> Result<(), PlannerError> {
if self.tables.remove(name).is_none() {
return Err(PlannerError::TableNotFound {
name: name.to_string(),
line: 0,
column: 0,
});
}
self.indexes.retain(|_, idx| idx.table != name);
Ok(())
}
fn create_index(&mut self, index: IndexMetadata) -> Result<(), PlannerError> {
if self.indexes.contains_key(&index.name) {
return Err(PlannerError::index_already_exists(&index.name));
}
let table = self
.tables
.get(&index.table)
.ok_or_else(|| PlannerError::TableNotFound {
name: index.table.clone(),
line: 0,
column: 0,
})?;
for column in &index.columns {
if table.get_column(column).is_none() {
return Err(PlannerError::ColumnNotFound {
column: column.clone(),
table: index.table.clone(),
line: 0,
col: 0,
});
}
}
self.indexes.insert(index.name.clone(), index);
Ok(())
}
fn get_index(&self, name: &str) -> Option<&IndexMetadata> {
self.indexes.get(name)
}
fn get_indexes_for_table(&self, table: &str) -> Vec<&IndexMetadata> {
self.indexes
.values()
.filter(|idx| idx.table == table)
.collect()
}
fn drop_index(&mut self, name: &str) -> Result<(), PlannerError> {
if self.indexes.remove(name).is_none() {
return Err(PlannerError::index_not_found(name));
}
Ok(())
}
fn table_exists(&self, name: &str) -> bool {
self.tables.contains_key(name)
}
fn index_exists(&self, name: &str) -> bool {
self.indexes.contains_key(name)
}
fn next_table_id(&mut self) -> u32 {
self.table_id_counter += 1;
self.table_id_counter
}
fn next_index_id(&mut self) -> u32 {
self.index_id_counter += 1;
self.index_id_counter
}
fn list_tables(&self) -> Vec<TableMetadata> {
self.tables.values().cloned().collect()
}
}