use std::ops::Deref;
use super::TryIntoRef;
use super::table::{TableView, TableViewMut};
use crate::catalog::typedefs::CatalogDataType;
use crate::catalog::{ArenaIdx, Catalog, CatalogColumn, CatalogTable, ColumnRef, TableRef};
use crate::{DucklakeError, DucklakeResult};
pub struct ColumnView<'a, C = &'a Catalog> {
catalog: C,
table_ref: TableRef,
column_arena_idx: ArenaIdx,
_marker: std::marker::PhantomData<&'a ()>,
}
pub type ColumnViewMut<'a> = ColumnView<'a, &'a mut Catalog>;
impl<'a, C: Deref<Target = Catalog>> ColumnView<'a, C> {
fn new(catalog: C, table_ref: TableRef, column_arena_idx: ArenaIdx) -> Self {
Self {
catalog,
table_ref,
column_arena_idx,
_marker: std::marker::PhantomData,
}
}
}
impl<'a, C: Deref<Target = Catalog>> TableView<'a, C> {
pub fn column<R: TryIntoRef<ColumnRef, TableView<'a, C>>>(
&self,
column_ref: R,
) -> Result<ColumnView<'_, &Catalog>, R::Error> {
let column_idx = column_ref.try_into_ref(self)?.column_idx;
let view = ColumnView::new(&*self.catalog, self.arena_idx.into(), column_idx);
Ok(view)
}
}
impl<'a> TableViewMut<'a> {
pub fn column_mut<R: TryIntoRef<ColumnRef, TableViewMut<'a>>>(
&mut self,
column_ref: R,
) -> Result<ColumnViewMut<'_>, R::Error> {
let column_idx = column_ref.try_into_ref(self)?.column_idx;
let view = ColumnView::new(&mut *self.catalog, self.arena_idx.into(), column_idx);
Ok(view)
}
}
impl<'a, C: Deref<Target = Catalog>> TryIntoRef<ColumnRef, TableView<'a, C>> for &str {
type Error = DucklakeError;
fn try_into_ref(self, container: &TableView<'a, C>) -> Result<ColumnRef, Self::Error> {
let into_ref: &[String] = &[self.to_string()];
into_ref.try_into_ref(container)
}
}
impl<'a, C: Deref<Target = Catalog>> TryIntoRef<ColumnRef, TableView<'a, C>> for &[String] {
type Error = DucklakeError;
fn try_into_ref(self, container: &TableView<'a, C>) -> Result<ColumnRef, Self::Error> {
let columns = &container.inner().columns;
let idx = columns.arena_idx_by_path(self)?;
Ok(ColumnRef {
table_ref: container.arena_idx.into(),
column_idx: idx,
})
}
}
impl<'a, C: Deref<Target = Catalog>> TryIntoRef<ColumnRef, TableView<'a, C>> for i64 {
type Error = DucklakeError;
fn try_into_ref(self, container: &TableView<'a, C>) -> Result<ColumnRef, Self::Error> {
let columns = &container.inner().columns;
let idx = columns
.by_id
.get(&self)
.ok_or_else(|| DucklakeError::ColumnNotFound { id: self })?;
Ok(ColumnRef {
table_ref: container.arena_idx.into(),
column_idx: *idx,
})
}
}
impl<'a, C: Deref<Target = Catalog>> ColumnView<'a, C> {
fn table(&self) -> &CatalogTable {
self.catalog.table_by_idx(self.table_ref.0)
}
pub(in crate::catalog) fn inner(&self) -> &CatalogColumn {
&self.table().columns.arena[self.column_arena_idx.0]
}
}
impl<'a> ColumnViewMut<'a> {
fn table_mut(&mut self) -> &mut CatalogTable {
self.catalog.table_by_idx_mut(self.table_ref.0)
}
pub(in crate::catalog) fn inner_mut(&mut self) -> &mut CatalogColumn {
let idx = self.column_arena_idx.0;
&mut self.table_mut().columns.arena[idx]
}
}
impl<'a, C: Deref<Target = Catalog>> ColumnView<'a, C> {
pub fn ref_(&self) -> ColumnRef {
ColumnRef {
table_ref: self.table_ref,
column_idx: self.column_arena_idx,
}
}
pub fn id(&self) -> i64 {
self.inner().id
}
pub fn info(&self) -> crate::Column {
self.table()
.columns
.schema_column_from_arena_index(self.column_arena_idx)
}
pub fn nullable(&self) -> bool {
self.inner().nullable
}
pub fn parent_ref(&self) -> Option<ColumnRef> {
self.inner()
.parent_column
.as_ref()
.map(|parent_idx| (self.table_ref.0, *parent_idx).into())
}
}
impl<'a> ColumnViewMut<'a> {
pub fn update_primitive_data_type(&mut self, data_type: crate::DataType) {
self.inner_mut().dtype = CatalogDataType::Primitive(data_type);
}
pub fn update_default_value(&mut self, default_value: crate::ColumnDefault) {
self.inner_mut().default_value = default_value;
}
pub fn update_nullability(&mut self, nullable: bool) {
self.inner_mut().nullable = nullable;
}
pub fn rename(&mut self, new_name: &str) -> DucklakeResult<()> {
let column_idx = self.column_arena_idx;
let table = self.table_mut();
table.columns.rename_column(column_idx, new_name)?;
Ok(())
}
pub fn add_tag(&mut self, tag: crate::Tag) {
let tags = &mut self.inner_mut().tags;
super::upsert_tag(tags, tag);
}
pub fn remove_tag(&mut self, key: &str) -> DucklakeResult<()> {
let tags = &mut self.inner_mut().tags;
super::remove_tag(tags, key)?;
Ok(())
}
pub fn remove(&mut self) -> DucklakeResult<Vec<ColumnRef>> {
let column_idx = self.column_arena_idx;
let table = self.table_mut();
if let Some(partition) = table.partition.as_ref()
&& partition.columns.iter().any(|col| col.column == column_idx)
{
return Err(DucklakeError::InvalidChanges(
"cannot remove column from table as the table is partitioned by it - reset or change the partitioning on this table in order to drop this column".to_string(),
));
}
let column_idxs = table.columns.remove_column(column_idx)?;
Ok(column_idxs
.into_iter()
.map(|column_idx| (self.table_ref.0, column_idx).into())
.collect())
}
}