reifydb_core/interceptor/
interceptor.rs

1// Copyright (c) reifydb.com 2025
2// This file is licensed under the AGPL-3.0-or-later, see license.md file
3
4use reifydb_type::RowNumber;
5
6use crate::{
7	CommitVersion,
8	interceptor::{
9		InterceptorChain, NamespaceDefPostCreateContext, NamespaceDefPostCreateInterceptor,
10		NamespaceDefPostUpdateContext, NamespaceDefPostUpdateInterceptor, NamespaceDefPreDeleteContext,
11		NamespaceDefPreDeleteInterceptor, NamespaceDefPreUpdateContext, NamespaceDefPreUpdateInterceptor,
12		PostCommitContext, PostCommitInterceptor, PreCommitContext, PreCommitInterceptor,
13		RingBufferDefPostCreateContext, RingBufferDefPostCreateInterceptor, RingBufferDefPostUpdateContext,
14		RingBufferDefPostUpdateInterceptor, RingBufferDefPreDeleteContext, RingBufferDefPreDeleteInterceptor,
15		RingBufferDefPreUpdateContext, RingBufferDefPreUpdateInterceptor, RingBufferPostDeleteContext,
16		RingBufferPostDeleteInterceptor, RingBufferPostInsertContext, RingBufferPostInsertInterceptor,
17		RingBufferPostUpdateContext, RingBufferPostUpdateInterceptor, RingBufferPreDeleteContext,
18		RingBufferPreDeleteInterceptor, RingBufferPreInsertContext, RingBufferPreInsertInterceptor,
19		RingBufferPreUpdateContext, RingBufferPreUpdateInterceptor, TableDefPostCreateContext,
20		TableDefPostCreateInterceptor, TableDefPostUpdateContext, TableDefPostUpdateInterceptor,
21		TableDefPreDeleteContext, TableDefPreDeleteInterceptor, TableDefPreUpdateContext,
22		TableDefPreUpdateInterceptor, TablePostDeleteContext, TablePostDeleteInterceptor,
23		TablePostInsertContext, TablePostInsertInterceptor, TablePostUpdateContext, TablePostUpdateInterceptor,
24		TablePreDeleteContext, TablePreDeleteInterceptor, TablePreInsertContext, TablePreInsertInterceptor,
25		TablePreUpdateContext, TablePreUpdateInterceptor, ViewDefPostCreateContext,
26		ViewDefPostCreateInterceptor, ViewDefPostUpdateContext, ViewDefPostUpdateInterceptor,
27		ViewDefPreDeleteContext, ViewDefPreDeleteInterceptor, ViewDefPreUpdateContext,
28		ViewDefPreUpdateInterceptor, ViewPostDeleteContext, ViewPostDeleteInterceptor, ViewPostInsertContext,
29		ViewPostInsertInterceptor, ViewPostUpdateContext, ViewPostUpdateInterceptor, ViewPreDeleteContext,
30		ViewPreDeleteInterceptor, ViewPreInsertContext, ViewPreInsertInterceptor, ViewPreUpdateContext,
31		ViewPreUpdateInterceptor,
32	},
33	interface::{
34		CommandTransaction, NamespaceDef, RingBufferDef, RowChange, TableDef, TransactionId,
35		TransactionalDefChanges, ViewDef,
36		interceptor::{
37			NamespaceDefInterceptor, RingBufferDefInterceptor, RingBufferInterceptor, TableDefInterceptor,
38			TableInterceptor, TransactionInterceptor, ViewDefInterceptor, ViewInterceptor,
39			WithInterceptors,
40		},
41	},
42	value::encoded::EncodedValues,
43};
44
45/// Macro to generate interceptor execution methods
46macro_rules! impl_interceptor_method {
47	(
48		$method_name:ident,
49		$accessor_method:ident,
50		$interceptor_trait:ident,
51		$context_type:ident,
52		($($param:ident: $type:ty),*)
53	) => {
54		fn $method_name(
55			&mut self,
56			$($param: $type),*
57		) -> crate::Result<()> {
58			if self.$accessor_method().is_empty() {
59				return Ok(());
60			}
61			// We need to use unsafe here to work around the borrow checker
62			// This is safe because:
63			// 1. We know the interceptor chain won't outlive this function
64			//    call
65			// 2. The execution is synchronous and single-threaded
66			// 3. We're only borrowing different parts of self
67			unsafe {
68				let chain_ptr: *mut InterceptorChain<
69					CT,
70					dyn $interceptor_trait<CT>,
71				> = self.$accessor_method() as *mut _;
72				let ctx = $context_type::new(self, $($param),*);
73				(*chain_ptr).execute(ctx)?
74			}
75			Ok(())
76		}
77	};
78}
79
80impl<CT: CommandTransaction + WithInterceptors<CT>> TableInterceptor<CT> for CT {
81	impl_interceptor_method!(
82		pre_insert,
83		table_pre_insert_interceptors,
84		TablePreInsertInterceptor,
85		TablePreInsertContext,
86		(table: &TableDef, rn: RowNumber, row: &EncodedValues)
87	);
88
89	impl_interceptor_method!(
90		post_insert,
91		table_post_insert_interceptors,
92		TablePostInsertInterceptor,
93		TablePostInsertContext,
94		(table: &TableDef, id: RowNumber, row: &EncodedValues)
95	);
96
97	impl_interceptor_method!(
98		pre_update,
99		table_pre_update_interceptors,
100		TablePreUpdateInterceptor,
101		TablePreUpdateContext,
102		(table: &TableDef, id: RowNumber, row: &EncodedValues)
103	);
104
105	impl_interceptor_method!(
106		post_update,
107		table_post_update_interceptors,
108		TablePostUpdateInterceptor,
109		TablePostUpdateContext,
110		(table: &TableDef, id: RowNumber, row: &EncodedValues, old_row: &EncodedValues)
111	);
112
113	impl_interceptor_method!(
114		pre_delete,
115		table_pre_delete_interceptors,
116		TablePreDeleteInterceptor,
117		TablePreDeleteContext,
118		(table: &TableDef, id: RowNumber)
119	);
120
121	impl_interceptor_method!(
122		post_delete,
123		table_post_delete_interceptors,
124		TablePostDeleteInterceptor,
125		TablePostDeleteContext,
126		(table: &TableDef, id: RowNumber, deleted_row: &EncodedValues)
127	);
128}
129
130impl<CT: CommandTransaction + WithInterceptors<CT>> RingBufferInterceptor<CT> for CT {
131	impl_interceptor_method!(
132		pre_insert,
133		ring_buffer_pre_insert_interceptors,
134		RingBufferPreInsertInterceptor,
135		RingBufferPreInsertContext,
136		(ring_buffer: &RingBufferDef, row: &EncodedValues)
137	);
138
139	impl_interceptor_method!(
140		post_insert,
141		ring_buffer_post_insert_interceptors,
142		RingBufferPostInsertInterceptor,
143		RingBufferPostInsertContext,
144		(ring_buffer: &RingBufferDef, id: RowNumber, row: &EncodedValues)
145	);
146
147	impl_interceptor_method!(
148		pre_update,
149		ring_buffer_pre_update_interceptors,
150		RingBufferPreUpdateInterceptor,
151		RingBufferPreUpdateContext,
152		(ring_buffer: &RingBufferDef, id: RowNumber, row: &EncodedValues)
153	);
154
155	impl_interceptor_method!(
156		post_update,
157		ring_buffer_post_update_interceptors,
158		RingBufferPostUpdateInterceptor,
159		RingBufferPostUpdateContext,
160		(ring_buffer: &RingBufferDef, id: RowNumber, row: &EncodedValues, old_row: &EncodedValues)
161	);
162
163	impl_interceptor_method!(
164		pre_delete,
165		ring_buffer_pre_delete_interceptors,
166		RingBufferPreDeleteInterceptor,
167		RingBufferPreDeleteContext,
168		(ring_buffer: &RingBufferDef, id: RowNumber)
169	);
170
171	impl_interceptor_method!(
172		post_delete,
173		ring_buffer_post_delete_interceptors,
174		RingBufferPostDeleteInterceptor,
175		RingBufferPostDeleteContext,
176		(ring_buffer: &RingBufferDef, id: RowNumber, deleted_row: &EncodedValues)
177	);
178}
179
180impl<CT: CommandTransaction + WithInterceptors<CT>> NamespaceDefInterceptor<CT> for CT {
181	impl_interceptor_method!(
182		post_create,
183		namespace_def_post_create_interceptors,
184		NamespaceDefPostCreateInterceptor,
185		NamespaceDefPostCreateContext,
186		(post: &NamespaceDef)
187	);
188
189	impl_interceptor_method!(
190		pre_update,
191		namespace_def_pre_update_interceptors,
192		NamespaceDefPreUpdateInterceptor,
193		NamespaceDefPreUpdateContext,
194		(pre: &NamespaceDef)
195	);
196
197	impl_interceptor_method!(
198		post_update,
199		namespace_def_post_update_interceptors,
200		NamespaceDefPostUpdateInterceptor,
201		NamespaceDefPostUpdateContext,
202		(pre: &NamespaceDef, post: &NamespaceDef)
203	);
204
205	impl_interceptor_method!(
206		pre_delete,
207		namespace_def_pre_delete_interceptors,
208		NamespaceDefPreDeleteInterceptor,
209		NamespaceDefPreDeleteContext,
210		(pre: &NamespaceDef)
211	);
212}
213
214impl<CT: CommandTransaction + WithInterceptors<CT>> TableDefInterceptor<CT> for CT {
215	impl_interceptor_method!(
216		post_create,
217		table_def_post_create_interceptors,
218		TableDefPostCreateInterceptor,
219		TableDefPostCreateContext,
220		(post: &TableDef)
221	);
222
223	impl_interceptor_method!(
224		pre_update,
225		table_def_pre_update_interceptors,
226		TableDefPreUpdateInterceptor,
227		TableDefPreUpdateContext,
228		(pre: &TableDef)
229	);
230
231	impl_interceptor_method!(
232		post_update,
233		table_def_post_update_interceptors,
234		TableDefPostUpdateInterceptor,
235		TableDefPostUpdateContext,
236		(pre: &TableDef, post: &TableDef)
237	);
238
239	impl_interceptor_method!(
240		pre_delete,
241		table_def_pre_delete_interceptors,
242		TableDefPreDeleteInterceptor,
243		TableDefPreDeleteContext,
244		(pre: &TableDef)
245	);
246}
247
248impl<CT: CommandTransaction + WithInterceptors<CT>> ViewDefInterceptor<CT> for CT {
249	impl_interceptor_method!(
250		post_create,
251		view_def_post_create_interceptors,
252		ViewDefPostCreateInterceptor,
253		ViewDefPostCreateContext,
254		(post: &ViewDef)
255	);
256
257	impl_interceptor_method!(
258		pre_update,
259		view_def_pre_update_interceptors,
260		ViewDefPreUpdateInterceptor,
261		ViewDefPreUpdateContext,
262		(pre: &ViewDef)
263	);
264
265	impl_interceptor_method!(
266		post_update,
267		view_def_post_update_interceptors,
268		ViewDefPostUpdateInterceptor,
269		ViewDefPostUpdateContext,
270		(pre: &ViewDef, post: &ViewDef)
271	);
272
273	impl_interceptor_method!(
274		pre_delete,
275		view_def_pre_delete_interceptors,
276		ViewDefPreDeleteInterceptor,
277		ViewDefPreDeleteContext,
278		(pre: &ViewDef)
279	);
280}
281
282impl<CT: CommandTransaction + WithInterceptors<CT>> RingBufferDefInterceptor<CT> for CT {
283	impl_interceptor_method!(
284		post_create,
285		ring_buffer_def_post_create_interceptors,
286		RingBufferDefPostCreateInterceptor,
287		RingBufferDefPostCreateContext,
288		(post: &RingBufferDef)
289	);
290
291	impl_interceptor_method!(
292		pre_update,
293		ring_buffer_def_pre_update_interceptors,
294		RingBufferDefPreUpdateInterceptor,
295		RingBufferDefPreUpdateContext,
296		(pre: &RingBufferDef)
297	);
298
299	impl_interceptor_method!(
300		post_update,
301		ring_buffer_def_post_update_interceptors,
302		RingBufferDefPostUpdateInterceptor,
303		RingBufferDefPostUpdateContext,
304		(pre: &RingBufferDef, post: &RingBufferDef)
305	);
306
307	impl_interceptor_method!(
308		pre_delete,
309		ring_buffer_def_pre_delete_interceptors,
310		RingBufferDefPreDeleteInterceptor,
311		RingBufferDefPreDeleteContext,
312		(pre: &RingBufferDef)
313	);
314}
315
316impl<CT: CommandTransaction + WithInterceptors<CT>> ViewInterceptor<CT> for CT {
317	impl_interceptor_method!(
318		pre_insert,
319		view_pre_insert_interceptors,
320		ViewPreInsertInterceptor,
321		ViewPreInsertContext,
322		(view: &ViewDef, rn: RowNumber, row: &EncodedValues)
323	);
324
325	impl_interceptor_method!(
326		post_insert,
327		view_post_insert_interceptors,
328		ViewPostInsertInterceptor,
329		ViewPostInsertContext,
330		(view: &ViewDef, id: RowNumber, row: &EncodedValues)
331	);
332
333	impl_interceptor_method!(
334		pre_update,
335		view_pre_update_interceptors,
336		ViewPreUpdateInterceptor,
337		ViewPreUpdateContext,
338		(view: &ViewDef, id: RowNumber, row: &EncodedValues)
339	);
340
341	impl_interceptor_method!(
342		post_update,
343		view_post_update_interceptors,
344		ViewPostUpdateInterceptor,
345		ViewPostUpdateContext,
346		(view: &ViewDef, id: RowNumber, row: &EncodedValues, old_row: &EncodedValues)
347	);
348
349	impl_interceptor_method!(
350		pre_delete,
351		view_pre_delete_interceptors,
352		ViewPreDeleteInterceptor,
353		ViewPreDeleteContext,
354		(view: &ViewDef, id: RowNumber)
355	);
356
357	impl_interceptor_method!(
358		post_delete,
359		view_post_delete_interceptors,
360		ViewPostDeleteInterceptor,
361		ViewPostDeleteContext,
362		(view: &ViewDef, id: RowNumber, deleted_row: &EncodedValues)
363	);
364}
365
366impl<CT: CommandTransaction + WithInterceptors<CT>> TransactionInterceptor<CT> for CT {
367	impl_interceptor_method!(pre_commit, pre_commit_interceptors, PreCommitInterceptor, PreCommitContext, ());
368
369	fn post_commit(
370		&mut self,
371		id: TransactionId,
372		version: CommitVersion,
373		changes: TransactionalDefChanges,
374		row_changes: Vec<RowChange>,
375	) -> crate::Result<()> {
376		if self.post_commit_interceptors().is_empty() {
377			return Ok(());
378		}
379		// We need to use unsafe here to work around the borrow checker
380		// This is safe because:
381		// 1. We know the interceptor chain won't outlive this function call
382		// 2. The execution is synchronous and single-threaded
383		// 3. We're only borrowing different parts of self
384		unsafe {
385			let chain_ptr: *mut InterceptorChain<CT, dyn PostCommitInterceptor<CT>> =
386				self.post_commit_interceptors() as *mut _;
387			let ctx = PostCommitContext::new(id, version, changes, row_changes);
388			(*chain_ptr).execute(ctx)?
389		}
390		Ok(())
391	}
392}