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