use crate::mutation::triggers::{context::TriggerContext, queue::StatementEvent};
use std::collections::BTreeSet;
use uqa_sql::{
plan::{MergePlan, MergeWhenPlan},
SQLError,
};
pub struct MergeStatementEvents {
pub insert: bool,
pub update: bool,
pub delete: bool,
pub updated_columns: Vec<String>,
}
impl MergeStatementEvents {
pub fn from_plan(plan: &MergePlan) -> Self {
let insert = plan
.when_clauses
.iter()
.any(|clause| matches!(clause, MergeWhenPlan::InsertNotMatched { .. }));
let update = plan.when_clauses.iter().any(|clause| {
matches!(
clause,
MergeWhenPlan::UpdateMatched { .. }
| MergeWhenPlan::UpdateNotMatchedBySource { .. }
)
});
let delete = plan.when_clauses.iter().any(|clause| {
matches!(
clause,
MergeWhenPlan::DeleteMatched { .. }
| MergeWhenPlan::DeleteNotMatchedBySource { .. }
)
});
let updated_columns = plan
.when_clauses
.iter()
.filter_map(|clause| match clause {
MergeWhenPlan::UpdateMatched { assignments, .. }
| MergeWhenPlan::UpdateNotMatchedBySource { assignments, .. } => Some(assignments),
_ => None,
})
.flatten()
.flat_map(|assignment| assignment.target.column_names())
.map(str::to_owned)
.collect::<BTreeSet<_>>()
.into_iter()
.collect();
Self {
insert,
update,
delete,
updated_columns,
}
}
pub fn has_before_statement_trigger(
&self,
context: &TriggerContext<'_>,
relation: &str,
) -> Result<bool, SQLError> {
for (enabled, event, columns) in self.before_order() {
if enabled
&& !context
.catalog
.triggers_for(
relation,
uqa_sql::ast::TriggerTiming::Before,
event,
false,
columns,
)?
.is_empty()
{
return Ok(true);
}
}
Ok(false)
}
pub fn before_statements(&self, relation: &str) -> Vec<StatementEvent> {
self.before_order()
.into_iter()
.filter(|(enabled, _, _)| *enabled)
.map(|(_, event, columns)| StatementEvent::new(relation, event, columns))
.collect()
}
pub fn after_statements(&self, relation: &str) -> Vec<StatementEvent> {
[
(self.delete, uqa_sql::ast::TriggerEvent::Delete, &[][..]),
(
self.update,
uqa_sql::ast::TriggerEvent::Update,
self.updated_columns.as_slice(),
),
(self.insert, uqa_sql::ast::TriggerEvent::Insert, &[][..]),
]
.into_iter()
.filter(|(enabled, _, _)| *enabled)
.map(|(_, event, columns)| StatementEvent::new(relation, event, columns))
.collect()
}
fn before_order(&self) -> [(bool, uqa_sql::ast::TriggerEvent, &[String]); 3] {
[
(self.insert, uqa_sql::ast::TriggerEvent::Insert, &[][..]),
(
self.update,
uqa_sql::ast::TriggerEvent::Update,
self.updated_columns.as_slice(),
),
(self.delete, uqa_sql::ast::TriggerEvent::Delete, &[][..]),
]
}
}