use crate::query::CteScope;
use uqa_sql::catalog::roles::RoleReference;
use uqa_sql::SQLError;
pub trait MutationCommandState {
fn prepare_writer(&self) -> Result<(), SQLError>;
fn begin_overlay(&self);
fn end_overlay(&self) -> super::overlay::CommandMutationOverlay;
}
pub trait CommandScopeSource<S: Clone> {
fn command_scope(
&self,
privilege_subject: Option<&RoleReference>,
relations_bound: bool,
) -> Result<CteScope<S>, SQLError>;
}
pub struct MutationOverlayScope<'a> {
state: Option<&'a dyn MutationCommandState>,
}
impl<'a> MutationOverlayScope<'a> {
pub fn new(state: &'a dyn MutationCommandState) -> Self {
state.begin_overlay();
Self { state: Some(state) }
}
pub fn finish(mut self) -> Option<super::overlay::CommandMutationOverlay> {
self.state
.take()
.expect("an active command overlay")
.end_overlay()
.published_rows()
}
}
impl Drop for MutationOverlayScope<'_> {
fn drop(&mut self) {
if let Some(state) = self.state.take() {
state.end_overlay();
}
}
}
pub fn capture_command_read_snapshot<S: Clone + 'static>(
snapshots: &dyn crate::query::statement::context::SnapshotSource<S>,
inherited: Option<&CteScope<S>>,
before_statement_trigger: bool,
ctes: &[uqa_sql::plan::CtePlan],
) -> Result<Option<std::sync::Arc<S>>, SQLError> {
match inherited.and_then(CteScope::command_cte_snapshot) {
Some(snapshot) => Ok(Some(snapshot)),
None if before_statement_trigger || ctes.iter().any(|cte| cte.body.modifies_data()) => {
Ok(Some(std::sync::Arc::new(snapshots.capture()?)))
}
None => Ok(None),
}
}