use ducklake_macros::visibility_if;
use super::changes::Change;
use super::{IfExistsStrategy, Transaction};
use crate::{DucklakeError, DucklakeResult, TableName, Tag, ViewInfo, view};
pub struct TransactionView<'tx, 'a> {
tx: &'tx mut Transaction<'a>,
name: TableName,
}
impl<'tx, 'a> TransactionView<'tx, 'a> {
fn new(tx: &'tx mut Transaction<'a>, name: TableName) -> Self {
Self { tx, name }
}
}
impl<'a> Transaction<'a> {
pub fn view(
&mut self,
name: impl TryInto<TableName, Error = impl Into<DucklakeError>>,
) -> DucklakeResult<TransactionView<'_, 'a>> {
let name = name.try_into().map_err(|e| e.into())?;
self.catalog().view(&name)?;
Ok(TransactionView::new(self, name))
}
}
impl<'a> Transaction<'a> {
pub fn create_view(
&mut self,
name: impl TryInto<TableName, Error = impl Into<DucklakeError>>,
sql: String,
column_aliases: Option<Vec<String>>,
tags: Option<Vec<Tag>>,
if_exists: IfExistsStrategy,
) -> DucklakeResult<TransactionView<'_, 'a>> {
let name = name.try_into().map_err(|e| e.into())?;
if matches!(if_exists, IfExistsStrategy::Skip) && self.catalog().view(&name).is_ok() {
return Ok(TransactionView::new(self, name));
}
let statement = view::parse_select_query(&sql, "duckdb")?;
let sql = format!("{statement:#}");
let dialect = "duckdb".to_string();
let info = ViewInfo {
name: name.clone(),
sql: sql.clone(),
dialect: dialect.clone(),
column_aliases: column_aliases.clone(),
tags: tags.clone().unwrap_or_default(),
};
let (schema_ref, view_ref) = self.catalog_mut().add_view(info)?;
let change = Change::CreateView {
schema_ref,
view_ref,
name: name.clone(),
sql,
dialect,
column_aliases,
tags,
};
self.changes.push(change);
Ok(TransactionView::new(self, name))
}
}
impl<'tx, 'a> TransactionView<'tx, 'a> {
pub fn delete(self) -> DucklakeResult<()> {
self.tx.delete_view(&self.name)
}
}
impl<'a> Transaction<'a> {
#[visibility_if(feature = "python", pub)]
pub(crate) fn delete_view(&mut self, name: &TableName) -> DucklakeResult<()> {
let mut view = self.catalog_mut().view_mut(name)?;
view.delete();
let change = Change::DeleteView {
view_ref: view.ref_(),
};
self.changes.push(change);
Ok(())
}
}