native_db_32bit/transaction/rw_transaction.rs
1use crate::db_type::{Input, Result};
2use crate::transaction::internal::rw_transaction::InternalRwTransaction;
3use crate::transaction::query::RwDrain;
4use crate::transaction::query::RwGet;
5use crate::transaction::query::RwLen;
6use crate::transaction::query::RwScan;
7use crate::watch;
8use crate::watch::Event;
9use std::cell::RefCell;
10use std::fmt::Debug;
11use std::sync::{Arc, RwLock};
12
13pub struct RwTransaction<'db> {
14 pub(crate) watcher: &'db Arc<RwLock<watch::Watchers>>,
15 pub(crate) batch: RefCell<watch::Batch>,
16 pub(crate) internal: InternalRwTransaction<'db>,
17}
18
19impl<'db> RwTransaction<'db> {
20 /// Get a value from the database.
21 ///
22 /// Same as [`RTransaction::get()`](struct.RTransaction.html#method.get).
23 pub fn get<'txn>(&'txn self) -> RwGet<'db, 'txn> {
24 RwGet {
25 internal: &self.internal,
26 }
27 }
28
29 /// Get values from the database.
30 ///
31 /// Same as [`RTransaction::scan()`](struct.RTransaction.html#method.scan).
32 pub fn scan<'txn>(&'txn self) -> RwScan<'db, 'txn> {
33 RwScan {
34 internal: &self.internal,
35 }
36 }
37
38 /// Get the number of values in the database.
39 ///
40 /// Same as [`RTransaction::len()`](struct.RTransaction.html#method.len).
41 pub fn len<'txn>(&'txn self) -> RwLen<'db, 'txn> {
42 RwLen {
43 internal: &self.internal,
44 }
45 }
46
47 /// Get all values from the database.
48 ///
49 /// Same as [`RTransaction::drain()`](struct.RTransaction.html#method.drain).
50 pub fn drain<'txn>(&'txn self) -> RwDrain<'db, 'txn> {
51 RwDrain {
52 internal: &self.internal,
53 }
54 }
55}
56
57impl<'db, 'txn> RwTransaction<'db> {
58 /// Commit the transaction.
59 /// All changes will be applied to the database. If the commit fails, the transaction will be aborted. The
60 /// database will be unchanged.
61 ///
62 /// # Example
63 /// ```rust
64 /// use native_db::*;
65 ///
66 /// fn main() -> Result<(), db_type::Error> {
67 /// let mut builder = DatabaseBuilder::new();
68 /// let db = builder.create_in_memory()?;
69 ///
70 /// // Open a read transaction
71 /// let rw = db.rw_transaction()?;
72 /// // Do some stuff..
73 /// rw.commit()?;
74 ///
75 /// Ok(())
76 /// }
77 /// ```
78 pub fn commit(self) -> Result<()> {
79 self.internal.commit()?;
80 // Send batch to watchers after commit succeeds
81 let batch = self.batch.into_inner();
82 watch::push_batch(Arc::clone(&self.watcher), batch)?;
83 Ok(())
84 }
85}
86
87impl<'db, 'txn> RwTransaction<'db> {
88 /// Insert a value into the database.
89 ///
90 /// # Example
91 /// ```rust
92 /// use native_db::*;
93 /// use native_model::{native_model, Model};
94 /// use serde::{Deserialize, Serialize};
95 ///
96 /// #[derive(Serialize, Deserialize)]
97 /// #[native_model(id=1, version=1)]
98 /// #[native_db]
99 /// struct Data {
100 /// #[primary_key]
101 /// id: u64,
102 /// }
103 ///
104 /// fn main() -> Result<(), db_type::Error> {
105 /// let mut builder = DatabaseBuilder::new();
106 /// builder.define::<Data>()?;
107 /// let db = builder.create_in_memory()?;
108 ///
109 /// // Open a read transaction
110 /// let rw = db.rw_transaction()?;
111 ///
112 /// // Insert a value
113 /// rw.insert(Data { id: 1 })?;
114 ///
115 /// // /!\ Don't forget to commit the transaction
116 /// rw.commit()?;
117 ///
118 /// Ok(())
119 /// }
120 /// ```
121 pub fn insert<T: Input>(&self, item: T) -> Result<()> {
122 let (watcher_request, binary_value) = self
123 .internal
124 .concrete_insert(T::native_db_model(), item.to_item())?;
125 let event = Event::new_insert(binary_value);
126 self.batch.borrow_mut().add(watcher_request, event);
127 Ok(())
128 }
129
130 /// Remove a value from the database.
131 ///
132 /// # Example
133 /// ```rust
134 /// use native_db::*;
135 /// use native_model::{native_model, Model};
136 /// use serde::{Deserialize, Serialize};
137 ///
138 /// #[derive(Serialize, Deserialize)]
139 /// #[native_model(id=1, version=1)]
140 /// #[native_db]
141 /// struct Data {
142 /// #[primary_key]
143 /// id: u64,
144 /// }
145 ///
146 /// fn main() -> Result<(), db_type::Error> {
147 /// let mut builder = DatabaseBuilder::new();
148 /// builder.define::<Data>()?;
149 /// let db = builder.create_in_memory()?;
150 ///
151 /// // Open a read transaction
152 /// let rw = db.rw_transaction()?;
153 ///
154 /// // Remove a value
155 /// let old_value = rw.remove(Data { id: 1 })?;
156 ///
157 /// // /!\ Don't forget to commit the transaction
158 /// rw.commit()?;
159 ///
160 /// Ok(())
161 /// }
162 /// ```
163 pub fn remove<T: Input>(&self, item: T) -> Result<T> {
164 let (watcher_request, binary_value) = self
165 .internal
166 .concrete_remove(T::native_db_model(), item.to_item())?;
167 let event = Event::new_delete(binary_value.clone());
168 self.batch.borrow_mut().add(watcher_request, event);
169 Ok(binary_value.inner())
170 }
171
172 /// Update a value in the database.
173 ///
174 /// That allow to update all keys (primary and secondary) of the value.
175 ///
176 /// # Example
177 /// ```rust
178 /// use native_db::*;
179 /// use native_model::{native_model, Model};
180 /// use serde::{Deserialize, Serialize};
181 ///
182 /// #[derive(Serialize, Deserialize)]
183 /// #[native_model(id=1, version=1)]
184 /// #[native_db]
185 /// struct Data {
186 /// #[primary_key]
187 /// id: u64,
188 /// }
189 ///
190 /// fn main() -> Result<(), db_type::Error> {
191 /// let mut builder = DatabaseBuilder::new();
192 /// builder.define::<Data>()?;
193 /// let db = builder.create_in_memory()?;
194 ///
195 /// // Open a read transaction
196 /// let rw = db.rw_transaction()?;
197 ///
198 /// // Remove a value
199 /// rw.update(Data { id: 1 }, Data { id: 2 })?;
200 ///
201 /// // /!\ Don't forget to commit the transaction
202 /// rw.commit()?;
203 ///
204 /// Ok(())
205 /// }
206 /// ```
207 pub fn update<T: Input>(&self, old_item: T, updated_item: T) -> Result<()> {
208 let (watcher_request, old_binary_value, new_binary_value) = self.internal.concrete_update(
209 T::native_db_model(),
210 old_item.to_item(),
211 updated_item.to_item(),
212 )?;
213 let event = Event::new_update(old_binary_value, new_binary_value);
214 self.batch.borrow_mut().add(watcher_request, event);
215 Ok(())
216 }
217
218 /// Convert all values from the database.
219 ///
220 /// This is useful when you want to change the type/model of a value.
221 /// You have to define [`From<SourceModel> for TargetModel`](https://doc.rust-lang.org/std/convert/trait.From.html) to convert the value.
222 ///
223 /// ```rust
224 /// use native_db::*;
225 /// use native_model::{native_model, Model};
226 /// use serde::{Deserialize, Serialize};
227 ///
228 /// #[derive(Serialize, Deserialize, Clone)]
229 /// #[native_model(id=1, version=1)]
230 /// #[native_db]
231 /// struct Dog {
232 /// #[primary_key]
233 /// name: String,
234 /// }
235 ///
236 /// #[derive(Serialize, Deserialize)]
237 /// #[native_model(id=2, version=1)]
238 /// #[native_db]
239 /// struct Animal {
240 /// #[primary_key]
241 /// name: String,
242 /// #[secondary_key]
243 /// specie: String,
244 /// }
245 ///
246 /// impl From<Dog> for Animal {
247 /// fn from(dog: Dog) -> Self {
248 /// Animal {
249 /// name: dog.name,
250 /// specie: "dog".to_string(),
251 /// }
252 /// }
253 /// }
254 ///
255 /// fn main() -> Result<(), db_type::Error> {
256 /// let mut builder = DatabaseBuilder::new();
257 /// builder.define::<Dog>()?;
258 /// builder.define::<Animal>()?;
259 /// let db = builder.create_in_memory()?;
260 ///
261 /// // Open a read transaction
262 /// let rw = db.rw_transaction()?;
263 ///
264 /// // Convert all values from Dog to Animal
265 /// rw.convert_all::<Dog, Animal>()?;
266 ///
267 /// // /!\ Don't forget to commit the transaction
268 /// rw.commit()?;
269 ///
270 /// Ok(())
271 /// }
272 /// ```
273 pub fn convert_all<OldType, NewType>(&self) -> Result<()>
274 where
275 OldType: Input + Clone,
276 NewType: Input + From<OldType>,
277 {
278 let find_all_old: Vec<OldType> = self.scan().primary()?.all().collect();
279 for old in find_all_old {
280 let new: NewType = old.clone().into();
281 self.internal
282 .concrete_insert(NewType::native_db_model(), new.to_item())?;
283 self.internal
284 .concrete_remove(OldType::native_db_model(), old.to_item())?;
285 }
286 Ok(())
287 }
288
289 /// Automatically migrate the data from the old model to the new model. **No matter the state of the database**,
290 /// if all models remain defined in the application as they are, the data will be migrated to the most recent version automatically.
291 ///
292 /// Native DB use the [`native_model`](https://crates.io/crates/native_model) identifier `id` to identify the model and `version` to identify the version of the model.
293 /// We can define a model with the same identifier `id` but with a different version `version`.
294 ///
295 /// In the example below we define one model with the identifier `id=1` with tow versions `version=1` and `version=2`.
296 /// - You **must** link the previous version from the new one with `from` option like `#[native_model(id=1, version=2, from=LegacyData)]`.
297 /// - You **must** define the interoperability between the two versions with implement `From<LegacyData> for Data` and `From<Data> for LegacyData` or implement `TryFrom<LegacyData> for Data` and `TryFrom<Data> for LegacyData`.
298 /// - You **must** define all models (by calling [`define`](#method.define)) before to call [`migration`](#method.migrate).
299 /// - You **must** call use the most recent/bigger version as the target version when you call [`migration`](#method.migrate): `migration::<Data>()`.
300 /// That means you can't call `migration::<LegacyData>()` because `LegacyData` has version `1` and `Data` has version `2`.
301 ///
302 /// After call `migration::<Data>()` all data of the model `LegacyData` will be migrated to the model `Data`.
303 ///
304 /// Under the hood, when you call [`migration`](#method.migrate) `native_model` is used to convert the data from the old model to the new model
305 /// using the `From` or `TryFrom` implementation for each to target the version defined when you call [`migration::<LastVersion>()`](#method.migrate).
306 ///
307 /// It's advisable to perform all migrations within a **single transaction** to ensure that all migrations are successfully completed.
308 ///
309 /// # Example
310 /// ```rust
311 /// use native_db::*;
312 /// use native_model::{native_model, Model};
313 /// use serde::{Deserialize, Serialize};
314 ///
315 /// #[derive(Serialize, Deserialize, Debug)]
316 /// #[native_model(id=1, version=1)]
317 /// #[native_db]
318 /// struct LegacyData {
319 /// #[primary_key]
320 /// id: u32,
321 /// }
322 ///
323 /// impl From<Data> for LegacyData {
324 /// fn from(data: Data) -> Self {
325 /// LegacyData {
326 /// id: data.id as u32,
327 /// }
328 /// }
329 /// }
330 ///
331 /// #[derive(Serialize, Deserialize, Debug)]
332 /// #[native_model(id=1, version=2, from=LegacyData)]
333 /// #[native_db]
334 /// struct Data {
335 /// #[primary_key]
336 /// id: u64,
337 /// }
338 ///
339 /// impl From<LegacyData> for Data {
340 /// fn from(legacy_data: LegacyData) -> Self {
341 /// Data {
342 /// id: legacy_data.id as u64,
343 /// }
344 /// }
345 /// }
346 ///
347 /// fn main() -> Result<(), db_type::Error> {
348 /// let mut builder = DatabaseBuilder::new();
349 /// builder.define::<LegacyData>()?;
350 /// builder.define::<Data>()?;
351 /// let db = builder.create_in_memory()?;
352 ///
353 /// let rw = db.rw_transaction()?;
354 /// rw.migrate::<Data>()?;
355 /// // Other migrations if needed..
356 /// rw.commit()
357 /// }
358 /// ```
359 pub fn migrate<T: Input + Debug>(&self) -> Result<()> {
360 self.internal.migrate::<T>()
361 }
362}