Skip to main content

doido_model/
callbacks.rs

1//! Active Record-style lifecycle callbacks.
2//!
3//! A model implements [`Callbacks`] (all hooks default to no-op) and persists
4//! through [`run_create`]/[`run_update`]/[`run_destroy`], which fire the hooks in
5//! Rails' order around the supplied persistence step. A hook returning `Err`
6//! aborts before the record is written.
7
8use doido_core::Result;
9
10/// Lifecycle hooks fired around persistence. Override the ones you need.
11pub trait Callbacks {
12    fn before_validation(&mut self) -> Result<()> {
13        Ok(())
14    }
15    fn before_save(&mut self) -> Result<()> {
16        Ok(())
17    }
18    fn after_save(&mut self) -> Result<()> {
19        Ok(())
20    }
21    fn before_create(&mut self) -> Result<()> {
22        Ok(())
23    }
24    fn after_create(&mut self) -> Result<()> {
25        Ok(())
26    }
27    fn before_update(&mut self) -> Result<()> {
28        Ok(())
29    }
30    fn after_update(&mut self) -> Result<()> {
31        Ok(())
32    }
33    fn before_destroy(&mut self) -> Result<()> {
34        Ok(())
35    }
36    fn after_destroy(&mut self) -> Result<()> {
37        Ok(())
38    }
39}
40
41/// Insert: `before_validation → before_save → before_create → persist →
42/// after_create → after_save`.
43pub async fn run_create<M: Callbacks>(
44    model: &mut M,
45    persist: impl AsyncFnOnce(&mut M) -> Result<()>,
46) -> Result<()> {
47    model.before_validation()?;
48    model.before_save()?;
49    model.before_create()?;
50    persist(model).await?;
51    model.after_create()?;
52    model.after_save()?;
53    Ok(())
54}
55
56/// Update: `before_validation → before_save → before_update → persist →
57/// after_update → after_save`.
58pub async fn run_update<M: Callbacks>(
59    model: &mut M,
60    persist: impl AsyncFnOnce(&mut M) -> Result<()>,
61) -> Result<()> {
62    model.before_validation()?;
63    model.before_save()?;
64    model.before_update()?;
65    persist(model).await?;
66    model.after_update()?;
67    model.after_save()?;
68    Ok(())
69}
70
71/// Destroy: `before_destroy → persist → after_destroy`.
72pub async fn run_destroy<M: Callbacks>(
73    model: &mut M,
74    persist: impl AsyncFnOnce(&mut M) -> Result<()>,
75) -> Result<()> {
76    model.before_destroy()?;
77    persist(model).await?;
78    model.after_destroy()?;
79    Ok(())
80}