Skip to main content

rustauth_core/db/
hooks.rs

1//! Database adapter wrapper that executes plugin hooks around mutations.
2
3mod pipeline;
4
5use std::sync::Arc;
6
7use super::{
8    AdapterCapabilities, AdapterFuture, Count, Create, DbAdapter, DbRecord, Delete, DeleteMany,
9    FindMany, FindOne, SchemaCreation, TransactionCallback, Update, UpdateMany,
10};
11use crate::db::DbSchema;
12use crate::env::logger::{create_logger, Logger, LoggerOptions};
13use crate::plugin::PluginDatabaseHook;
14use pipeline::{
15    hooked_create, hooked_delete, hooked_delete_many, hooked_update, hooked_update_many,
16    AfterHookQueue,
17};
18
19/// Adapter wrapper that runs plugin database hooks for mutating operations.
20#[derive(Clone)]
21pub struct HookedAdapter<A = Arc<dyn DbAdapter>> {
22    inner: A,
23    hooks: Arc<Vec<PluginDatabaseHook>>,
24    logger: Logger,
25    after_queue: Option<AfterHookQueue>,
26}
27
28impl<A> HookedAdapter<A> {
29    pub fn new(inner: A, hooks: Vec<PluginDatabaseHook>) -> Self {
30        Self::with_logger(inner, hooks, create_logger(LoggerOptions::default()))
31    }
32
33    pub fn with_logger(inner: A, hooks: Vec<PluginDatabaseHook>, logger: Logger) -> Self {
34        Self {
35            inner,
36            hooks: Arc::new(hooks),
37            logger,
38            after_queue: None,
39        }
40    }
41
42    pub fn hooks(&self) -> &[PluginDatabaseHook] {
43        self.hooks.as_slice()
44    }
45
46    fn with_after_queue(
47        inner: A,
48        hooks: Arc<Vec<PluginDatabaseHook>>,
49        logger: Logger,
50        after_queue: AfterHookQueue,
51    ) -> Self {
52        Self {
53            inner,
54            hooks,
55            logger,
56            after_queue: Some(after_queue),
57        }
58    }
59}
60
61impl<A> DbAdapter for HookedAdapter<A>
62where
63    A: DbAdapter,
64{
65    fn id(&self) -> &str {
66        self.inner.id()
67    }
68
69    fn capabilities(&self) -> AdapterCapabilities {
70        self.inner.capabilities()
71    }
72
73    fn create<'a>(&'a self, query: Create) -> AdapterFuture<'a, DbRecord> {
74        hooked_create(
75            &self.inner,
76            Arc::clone(&self.hooks),
77            self.logger.clone(),
78            self.after_queue.clone(),
79            query,
80        )
81    }
82
83    fn find_one<'a>(&'a self, query: FindOne) -> AdapterFuture<'a, Option<DbRecord>> {
84        self.inner.find_one(query)
85    }
86
87    fn find_many<'a>(&'a self, query: FindMany) -> AdapterFuture<'a, Vec<DbRecord>> {
88        self.inner.find_many(query)
89    }
90
91    fn count<'a>(&'a self, query: Count) -> AdapterFuture<'a, u64> {
92        self.inner.count(query)
93    }
94
95    fn update<'a>(&'a self, query: Update) -> AdapterFuture<'a, Option<DbRecord>> {
96        hooked_update(
97            &self.inner,
98            Arc::clone(&self.hooks),
99            self.logger.clone(),
100            self.after_queue.clone(),
101            query,
102        )
103    }
104
105    fn update_many<'a>(&'a self, query: UpdateMany) -> AdapterFuture<'a, u64> {
106        hooked_update_many(
107            &self.inner,
108            Arc::clone(&self.hooks),
109            self.logger.clone(),
110            self.after_queue.clone(),
111            query,
112        )
113    }
114
115    fn delete<'a>(&'a self, query: Delete) -> AdapterFuture<'a, ()> {
116        hooked_delete(
117            &self.inner,
118            Arc::clone(&self.hooks),
119            self.logger.clone(),
120            self.after_queue.clone(),
121            query,
122        )
123    }
124
125    fn delete_many<'a>(&'a self, query: DeleteMany) -> AdapterFuture<'a, u64> {
126        hooked_delete_many(
127            &self.inner,
128            Arc::clone(&self.hooks),
129            self.logger.clone(),
130            self.after_queue.clone(),
131            query,
132        )
133    }
134
135    fn transaction<'a>(&'a self, callback: TransactionCallback<'a>) -> AdapterFuture<'a, ()> {
136        Box::pin(async move {
137            let should_run_after_hooks = self.after_queue.is_none();
138            let after_queue = self.after_queue.clone().unwrap_or_default();
139            let transaction_queue = after_queue.clone();
140            let hooks = Arc::clone(&self.hooks);
141            let logger = self.logger.clone();
142            self.inner
143                .transaction(Box::new(move |transaction| {
144                    let adapter = HookedAdapter::with_after_queue(
145                        transaction,
146                        Arc::clone(&hooks),
147                        logger.clone(),
148                        transaction_queue,
149                    );
150                    callback(Box::new(adapter))
151                }))
152                .await?;
153            if should_run_after_hooks {
154                after_queue
155                    .run(self.hooks.as_slice(), &self.logger, &self.inner)
156                    .await?;
157            }
158            Ok(())
159        })
160    }
161
162    fn create_schema<'a>(
163        &'a self,
164        schema: &'a DbSchema,
165        file: Option<&'a str>,
166    ) -> AdapterFuture<'a, Option<SchemaCreation>> {
167        self.inner.create_schema(schema, file)
168    }
169
170    fn run_migrations<'a>(&'a self, schema: &'a DbSchema) -> AdapterFuture<'a, ()> {
171        self.inner.run_migrations(schema)
172    }
173}