use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use vantage_types::{EmptyEntity, Entity, Record};
use crate::table::Table;
use crate::traits::table_source::TableSource;
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Phase {
Normalize,
Populate,
Validate,
}
pub enum HookReturn {
Proceed,
Handled,
}
pub type BeforeFn<T> = Arc<
dyn for<'r> Fn(
&'r mut Record<<T as TableSource>::Value>,
&'r Table<T, EmptyEntity>,
) -> Pin<Box<dyn Future<Output = vantage_core::Result<()>> + Send + 'r>>
+ Send
+ Sync,
>;
pub type BeforeDeleteFn<T> = Arc<
dyn for<'r> Fn(
&'r <T as TableSource>::Id,
&'r Record<<T as TableSource>::Value>,
&'r Table<T, EmptyEntity>,
)
-> Pin<Box<dyn Future<Output = vantage_core::Result<HookReturn>> + Send + 'r>>
+ Send
+ Sync,
>;
pub type AfterFn<T> = Arc<
dyn for<'r> Fn(
&'r <T as TableSource>::Id,
&'r Record<<T as TableSource>::Value>,
&'r Table<T, EmptyEntity>,
) -> Pin<Box<dyn Future<Output = vantage_core::Result<()>> + Send + 'r>>
+ Send
+ Sync,
>;
pub enum Hook<T: TableSource> {
BeforeInsert(Phase, BeforeFn<T>),
BeforeUpdate(Phase, BeforeFn<T>),
BeforeSave(Phase, BeforeFn<T>),
BeforeDelete(BeforeDeleteFn<T>),
AfterInsert(AfterFn<T>),
AfterUpdate(AfterFn<T>),
AfterSave(AfterFn<T>),
AfterDelete(AfterFn<T>),
}
#[derive(Clone)]
pub struct Hooks<T: TableSource> {
pub(crate) before_insert: Vec<(Phase, BeforeFn<T>)>,
pub(crate) before_update: Vec<(Phase, BeforeFn<T>)>,
pub(crate) before_delete: Vec<BeforeDeleteFn<T>>,
pub(crate) after_insert: Vec<AfterFn<T>>,
pub(crate) after_update: Vec<AfterFn<T>>,
pub(crate) after_delete: Vec<AfterFn<T>>,
}
impl<T: TableSource> Default for Hooks<T> {
fn default() -> Self {
Self {
before_insert: Vec::new(),
before_update: Vec::new(),
before_delete: Vec::new(),
after_insert: Vec::new(),
after_update: Vec::new(),
after_delete: Vec::new(),
}
}
}
impl<T: TableSource, E: Entity<T::Value>> Table<T, E> {
pub(crate) fn before_insert_hooks(&self) -> &[(Phase, BeforeFn<T>)] {
&self.hooks.before_insert
}
pub(crate) fn before_update_hooks(&self) -> &[(Phase, BeforeFn<T>)] {
&self.hooks.before_update
}
pub(crate) fn before_delete_hooks(&self) -> &[BeforeDeleteFn<T>] {
&self.hooks.before_delete
}
pub(crate) fn after_insert_hooks(&self) -> &[AfterFn<T>] {
&self.hooks.after_insert
}
pub(crate) fn after_update_hooks(&self) -> &[AfterFn<T>] {
&self.hooks.after_update
}
pub(crate) fn after_delete_hooks(&self) -> &[AfterFn<T>] {
&self.hooks.after_delete
}
pub fn add_hook(&mut self, hook: Hook<T>) {
let hooks = &mut self.hooks;
match hook {
Hook::BeforeInsert(phase, f) => push_phased(&mut hooks.before_insert, phase, f),
Hook::BeforeUpdate(phase, f) => push_phased(&mut hooks.before_update, phase, f),
Hook::BeforeSave(phase, f) => {
push_phased(&mut hooks.before_insert, phase, f.clone());
push_phased(&mut hooks.before_update, phase, f);
}
Hook::BeforeDelete(f) => hooks.before_delete.push(f),
Hook::AfterInsert(f) => hooks.after_insert.push(f),
Hook::AfterUpdate(f) => hooks.after_update.push(f),
Hook::AfterSave(f) => {
hooks.after_insert.push(f.clone());
hooks.after_update.push(f);
}
Hook::AfterDelete(f) => hooks.after_delete.push(f),
}
}
pub fn with_hook(mut self, hook: Hook<T>) -> Self {
self.add_hook(hook);
self
}
}
fn push_phased<T: TableSource>(
hooks: &mut Vec<(Phase, BeforeFn<T>)>,
phase: Phase,
f: BeforeFn<T>,
) {
hooks.push((phase, f));
hooks.sort_by_key(|(p, _)| *p);
}