use std::ops::Deref;
use super::TryIntoRef;
use crate::catalog::{ArenaIdx, Catalog, CatalogSchema, SchemaRef};
use crate::{DucklakeError, DucklakeResult};
pub struct SchemaView<'a, C = &'a Catalog> {
catalog: C,
arena_idx: ArenaIdx,
_marker: std::marker::PhantomData<&'a ()>,
}
pub type SchemaViewMut<'a> = SchemaView<'a, &'a mut Catalog>;
impl<'a, C: Deref<Target = Catalog>> SchemaView<'a, C> {
fn new(catalog: C, schema_ref: SchemaRef) -> Self {
Self {
catalog,
arena_idx: schema_ref.0,
_marker: std::marker::PhantomData,
}
}
}
impl Catalog {
pub fn list_schemas(&self) -> Vec<SchemaView<'_>> {
self.schemas
.values()
.map(|arena_idx| SchemaView::new(self, (*arena_idx).into()))
.collect()
}
pub fn schema<R: TryIntoRef<SchemaRef>>(
&self,
schema_ref: R,
) -> Result<SchemaView<'_>, R::Error> {
let schema_ref = schema_ref.try_into_ref(self)?;
Ok(SchemaView::new(self, schema_ref))
}
pub fn schema_mut<R: TryIntoRef<SchemaRef>>(
&mut self,
schema_ref: R,
) -> Result<SchemaViewMut<'_>, R::Error> {
let schema_ref = schema_ref.try_into_ref(self)?;
Ok(SchemaViewMut::new(self, schema_ref))
}
}
impl<S: AsRef<str> + ?Sized> TryIntoRef<SchemaRef> for &S {
type Error = DucklakeError;
fn try_into_ref(self, catalog: &Catalog) -> Result<SchemaRef, Self::Error> {
let idx = *catalog
.schemas
.get(self.as_ref())
.ok_or(DucklakeError::schema_not_found(self.as_ref()))?;
Ok(idx.into())
}
}
impl TryIntoRef<SchemaRef> for i64 {
type Error = DucklakeError;
fn try_into_ref(self, catalog: &Catalog) -> Result<SchemaRef, Self::Error> {
let idx = catalog
.schema_arena
.map_id(self)
.ok_or(DucklakeError::EntityNotFound { id: self })?;
Ok(idx.into())
}
}
impl<'a, C: Deref<Target = Catalog>> SchemaView<'a, C> {
pub(in crate::catalog) fn inner(&self) -> &CatalogSchema {
self.catalog.schema_arena.get(self.arena_idx)
}
}
impl<'a> SchemaViewMut<'a> {
pub(in crate::catalog) fn inner_mut(&mut self) -> &mut CatalogSchema {
self.catalog.schema_arena.get_mut(self.arena_idx)
}
}
impl<'a, C: Deref<Target = Catalog>> SchemaView<'a, C> {
pub fn ref_(&self) -> SchemaRef {
SchemaRef(self.arena_idx)
}
pub fn id(&self) -> Option<i64> {
self.inner().id
}
pub fn name(&self) -> &str {
&self.inner().name
}
pub fn list_tables(&self) -> Vec<super::TableView<'_>> {
let catalog: &Catalog = &self.catalog;
self.inner()
.tables
.values()
.map(|arena_idx| super::TableView::new(catalog, (*arena_idx).into()))
.collect()
}
}
impl<'a> SchemaViewMut<'a> {
pub fn resolve_id(&mut self, id: i64) {
let schema = self.inner_mut();
match schema.id {
None => {
schema.id = Some(id);
self.catalog.schema_arena.register_id(self.arena_idx, id);
}
_ => panic!("schema ID must not be overwritten"),
}
}
pub fn delete(&mut self) -> DucklakeResult<()> {
let schema = self.inner_mut();
if !schema.tables.is_empty() {
return Err(DucklakeError::InvalidChanges(format!(
"cannot delete schema {} which is not empty",
schema.name
)));
}
let name = schema.name.clone();
self.catalog.schemas.remove(&name);
Ok(())
}
}