Skip to main content

icydb_core/db/session/
write.rs

1#[cfg(test)]
2use crate::db::{DataStore, IndexStore};
3use crate::{
4    db::{DbSession, WriteBatchResponse},
5    error::InternalError,
6    traits::{CanisterKind, EntityKind, EntityValue},
7};
8
9impl<C: CanisterKind> DbSession<C> {
10    /// Insert one entity row.
11    pub fn insert<E>(&self, entity: E) -> Result<E, InternalError>
12    where
13        E: EntityKind<Canister = C> + EntityValue,
14    {
15        self.execute_save_entity(|save| save.insert(entity))
16    }
17
18    /// Insert a single-entity-type batch atomically in one commit window.
19    ///
20    /// If any item fails pre-commit validation, no row in the batch is persisted.
21    ///
22    /// This API is not a multi-entity transaction surface.
23    pub fn insert_many_atomic<E>(
24        &self,
25        entities: impl IntoIterator<Item = E>,
26    ) -> Result<WriteBatchResponse<E>, InternalError>
27    where
28        E: EntityKind<Canister = C> + EntityValue,
29    {
30        self.execute_save_batch(|save| save.insert_many_atomic(entities))
31    }
32
33    /// Insert a batch with explicitly non-atomic semantics.
34    ///
35    /// WARNING: fail-fast and non-atomic. Earlier inserts may commit before an error.
36    pub fn insert_many_non_atomic<E>(
37        &self,
38        entities: impl IntoIterator<Item = E>,
39    ) -> Result<WriteBatchResponse<E>, InternalError>
40    where
41        E: EntityKind<Canister = C> + EntityValue,
42    {
43        self.execute_save_batch(|save| save.insert_many_non_atomic(entities))
44    }
45
46    /// Replace one existing entity row.
47    pub fn replace<E>(&self, entity: E) -> Result<E, InternalError>
48    where
49        E: EntityKind<Canister = C> + EntityValue,
50    {
51        self.execute_save_entity(|save| save.replace(entity))
52    }
53
54    /// Replace a single-entity-type batch atomically in one commit window.
55    ///
56    /// If any item fails pre-commit validation, no row in the batch is persisted.
57    ///
58    /// This API is not a multi-entity transaction surface.
59    pub fn replace_many_atomic<E>(
60        &self,
61        entities: impl IntoIterator<Item = E>,
62    ) -> Result<WriteBatchResponse<E>, InternalError>
63    where
64        E: EntityKind<Canister = C> + EntityValue,
65    {
66        self.execute_save_batch(|save| save.replace_many_atomic(entities))
67    }
68
69    /// Replace a batch with explicitly non-atomic semantics.
70    ///
71    /// WARNING: fail-fast and non-atomic. Earlier replaces may commit before an error.
72    pub fn replace_many_non_atomic<E>(
73        &self,
74        entities: impl IntoIterator<Item = E>,
75    ) -> Result<WriteBatchResponse<E>, InternalError>
76    where
77        E: EntityKind<Canister = C> + EntityValue,
78    {
79        self.execute_save_batch(|save| save.replace_many_non_atomic(entities))
80    }
81
82    /// Update one existing entity row.
83    pub fn update<E>(&self, entity: E) -> Result<E, InternalError>
84    where
85        E: EntityKind<Canister = C> + EntityValue,
86    {
87        self.execute_save_entity(|save| save.update(entity))
88    }
89
90    /// Update a single-entity-type batch atomically in one commit window.
91    ///
92    /// If any item fails pre-commit validation, no row in the batch is persisted.
93    ///
94    /// This API is not a multi-entity transaction surface.
95    pub fn update_many_atomic<E>(
96        &self,
97        entities: impl IntoIterator<Item = E>,
98    ) -> Result<WriteBatchResponse<E>, InternalError>
99    where
100        E: EntityKind<Canister = C> + EntityValue,
101    {
102        self.execute_save_batch(|save| save.update_many_atomic(entities))
103    }
104
105    /// Update a batch with explicitly non-atomic semantics.
106    ///
107    /// WARNING: fail-fast and non-atomic. Earlier updates may commit before an error.
108    pub fn update_many_non_atomic<E>(
109        &self,
110        entities: impl IntoIterator<Item = E>,
111    ) -> Result<WriteBatchResponse<E>, InternalError>
112    where
113        E: EntityKind<Canister = C> + EntityValue,
114    {
115        self.execute_save_batch(|save| save.update_many_non_atomic(entities))
116    }
117
118    /// Insert one view value and return the stored view.
119    pub fn insert_view<E>(&self, view: E::ViewType) -> Result<E::ViewType, InternalError>
120    where
121        E: EntityKind<Canister = C> + EntityValue,
122    {
123        self.execute_save_view::<E>(|save| save.insert_view(view))
124    }
125
126    /// Replace one view value and return the stored view.
127    pub fn replace_view<E>(&self, view: E::ViewType) -> Result<E::ViewType, InternalError>
128    where
129        E: EntityKind<Canister = C> + EntityValue,
130    {
131        self.execute_save_view::<E>(|save| save.replace_view(view))
132    }
133
134    /// Update one view value and return the stored view.
135    pub fn update_view<E>(&self, view: E::ViewType) -> Result<E::ViewType, InternalError>
136    where
137        E: EntityKind<Canister = C> + EntityValue,
138    {
139        self.execute_save_view::<E>(|save| save.update_view(view))
140    }
141
142    /// TEST ONLY: clear all registered data and index stores for this database.
143    #[cfg(test)]
144    #[doc(hidden)]
145    pub fn clear_stores_for_tests(&self) {
146        self.db.with_store_registry(|reg| {
147            // Test cleanup only: clearing all stores is set-like and does not
148            // depend on registry iteration order.
149            for (_, store) in reg.iter() {
150                store.with_data_mut(DataStore::clear);
151                store.with_index_mut(IndexStore::clear);
152            }
153        });
154    }
155}