MCPcopy Create free account
hub / github.com/NodeDB-Lab/nodedb / fire_triggers

Function fire_triggers

nodedb/src/control/trigger/fire_common.rs:39–102  ·  view source on GitHub ↗

Execute a list of triggers with the given bindings. Evaluates WHEN clauses, parses trigger bodies, and executes each matching trigger body through the statement executor. Handles SECURITY DEFINER: when a trigger has `security = Definer`, the executor runs with the trigger owner's identity instead of the caller's. Tenant boundary is enforced — DEFINER identity always uses the trigger's tenant.

(
    state: &SharedState,
    identity: &AuthenticatedIdentity,
    tenant_id: TenantId,
    collection: &str,
    triggers: &[StoredTrigger],
    bindings: &RowBindings,
    cascade_depth: u32,
)

Source from the content-addressed store, hash-verified

37/// the executor runs with the trigger owner's identity instead of the caller's.
38/// Tenant boundary is enforced — DEFINER identity always uses the trigger's tenant.
39pub async fn fire_triggers(
40 state: &SharedState,
41 identity: &AuthenticatedIdentity,
42 tenant_id: TenantId,
43 collection: &str,
44 triggers: &[StoredTrigger],
45 bindings: &RowBindings,
46 cascade_depth: u32,
47) -> crate::Result<()> {
48 for trigger in triggers {
49 if let Some(ref when_cond) = trigger.when_condition {
50 let bound_cond = bindings.substitute(when_cond);
51 if !evaluate_simple_condition(&bound_cond) {
52 continue;
53 }
54 }
55
56 let block = match state.block_cache.get_or_parse(&trigger.body_sql) {
57 Ok(b) => b,
58 Err(e) => {
59 warn!(
60 trigger = %trigger.name,
61 error = %e,
62 "failed to parse trigger body, skipping"
63 );
64 continue;
65 }
66 };
67
68 // Resolve effective identity based on security mode.
69 let effective_identity = resolve_trigger_identity(trigger, identity, tenant_id);
70
71 // Audit log the trigger invocation with effective identity.
72 info!(
73 trigger = %trigger.name,
74 collection = collection,
75 timing = trigger.timing.as_str(),
76 security = trigger.security.as_str(),
77 caller = %identity.username,
78 effective_user = %effective_identity.username,
79 cascade_depth = cascade_depth,
80 "trigger invoked"
81 );
82
83 let executor = StatementExecutor::with_source(
84 state,
85 effective_identity,
86 tenant_id,
87 cascade_depth + 1,
88 crate::event::EventSource::Trigger,
89 );
90
91 if let Err(e) = executor.execute_block(&block, bindings).await {
92 return Err(crate::Error::BadRequest {
93 detail: format!(
94 "trigger '{}' on '{}' failed: {}",
95 trigger.name, collection, e
96 ),

Callers 9

fire_after_statementFunction · 0.85
fire_before_deleteFunction · 0.85
fire_instead_of_insertFunction · 0.85
fire_instead_of_updateFunction · 0.85
fire_instead_of_deleteFunction · 0.85
fire_after_insertFunction · 0.85
fire_after_updateFunction · 0.85
fire_after_deleteFunction · 0.85
dispatch_trigger_batchFunction · 0.85

Calls 5

resolve_trigger_identityFunction · 0.85
get_or_parseMethod · 0.80
execute_blockMethod · 0.80
substituteMethod · 0.45

Tested by

no test coverage detected