Skip to main content

valence_core/
side_effect.rs

1//! Side effect types for post-mutation hooks.
2
3use crate::model::Model;
4use crate::runtime::Valence;
5use async_trait::async_trait;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum MutationKind {
9    Create,
10    Update,
11    Delete,
12}
13
14#[derive(Debug, Clone)]
15pub struct FieldChange<T> {
16    before: Option<T>,
17    after: Option<T>,
18}
19
20impl<T> FieldChange<T> {
21    pub fn new(before: Option<T>, after: Option<T>) -> Self {
22        Self { before, after }
23    }
24
25    pub fn before(&self) -> Option<&T> {
26        self.before.as_ref()
27    }
28
29    pub fn after(&self) -> Option<&T> {
30        self.after.as_ref()
31    }
32}
33
34impl<T: PartialEq> FieldChange<T> {
35    pub fn has_changed(&self) -> bool {
36        self.before != self.after
37    }
38}
39
40pub struct Mutation<'v, T: Model> {
41    kind: MutationKind,
42    before: Option<T>,
43    after: Option<T>,
44    fields: T::FieldChanges,
45    valence: &'v Valence,
46}
47
48impl<'v, T: Model> Mutation<'v, T> {
49    pub fn new(
50        kind: MutationKind,
51        before: Option<T>,
52        after: Option<T>,
53        fields: T::FieldChanges,
54        valence: &'v Valence,
55    ) -> Self {
56        Self {
57            kind,
58            before,
59            after,
60            fields,
61            valence,
62        }
63    }
64
65    pub fn kind(&self) -> &MutationKind {
66        &self.kind
67    }
68
69    pub fn before(&self) -> Option<&T> {
70        self.before.as_ref()
71    }
72
73    pub fn after(&self) -> Option<&T> {
74        self.after.as_ref()
75    }
76
77    pub fn fields(&self) -> &T::FieldChanges {
78        &self.fields
79    }
80
81    pub fn valence(&self) -> &Valence {
82        self.valence
83    }
84}
85
86#[async_trait]
87pub trait SideEffect<T: Model>: Send + Sync {
88    async fn on_mutation(&self, mutation: &Mutation<'_, T>) -> anyhow::Result<()>;
89}
90
91#[cfg(test)]
92mod tests {
93    use super::*;
94
95    #[test]
96    fn field_change_detects_updates() {
97        let change = FieldChange::new(Some(10i64), Some(20i64));
98        assert!(change.has_changed());
99    }
100}