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		RingBufferPostDeleteContext, RingBufferPostDeleteInterceptor, RingBufferPostInsertContext,
14		RingBufferPostInsertInterceptor, RingBufferPostUpdateContext, RingBufferPostUpdateInterceptor,
15		RingBufferPreDeleteContext, RingBufferPreDeleteInterceptor, RingBufferPreInsertContext,
16		RingBufferPreInsertInterceptor, RingBufferPreUpdateContext, RingBufferPreUpdateInterceptor,
17		TableDefPostCreateContext, TableDefPostCreateInterceptor, TableDefPostUpdateContext,
18		TableDefPostUpdateInterceptor, TableDefPreDeleteContext, TableDefPreDeleteInterceptor,
19		TableDefPreUpdateContext, TableDefPreUpdateInterceptor, TablePostDeleteContext,
20		TablePostDeleteInterceptor, TablePostInsertContext, TablePostInsertInterceptor, TablePostUpdateContext,
21		TablePostUpdateInterceptor, TablePreDeleteContext, TablePreDeleteInterceptor, TablePreInsertContext,
22		TablePreInsertInterceptor, TablePreUpdateContext, TablePreUpdateInterceptor, ViewDefPostCreateContext,
23		ViewDefPostCreateInterceptor, ViewDefPostUpdateContext, ViewDefPostUpdateInterceptor,
24		ViewDefPreDeleteContext, ViewDefPreDeleteInterceptor, ViewDefPreUpdateContext,
25		ViewDefPreUpdateInterceptor,
26	},
27	interface::{
28		CommandTransaction, NamespaceDef, RingBufferDef, TableDef, TransactionId, TransactionalDefChanges,
29		ViewDef,
30		interceptor::{
31			NamespaceDefInterceptor, RingBufferInterceptor, TableDefInterceptor, TableInterceptor,
32			TransactionInterceptor, ViewDefInterceptor, WithInterceptors,
33		},
34	},
35	value::encoded::EncodedValues,
36};
37
38/// Macro to generate interceptor execution methods
39macro_rules! impl_interceptor_method {
40	(
41		$method_name:ident,
42		$accessor_method:ident,
43		$interceptor_trait:ident,
44		$context_type:ident,
45		($($param:ident: $type:ty),*)
46	) => {
47		fn $method_name(
48			&mut self,
49			$($param: $type),*
50		) -> crate::Result<()> {
51			if self.$accessor_method().is_empty() {
52				return Ok(());
53			}
54			// We need to use unsafe here to work around the borrow checker
55			// This is safe because:
56			// 1. We know the interceptor chain won't outlive this function
57			//    call
58			// 2. The execution is synchronous and single-threaded
59			// 3. We're only borrowing different parts of self
60			unsafe {
61				let chain_ptr: *mut InterceptorChain<
62					CT,
63					dyn $interceptor_trait<CT>,
64				> = self.$accessor_method() as *mut _;
65				let ctx = $context_type::new(self, $($param),*);
66				(*chain_ptr).execute(ctx)?
67			}
68			Ok(())
69		}
70	};
71}
72
73impl<CT: CommandTransaction + WithInterceptors<CT>> TableInterceptor<CT> for CT {
74	impl_interceptor_method!(
75		pre_insert,
76		table_pre_insert_interceptors,
77		TablePreInsertInterceptor,
78		TablePreInsertContext,
79		(table: &TableDef, row: &EncodedValues)
80	);
81
82	impl_interceptor_method!(
83		post_insert,
84		table_post_insert_interceptors,
85		TablePostInsertInterceptor,
86		TablePostInsertContext,
87		(table: &TableDef, id: RowNumber, row: &EncodedValues)
88	);
89
90	impl_interceptor_method!(
91		pre_update,
92		table_pre_update_interceptors,
93		TablePreUpdateInterceptor,
94		TablePreUpdateContext,
95		(table: &TableDef, id: RowNumber, row: &EncodedValues)
96	);
97
98	impl_interceptor_method!(
99		post_update,
100		table_post_update_interceptors,
101		TablePostUpdateInterceptor,
102		TablePostUpdateContext,
103		(table: &TableDef, id: RowNumber, row: &EncodedValues, old_row: &EncodedValues)
104	);
105
106	impl_interceptor_method!(
107		pre_delete,
108		table_pre_delete_interceptors,
109		TablePreDeleteInterceptor,
110		TablePreDeleteContext,
111		(table: &TableDef, id: RowNumber)
112	);
113
114	impl_interceptor_method!(
115		post_delete,
116		table_post_delete_interceptors,
117		TablePostDeleteInterceptor,
118		TablePostDeleteContext,
119		(table: &TableDef, id: RowNumber, deleted_row: &EncodedValues)
120	);
121}
122
123impl<CT: CommandTransaction + WithInterceptors<CT>> RingBufferInterceptor<CT> for CT {
124	impl_interceptor_method!(
125		pre_insert,
126		ring_buffer_pre_insert_interceptors,
127		RingBufferPreInsertInterceptor,
128		RingBufferPreInsertContext,
129		(ring_buffer: &RingBufferDef, row: &EncodedValues)
130	);
131
132	impl_interceptor_method!(
133		post_insert,
134		ring_buffer_post_insert_interceptors,
135		RingBufferPostInsertInterceptor,
136		RingBufferPostInsertContext,
137		(ring_buffer: &RingBufferDef, id: RowNumber, row: &EncodedValues)
138	);
139
140	impl_interceptor_method!(
141		pre_update,
142		ring_buffer_pre_update_interceptors,
143		RingBufferPreUpdateInterceptor,
144		RingBufferPreUpdateContext,
145		(ring_buffer: &RingBufferDef, id: RowNumber, row: &EncodedValues)
146	);
147
148	impl_interceptor_method!(
149		post_update,
150		ring_buffer_post_update_interceptors,
151		RingBufferPostUpdateInterceptor,
152		RingBufferPostUpdateContext,
153		(ring_buffer: &RingBufferDef, id: RowNumber, row: &EncodedValues, old_row: &EncodedValues)
154	);
155
156	impl_interceptor_method!(
157		pre_delete,
158		ring_buffer_pre_delete_interceptors,
159		RingBufferPreDeleteInterceptor,
160		RingBufferPreDeleteContext,
161		(ring_buffer: &RingBufferDef, id: RowNumber)
162	);
163
164	impl_interceptor_method!(
165		post_delete,
166		ring_buffer_post_delete_interceptors,
167		RingBufferPostDeleteInterceptor,
168		RingBufferPostDeleteContext,
169		(ring_buffer: &RingBufferDef, id: RowNumber, deleted_row: &EncodedValues)
170	);
171}
172
173impl<CT: CommandTransaction + WithInterceptors<CT>> NamespaceDefInterceptor<CT> for CT {
174	impl_interceptor_method!(
175		post_create,
176		namespace_def_post_create_interceptors,
177		NamespaceDefPostCreateInterceptor,
178		NamespaceDefPostCreateContext,
179		(post: &NamespaceDef)
180	);
181
182	impl_interceptor_method!(
183		pre_update,
184		namespace_def_pre_update_interceptors,
185		NamespaceDefPreUpdateInterceptor,
186		NamespaceDefPreUpdateContext,
187		(pre: &NamespaceDef)
188	);
189
190	impl_interceptor_method!(
191		post_update,
192		namespace_def_post_update_interceptors,
193		NamespaceDefPostUpdateInterceptor,
194		NamespaceDefPostUpdateContext,
195		(pre: &NamespaceDef, post: &NamespaceDef)
196	);
197
198	impl_interceptor_method!(
199		pre_delete,
200		namespace_def_pre_delete_interceptors,
201		NamespaceDefPreDeleteInterceptor,
202		NamespaceDefPreDeleteContext,
203		(pre: &NamespaceDef)
204	);
205}
206
207impl<CT: CommandTransaction + WithInterceptors<CT>> TableDefInterceptor<CT> for CT {
208	impl_interceptor_method!(
209		post_create,
210		table_def_post_create_interceptors,
211		TableDefPostCreateInterceptor,
212		TableDefPostCreateContext,
213		(post: &TableDef)
214	);
215
216	impl_interceptor_method!(
217		pre_update,
218		table_def_pre_update_interceptors,
219		TableDefPreUpdateInterceptor,
220		TableDefPreUpdateContext,
221		(pre: &TableDef)
222	);
223
224	impl_interceptor_method!(
225		post_update,
226		table_def_post_update_interceptors,
227		TableDefPostUpdateInterceptor,
228		TableDefPostUpdateContext,
229		(pre: &TableDef, post: &TableDef)
230	);
231
232	impl_interceptor_method!(
233		pre_delete,
234		table_def_pre_delete_interceptors,
235		TableDefPreDeleteInterceptor,
236		TableDefPreDeleteContext,
237		(pre: &TableDef)
238	);
239}
240
241impl<CT: CommandTransaction + WithInterceptors<CT>> ViewDefInterceptor<CT> for CT {
242	impl_interceptor_method!(
243		post_create,
244		view_def_post_create_interceptors,
245		ViewDefPostCreateInterceptor,
246		ViewDefPostCreateContext,
247		(post: &ViewDef)
248	);
249
250	impl_interceptor_method!(
251		pre_update,
252		view_def_pre_update_interceptors,
253		ViewDefPreUpdateInterceptor,
254		ViewDefPreUpdateContext,
255		(pre: &ViewDef)
256	);
257
258	impl_interceptor_method!(
259		post_update,
260		view_def_post_update_interceptors,
261		ViewDefPostUpdateInterceptor,
262		ViewDefPostUpdateContext,
263		(pre: &ViewDef, post: &ViewDef)
264	);
265
266	impl_interceptor_method!(
267		pre_delete,
268		view_def_pre_delete_interceptors,
269		ViewDefPreDeleteInterceptor,
270		ViewDefPreDeleteContext,
271		(pre: &ViewDef)
272	);
273}
274
275impl<CT: CommandTransaction + WithInterceptors<CT>> TransactionInterceptor<CT> for CT {
276	impl_interceptor_method!(pre_commit, pre_commit_interceptors, PreCommitInterceptor, PreCommitContext, ());
277
278	fn post_commit(
279		&mut self,
280		id: TransactionId,
281		version: CommitVersion,
282		changes: TransactionalDefChanges,
283	) -> crate::Result<()> {
284		if self.post_commit_interceptors().is_empty() {
285			return Ok(());
286		}
287		// We need to use unsafe here to work around the borrow checker
288		// This is safe because:
289		// 1. We know the interceptor chain won't outlive this function call
290		// 2. The execution is synchronous and single-threaded
291		// 3. We're only borrowing different parts of self
292		unsafe {
293			let chain_ptr: *mut InterceptorChain<CT, dyn PostCommitInterceptor<CT>> =
294				self.post_commit_interceptors() as *mut _;
295			let ctx = PostCommitContext::new(id, version, changes);
296			(*chain_ptr).execute(ctx)?
297		}
298		Ok(())
299	}
300}