Skip to main content

reifydb_sub_flow/transaction/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use std::{any::Any, collections::HashMap, mem, sync::Arc};
5
6use read::ReadFrom;
7use reifydb_catalog::catalog::Catalog;
8use reifydb_codec::{
9	encoded::{row::EncodedRow, shape::RowShape},
10	key::encoded::EncodedKey,
11};
12use reifydb_core::{
13	actors::pending::{Pending, PendingWrite},
14	common::CommitVersion,
15	interface::{
16		catalog::{flow::FlowNodeId, shape::ShapeId},
17		change::{Change, ChangeOrigin, Diff},
18	},
19};
20use reifydb_runtime::context::clock::Clock;
21use reifydb_transaction::{
22	change_accumulator::ChangeAccumulator,
23	dictionary::DictionaryAllocatorRegistry,
24	interceptor::{
25		WithInterceptors,
26		authentication::{AuthenticationPostCreateInterceptor, AuthenticationPreDeleteInterceptor},
27		chain::InterceptorChain as Chain,
28		dictionary::{
29			DictionaryPostCreateInterceptor, DictionaryPostUpdateInterceptor,
30			DictionaryPreDeleteInterceptor, DictionaryPreUpdateInterceptor,
31		},
32		dictionary_row::{
33			DictionaryRowPostDeleteInterceptor, DictionaryRowPostInsertInterceptor,
34			DictionaryRowPostUpdateInterceptor, DictionaryRowPreDeleteInterceptor,
35			DictionaryRowPreInsertInterceptor, DictionaryRowPreUpdateInterceptor,
36		},
37		granted_role::{GrantedRolePostCreateInterceptor, GrantedRolePreDeleteInterceptor},
38		identity::{
39			IdentityPostCreateInterceptor, IdentityPostUpdateInterceptor, IdentityPreDeleteInterceptor,
40			IdentityPreUpdateInterceptor,
41		},
42		interceptors::Interceptors,
43		namespace::{
44			NamespacePostCreateInterceptor, NamespacePostUpdateInterceptor, NamespacePreDeleteInterceptor,
45			NamespacePreUpdateInterceptor,
46		},
47		ringbuffer::{
48			RingBufferPostCreateInterceptor, RingBufferPostUpdateInterceptor,
49			RingBufferPreDeleteInterceptor, RingBufferPreUpdateInterceptor,
50		},
51		ringbuffer_row::{
52			RingBufferRowPostDeleteInterceptor, RingBufferRowPostInsertInterceptor,
53			RingBufferRowPostUpdateInterceptor, RingBufferRowPreDeleteInterceptor,
54			RingBufferRowPreInsertInterceptor, RingBufferRowPreUpdateInterceptor,
55		},
56		role::{
57			RolePostCreateInterceptor, RolePostUpdateInterceptor, RolePreDeleteInterceptor,
58			RolePreUpdateInterceptor,
59		},
60		series::{
61			SeriesPostCreateInterceptor, SeriesPostUpdateInterceptor, SeriesPreDeleteInterceptor,
62			SeriesPreUpdateInterceptor,
63		},
64		series_row::{
65			SeriesRowPostDeleteInterceptor, SeriesRowPostInsertInterceptor, SeriesRowPostUpdateInterceptor,
66			SeriesRowPreDeleteInterceptor, SeriesRowPreInsertInterceptor, SeriesRowPreUpdateInterceptor,
67		},
68		table::{
69			TablePostCreateInterceptor, TablePostUpdateInterceptor, TablePreDeleteInterceptor,
70			TablePreUpdateInterceptor,
71		},
72		table_row::{
73			TableRowPostDeleteInterceptor, TableRowPostInsertInterceptor, TableRowPostUpdateInterceptor,
74			TableRowPreDeleteInterceptor, TableRowPreInsertInterceptor, TableRowPreUpdateInterceptor,
75		},
76		transaction::{PostCommitInterceptor, PreCommitInterceptor},
77		view::{
78			ViewPostCreateInterceptor, ViewPostUpdateInterceptor, ViewPreDeleteInterceptor,
79			ViewPreUpdateInterceptor,
80		},
81	},
82	multi::transaction::read::MultiReadTransaction,
83	single::SingleTransaction,
84	transaction::{admin::AdminTransaction, command::CommandTransaction},
85};
86use reifydb_value::Result;
87use tracing::instrument;
88
89pub mod allocators;
90pub mod dictionary;
91pub mod read;
92pub mod row_allocator;
93pub mod slot;
94pub mod state;
95pub mod write;
96
97use allocators::FlowAllocators;
98use row_allocator::RowAllocatorRegistry;
99use slot::{OperatorStateSlot, PersistFn};
100
101use crate::host::{HostCatalog, StandardHostCatalog};
102
103pub struct TransactionalParams {
104	pub version: CommitVersion,
105	pub pending: Pending,
106	pub base_pending: Pending,
107	pub query: MultiReadTransaction,
108	pub state_query: MultiReadTransaction,
109	pub single: SingleTransaction,
110	pub catalog: Catalog,
111	pub interceptors: Interceptors,
112	pub clock: Clock,
113
114	pub view_overlay: Arc<Vec<Change>>,
115
116	pub allocators: FlowAllocators,
117}
118
119pub struct DeferredParams {
120	pub version: CommitVersion,
121	pub pending: Pending,
122	pub query: MultiReadTransaction,
123	pub state_query: MultiReadTransaction,
124	// Read source for dictionary interning state, resolved against the latest committed
125	// version rather than the per-item source-version `query` snapshot. `None` falls back to
126	// `query` (used by auxiliary/test paths that never intern across batches).
127	pub dictionary_query: Option<MultiReadTransaction>,
128	pub single: SingleTransaction,
129	pub catalog: Catalog,
130	pub interceptors: Interceptors,
131	pub clock: Clock,
132
133	pub allocators: FlowAllocators,
134}
135
136pub struct CommittingParams {
137	pub cmd: CommandTransaction,
138	pub catalog: Catalog,
139	pub interceptors: Interceptors,
140	pub clock: Clock,
141
142	pub allocators: FlowAllocators,
143}
144
145pub struct FlowTransactionInner {
146	pub version: CommitVersion,
147	pub pending: Pending,
148	pub pending_shapes: Vec<RowShape>,
149	pub query: MultiReadTransaction,
150	pub state_query: Option<MultiReadTransaction>,
151	pub dictionary_query: Option<MultiReadTransaction>,
152	pub single: SingleTransaction,
153	pub catalog: Catalog,
154	pub host_catalog: Arc<dyn HostCatalog>,
155	pub interceptors: Interceptors,
156	pub accumulator: ChangeAccumulator,
157	pub clock: Clock,
158
159	pub operator_states: HashMap<FlowNodeId, OperatorStateSlot>,
160
161	pub prefetch: HashMap<EncodedKey, Option<EncodedRow>>,
162
163	pub allocators: FlowAllocators,
164}
165
166pub enum FlowTransaction {
167	Deferred {
168		inner: FlowTransactionInner,
169	},
170
171	Transactional {
172		inner: FlowTransactionInner,
173
174		base_pending: Pending,
175
176		view_overlay: Arc<Vec<Change>>,
177	},
178
179	Ephemeral {
180		inner: FlowTransactionInner,
181
182		state: HashMap<EncodedKey, EncodedRow>,
183	},
184
185	Committing {
186		inner: FlowTransactionInner,
187
188		cmd: Box<CommandTransaction>,
189	},
190}
191
192impl FlowTransaction {
193	fn inner(&self) -> &FlowTransactionInner {
194		match self {
195			Self::Deferred {
196				inner,
197				..
198			}
199			| Self::Transactional {
200				inner,
201				..
202			}
203			| Self::Ephemeral {
204				inner,
205				..
206			}
207			| Self::Committing {
208				inner,
209				..
210			} => inner,
211		}
212	}
213
214	pub(crate) fn inner_mut(&mut self) -> &mut FlowTransactionInner {
215		match self {
216			Self::Deferred {
217				inner,
218				..
219			}
220			| Self::Transactional {
221				inner,
222				..
223			}
224			| Self::Ephemeral {
225				inner,
226				..
227			}
228			| Self::Committing {
229				inner,
230				..
231			} => inner,
232		}
233	}
234
235	#[instrument(name = "flow::transaction::deferred", level = "debug", skip(parent, catalog, interceptors, clock), fields(version = version.0))]
236	pub fn deferred(
237		parent: &AdminTransaction,
238		version: CommitVersion,
239		catalog: Catalog,
240		interceptors: Interceptors,
241		clock: Clock,
242	) -> Self {
243		let mut query = parent.multi.begin_query().unwrap();
244		query.read_as_of_version_inclusive(version);
245
246		let state_query = parent.multi.begin_query().unwrap();
247		// Dictionary state reads resolve against the latest committed version (unpinned),
248		// not the source-version `query`. See ReadFrom::DictionaryQuery.
249		let dictionary_query = parent.multi.begin_query().unwrap();
250		Self::Deferred {
251			inner: FlowTransactionInner {
252				version,
253				pending: Pending::new(),
254				pending_shapes: Vec::new(),
255				query,
256				state_query: Some(state_query),
257				dictionary_query: Some(dictionary_query),
258				single: parent.single.clone(),
259				catalog: catalog.clone(),
260				host_catalog: Arc::new(StandardHostCatalog::new(catalog)),
261				interceptors,
262				accumulator: ChangeAccumulator::new(),
263				clock,
264				operator_states: HashMap::new(),
265				prefetch: HashMap::new(),
266				allocators: FlowAllocators::new(),
267			},
268		}
269	}
270
271	pub fn deferred_from_parts(params: DeferredParams) -> Self {
272		let mut query = params.query;
273		query.read_as_of_version_inclusive(params.version);
274		let state_query = params.state_query;
275		let dictionary_query = params.dictionary_query;
276
277		Self::Deferred {
278			inner: FlowTransactionInner {
279				version: params.version,
280				pending: params.pending,
281				pending_shapes: Vec::new(),
282				query,
283				state_query: Some(state_query),
284				dictionary_query,
285				single: params.single,
286				catalog: params.catalog.clone(),
287				host_catalog: Arc::new(StandardHostCatalog::new(params.catalog)),
288				interceptors: params.interceptors,
289				accumulator: ChangeAccumulator::new(),
290				clock: params.clock,
291				operator_states: HashMap::new(),
292				prefetch: HashMap::new(),
293				allocators: params.allocators,
294			},
295		}
296	}
297
298	pub fn committing(mut params: CommittingParams) -> Result<Self> {
299		params.cmd.disable_conflict_tracking()?;
300		let version = params.cmd.version();
301		let mut query = params.cmd.multi.begin_query()?;
302		query.read_as_of_version_inclusive(version);
303		let mut state_query = params.cmd.multi.begin_query()?;
304		state_query.read_as_of_version_inclusive(version);
305		let single = params.cmd.single.clone();
306
307		Ok(Self::Committing {
308			inner: FlowTransactionInner {
309				version,
310				pending: Pending::new(),
311				pending_shapes: Vec::new(),
312				query,
313				state_query: Some(state_query),
314				dictionary_query: None,
315				single,
316				catalog: params.catalog.clone(),
317				host_catalog: Arc::new(StandardHostCatalog::new(params.catalog)),
318				interceptors: params.interceptors,
319				accumulator: ChangeAccumulator::new(),
320				clock: params.clock,
321				operator_states: HashMap::new(),
322				prefetch: HashMap::new(),
323				allocators: params.allocators,
324			},
325			cmd: Box::new(params.cmd),
326		})
327	}
328
329	pub fn commit(self) -> Result<CommitVersion> {
330		match self {
331			Self::Committing {
332				mut cmd,
333				..
334			} => cmd.commit_unchecked(),
335			_ => panic!("FlowTransaction::commit only valid on Committing variant"),
336		}
337	}
338
339	pub fn transactional(params: TransactionalParams) -> Self {
340		Self::Transactional {
341			inner: FlowTransactionInner {
342				version: params.version,
343				pending: params.pending,
344				pending_shapes: Vec::new(),
345				query: params.query,
346				state_query: Some(params.state_query),
347				dictionary_query: None,
348				single: params.single,
349				catalog: params.catalog.clone(),
350				host_catalog: Arc::new(StandardHostCatalog::new(params.catalog)),
351				interceptors: params.interceptors,
352				accumulator: ChangeAccumulator::new(),
353				clock: params.clock,
354				operator_states: HashMap::new(),
355				prefetch: HashMap::new(),
356				allocators: params.allocators,
357			},
358			base_pending: params.base_pending,
359			view_overlay: params.view_overlay,
360		}
361	}
362
363	pub fn row_allocators(&self) -> RowAllocatorRegistry {
364		self.inner().allocators.row.clone()
365	}
366
367	pub fn dictionary_allocators(&self) -> DictionaryAllocatorRegistry {
368		self.inner().allocators.dictionary.clone()
369	}
370
371	pub fn view_overlay(&self) -> Option<Arc<Vec<Change>>> {
372		match self {
373			Self::Transactional {
374				view_overlay,
375				..
376			} => Some(Arc::clone(view_overlay)),
377			_ => None,
378		}
379	}
380
381	pub fn ephemeral(
382		version: CommitVersion,
383		query: MultiReadTransaction,
384		single: SingleTransaction,
385		catalog: Catalog,
386		state: HashMap<EncodedKey, EncodedRow>,
387		clock: Clock,
388	) -> Self {
389		let mut pq = query;
390		pq.read_as_of_version_inclusive(version);
391
392		Self::Ephemeral {
393			inner: FlowTransactionInner {
394				version,
395				pending: Pending::new(),
396				pending_shapes: Vec::new(),
397				query: pq,
398				state_query: None,
399				dictionary_query: None,
400				single,
401				catalog: catalog.clone(),
402				host_catalog: Arc::new(StandardHostCatalog::new(catalog)),
403				interceptors: Interceptors::new(),
404				accumulator: ChangeAccumulator::new(),
405				clock,
406				operator_states: HashMap::new(),
407				prefetch: HashMap::new(),
408				allocators: FlowAllocators::new(),
409			},
410			state,
411		}
412	}
413
414	pub fn merge_state(&mut self) {
415		if let Self::Ephemeral {
416			inner,
417			state,
418		} = self
419		{
420			for (key, write) in inner.pending.iter_sorted() {
421				if matches!(Self::read_from(key), ReadFrom::StateQuery) {
422					match write {
423						PendingWrite::Set(row) => {
424							state.insert(key.clone(), row.clone());
425						}
426						PendingWrite::Remove | PendingWrite::Drop => {
427							state.remove(key);
428						}
429					}
430				}
431			}
432			inner.pending = Pending::new();
433		}
434	}
435
436	pub fn take_state(&mut self) -> HashMap<EncodedKey, EncodedRow> {
437		if let Self::Ephemeral {
438			state,
439			..
440		} = self
441		{
442			mem::take(state)
443		} else {
444			HashMap::new()
445		}
446	}
447
448	pub fn version(&self) -> CommitVersion {
449		self.inner().version
450	}
451
452	pub fn take_pending(&mut self) -> Pending {
453		mem::take(&mut self.inner_mut().pending)
454	}
455
456	pub fn take_pending_shapes(&mut self) -> Vec<RowShape> {
457		mem::take(&mut self.inner_mut().pending_shapes)
458	}
459
460	pub fn track_flow_change(&mut self, change: Change) {
461		if let ChangeOrigin::Shape(id) = change.origin {
462			for diff in change.diffs {
463				self.inner_mut().accumulator.track(id, diff);
464			}
465		}
466	}
467
468	pub fn take_accumulator_entries(&mut self) -> Vec<(ShapeId, Diff)> {
469		let acc = &mut self.inner_mut().accumulator;
470		let entries: Vec<_> = acc.entries_from(0).to_vec();
471		acc.clear();
472		entries
473	}
474
475	pub(crate) fn pending(&self) -> &Pending {
476		&self.inner().pending
477	}
478
479	pub fn update_version(&mut self, new_version: CommitVersion) {
480		let inner = self.inner_mut();
481		inner.version = new_version;
482		inner.query.read_as_of_version_inclusive(new_version);
483	}
484
485	pub fn catalog(&self) -> &Catalog {
486		&self.inner().catalog
487	}
488
489	pub fn host_catalog(&self) -> &dyn HostCatalog {
490		&*self.inner().host_catalog
491	}
492
493	pub fn clock(&self) -> &Clock {
494		&self.inner().clock
495	}
496
497	pub fn operator_state<S, F>(&mut self, node: FlowNodeId, load: F) -> Result<&mut S>
498	where
499		S: 'static + Send,
500		F: FnOnce(&mut Self) -> Result<(S, PersistFn)>,
501	{
502		if !self.inner().operator_states.contains_key(&node) {
503			let (state, persist) = load(self)?;
504			let slot = OperatorStateSlot {
505				value: Box::new(state),
506				dirty: false,
507				persist,
508			};
509			self.inner_mut().operator_states.insert(node, slot);
510		}
511		let slot = self.inner_mut().operator_states.get_mut(&node).expect("just inserted");
512		Ok(slot.value.downcast_mut::<S>().expect("operator state type mismatch"))
513	}
514
515	pub fn mark_state_dirty(&mut self, node: FlowNodeId) {
516		if let Some(slot) = self.inner_mut().operator_states.get_mut(&node) {
517			slot.dirty = true;
518		}
519	}
520
521	pub fn take_operator_state<S, F>(&mut self, node: FlowNodeId, load: F) -> Result<(S, PersistFn)>
522	where
523		S: 'static + Send,
524		F: FnOnce(&mut Self) -> Result<(S, PersistFn)>,
525	{
526		if let Some(slot) = self.inner_mut().operator_states.remove(&node) {
527			let value = slot.value.downcast::<S>().map_err(|_| ()).expect("operator state type mismatch");
528			Ok((*value, slot.persist))
529		} else {
530			load(self)
531		}
532	}
533
534	pub fn put_operator_state<S>(&mut self, node: FlowNodeId, state: S, persist: PersistFn)
535	where
536		S: 'static + Send,
537	{
538		self.inner_mut().operator_states.insert(
539			node,
540			OperatorStateSlot {
541				value: Box::new(state),
542				dirty: true,
543				persist,
544			},
545		);
546	}
547
548	pub fn flush_operator_states(&mut self) -> Result<()> {
549		let states = mem::take(&mut self.inner_mut().operator_states);
550		for (_, slot) in states {
551			if slot.dirty {
552				(slot.persist)(self, slot.value)?;
553			}
554		}
555		Ok(())
556	}
557
558	pub fn install_operator_states(&mut self, states: HashMap<FlowNodeId, Box<dyn Any + Send>>) {
559		let inner = self.inner_mut();
560		for (node, value) in states {
561			inner.operator_states.entry(node).or_insert_with(|| OperatorStateSlot {
562				value,
563				dirty: false,
564				persist: Box::new(|_, _| Ok(())),
565			});
566		}
567	}
568
569	pub fn drain_operator_states(&mut self) -> HashMap<FlowNodeId, Box<dyn Any + Send>> {
570		mem::take(&mut self.inner_mut().operator_states)
571			.into_iter()
572			.map(|(node, slot)| (node, slot.value))
573			.collect()
574	}
575}
576
577macro_rules! interceptor_method {
578	($method:ident, $field:ident, $trait_name:ident) => {
579		fn $method(&mut self) -> &mut Chain<dyn $trait_name + Send + Sync> {
580			&mut self.inner_mut().interceptors.$field
581		}
582	};
583}
584
585impl WithInterceptors for FlowTransaction {
586	interceptor_method!(table_row_pre_insert_interceptors, table_row_pre_insert, TableRowPreInsertInterceptor);
587	interceptor_method!(table_row_post_insert_interceptors, table_row_post_insert, TableRowPostInsertInterceptor);
588	interceptor_method!(table_row_pre_update_interceptors, table_row_pre_update, TableRowPreUpdateInterceptor);
589	interceptor_method!(table_row_post_update_interceptors, table_row_post_update, TableRowPostUpdateInterceptor);
590	interceptor_method!(table_row_pre_delete_interceptors, table_row_pre_delete, TableRowPreDeleteInterceptor);
591	interceptor_method!(table_row_post_delete_interceptors, table_row_post_delete, TableRowPostDeleteInterceptor);
592
593	interceptor_method!(
594		ringbuffer_row_pre_insert_interceptors,
595		ringbuffer_row_pre_insert,
596		RingBufferRowPreInsertInterceptor
597	);
598	interceptor_method!(
599		ringbuffer_row_post_insert_interceptors,
600		ringbuffer_row_post_insert,
601		RingBufferRowPostInsertInterceptor
602	);
603	interceptor_method!(
604		ringbuffer_row_pre_update_interceptors,
605		ringbuffer_row_pre_update,
606		RingBufferRowPreUpdateInterceptor
607	);
608	interceptor_method!(
609		ringbuffer_row_post_update_interceptors,
610		ringbuffer_row_post_update,
611		RingBufferRowPostUpdateInterceptor
612	);
613	interceptor_method!(
614		ringbuffer_row_pre_delete_interceptors,
615		ringbuffer_row_pre_delete,
616		RingBufferRowPreDeleteInterceptor
617	);
618	interceptor_method!(
619		ringbuffer_row_post_delete_interceptors,
620		ringbuffer_row_post_delete,
621		RingBufferRowPostDeleteInterceptor
622	);
623
624	interceptor_method!(pre_commit_interceptors, pre_commit, PreCommitInterceptor);
625	interceptor_method!(post_commit_interceptors, post_commit, PostCommitInterceptor);
626
627	interceptor_method!(namespace_post_create_interceptors, namespace_post_create, NamespacePostCreateInterceptor);
628	interceptor_method!(namespace_pre_update_interceptors, namespace_pre_update, NamespacePreUpdateInterceptor);
629	interceptor_method!(namespace_post_update_interceptors, namespace_post_update, NamespacePostUpdateInterceptor);
630	interceptor_method!(namespace_pre_delete_interceptors, namespace_pre_delete, NamespacePreDeleteInterceptor);
631
632	interceptor_method!(table_post_create_interceptors, table_post_create, TablePostCreateInterceptor);
633	interceptor_method!(table_pre_update_interceptors, table_pre_update, TablePreUpdateInterceptor);
634	interceptor_method!(table_post_update_interceptors, table_post_update, TablePostUpdateInterceptor);
635	interceptor_method!(table_pre_delete_interceptors, table_pre_delete, TablePreDeleteInterceptor);
636
637	interceptor_method!(view_post_create_interceptors, view_post_create, ViewPostCreateInterceptor);
638	interceptor_method!(view_pre_update_interceptors, view_pre_update, ViewPreUpdateInterceptor);
639	interceptor_method!(view_post_update_interceptors, view_post_update, ViewPostUpdateInterceptor);
640	interceptor_method!(view_pre_delete_interceptors, view_pre_delete, ViewPreDeleteInterceptor);
641
642	interceptor_method!(
643		ringbuffer_post_create_interceptors,
644		ringbuffer_post_create,
645		RingBufferPostCreateInterceptor
646	);
647	interceptor_method!(ringbuffer_pre_update_interceptors, ringbuffer_pre_update, RingBufferPreUpdateInterceptor);
648	interceptor_method!(
649		ringbuffer_post_update_interceptors,
650		ringbuffer_post_update,
651		RingBufferPostUpdateInterceptor
652	);
653	interceptor_method!(ringbuffer_pre_delete_interceptors, ringbuffer_pre_delete, RingBufferPreDeleteInterceptor);
654
655	interceptor_method!(
656		dictionary_row_pre_insert_interceptors,
657		dictionary_row_pre_insert,
658		DictionaryRowPreInsertInterceptor
659	);
660	interceptor_method!(
661		dictionary_row_post_insert_interceptors,
662		dictionary_row_post_insert,
663		DictionaryRowPostInsertInterceptor
664	);
665	interceptor_method!(
666		dictionary_row_pre_update_interceptors,
667		dictionary_row_pre_update,
668		DictionaryRowPreUpdateInterceptor
669	);
670	interceptor_method!(
671		dictionary_row_post_update_interceptors,
672		dictionary_row_post_update,
673		DictionaryRowPostUpdateInterceptor
674	);
675	interceptor_method!(
676		dictionary_row_pre_delete_interceptors,
677		dictionary_row_pre_delete,
678		DictionaryRowPreDeleteInterceptor
679	);
680	interceptor_method!(
681		dictionary_row_post_delete_interceptors,
682		dictionary_row_post_delete,
683		DictionaryRowPostDeleteInterceptor
684	);
685
686	interceptor_method!(
687		dictionary_post_create_interceptors,
688		dictionary_post_create,
689		DictionaryPostCreateInterceptor
690	);
691	interceptor_method!(dictionary_pre_update_interceptors, dictionary_pre_update, DictionaryPreUpdateInterceptor);
692	interceptor_method!(
693		dictionary_post_update_interceptors,
694		dictionary_post_update,
695		DictionaryPostUpdateInterceptor
696	);
697	interceptor_method!(dictionary_pre_delete_interceptors, dictionary_pre_delete, DictionaryPreDeleteInterceptor);
698
699	interceptor_method!(series_row_pre_insert_interceptors, series_row_pre_insert, SeriesRowPreInsertInterceptor);
700	interceptor_method!(
701		series_row_post_insert_interceptors,
702		series_row_post_insert,
703		SeriesRowPostInsertInterceptor
704	);
705	interceptor_method!(series_row_pre_update_interceptors, series_row_pre_update, SeriesRowPreUpdateInterceptor);
706	interceptor_method!(
707		series_row_post_update_interceptors,
708		series_row_post_update,
709		SeriesRowPostUpdateInterceptor
710	);
711	interceptor_method!(series_row_pre_delete_interceptors, series_row_pre_delete, SeriesRowPreDeleteInterceptor);
712	interceptor_method!(
713		series_row_post_delete_interceptors,
714		series_row_post_delete,
715		SeriesRowPostDeleteInterceptor
716	);
717
718	interceptor_method!(series_post_create_interceptors, series_post_create, SeriesPostCreateInterceptor);
719	interceptor_method!(series_pre_update_interceptors, series_pre_update, SeriesPreUpdateInterceptor);
720	interceptor_method!(series_post_update_interceptors, series_post_update, SeriesPostUpdateInterceptor);
721	interceptor_method!(series_pre_delete_interceptors, series_pre_delete, SeriesPreDeleteInterceptor);
722	interceptor_method!(identity_post_create_interceptors, identity_post_create, IdentityPostCreateInterceptor);
723	interceptor_method!(identity_pre_update_interceptors, identity_pre_update, IdentityPreUpdateInterceptor);
724	interceptor_method!(identity_post_update_interceptors, identity_post_update, IdentityPostUpdateInterceptor);
725	interceptor_method!(identity_pre_delete_interceptors, identity_pre_delete, IdentityPreDeleteInterceptor);
726	interceptor_method!(role_post_create_interceptors, role_post_create, RolePostCreateInterceptor);
727	interceptor_method!(role_pre_update_interceptors, role_pre_update, RolePreUpdateInterceptor);
728	interceptor_method!(role_post_update_interceptors, role_post_update, RolePostUpdateInterceptor);
729	interceptor_method!(role_pre_delete_interceptors, role_pre_delete, RolePreDeleteInterceptor);
730	interceptor_method!(
731		granted_role_post_create_interceptors,
732		granted_role_post_create,
733		GrantedRolePostCreateInterceptor
734	);
735	interceptor_method!(
736		granted_role_pre_delete_interceptors,
737		granted_role_pre_delete,
738		GrantedRolePreDeleteInterceptor
739	);
740	interceptor_method!(
741		authentication_post_create_interceptors,
742		authentication_post_create,
743		AuthenticationPostCreateInterceptor
744	);
745	interceptor_method!(
746		authentication_pre_delete_interceptors,
747		authentication_pre_delete,
748		AuthenticationPreDeleteInterceptor
749	);
750}