valence_core/
side_effect.rs1use 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}