1use crate::Row;
8use crate::DbResult;
9use async_trait::async_trait;
10
11#[async_trait]
29pub trait Hook: Send + Sync {
30 async fn before_insert(&self, row: &mut Row) -> DbResult<()> { let _ = row; Ok(()) }
32
33 async fn after_insert(&self, row: &Row) -> DbResult<()> { let _ = row; Ok(()) }
35
36 async fn before_update(&self, row: &mut Row) -> DbResult<()> { let _ = row; Ok(()) }
38
39 async fn after_update(&self, row: &Row) -> DbResult<()> { let _ = row; Ok(()) }
41
42 async fn before_delete(&self, table: &str, id: &str) -> DbResult<()> {
44 let _ = (table, id); Ok(())
45 }
46
47 async fn after_delete(&self, table: &str, id: &str) -> DbResult<()> {
49 let _ = (table, id); Ok(())
50 }
51}
52
53pub struct NullHook;
57
58#[async_trait]
59impl Hook for NullHook {}
60
61pub struct HookChain {
66 hooks: Vec<Box<dyn Hook>>,
68}
69
70impl HookChain {
71 pub fn new() -> Self {
73 Self { hooks: Vec::new() }
74 }
75
76 pub fn add<H: Hook + 'static>(&mut self, hook: H) -> &mut Self {
78 self.hooks.push(Box::new(hook));
79 self
80 }
81}
82
83#[async_trait]
84impl Hook for HookChain {
85 async fn before_insert(&self, row: &mut Row) -> DbResult<()> {
86 for hook in &self.hooks {
87 hook.before_insert(row).await?;
88 }
89 Ok(())
90 }
91
92 async fn after_insert(&self, row: &Row) -> DbResult<()> {
93 for hook in &self.hooks {
94 hook.after_insert(row).await?;
95 }
96 Ok(())
97 }
98
99 async fn before_update(&self, row: &mut Row) -> DbResult<()> {
100 for hook in &self.hooks {
101 hook.before_update(row).await?;
102 }
103 Ok(())
104 }
105
106 async fn after_update(&self, row: &Row) -> DbResult<()> {
107 for hook in &self.hooks {
108 hook.after_update(row).await?;
109 }
110 Ok(())
111 }
112
113 async fn before_delete(&self, table: &str, id: &str) -> DbResult<()> {
114 for hook in &self.hooks {
115 hook.before_delete(table, id).await?;
116 }
117 Ok(())
118 }
119
120 async fn after_delete(&self, table: &str, id: &str) -> DbResult<()> {
121 for hook in &self.hooks {
122 hook.after_delete(table, id).await?;
123 }
124 Ok(())
125 }
126}
127
128impl Default for HookChain {
129 fn default() -> Self {
130 Self::new()
131 }
132}
133
134pub struct TimestampHook;
139
140#[async_trait]
141impl Hook for TimestampHook {
142 async fn before_insert(&self, row: &mut Row) -> DbResult<()> {
143 let now = chrono::Utc::now().to_rfc3339();
144 row.set("created_at", now.as_str());
145 row.set("updated_at", now.as_str());
146 Ok(())
147 }
148
149 async fn before_update(&self, row: &mut Row) -> DbResult<()> {
150 let now = chrono::Utc::now().to_rfc3339();
151 row.set("updated_at", now.as_str());
152 Ok(())
153 }
154}