use std::collections::HashMap;
use crate::control::planner::procedural::executor::bindings::RowBindings;
use crate::control::security::catalog::trigger_types::TriggerTiming;
use crate::control::security::identity::AuthenticatedIdentity;
use crate::control::state::SharedState;
use crate::types::TenantId;
use super::fire_common::{check_cascade_depth, fire_triggers};
use super::registry::DmlEvent;
pub enum InsteadOfResult {
NoTrigger,
Handled,
}
pub async fn fire_instead_of_insert(
state: &SharedState,
identity: &AuthenticatedIdentity,
tenant_id: TenantId,
collection: &str,
new_fields: &HashMap<String, nodedb_types::Value>,
cascade_depth: u32,
) -> crate::Result<InsteadOfResult> {
let triggers =
state
.trigger_registry
.get_matching(tenant_id.as_u64(), collection, DmlEvent::Insert);
let instead_triggers: Vec<_> = triggers
.into_iter()
.filter(|t| t.timing == TriggerTiming::InsteadOf)
.collect();
if instead_triggers.is_empty() {
return Ok(InsteadOfResult::NoTrigger);
}
check_cascade_depth(cascade_depth, collection)?;
let bindings = RowBindings::before_insert(collection, new_fields.clone());
fire_triggers(
state,
identity,
tenant_id,
collection,
&instead_triggers,
&bindings,
cascade_depth,
)
.await?;
Ok(InsteadOfResult::Handled)
}
#[allow(clippy::too_many_arguments)]
pub async fn fire_instead_of_update(
state: &SharedState,
identity: &AuthenticatedIdentity,
tenant_id: TenantId,
collection: &str,
old_fields: &HashMap<String, nodedb_types::Value>,
new_fields: &HashMap<String, nodedb_types::Value>,
cascade_depth: u32,
) -> crate::Result<InsteadOfResult> {
let triggers =
state
.trigger_registry
.get_matching(tenant_id.as_u64(), collection, DmlEvent::Update);
let instead_triggers: Vec<_> = triggers
.into_iter()
.filter(|t| t.timing == TriggerTiming::InsteadOf)
.collect();
if instead_triggers.is_empty() {
return Ok(InsteadOfResult::NoTrigger);
}
check_cascade_depth(cascade_depth, collection)?;
let bindings = RowBindings::before_update(collection, old_fields.clone(), new_fields.clone());
fire_triggers(
state,
identity,
tenant_id,
collection,
&instead_triggers,
&bindings,
cascade_depth,
)
.await?;
Ok(InsteadOfResult::Handled)
}
pub async fn fire_instead_of_delete(
state: &SharedState,
identity: &AuthenticatedIdentity,
tenant_id: TenantId,
collection: &str,
old_fields: &HashMap<String, nodedb_types::Value>,
cascade_depth: u32,
) -> crate::Result<InsteadOfResult> {
let triggers =
state
.trigger_registry
.get_matching(tenant_id.as_u64(), collection, DmlEvent::Delete);
let instead_triggers: Vec<_> = triggers
.into_iter()
.filter(|t| t.timing == TriggerTiming::InsteadOf)
.collect();
if instead_triggers.is_empty() {
return Ok(InsteadOfResult::NoTrigger);
}
check_cascade_depth(cascade_depth, collection)?;
let bindings = RowBindings::before_delete(collection, old_fields.clone());
fire_triggers(
state,
identity,
tenant_id,
collection,
&instead_triggers,
&bindings,
cascade_depth,
)
.await?;
Ok(InsteadOfResult::Handled)
}