1use crate::{
8 db::{
9 DbSession, PersistedRow, WriteBatchResponse,
10 data::{FieldSlot, StructuralPatch},
11 executor::{EntityAuthority, MutationMode},
12 schema::AcceptedRowLayoutRuntimeDescriptor,
13 },
14 error::InternalError,
15 traits::{CanisterKind, EntityCreateInput, EntityValue},
16 value::Value,
17};
18
19fn append_accepted_structural_patch_field(
24 entity_path: &'static str,
25 descriptor: &AcceptedRowLayoutRuntimeDescriptor<'_>,
26 patch: StructuralPatch,
27 field_name: &str,
28 value: Value,
29) -> Result<StructuralPatch, InternalError> {
30 let slot = descriptor
31 .field_slot_index_by_name(field_name)
32 .ok_or_else(|| InternalError::mutation_structural_field_unknown(entity_path, field_name))?;
33
34 Ok(patch.set(FieldSlot::from_validated_index(slot), value))
35}
36
37impl<C: CanisterKind> DbSession<C> {
38 pub fn insert<E>(&self, entity: E) -> Result<E, InternalError>
40 where
41 E: PersistedRow<Canister = C> + EntityValue,
42 {
43 self.execute_save_entity(|save| save.insert(entity))
44 }
45
46 pub fn create<I>(&self, input: I) -> Result<I::Entity, InternalError>
48 where
49 I: EntityCreateInput,
50 I::Entity: PersistedRow<Canister = C> + EntityValue,
51 {
52 self.execute_save_entity(|save| save.create(input))
53 }
54
55 pub fn insert_many_atomic<E>(
61 &self,
62 entities: impl IntoIterator<Item = E>,
63 ) -> Result<WriteBatchResponse<E>, InternalError>
64 where
65 E: PersistedRow<Canister = C> + EntityValue,
66 {
67 self.execute_save_batch(|save| save.insert_many_atomic(entities))
68 }
69
70 pub fn insert_many_non_atomic<E>(
74 &self,
75 entities: impl IntoIterator<Item = E>,
76 ) -> Result<WriteBatchResponse<E>, InternalError>
77 where
78 E: PersistedRow<Canister = C> + EntityValue,
79 {
80 self.execute_save_batch(|save| save.insert_many_non_atomic(entities))
81 }
82
83 pub fn replace<E>(&self, entity: E) -> Result<E, InternalError>
85 where
86 E: PersistedRow<Canister = C> + EntityValue,
87 {
88 self.execute_save_entity(|save| save.replace(entity))
89 }
90
91 pub fn mutate_structural<E>(
97 &self,
98 key: E::Key,
99 patch: StructuralPatch,
100 mode: MutationMode,
101 ) -> Result<E, InternalError>
102 where
103 E: PersistedRow<Canister = C> + EntityValue,
104 {
105 self.execute_save_entity(|save| save.apply_structural_mutation(mode, key, patch))
106 }
107
108 pub fn structural_patch<E, I, S>(&self, fields: I) -> Result<StructuralPatch, InternalError>
115 where
116 E: PersistedRow<Canister = C> + EntityValue,
117 I: IntoIterator<Item = (S, Value)>,
118 S: AsRef<str>,
119 {
120 let (accepted_schema, _) =
121 self.ensure_accepted_schema_snapshot_and_authority(EntityAuthority::for_type::<E>())?;
122 let descriptor =
123 AcceptedRowLayoutRuntimeDescriptor::from_accepted_schema(&accepted_schema)?;
124 let mut patch = StructuralPatch::new();
125
126 for (field_name, value) in fields {
130 let field_name = field_name.as_ref();
131 patch = append_accepted_structural_patch_field(
132 E::PATH,
133 &descriptor,
134 patch,
135 field_name,
136 value,
137 )?;
138 }
139
140 Ok(patch)
141 }
142
143 #[cfg(test)]
149 pub(in crate::db) fn replace_structural<E>(
150 &self,
151 key: E::Key,
152 patch: StructuralPatch,
153 ) -> Result<E, InternalError>
154 where
155 E: PersistedRow<Canister = C> + EntityValue,
156 {
157 self.mutate_structural(key, patch, MutationMode::Replace)
158 }
159
160 pub fn replace_many_atomic<E>(
166 &self,
167 entities: impl IntoIterator<Item = E>,
168 ) -> Result<WriteBatchResponse<E>, InternalError>
169 where
170 E: PersistedRow<Canister = C> + EntityValue,
171 {
172 self.execute_save_batch(|save| save.replace_many_atomic(entities))
173 }
174
175 pub fn replace_many_non_atomic<E>(
179 &self,
180 entities: impl IntoIterator<Item = E>,
181 ) -> Result<WriteBatchResponse<E>, InternalError>
182 where
183 E: PersistedRow<Canister = C> + EntityValue,
184 {
185 self.execute_save_batch(|save| save.replace_many_non_atomic(entities))
186 }
187
188 pub fn update<E>(&self, entity: E) -> Result<E, InternalError>
190 where
191 E: PersistedRow<Canister = C> + EntityValue,
192 {
193 self.execute_save_entity(|save| save.update(entity))
194 }
195
196 #[cfg(test)]
202 pub(in crate::db) fn insert_structural<E>(
203 &self,
204 key: E::Key,
205 patch: StructuralPatch,
206 ) -> Result<E, InternalError>
207 where
208 E: PersistedRow<Canister = C> + EntityValue,
209 {
210 self.mutate_structural(key, patch, MutationMode::Insert)
211 }
212
213 #[cfg(test)]
219 pub(in crate::db) fn update_structural<E>(
220 &self,
221 key: E::Key,
222 patch: StructuralPatch,
223 ) -> Result<E, InternalError>
224 where
225 E: PersistedRow<Canister = C> + EntityValue,
226 {
227 self.mutate_structural(key, patch, MutationMode::Update)
228 }
229
230 pub fn update_many_atomic<E>(
236 &self,
237 entities: impl IntoIterator<Item = E>,
238 ) -> Result<WriteBatchResponse<E>, InternalError>
239 where
240 E: PersistedRow<Canister = C> + EntityValue,
241 {
242 self.execute_save_batch(|save| save.update_many_atomic(entities))
243 }
244
245 pub fn update_many_non_atomic<E>(
249 &self,
250 entities: impl IntoIterator<Item = E>,
251 ) -> Result<WriteBatchResponse<E>, InternalError>
252 where
253 E: PersistedRow<Canister = C> + EntityValue,
254 {
255 self.execute_save_batch(|save| save.update_many_non_atomic(entities))
256 }
257}