vantage_table/table/sets/
hooks.rs1use vantage_core::Result;
10use vantage_types::{EmptyEntity, Entity, InvariantValue, Record};
11
12use super::invariants::enforce_invariants;
13use crate::table::{
14 AfterCx, AfterFn, BeforeCx, BeforeDeleteFn, BeforeFn, DeleteAllCx, DeleteAllFn, DeleteCx,
15 HookReturn, Phase, Table,
16};
17use crate::traits::table_source::TableSource;
18use crate::write_context::WriteContext;
19
20impl<T: TableSource, E: Entity<T::Value>> Table<T, E>
24where
25 T::Value: InvariantValue,
26{
27 pub async fn prepare_insert(&self, record: &Record<T::Value>) -> Result<Record<T::Value>> {
32 self.require_confined_writes("insert")?;
33 let mut record = record.clone();
34 run_before(
35 self.before_insert_hooks(),
36 &mut record,
37 None,
38 self.as_entity_erased(),
39 )
40 .await?;
41 self.strip_imported_columns(&mut record);
42 enforce_invariants(&mut record, self.invariants())?;
43 Ok(record)
44 }
45
46 pub async fn finish_insert(&self, id: &T::Id, record: &Record<T::Value>) -> Result<()> {
49 run_after(
50 self.after_insert_hooks(),
51 id,
52 record,
53 None,
54 self.as_entity_erased(),
55 )
56 .await
57 }
58}
59
60pub(crate) struct UpdateOf<'a, T: TableSource> {
63 pub id: &'a T::Id,
64 pub stored: Option<&'a Record<T::Value>>,
65 pub patch: bool,
66}
67
68pub(crate) async fn run_before<T: TableSource>(
70 hooks: &[(Phase, BeforeFn<T>)],
71 record: &mut Record<T::Value>,
72 update: Option<UpdateOf<'_, T>>,
73 table: &Table<T, EmptyEntity>,
74) -> Result<()> {
75 if hooks.is_empty() {
76 return Ok(());
77 }
78 let context = WriteContext::current();
79 for (_phase, hook) in hooks {
80 hook(BeforeCx {
81 record: &mut *record,
82 id: update.as_ref().map(|u| u.id),
83 stored: update.as_ref().and_then(|u| u.stored),
84 patch: update.as_ref().is_some_and(|u| u.patch),
85 context: context.as_ref(),
86 table,
87 })
88 .await?;
89 }
90 Ok(())
91}
92
93pub(crate) async fn run_after<T: TableSource>(
94 hooks: &[AfterFn<T>],
95 id: &T::Id,
96 record: &Record<T::Value>,
97 before: Option<&Record<T::Value>>,
98 table: &Table<T, EmptyEntity>,
99) -> Result<()> {
100 if hooks.is_empty() {
101 return Ok(());
102 }
103 let context = WriteContext::current();
104 for hook in hooks {
105 hook(AfterCx {
106 id,
107 record,
108 before,
109 context: context.as_ref(),
110 table,
111 })
112 .await?;
113 }
114 Ok(())
115}
116
117pub(crate) async fn run_delete_all<T: TableSource>(
118 hooks: &[DeleteAllFn<T>],
119 table: &Table<T, EmptyEntity>,
120) -> Result<()> {
121 if hooks.is_empty() {
122 return Ok(());
123 }
124 let context = WriteContext::current();
125 for hook in hooks {
126 hook(DeleteAllCx {
127 context: context.as_ref(),
128 table,
129 })
130 .await?;
131 }
132 Ok(())
133}
134
135pub(crate) async fn run_before_delete<T: TableSource>(
138 hooks: &[BeforeDeleteFn<T>],
139 id: &T::Id,
140 record: &Record<T::Value>,
141 table: &Table<T, EmptyEntity>,
142) -> Result<HookReturn> {
143 let context = WriteContext::current();
144 for hook in hooks {
145 let cx = DeleteCx {
146 id,
147 record,
148 context: context.as_ref(),
149 table,
150 };
151 if let HookReturn::Handled = hook(cx).await? {
152 return Ok(HookReturn::Handled);
153 }
154 }
155 Ok(HookReturn::Proceed)
156}