1use std::any::Any;
2use std::sync::{Arc, RwLock};
3
4use sofie_core::{Uuid, unpoisoned};
5
6use crate::{Db, Driver};
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq)]
9pub struct ChangedRecord {
10 pub module: &'static str,
11 pub aggregate: &'static str,
12 pub id: Option<Uuid>,
14}
15
16pub trait CommitHook: Any + Send + Sync {
19 fn committed(&self, changes: &[ChangedRecord]);
20}
21
22pub fn add_commit_hook(db: &Db, hook: Arc<dyn CommitHook>) {
24 unpoisoned::write(&db.commit_hooks.0).push(hook);
25}
26
27#[must_use]
28pub fn commit_hook<T: CommitHook>(db: &Db) -> Option<Arc<T>> {
29 let hooks = unpoisoned::read(&db.commit_hooks.0);
30 hooks.iter().find_map(|hook| {
31 let hook: Arc<dyn Any + Send + Sync> = hook.clone();
32 hook.downcast().ok()
33 })
34}
35
36#[must_use]
38pub fn cache_driver(db: &Db) -> &dyn Driver {
39 db.driver()
40}
41
42#[derive(Default)]
43pub(crate) struct CommitHooks(RwLock<Vec<Arc<dyn CommitHook>>>);
44
45impl CommitHooks {
46 pub(crate) fn run(&self, changes: &[ChangedRecord]) {
47 if changes.is_empty() {
48 return;
49 }
50 let hooks = unpoisoned::read(&self.0);
51 for hook in hooks.iter() {
52 hook.committed(changes);
53 }
54 }
55}