use crate::model::Model;
use std::marker::PhantomData;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HookOperation {
Insert,
Update,
Delete,
}
#[derive(Debug, Clone, Copy)]
pub struct HookContext<'a> {
operation: HookOperation,
batch_index: Option<usize>,
in_transaction: bool,
_marker: PhantomData<&'a ()>,
}
impl<'a> HookContext<'a> {
pub fn new(operation: HookOperation) -> Self {
Self {
operation,
batch_index: None,
in_transaction: false,
_marker: PhantomData,
}
}
pub fn operation(&self) -> HookOperation {
self.operation
}
pub fn batch_index(&self) -> Option<usize> {
self.batch_index
}
pub fn in_transaction(&self) -> bool {
self.in_transaction
}
pub fn for_batch(&self, index: usize) -> Self {
Self {
operation: self.operation,
batch_index: Some(index),
in_transaction: self.in_transaction,
_marker: PhantomData,
}
}
pub fn transaction(mut self) -> Self {
self.in_transaction = true;
self
}
}
macro_rules! define_lifecycle_hook {
($(#[$meta:meta])* $public:ident, $method:ident, $hidden:ident, $call:ident, mut, $($bound:tt)+) => {
$(#[$meta])*
#[async_trait::async_trait]
pub trait $public: Model {
async fn $method(&mut self, ctx: &mut HookContext<'_>) -> crate::Result<()>;
}
#[doc(hidden)]
#[async_trait::async_trait]
pub trait $hidden {
async fn $call(&mut self, ctx: &mut HookContext<'_>) -> crate::Result<()>;
}
#[async_trait::async_trait]
impl<M: $public + $($bound)+> $hidden for M {
async fn $call(&mut self, ctx: &mut HookContext<'_>) -> crate::Result<()> {
self.$method(ctx).await
}
}
};
($(#[$meta:meta])* $public:ident, $method:ident, $hidden:ident, $call:ident, ref, $($bound:tt)+) => {
$(#[$meta])*
#[async_trait::async_trait]
pub trait $public: Model {
async fn $method(&self, ctx: &mut HookContext<'_>) -> crate::Result<()>;
}
#[doc(hidden)]
#[async_trait::async_trait]
pub trait $hidden {
async fn $call(&self, ctx: &mut HookContext<'_>) -> crate::Result<()>;
}
#[async_trait::async_trait]
impl<M: $public + $($bound)+> $hidden for M {
async fn $call(&self, ctx: &mut HookContext<'_>) -> crate::Result<()> {
self.$method(ctx).await
}
}
};
}
define_lifecycle_hook!(
BeforeInsert,
before_insert,
HookBeforeInsert,
call_before_insert,
mut,
Send
);
define_lifecycle_hook!(
AfterInsert,
after_insert,
HookAfterInsert,
call_after_insert,
ref,
Send + Sync
);
define_lifecycle_hook!(
BeforeUpdate,
before_update,
HookBeforeUpdate,
call_before_update,
mut,
Send
);
define_lifecycle_hook!(
AfterUpdate,
after_update,
HookAfterUpdate,
call_after_update,
ref,
Send + Sync
);
define_lifecycle_hook!(
BeforeDelete,
before_delete,
HookBeforeDelete,
call_before_delete,
ref,
Send + Sync
);
define_lifecycle_hook!(
AfterDelete,
after_delete,
HookAfterDelete,
call_after_delete,
ref,
Send + Sync
);