atmosphere_core/hooks/mod.rs
1//! Atmosphere Hook System
2//!
3//! This module provides a system for defining and applying hooks at various stages of query
4//! execution. Hooks allow for custom logic to be executed at predetermined points in the query
5//! lifecycle, such as before binding, before execution, and after execution. This functionality is
6//! essential for implementing side effects, validations, or augmentations to the standard query
7//! process.
8//!
9//! # Concepts
10//!
11//! - `HookStage`: An enum representing different stages in the query lifecycle where hooks can be applied.
12//! - `HookInput`: An enum representing different types of input that can be provided to hooks.
13//! - `Hook`: A trait defining a hook with a specific stage and an application method.
14//! - `Hooks`: A trait for associating a set of hooks with a table entity.
15//! - `execute`: A function to execute the appropriate hooks for a given stage and context.
16//!
17//! The hooks system is a powerful tool for extending and customizing the behavior of database operations,
18//! enabling developers to embed additional logic seamlessly within the query execution flow.
19
20use async_trait::async_trait;
21
22use crate::{
23 Bind, Result, Table,
24 query::{Query, QueryResult},
25};
26
27/// Enumerates different stages in the query lifecycle for hook application.
28#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
29pub enum HookStage {
30 /// Represents the stage before query parameters are bound.
31 PreBind,
32 /// Indicates the stage before query execution.
33 PreExec,
34 /// Denotes the stage after the query has been executed.
35 PostExec,
36}
37
38/// Represents different types of input that can be provided to hooks.
39pub enum HookInput<'t, T: Table + Bind> {
40 /// No input is provided to the hook.
41 None,
42 /// A mutable reference to a table row entity.
43 Row(&'t mut T),
44 /// A reference to the primary key of a table entity.
45 PrimaryKey(&'t T::PrimaryKey),
46 /// The result of a query operation.
47 QueryResult(QueryResult<'t, T>),
48}
49
50impl<'t, T: Table + Bind> From<QueryResult<'t, T>> for HookInput<'t, T> {
51 fn from(value: QueryResult<'t, T>) -> Self {
52 Self::QueryResult(value)
53 }
54}
55
56/// A trait defining a hook for query execution.
57///
58/// Implementors of this trait can define custom logic to be executed at a specific stage of the
59/// query lifecycle. The trait provides a method to specify the stage at which the hook should be
60/// applied and another method to implement the hook's logic.
61#[async_trait]
62pub trait Hook<T: Table + Bind + Sync>: Sync + Send {
63 /// Returns the stage at which the hook should be applied.
64 fn stage(&self) -> HookStage;
65
66 /// Asynchronously applies the hook logic to a given query context and input.
67 async fn apply(&self, ctx: &Query<T>, input: &mut HookInput<'_, T>) -> Result<()> {
68 let _ = ctx;
69 let _ = input;
70 Ok(())
71 }
72}
73
74/// A trait for associating a set of hooks with a table entity.
75///
76/// Implementors can define a static array of hooks that are associated with a table entity. These
77/// hooks are invoked at their respective stages during the query execution process, enabling
78/// custom behaviors or validations.
79pub trait Hooks: Table + Bind {
80 /// A static array of references to hooks associated with the implementing table entity.
81 const HOOKS: &'static [&'static dyn Hook<Self>];
82}
83
84pub(crate) async fn execute<T: Hooks + Sync>(
85 stage: HookStage,
86 ctx: &Query<T>,
87 mut input: HookInput<'_, T>,
88) -> Result<()> {
89 for hook in T::HOOKS {
90 if hook.stage() != stage {
91 continue;
92 }
93
94 hook.apply(ctx, &mut input).await?;
95 }
96
97 Ok(())
98}