use std::sync::Arc;
use datafusion::arrow::record_batch::RecordBatch;
use smol_str::SmolStr;
use crate::errors::FnError;
use crate::traits::procedure::ProcedureHost;
pub trait TriggerPlugin: Send + Sync {
fn subscription(&self) -> &TriggerSubscription;
fn fire(
&self,
ctx: TriggerContext<'_>,
events: &MutationBatch,
) -> Result<TriggerOutcome, FnError>;
fn on_deferred(
&self,
ctx: TriggerContext<'_>,
events: &MutationBatch,
_payload: &str,
) -> Result<TriggerOutcome, FnError> {
self.fire(ctx, events)
}
}
#[derive(Clone, Debug)]
pub struct TriggerSubscription {
pub phase: TriggerPhase,
pub events: TriggerEventMask,
pub labels: Option<Vec<SmolStr>>,
pub edge_types: Option<Vec<SmolStr>>,
pub properties: Option<Vec<SmolStr>>,
pub predicate_source: Option<String>,
pub fire_mode: FireMode,
pub docs: String,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum TriggerPhase {
BeforeMutation,
AfterMutation,
BeforeCommit,
AfterCommit,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct TriggerEventMask(pub u32);
impl TriggerEventMask {
pub const NODE_CREATE: Self = Self(1 << 0);
pub const NODE_UPDATE: Self = Self(1 << 1);
pub const NODE_DELETE: Self = Self(1 << 2);
pub const EDGE_CREATE: Self = Self(1 << 3);
pub const EDGE_UPDATE: Self = Self(1 << 4);
pub const EDGE_DELETE: Self = Self(1 << 5);
pub const PROPERTY_CHANGE: Self = Self(1 << 6);
pub const LABEL_ADDED: Self = Self(1 << 7);
pub const LABEL_REMOVED: Self = Self(1 << 8);
#[must_use]
pub const fn union(self, other: Self) -> Self {
Self(self.0 | other.0)
}
#[must_use]
pub const fn contains(self, other: Self) -> bool {
(self.0 & other.0) == other.0
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum FireMode {
Synchronous,
Async,
EventualConsistency,
}
#[derive(Debug)]
#[non_exhaustive]
pub enum TriggerOutcome {
Continue,
Reject {
reason: String,
},
Defer {
until: TriggerDeferral,
},
}
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct TriggerDeferral {
pub payload: String,
pub delay: Option<std::time::Duration>,
}
impl TriggerDeferral {
#[must_use]
pub fn from_payload(payload: impl Into<String>) -> Self {
Self {
payload: payload.into(),
delay: None,
}
}
#[must_use]
pub fn after(payload: impl Into<String>, delay: std::time::Duration) -> Self {
Self {
payload: payload.into(),
delay: Some(delay),
}
}
}
#[non_exhaustive]
pub struct TriggerContext<'a> {
pub session_id: &'a str,
pub tx_id: u64,
host: Option<Arc<dyn ProcedureHost>>,
}
impl std::fmt::Debug for TriggerContext<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TriggerContext")
.field("session_id", &self.session_id)
.field("tx_id", &self.tx_id)
.field("host", &self.host.as_ref().map(|_| "<ProcedureHost>"))
.finish()
}
}
impl<'a> TriggerContext<'a> {
#[must_use]
pub fn new(session_id: &'a str, tx_id: u64) -> Self {
Self {
session_id,
tx_id,
host: None,
}
}
#[must_use]
pub fn with_host(mut self, host: Arc<dyn ProcedureHost>) -> Self {
self.host = Some(host);
self
}
#[must_use]
pub fn host(&self) -> Option<&Arc<dyn ProcedureHost>> {
self.host.as_ref()
}
}
#[derive(Clone, Debug)]
pub struct MutationBatch {
pub events: Arc<RecordBatch>,
}