Skip to main content

sz_orm_core/
observer.rs

1//! Observer + Event Subscriber — 模型生命周期观察者模式
2//!
3//! 对应文档 6.8 节改进项 32(Observer)+ 33(Event Subscriber)。
4//!
5//! # 核心概念
6//!
7//! - **Observer**:观察者接口,订阅模型生命周期事件(INSERT/UPDATE/DELETE/FIND)
8//! - **EventSubscriber**:事件订阅者,按事件类型订阅(比 Observer 更细粒度)
9//! - **EventDispatcher**:事件分发器,管理 Observer 与 EventSubscriber 的注册和分发
10//!
11//! # 与 Behaviors 的区别
12//!
13//! | 特性 | Behaviors (behaviors.rs) | Observer (本模块) |
14//! |------|--------------------------|-------------------|
15//! | 注册方式 | Model 内部声明 | 外部注册到 Dispatcher |
16//! | 解耦程度 | Model 与 Behavior 强耦合 | 完全解耦,Model 无需感知 |
17//! | 适用场景 | 字段自动填充(时间戳/操作人) | 审计日志、缓存失效、外部通知 |
18//! | 事件粒度 | 4 个生命周期事件 | 可订阅特定事件类型 |
19//!
20//! # 设计灵感
21//!
22//! - Doctrine `EventSubscriber` / `LifecycleCallback`
23//! - Hibernate `EntityListener` / `@PostPersist`
24//! - Laravel Eloquent `Observer` 类
25//! - Rails ActiveRecord `Callbacks` + `Observers`
26//!
27//! # 使用示例
28//!
29//! ```
30//! use sz_orm_core::observer::{
31//!     Event, EventDispatcher, EventSubscriber, Observer, SubscriberResult,
32//! };
33//! use sz_orm_core::hooks::HookContext;
34//! use std::collections::HashMap;
35//! use std::sync::{Arc, Mutex};
36//! use sz_orm_core::Value;
37//!
38//! // 1. 审计日志订阅者(订阅所有事件)
39//! struct AuditLogSubscriber {
40//!     logs: Arc<Mutex<Vec<String>>>,
41//! }
42//!
43//! impl EventSubscriber for AuditLogSubscriber {
44//!     fn subscribed_events(&self) -> Vec<Event> {
45//!         vec![Event::AfterInsert, Event::AfterUpdate, Event::AfterDelete]
46//!     }
47//!
48//!     fn on_event(&self, event: Event, ctx: &HookContext, attrs: &HashMap<String, Value>) -> SubscriberResult<()> {
49//!         let mut logs = self.logs.lock().unwrap();
50//!         logs.push(format!("{:?} on attrs with {} fields", event, attrs.len()));
51//!         Ok(())
52//!     }
53//! }
54//!
55//! // 2. 缓存失效订阅者(仅订阅写入事件)
56//! struct CacheInvalidationSubscriber;
57//!
58//! impl EventSubscriber for CacheInvalidationSubscriber {
59//!     fn subscribed_events(&self) -> Vec<Event> {
60//!         vec![Event::AfterUpdate, Event::AfterDelete]
61//!     }
62//!
63//!     fn on_event(&self, event: Event, _ctx: &HookContext, attrs: &HashMap<String, Value>) -> SubscriberResult<()> {
64//!         // 失效缓存逻辑...
65//!         let _ = (event, attrs);
66//!         Ok(())
67//!     }
68//! }
69//!
70//! // 3. 注册并触发事件
71//! let logs = Arc::new(Mutex::new(Vec::new()));
72//! let mut dispatcher = EventDispatcher::new();
73//! dispatcher.subscribe(Box::new(AuditLogSubscriber { logs: logs.clone() }));
74//! dispatcher.subscribe(Box::new(CacheInvalidationSubscriber));
75//!
76//! let ctx = HookContext::default();
77//! let attrs = HashMap::new();
78//! dispatcher.dispatch(Event::AfterInsert, &ctx, &attrs);
79//!
80//! assert_eq!(logs.lock().unwrap().len(), 1);
81//! ```
82
83use crate::hooks::HookContext;
84use crate::Value;
85use std::collections::HashMap;
86use std::sync::{Arc, RwLock};
87
88// ============================================================================
89// Event — 事件类型
90// ============================================================================
91
92/// 模型生命周期事件类型
93///
94/// 与 `hooks::HookEvent` 类似但简化为运行时分发用的事件枚举。
95#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
96pub enum Event {
97    /// 插入前
98    BeforeInsert,
99    /// 插入后
100    AfterInsert,
101    /// 更新前
102    BeforeUpdate,
103    /// 更新后
104    AfterUpdate,
105    /// 删除前
106    BeforeDelete,
107    /// 删除后
108    AfterDelete,
109    /// 单行查询后
110    AfterFind,
111    /// 软删除恢复前
112    BeforeRestore,
113    /// 软删除恢复后
114    AfterRestore,
115}
116
117impl Event {
118    /// 是否为 before 事件
119    pub fn is_before(&self) -> bool {
120        matches!(
121            self,
122            Event::BeforeInsert | Event::BeforeUpdate | Event::BeforeDelete | Event::BeforeRestore
123        )
124    }
125
126    /// 是否为 after 事件
127    pub fn is_after(&self) -> bool {
128        matches!(
129            self,
130            Event::AfterInsert
131                | Event::AfterUpdate
132                | Event::AfterDelete
133                | Event::AfterFind
134                | Event::AfterRestore
135        )
136    }
137
138    /// 是否为写入事件(INSERT/UPDATE/DELETE)
139    pub fn is_write_event(&self) -> bool {
140        matches!(
141            self,
142            Event::BeforeInsert
143                | Event::AfterInsert
144                | Event::BeforeUpdate
145                | Event::AfterUpdate
146                | Event::BeforeDelete
147                | Event::AfterDelete
148        )
149    }
150
151    /// 事件名称(用于日志与错误信息)
152    pub fn name(&self) -> &'static str {
153        match self {
154            Event::BeforeInsert => "before_insert",
155            Event::AfterInsert => "after_insert",
156            Event::BeforeUpdate => "before_update",
157            Event::AfterUpdate => "after_update",
158            Event::BeforeDelete => "before_delete",
159            Event::AfterDelete => "after_delete",
160            Event::AfterFind => "after_find",
161            Event::BeforeRestore => "before_restore",
162            Event::AfterRestore => "after_restore",
163        }
164    }
165}
166
167// ============================================================================
168// SubscriberError — 订阅者错误
169// ============================================================================
170
171/// 订阅者错误类型
172#[derive(Debug)]
173pub enum SubscriberError {
174    /// 订阅者执行失败(携带错误描述)
175    Failed {
176        /// 订阅者名称
177        subscriber: String,
178        /// 错误描述
179        reason: String,
180    },
181    /// 中止后续订阅者执行(用于 veto 模式)
182    ///
183    /// 例如:before_insert 钩子拒绝该次插入
184    Vetoed {
185        /// 订阅者名称
186        subscriber: String,
187        /// 拒绝原因
188        reason: String,
189    },
190}
191
192impl std::fmt::Display for SubscriberError {
193    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
194        match self {
195            SubscriberError::Failed { subscriber, reason } => {
196                write!(f, "Subscriber `{}` failed: {}", subscriber, reason)
197            }
198            SubscriberError::Vetoed { subscriber, reason } => {
199                write!(f, "Subscriber `{}` vetoed: {}", subscriber, reason)
200            }
201        }
202    }
203}
204
205impl std::error::Error for SubscriberError {}
206
207/// 订阅者结果类型
208pub type SubscriberResult<T> = Result<T, SubscriberError>;
209
210// ============================================================================
211// Observer — 模型观察者 trait
212// ============================================================================
213
214/// 模型观察者 trait
215///
216/// 与 `EventSubscriber` 不同,`Observer` 默认订阅所有事件。
217/// 适合需要监控所有生命周期事件的场景(如审计日志)。
218///
219/// # 实现要点
220///
221/// - 所有方法默认实现为 no-op,按需 override
222/// - 任何方法返回 `Err(SubscriberError::Vetoed)` 会中止 before 事件的后续执行
223pub trait Observer: Send + Sync {
224    /// 观察者名称(用于日志与错误信息)
225    fn name(&self) -> &str {
226        "anonymous_observer"
227    }
228
229    /// 插入前
230    fn before_insert(
231        &self,
232        _ctx: &HookContext,
233        _attrs: &mut HashMap<String, Value>,
234    ) -> SubscriberResult<()> {
235        Ok(())
236    }
237
238    /// 插入后
239    fn after_insert(
240        &self,
241        _ctx: &HookContext,
242        _attrs: &HashMap<String, Value>,
243    ) -> SubscriberResult<()> {
244        Ok(())
245    }
246
247    /// 更新前
248    fn before_update(
249        &self,
250        _ctx: &HookContext,
251        _attrs: &mut HashMap<String, Value>,
252    ) -> SubscriberResult<()> {
253        Ok(())
254    }
255
256    /// 更新后
257    fn after_update(
258        &self,
259        _ctx: &HookContext,
260        _attrs: &HashMap<String, Value>,
261    ) -> SubscriberResult<()> {
262        Ok(())
263    }
264
265    /// 删除前
266    fn before_delete(
267        &self,
268        _ctx: &HookContext,
269        _attrs: &HashMap<String, Value>,
270    ) -> SubscriberResult<()> {
271        Ok(())
272    }
273
274    /// 删除后
275    fn after_delete(
276        &self,
277        _ctx: &HookContext,
278        _attrs: &HashMap<String, Value>,
279    ) -> SubscriberResult<()> {
280        Ok(())
281    }
282
283    /// 单行查询后
284    fn after_find(
285        &self,
286        _ctx: &HookContext,
287        _attrs: &mut HashMap<String, Value>,
288    ) -> SubscriberResult<()> {
289        Ok(())
290    }
291}
292
293// ============================================================================
294// EventSubscriber — 事件订阅者 trait
295// ============================================================================
296
297/// 事件订阅者 trait
298///
299/// 与 `Observer` 不同,`EventSubscriber` 只接收订阅的特定事件。
300/// 适合只关心特定事件的场景(如缓存失效仅关心 UPDATE/DELETE)。
301pub trait EventSubscriber: Send + Sync {
302    /// 订阅者名称
303    fn name(&self) -> &str {
304        "anonymous_subscriber"
305    }
306
307    /// 返回订阅的事件列表
308    ///
309    /// 仅当事件在此列表中时,`on_event` 才会被调用。
310    fn subscribed_events(&self) -> Vec<Event>;
311
312    /// 事件回调
313    ///
314    /// # 参数
315    /// - `event`:触发的事件
316    /// - `ctx`:钩子上下文
317    /// - `attrs`:当前属性(before 事件可修改)
318    ///
319    /// # 返回
320    /// - `Ok(())`:继续执行后续订阅者
321    /// - `Err(SubscriberError::Vetoed)`:中止 before 事件的后续执行
322    /// - `Err(SubscriberError::Failed)`:记录错误,继续执行后续订阅者
323    fn on_event(
324        &self,
325        event: Event,
326        ctx: &HookContext,
327        attrs: &HashMap<String, Value>,
328    ) -> SubscriberResult<()>;
329}
330
331// ============================================================================
332// EventDispatcher — 事件分发器
333// ============================================================================
334
335/// 事件分发器
336///
337/// 管理 `Observer` 与 `EventSubscriber` 的注册与分发。
338///
339/// # 分发顺序
340///
341/// 1. 先按注册顺序调用所有 `Observer` 的对应方法
342/// 2. 再按注册顺序调用所有订阅了该事件的 `EventSubscriber`
343///
344/// # 错误处理
345///
346/// - `before_*` 事件中任何订阅者返回 `Err(Vetoed)` 会立即中止后续执行
347/// - `after_*` 事件中的错误仅记录,不影响后续执行
348///
349/// # 线程安全
350///
351/// 内部使用 `RwLock<Vec<Arc<...>>>`,支持多线程并发。
352///
353/// # 死锁防护(v0.2.1 修复 Critical C-3)
354///
355/// `dispatch` / `dispatch_before_mut` 在调用用户回调前会先 clone 一份
356/// `Vec<Arc<dyn ...>>` 快照并释放读锁,避免持读锁调用用户代码——
357/// 否则用户回调中若尝试注册新订阅者(需要写锁)会自我死锁。
358pub struct EventDispatcher {
359    observers: RwLock<Vec<Arc<dyn Observer>>>,
360    subscribers: RwLock<Vec<Arc<dyn EventSubscriber>>>,
361    /// 错误收集(非致命错误,不影响流程)
362    errors: RwLock<Vec<SubscriberError>>,
363    /// 错误缓冲区最大容量(防止内存无限增长)
364    ///
365    /// 当 errors 长度达到此上限时,新增错误会以 FIFO 方式淘汰最早错误。
366    /// 默认 1024,可通过 `with_max_errors` 调整。
367    max_errors: usize,
368}
369
370/// 默认错误缓冲区容量
371const DEFAULT_MAX_ERRORS: usize = 1024;
372
373impl EventDispatcher {
374    /// 创建空的事件分发器
375    pub fn new() -> Self {
376        Self {
377            observers: RwLock::new(Vec::new()),
378            subscribers: RwLock::new(Vec::new()),
379            errors: RwLock::new(Vec::new()),
380            max_errors: DEFAULT_MAX_ERRORS,
381        }
382    }
383
384    /// 设置错误缓冲区最大容量
385    ///
386    /// 当 errors 达到此容量时,新增错误会淘汰最早错误(FIFO)。
387    /// 设置为 0 表示无限制(不推荐,可能导致内存泄漏)。
388    pub fn with_max_errors(mut self, max_errors: usize) -> Self {
389        self.max_errors = max_errors;
390        self
391    }
392
393    /// 注册 Observer
394    ///
395    /// 接收 `Box<dyn Observer>`(向后兼容),内部转 `Arc<dyn Observer>` 存储,
396    /// 以便 dispatch 时可以 cheap clone 快照后释放读锁。
397    pub fn add_observer(&self, observer: Box<dyn Observer>) {
398        let arc: Arc<dyn Observer> = Arc::from(observer);
399        self.observers.write().unwrap().push(arc);
400    }
401
402    /// 注册 EventSubscriber
403    ///
404    /// 接收 `Box<dyn EventSubscriber>`(向后兼容),内部转 `Arc<dyn EventSubscriber>` 存储。
405    pub fn subscribe(&self, subscriber: Box<dyn EventSubscriber>) {
406        let arc: Arc<dyn EventSubscriber> = Arc::from(subscriber);
407        self.subscribers.write().unwrap().push(arc);
408    }
409
410    /// 清空所有注册
411    pub fn clear(&self) {
412        self.observers.write().unwrap().clear();
413        self.subscribers.write().unwrap().clear();
414        self.errors.write().unwrap().clear();
415    }
416
417    /// 返回已注册的 Observer 数量
418    pub fn observer_count(&self) -> usize {
419        self.observers.read().unwrap().len()
420    }
421
422    /// 返回已注册的 EventSubscriber 数量
423    pub fn subscriber_count(&self) -> usize {
424        self.subscribers.read().unwrap().len()
425    }
426
427    /// 取出收集到的非致命错误(清空内部缓冲)
428    pub fn drain_errors(&self) -> Vec<SubscriberError> {
429        std::mem::take(&mut *self.errors.write().unwrap())
430    }
431
432    /// 返回当前错误缓冲区中的错误数量
433    pub fn error_count(&self) -> usize {
434        self.errors.read().unwrap().len()
435    }
436
437    /// 将本地错误批量写入 errors 缓冲区,遵循 max_errors 限制(FIFO 淘汰)
438    ///
439    /// - `max_errors = 0` 表示无限制
440    /// - 否则当 errors 达到上限时,淘汰最早错误以腾出空间
441    fn push_errors(&self, new_errors: Vec<SubscriberError>) {
442        if new_errors.is_empty() {
443            return;
444        }
445        let mut errors = self.errors.write().unwrap();
446        if self.max_errors == 0 {
447            errors.extend(new_errors);
448            return;
449        }
450        for e in new_errors {
451            if errors.len() >= self.max_errors {
452                // FIFO 淘汰最早错误
453                errors.remove(0);
454            }
455            errors.push(e);
456        }
457    }
458
459    /// 分发事件(after_* 事件,attrs 不可变)
460    ///
461    /// 错误仅记录,不影响后续订阅者执行。
462    ///
463    /// # 实现要点
464    ///
465    /// - **v0.2.1 修复 Critical C-3**:调用用户回调前先 clone `Vec<Arc<...>>` 快照
466    ///   并释放读锁,避免持读锁调用用户代码(防止死锁)
467    /// - 错误先收集到本地 `Vec`,循环结束后一次性批量写入 `self.errors`
468    pub fn dispatch(&self, event: Event, ctx: &HookContext, attrs: &HashMap<String, Value>) {
469        let mut local_errors: Vec<SubscriberError> = Vec::new();
470
471        // 1. 调用 Observers — 持读锁仅 clone 快照,立即释放
472        let observers_snapshot: Vec<Arc<dyn Observer>> = {
473            let observers = self.observers.read().unwrap();
474            observers.clone()
475        };
476        // 释放读锁后调用用户代码
477        for observer in observers_snapshot.iter() {
478            let result = match event {
479                Event::AfterInsert => observer.after_insert(ctx, attrs),
480                Event::AfterUpdate => observer.after_update(ctx, attrs),
481                Event::AfterDelete => observer.after_delete(ctx, attrs),
482                _ => Ok(()),
483            };
484            if let Err(e) = result {
485                local_errors.push(e);
486            }
487        }
488
489        // 2. 调用 EventSubscribers — 持读锁仅 clone 快照,立即释放
490        let subscribers_snapshot: Vec<Arc<dyn EventSubscriber>> = {
491            let subscribers = self.subscribers.read().unwrap();
492            subscribers.clone()
493        };
494        for subscriber in subscribers_snapshot.iter() {
495            if !subscriber.subscribed_events().contains(&event) {
496                continue;
497            }
498            if let Err(e) = subscriber.on_event(event, ctx, attrs) {
499                local_errors.push(e);
500            }
501        }
502
503        if !local_errors.is_empty() {
504            self.push_errors(local_errors);
505        }
506    }
507
508    /// 分发 before 事件(attrs 可变)
509    ///
510    /// 任何订阅者返回 `Err(Vetoed)` 会立即中止并返回错误。
511    ///
512    /// # 实现要点
513    ///
514    /// - Vetoed 时直接返回该错误,**不会再次调用 `on_event`**(避免订阅者副作用翻倍)
515    /// - **v0.2.1 修复 Critical C-3**:调用用户回调前先 clone 快照并释放读锁
516    /// - 错误先收集到本地 `Vec`,避免持读锁时获取写锁造成死锁
517    pub fn dispatch_before_mut(
518        &self,
519        event: Event,
520        ctx: &HookContext,
521        attrs: &mut HashMap<String, Value>,
522    ) -> SubscriberResult<()> {
523        let mut local_errors: Vec<SubscriberError> = Vec::new();
524        let mut vetoed: Option<SubscriberError> = None;
525
526        // 1. 调用 Observers — 持读锁仅 clone 快照,立即释放
527        let observers_snapshot: Vec<Arc<dyn Observer>> = {
528            let observers = self.observers.read().unwrap();
529            observers.clone()
530        };
531        for observer in observers_snapshot.iter() {
532            let result = match event {
533                Event::BeforeInsert => observer.before_insert(ctx, attrs),
534                Event::BeforeUpdate => observer.before_update(ctx, attrs),
535                _ => Ok(()),
536            };
537            match result {
538                Ok(()) => {}
539                Err(e @ SubscriberError::Vetoed { .. }) => {
540                    vetoed = Some(e);
541                    break;
542                }
543                Err(e) => local_errors.push(e),
544            }
545        }
546
547        // 2. 调用 EventSubscribers(仅当未被 vetoed)— 持读锁仅 clone 快照,立即释放
548        if vetoed.is_none() {
549            let subscribers_snapshot: Vec<Arc<dyn EventSubscriber>> = {
550                let subscribers = self.subscribers.read().unwrap();
551                subscribers.clone()
552            };
553            for subscriber in subscribers_snapshot.iter() {
554                if !subscriber.subscribed_events().contains(&event) {
555                    continue;
556                }
557                match subscriber.on_event(event, ctx, attrs) {
558                    Ok(()) => {}
559                    Err(e @ SubscriberError::Vetoed { .. }) => {
560                        vetoed = Some(e);
561                        break;
562                    }
563                    Err(e) => local_errors.push(e),
564                }
565            }
566        }
567
568        if !local_errors.is_empty() {
569            self.push_errors(local_errors);
570        }
571
572        if let Some(e) = vetoed {
573            return Err(e);
574        }
575        Ok(())
576    }
577
578    /// 分发 after_find 事件(attrs 可变,用于修改读出的数据)
579    ///
580    /// # 实现要点
581    ///
582    /// - **v0.2.1 修复 Critical C-3**:调用用户回调前先 clone 快照并释放读锁
583    /// - 错误先收集到本地 `Vec`,避免持读锁时获取写锁造成死锁
584    pub fn dispatch_after_find(
585        &self,
586        ctx: &HookContext,
587        attrs: &mut HashMap<String, Value>,
588    ) -> SubscriberResult<()> {
589        let mut local_errors: Vec<SubscriberError> = Vec::new();
590
591        let observers_snapshot: Vec<Arc<dyn Observer>> = {
592            let observers = self.observers.read().unwrap();
593            observers.clone()
594        };
595        for observer in observers_snapshot.iter() {
596            if let Err(e) = observer.after_find(ctx, attrs) {
597                local_errors.push(e);
598            }
599        }
600
601        let subscribers_snapshot: Vec<Arc<dyn EventSubscriber>> = {
602            let subscribers = self.subscribers.read().unwrap();
603            subscribers.clone()
604        };
605        for subscriber in subscribers_snapshot.iter() {
606            if !subscriber.subscribed_events().contains(&Event::AfterFind) {
607                continue;
608            }
609            if let Err(e) = subscriber.on_event(Event::AfterFind, ctx, attrs) {
610                local_errors.push(e);
611            }
612        }
613
614        if !local_errors.is_empty() {
615            self.push_errors(local_errors);
616        }
617
618        Ok(())
619    }
620}
621
622impl Default for EventDispatcher {
623    fn default() -> Self {
624        Self::new()
625    }
626}
627
628// ============================================================================
629// 内置订阅者实现
630// ============================================================================
631
632// -------------------- AuditLogSubscriber --------------------
633
634/// 审计日志订阅者
635///
636/// 记录所有写入操作到内部日志缓冲,可用于调试或审计。
637///
638/// # 示例
639///
640/// ```
641/// use sz_orm_core::observer::{EventDispatcher, AuditLogSubscriber, Event};
642/// use sz_orm_core::hooks::HookContext;
643/// use std::collections::HashMap;
644///
645/// let audit = AuditLogSubscriber::new();
646/// let mut dispatcher = EventDispatcher::new();
647/// dispatcher.subscribe(Box::new(audit.clone()));
648///
649/// let ctx = HookContext::default();
650/// let attrs = HashMap::new();
651/// dispatcher.dispatch(Event::AfterInsert, &ctx, &attrs);
652///
653/// assert_eq!(audit.logs().lock().unwrap().len(), 1);
654/// ```
655#[derive(Clone)]
656pub struct AuditLogSubscriber {
657    logs: std::sync::Arc<std::sync::Mutex<Vec<String>>>,
658}
659
660impl AuditLogSubscriber {
661    /// 创建审计日志订阅者
662    pub fn new() -> Self {
663        Self {
664            logs: std::sync::Arc::new(std::sync::Mutex::new(Vec::new())),
665        }
666    }
667
668    /// 获取日志列表(用于断言)
669    pub fn logs(&self) -> &std::sync::Arc<std::sync::Mutex<Vec<String>>> {
670        &self.logs
671    }
672}
673
674impl Default for AuditLogSubscriber {
675    fn default() -> Self {
676        Self::new()
677    }
678}
679
680impl EventSubscriber for AuditLogSubscriber {
681    fn name(&self) -> &str {
682        "audit_log"
683    }
684
685    fn subscribed_events(&self) -> Vec<Event> {
686        vec![Event::AfterInsert, Event::AfterUpdate, Event::AfterDelete]
687    }
688
689    fn on_event(
690        &self,
691        event: Event,
692        ctx: &HookContext,
693        attrs: &HashMap<String, Value>,
694    ) -> SubscriberResult<()> {
695        let mut logs = self.logs.lock().unwrap();
696        logs.push(format!(
697            "event={} operator={:?} field_count={}",
698            event.name(),
699            ctx.operator_id,
700            attrs.len()
701        ));
702        Ok(())
703    }
704}
705
706// ============================================================================
707// 单元测试
708// ============================================================================
709
710#[cfg(test)]
711mod tests {
712    use super::*;
713    use std::sync::{Arc, Mutex};
714
715    // ===== Event 测试 =====
716
717    #[test]
718    fn test_event_is_before_after() {
719        assert!(Event::BeforeInsert.is_before());
720        assert!(!Event::BeforeInsert.is_after());
721        assert!(Event::AfterInsert.is_after());
722        assert!(!Event::AfterInsert.is_before());
723    }
724
725    #[test]
726    fn test_event_is_write_event() {
727        assert!(Event::BeforeInsert.is_write_event());
728        assert!(Event::AfterUpdate.is_write_event());
729        assert!(Event::BeforeDelete.is_write_event());
730        assert!(!Event::AfterFind.is_write_event());
731    }
732
733    #[test]
734    fn test_event_name() {
735        assert_eq!(Event::BeforeInsert.name(), "before_insert");
736        assert_eq!(Event::AfterDelete.name(), "after_delete");
737        assert_eq!(Event::AfterFind.name(), "after_find");
738    }
739
740    // ===== EventDispatcher 基础测试 =====
741
742    #[test]
743    fn test_new_dispatcher_is_empty() {
744        let d = EventDispatcher::new();
745        assert_eq!(d.observer_count(), 0);
746        assert_eq!(d.subscriber_count(), 0);
747    }
748
749    #[test]
750    fn test_add_observer() {
751        struct DummyObserver;
752        impl Observer for DummyObserver {}
753
754        let d = EventDispatcher::new();
755        d.add_observer(Box::new(DummyObserver));
756        assert_eq!(d.observer_count(), 1);
757    }
758
759    #[test]
760    fn test_subscribe() {
761        struct DummySubscriber;
762        impl EventSubscriber for DummySubscriber {
763            fn subscribed_events(&self) -> Vec<Event> {
764                vec![Event::AfterInsert]
765            }
766            fn on_event(
767                &self,
768                _event: Event,
769                _ctx: &HookContext,
770                _attrs: &HashMap<String, Value>,
771            ) -> SubscriberResult<()> {
772                Ok(())
773            }
774        }
775
776        let d = EventDispatcher::new();
777        d.subscribe(Box::new(DummySubscriber));
778        assert_eq!(d.subscriber_count(), 1);
779    }
780
781    #[test]
782    fn test_clear() {
783        struct DummyObserver;
784        impl Observer for DummyObserver {}
785
786        let d = EventDispatcher::new();
787        d.add_observer(Box::new(DummyObserver));
788        d.clear();
789        assert_eq!(d.observer_count(), 0);
790    }
791
792    // ===== Observer 触发测试 =====
793
794    /// 计数 Observer,用于测试
795    struct CountingObserver {
796        insert_count: Arc<Mutex<u32>>,
797        update_count: Arc<Mutex<u32>>,
798        delete_count: Arc<Mutex<u32>>,
799    }
800
801    impl Observer for CountingObserver {
802        fn name(&self) -> &str {
803            "counting"
804        }
805
806        fn after_insert(
807            &self,
808            _ctx: &HookContext,
809            _attrs: &HashMap<String, Value>,
810        ) -> SubscriberResult<()> {
811            *self.insert_count.lock().unwrap() += 1;
812            Ok(())
813        }
814
815        fn after_update(
816            &self,
817            _ctx: &HookContext,
818            _attrs: &HashMap<String, Value>,
819        ) -> SubscriberResult<()> {
820            *self.update_count.lock().unwrap() += 1;
821            Ok(())
822        }
823
824        fn after_delete(
825            &self,
826            _ctx: &HookContext,
827            _attrs: &HashMap<String, Value>,
828        ) -> SubscriberResult<()> {
829            *self.delete_count.lock().unwrap() += 1;
830            Ok(())
831        }
832    }
833
834    #[test]
835    fn test_observer_triggered_on_dispatch() {
836        let insert = Arc::new(Mutex::new(0u32));
837        let update = Arc::new(Mutex::new(0u32));
838        let delete = Arc::new(Mutex::new(0u32));
839
840        let observer = CountingObserver {
841            insert_count: insert.clone(),
842            update_count: update.clone(),
843            delete_count: delete.clone(),
844        };
845
846        let d = EventDispatcher::new();
847        d.add_observer(Box::new(observer));
848
849        let ctx = HookContext::default();
850        let attrs = HashMap::new();
851
852        d.dispatch(Event::AfterInsert, &ctx, &attrs);
853        d.dispatch(Event::AfterInsert, &ctx, &attrs);
854        d.dispatch(Event::AfterUpdate, &ctx, &attrs);
855        d.dispatch(Event::AfterDelete, &ctx, &attrs);
856
857        assert_eq!(*insert.lock().unwrap(), 2);
858        assert_eq!(*update.lock().unwrap(), 1);
859        assert_eq!(*delete.lock().unwrap(), 1);
860    }
861
862    #[test]
863    fn test_observer_before_event_can_modify_attrs() {
864        struct TimestampInjector;
865        impl Observer for TimestampInjector {
866            fn before_insert(
867                &self,
868                _ctx: &HookContext,
869                attrs: &mut HashMap<String, Value>,
870            ) -> SubscriberResult<()> {
871                attrs.insert(
872                    "created_at".to_string(),
873                    Value::String("2026-07-19".to_string()),
874                );
875                Ok(())
876            }
877        }
878
879        let d = EventDispatcher::new();
880        d.add_observer(Box::new(TimestampInjector));
881
882        let ctx = HookContext::default();
883        let mut attrs = HashMap::new();
884        d.dispatch_before_mut(Event::BeforeInsert, &ctx, &mut attrs)
885            .unwrap();
886
887        assert_eq!(
888            attrs.get("created_at"),
889            Some(&Value::String("2026-07-19".to_string()))
890        );
891    }
892
893    // ===== EventSubscriber 测试 =====
894
895    /// 只订阅 AfterInsert 的订阅者
896    struct InsertOnlySubscriber {
897        called: Arc<Mutex<u32>>,
898    }
899
900    impl EventSubscriber for InsertOnlySubscriber {
901        fn name(&self) -> &str {
902            "insert_only"
903        }
904
905        fn subscribed_events(&self) -> Vec<Event> {
906            vec![Event::AfterInsert]
907        }
908
909        fn on_event(
910            &self,
911            _event: Event,
912            _ctx: &HookContext,
913            _attrs: &HashMap<String, Value>,
914        ) -> SubscriberResult<()> {
915            *self.called.lock().unwrap() += 1;
916            Ok(())
917        }
918    }
919
920    #[test]
921    fn test_subscriber_only_called_for_subscribed_events() {
922        let called = Arc::new(Mutex::new(0u32));
923        let subscriber = InsertOnlySubscriber {
924            called: called.clone(),
925        };
926
927        let d = EventDispatcher::new();
928        d.subscribe(Box::new(subscriber));
929
930        let ctx = HookContext::default();
931        let attrs = HashMap::new();
932
933        // AfterInsert 应触发
934        d.dispatch(Event::AfterInsert, &ctx, &attrs);
935        // AfterUpdate 不应触发(未订阅)
936        d.dispatch(Event::AfterUpdate, &ctx, &attrs);
937        // AfterDelete 不应触发
938        d.dispatch(Event::AfterDelete, &ctx, &attrs);
939        // 再触发一次 AfterInsert
940        d.dispatch(Event::AfterInsert, &ctx, &attrs);
941
942        assert_eq!(*called.lock().unwrap(), 2);
943    }
944
945    #[test]
946    fn test_subscriber_veto_aborts_before_event() {
947        struct VetoSubscriber;
948        impl EventSubscriber for VetoSubscriber {
949            fn name(&self) -> &str {
950                "veto"
951            }
952            fn subscribed_events(&self) -> Vec<Event> {
953                vec![Event::BeforeInsert]
954            }
955            fn on_event(
956                &self,
957                _event: Event,
958                _ctx: &HookContext,
959                _attrs: &HashMap<String, Value>,
960            ) -> SubscriberResult<()> {
961                Err(SubscriberError::Vetoed {
962                    subscriber: "veto".to_string(),
963                    reason: "Business rule violation".to_string(),
964                })
965            }
966        }
967
968        let d = EventDispatcher::new();
969        d.subscribe(Box::new(VetoSubscriber));
970
971        let ctx = HookContext::default();
972        let mut attrs = HashMap::new();
973        let result = d.dispatch_before_mut(Event::BeforeInsert, &ctx, &mut attrs);
974
975        assert!(matches!(result, Err(SubscriberError::Vetoed { .. })));
976    }
977
978    #[test]
979    fn test_subscriber_failed_does_not_abort_after_event() {
980        struct FailingSubscriber;
981        impl EventSubscriber for FailingSubscriber {
982            fn name(&self) -> &str {
983                "failing"
984            }
985            fn subscribed_events(&self) -> Vec<Event> {
986                vec![Event::AfterInsert]
987            }
988            fn on_event(
989                &self,
990                _event: Event,
991                _ctx: &HookContext,
992                _attrs: &HashMap<String, Value>,
993            ) -> SubscriberResult<()> {
994                Err(SubscriberError::Failed {
995                    subscriber: "failing".to_string(),
996                    reason: "Connection lost".to_string(),
997                })
998            }
999        }
1000
1001        struct CountingSubscriber {
1002            called: Arc<Mutex<u32>>,
1003        }
1004        impl EventSubscriber for CountingSubscriber {
1005            fn name(&self) -> &str {
1006                "counting"
1007            }
1008            fn subscribed_events(&self) -> Vec<Event> {
1009                vec![Event::AfterInsert]
1010            }
1011            fn on_event(
1012                &self,
1013                _event: Event,
1014                _ctx: &HookContext,
1015                _attrs: &HashMap<String, Value>,
1016            ) -> SubscriberResult<()> {
1017                *self.called.lock().unwrap() += 1;
1018                Ok(())
1019            }
1020        }
1021
1022        let called = Arc::new(Mutex::new(0u32));
1023        let d = EventDispatcher::new();
1024        d.subscribe(Box::new(FailingSubscriber));
1025        d.subscribe(Box::new(CountingSubscriber {
1026            called: called.clone(),
1027        }));
1028
1029        let ctx = HookContext::default();
1030        let attrs = HashMap::new();
1031        d.dispatch(Event::AfterInsert, &ctx, &attrs);
1032
1033        // 即使 FailingSubscriber 失败,CountingSubscriber 仍应被调用
1034        assert_eq!(*called.lock().unwrap(), 1);
1035    }
1036
1037    // ===== AuditLogSubscriber 测试 =====
1038
1039    #[test]
1040    fn test_audit_log_subscriber() {
1041        let audit = AuditLogSubscriber::new();
1042        let audit_clone = audit.clone();
1043
1044        let d = EventDispatcher::new();
1045        d.subscribe(Box::new(audit_clone));
1046
1047        let ctx = HookContext {
1048            operator_id: Some(42),
1049            ..Default::default()
1050        };
1051        let mut attrs = HashMap::new();
1052        attrs.insert("name".to_string(), Value::String("alice".to_string()));
1053
1054        d.dispatch(Event::AfterInsert, &ctx, &attrs);
1055        d.dispatch(Event::AfterUpdate, &ctx, &attrs);
1056        d.dispatch(Event::AfterDelete, &ctx, &attrs);
1057        // AfterFind 不在订阅列表,不应记录
1058        d.dispatch_after_find(&ctx, &mut attrs).unwrap();
1059
1060        let logs = audit.logs().lock().unwrap();
1061        assert_eq!(logs.len(), 3);
1062        assert!(logs[0].contains("event=after_insert"));
1063        assert!(logs[0].contains("operator=Some(42)"));
1064        assert!(logs[0].contains("field_count=1"));
1065    }
1066
1067    // ===== 多订阅者协同测试 =====
1068
1069    #[test]
1070    fn test_multiple_subscribers_and_observers() {
1071        let sub1_called = Arc::new(Mutex::new(0u32));
1072        let sub2_called = Arc::new(Mutex::new(0u32));
1073        let obs_called = Arc::new(Mutex::new(0u32));
1074
1075        struct Sub1(Arc<Mutex<u32>>);
1076        impl EventSubscriber for Sub1 {
1077            fn name(&self) -> &str {
1078                "sub1"
1079            }
1080            fn subscribed_events(&self) -> Vec<Event> {
1081                vec![Event::AfterInsert]
1082            }
1083            fn on_event(
1084                &self,
1085                _e: Event,
1086                _c: &HookContext,
1087                _a: &HashMap<String, Value>,
1088            ) -> SubscriberResult<()> {
1089                *self.0.lock().unwrap() += 1;
1090                Ok(())
1091            }
1092        }
1093
1094        struct Sub2(Arc<Mutex<u32>>);
1095        impl EventSubscriber for Sub2 {
1096            fn name(&self) -> &str {
1097                "sub2"
1098            }
1099            fn subscribed_events(&self) -> Vec<Event> {
1100                vec![Event::AfterInsert, Event::AfterUpdate]
1101            }
1102            fn on_event(
1103                &self,
1104                _e: Event,
1105                _c: &HookContext,
1106                _a: &HashMap<String, Value>,
1107            ) -> SubscriberResult<()> {
1108                *self.0.lock().unwrap() += 1;
1109                Ok(())
1110            }
1111        }
1112
1113        struct Obs(Arc<Mutex<u32>>);
1114        impl Observer for Obs {
1115            fn name(&self) -> &str {
1116                "obs"
1117            }
1118            fn after_insert(
1119                &self,
1120                _c: &HookContext,
1121                _a: &HashMap<String, Value>,
1122            ) -> SubscriberResult<()> {
1123                *self.0.lock().unwrap() += 1;
1124                Ok(())
1125            }
1126        }
1127
1128        let d = EventDispatcher::new();
1129        d.subscribe(Box::new(Sub1(sub1_called.clone())));
1130        d.subscribe(Box::new(Sub2(sub2_called.clone())));
1131        d.add_observer(Box::new(Obs(obs_called.clone())));
1132
1133        let ctx = HookContext::default();
1134        let attrs = HashMap::new();
1135
1136        d.dispatch(Event::AfterInsert, &ctx, &attrs);
1137
1138        assert_eq!(*sub1_called.lock().unwrap(), 1);
1139        assert_eq!(*sub2_called.lock().unwrap(), 1);
1140        assert_eq!(*obs_called.lock().unwrap(), 1);
1141    }
1142
1143    // ===== 错误收集测试 =====
1144
1145    #[test]
1146    fn test_drain_errors() {
1147        struct ErrSub;
1148        impl EventSubscriber for ErrSub {
1149            fn name(&self) -> &str {
1150                "err"
1151            }
1152            fn subscribed_events(&self) -> Vec<Event> {
1153                vec![Event::AfterInsert]
1154            }
1155            fn on_event(
1156                &self,
1157                _e: Event,
1158                _c: &HookContext,
1159                _a: &HashMap<String, Value>,
1160            ) -> SubscriberResult<()> {
1161                Err(SubscriberError::Failed {
1162                    subscriber: "err".to_string(),
1163                    reason: "test".to_string(),
1164                })
1165            }
1166        }
1167
1168        let d = EventDispatcher::new();
1169        d.subscribe(Box::new(ErrSub));
1170
1171        let ctx = HookContext::default();
1172        let attrs = HashMap::new();
1173        d.dispatch(Event::AfterInsert, &ctx, &attrs);
1174        d.dispatch(Event::AfterInsert, &ctx, &attrs);
1175
1176        let errors = d.drain_errors();
1177        assert_eq!(errors.len(), 2);
1178        assert!(matches!(errors[0], SubscriberError::Failed { .. }));
1179
1180        // drain 后内部应为空
1181        let errors = d.drain_errors();
1182        assert!(errors.is_empty());
1183    }
1184
1185    // ===== max_errors 限制测试(防内存无限增长) =====
1186
1187    #[test]
1188    fn test_max_errors_limits_buffer_size() {
1189        struct ErrSub;
1190        impl EventSubscriber for ErrSub {
1191            fn name(&self) -> &str {
1192                "err"
1193            }
1194            fn subscribed_events(&self) -> Vec<Event> {
1195                vec![Event::AfterInsert]
1196            }
1197            fn on_event(
1198                &self,
1199                _e: Event,
1200                _c: &HookContext,
1201                _a: &HashMap<String, Value>,
1202            ) -> SubscriberResult<()> {
1203                Err(SubscriberError::Failed {
1204                    subscriber: "err".to_string(),
1205                    reason: "test".to_string(),
1206                })
1207            }
1208        }
1209
1210        // 设置 max_errors = 3,触发 5 次错误,应只保留最新 3 个
1211        let d = EventDispatcher::new().with_max_errors(3);
1212        d.subscribe(Box::new(ErrSub));
1213
1214        let ctx = HookContext::default();
1215        let attrs = HashMap::new();
1216        for _ in 0..5 {
1217            d.dispatch(Event::AfterInsert, &ctx, &attrs);
1218        }
1219
1220        assert_eq!(d.error_count(), 3);
1221        let errors = d.drain_errors();
1222        assert_eq!(errors.len(), 3);
1223    }
1224
1225    #[test]
1226    fn test_max_errors_zero_means_unlimited() {
1227        struct ErrSub;
1228        impl EventSubscriber for ErrSub {
1229            fn name(&self) -> &str {
1230                "err"
1231            }
1232            fn subscribed_events(&self) -> Vec<Event> {
1233                vec![Event::AfterInsert]
1234            }
1235            fn on_event(
1236                &self,
1237                _e: Event,
1238                _c: &HookContext,
1239                _a: &HashMap<String, Value>,
1240            ) -> SubscriberResult<()> {
1241                Err(SubscriberError::Failed {
1242                    subscriber: "err".to_string(),
1243                    reason: "test".to_string(),
1244                })
1245            }
1246        }
1247
1248        let d = EventDispatcher::new().with_max_errors(0);
1249        d.subscribe(Box::new(ErrSub));
1250
1251        let ctx = HookContext::default();
1252        let attrs = HashMap::new();
1253        for _ in 0..10 {
1254            d.dispatch(Event::AfterInsert, &ctx, &attrs);
1255        }
1256
1257        assert_eq!(d.error_count(), 10);
1258    }
1259
1260    #[test]
1261    fn test_max_errors_fifo_eviction_order() {
1262        // 验证 FIFO 淘汰:保留的是最新错误
1263        struct CounterSub(Arc<Mutex<u32>>);
1264        impl EventSubscriber for CounterSub {
1265            fn name(&self) -> &str {
1266                "counter"
1267            }
1268            fn subscribed_events(&self) -> Vec<Event> {
1269                vec![Event::AfterInsert]
1270            }
1271            fn on_event(
1272                &self,
1273                _e: Event,
1274                _c: &HookContext,
1275                _a: &HashMap<String, Value>,
1276            ) -> SubscriberResult<()> {
1277                let mut n = self.0.lock().unwrap();
1278                *n += 1;
1279                Err(SubscriberError::Failed {
1280                    subscriber: "counter".to_string(),
1281                    reason: format!("call-{}", *n),
1282                })
1283            }
1284        }
1285
1286        let counter = Arc::new(Mutex::new(0u32));
1287        let d = EventDispatcher::new().with_max_errors(2);
1288        d.subscribe(Box::new(CounterSub(counter.clone())));
1289
1290        let ctx = HookContext::default();
1291        let attrs = HashMap::new();
1292        for _ in 0..4 {
1293            d.dispatch(Event::AfterInsert, &ctx, &attrs);
1294        }
1295
1296        let errors = d.drain_errors();
1297        assert_eq!(errors.len(), 2);
1298        // 应保留最新的两个(call-3, call-4)
1299        match &errors[0] {
1300            SubscriberError::Failed { reason, .. } => assert_eq!(reason, "call-3"),
1301            other => panic!("expected Failed, got {:?}", other),
1302        }
1303        match &errors[1] {
1304            SubscriberError::Failed { reason, .. } => assert_eq!(reason, "call-4"),
1305            other => panic!("expected Failed, got {:?}", other),
1306        }
1307    }
1308
1309    // ===== before 事件 Veto 测试 =====
1310
1311    #[test]
1312    fn test_veto_aborts_subsequent_observers() {
1313        let second_called = Arc::new(Mutex::new(0u32));
1314
1315        struct VetoObs;
1316        impl Observer for VetoObs {
1317            fn name(&self) -> &str {
1318                "veto"
1319            }
1320            fn before_insert(
1321                &self,
1322                _c: &HookContext,
1323                _a: &mut HashMap<String, Value>,
1324            ) -> SubscriberResult<()> {
1325                Err(SubscriberError::Vetoed {
1326                    subscriber: "veto".to_string(),
1327                    reason: "no".to_string(),
1328                })
1329            }
1330        }
1331
1332        struct CountingObs(Arc<Mutex<u32>>);
1333        impl Observer for CountingObs {
1334            fn name(&self) -> &str {
1335                "counting"
1336            }
1337            fn before_insert(
1338                &self,
1339                _c: &HookContext,
1340                _a: &mut HashMap<String, Value>,
1341            ) -> SubscriberResult<()> {
1342                *self.0.lock().unwrap() += 1;
1343                Ok(())
1344            }
1345        }
1346
1347        let d = EventDispatcher::new();
1348        d.add_observer(Box::new(VetoObs));
1349        d.add_observer(Box::new(CountingObs(second_called.clone())));
1350
1351        let ctx = HookContext::default();
1352        let mut attrs = HashMap::new();
1353        let result = d.dispatch_before_mut(Event::BeforeInsert, &ctx, &mut attrs);
1354
1355        assert!(result.is_err());
1356        // 第二个 observer 不应被调用
1357        assert_eq!(*second_called.lock().unwrap(), 0);
1358    }
1359
1360    // ===== Display 测试 =====
1361
1362    #[test]
1363    fn test_error_display() {
1364        let e = SubscriberError::Failed {
1365            subscriber: "test".to_string(),
1366            reason: "boom".to_string(),
1367        };
1368        assert!(e.to_string().contains("test"));
1369        assert!(e.to_string().contains("boom"));
1370
1371        let e = SubscriberError::Vetoed {
1372            subscriber: "vetoer".to_string(),
1373            reason: "rejected".to_string(),
1374        };
1375        assert!(e.to_string().contains("vetoer"));
1376        assert!(e.to_string().contains("rejected"));
1377    }
1378}