icydb_core/db/commit/
hooks.rs1use crate::{
7 db::{
8 Db,
9 commit::{
10 CommitRowOp, CommitSchemaFingerprint, PreparedRowCommitOp,
11 commit_schema_fingerprint_for_entity, prepare_row_commit_for_entity,
12 },
13 relation::StrongRelationDeleteValidateFn,
14 },
15 error::InternalError,
16 traits::{CanisterKind, EntityIdentity, EntityKind, EntityValue},
17};
18
19pub struct EntityRuntimeHooks<C: CanisterKind> {
27 pub(crate) entity_name: &'static str,
28 pub(crate) entity_path: &'static str,
29 pub(in crate::db) commit_schema_fingerprint: fn() -> CommitSchemaFingerprint,
30 pub(in crate::db) prepare_row_commit:
31 fn(&Db<C>, &CommitRowOp) -> Result<PreparedRowCommitOp, InternalError>,
32 pub(crate) validate_delete_strong_relations: StrongRelationDeleteValidateFn<C>,
33}
34
35impl<C: CanisterKind> EntityRuntimeHooks<C> {
36 #[must_use]
37 pub(in crate::db) const fn new(
39 entity_name: &'static str,
40 entity_path: &'static str,
41 commit_schema_fingerprint: fn() -> CommitSchemaFingerprint,
42 prepare_row_commit: fn(&Db<C>, &CommitRowOp) -> Result<PreparedRowCommitOp, InternalError>,
43 validate_delete_strong_relations: StrongRelationDeleteValidateFn<C>,
44 ) -> Self {
45 Self {
46 entity_name,
47 entity_path,
48 commit_schema_fingerprint,
49 prepare_row_commit,
50 validate_delete_strong_relations,
51 }
52 }
53
54 #[must_use]
55 pub const fn for_entity<E>() -> Self
57 where
58 E: EntityKind<Canister = C> + EntityValue,
59 {
60 Self::new(
61 <E as EntityIdentity>::ENTITY_NAME,
62 E::PATH,
63 commit_schema_fingerprint_for_runtime_entity::<E>,
64 prepare_row_commit_for_entity::<E>,
65 crate::db::relation::validate_delete_strong_relations_for_source::<E>,
66 )
67 }
68}
69
70fn commit_schema_fingerprint_for_runtime_entity<E>() -> CommitSchemaFingerprint
71where
72 E: EntityKind,
73{
74 commit_schema_fingerprint_for_entity::<E>()
75}
76
77#[must_use]
79pub(in crate::db) const fn has_runtime_hooks<C: CanisterKind>(
80 entity_runtime_hooks: &[EntityRuntimeHooks<C>],
81) -> bool {
82 !entity_runtime_hooks.is_empty()
83}
84
85pub(in crate::db) fn resolve_runtime_hook_by_name<'a, C: CanisterKind>(
88 entity_runtime_hooks: &'a [EntityRuntimeHooks<C>],
89 entity_name: &str,
90) -> Result<&'a EntityRuntimeHooks<C>, InternalError> {
91 let mut matched = None;
92 for hooks in entity_runtime_hooks {
93 if hooks.entity_name != entity_name {
94 continue;
95 }
96
97 if matched.is_some() {
98 return Err(InternalError::store_invariant(format!(
99 "duplicate runtime hooks for entity name '{entity_name}'"
100 )));
101 }
102
103 matched = Some(hooks);
104 }
105
106 matched.ok_or_else(|| {
107 InternalError::store_unsupported(format!(
108 "unsupported entity name in data store: '{entity_name}'"
109 ))
110 })
111}
112
113pub(in crate::db) fn resolve_runtime_hook_by_path<'a, C: CanisterKind>(
116 entity_runtime_hooks: &'a [EntityRuntimeHooks<C>],
117 entity_path: &str,
118) -> Result<&'a EntityRuntimeHooks<C>, InternalError> {
119 let mut matched = None;
120 for hooks in entity_runtime_hooks {
121 if hooks.entity_path != entity_path {
122 continue;
123 }
124
125 if matched.is_some() {
126 return Err(InternalError::store_invariant(format!(
127 "duplicate runtime hooks for entity path '{entity_path}'"
128 )));
129 }
130
131 matched = Some(hooks);
132 }
133
134 matched.ok_or_else(|| InternalError::unsupported_entity_path(entity_path))
135}