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}