Skip to main content

runique/migration/hooks/
mod.rs

1//! SeaORM Hooks — before/after save/delete, ordered by execution slot.
2//!
3//! [`HooksDef`] is optional in [`crate::migration::ModelSchema`]:
4//! absent = empty `impl ActiveModelBehavior for ActiveModel {}`.
5
6/// SeaORM hook type.
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub enum HookType {
9    BeforeSave,
10    AfterSave,
11    BeforeDelete,
12    AfterDelete,
13}
14
15/// A hook with its slot (execution order)
16#[derive(Debug, Clone)]
17pub struct Hook {
18    pub hook_type: HookType,
19    pub slot: u8,
20    pub handler_path: String, // path to the handler function
21}
22
23/// Definition of hooks — optional, None = empty ActiveModelBehavior
24#[derive(Debug, Clone, Default)]
25pub struct HooksDef {
26    pub hooks: Vec<Hook>,
27    pub file_path: Option<String>, // src/hooks/article.rs
28}
29
30impl HooksDef {
31    /// Creates an empty hook set.
32    pub fn new() -> Self {
33        Self::default()
34    }
35
36    /// Points to an external file containing business logic
37    pub fn from_file(path: impl Into<String>) -> Self {
38        Self {
39            hooks: Vec::new(),
40            file_path: Some(path.into()),
41        }
42    }
43
44    /// Registers a hook of `hook_type` at `slot`, pointing to `handler`. Hooks
45    /// are kept sorted by slot after every insertion, so execution order is
46    /// always consistent regardless of registration order.
47    pub fn add(mut self, hook_type: HookType, slot: u8, handler: impl Into<String>) -> Self {
48        self.hooks.push(Hook {
49            hook_type,
50            slot,
51            handler_path: handler.into(),
52        });
53        // Sort by slot to guarantee execution order
54        self.hooks.sort_by_key(|h| h.slot);
55        self
56    }
57
58    /// Registers a `BeforeSave` hook at `slot`.
59    pub fn before_save(self, slot: u8, handler: impl Into<String>) -> Self {
60        self.add(HookType::BeforeSave, slot, handler)
61    }
62
63    /// Registers an `AfterSave` hook at `slot`.
64    pub fn after_save(self, slot: u8, handler: impl Into<String>) -> Self {
65        self.add(HookType::AfterSave, slot, handler)
66    }
67
68    /// Registers a `BeforeDelete` hook at `slot`.
69    pub fn before_delete(self, slot: u8, handler: impl Into<String>) -> Self {
70        self.add(HookType::BeforeDelete, slot, handler)
71    }
72
73    /// Registers an `AfterDelete` hook at `slot`.
74    pub fn after_delete(self, slot: u8, handler: impl Into<String>) -> Self {
75        self.add(HookType::AfterDelete, slot, handler)
76    }
77}