structsy/
transaction.rs

1use crate::{Fetch, FilterBuilder, Persistent, Ref, SRes, StructsyImpl, StructsyIter, StructsyQueryTx};
2use persy::Transaction;
3use std::{io::Cursor, marker::PhantomData, sync::Arc};
4
5/// Owned transation to use with [`StructsyTx`] trait
6///
7/// [`StructsyTx`]: trait.StructsyTx.html
8pub struct OwnedSytx {
9    pub(crate) structsy_impl: Arc<StructsyImpl>,
10    pub(crate) trans: Transaction,
11}
12
13impl OwnedSytx {
14    /// Query for a persistent struct considering in transaction changes.
15    ///
16    /// # Example
17    /// ```
18    /// use structsy::{ Structsy, StructsyTx, StructsyError};
19    /// use structsy_derive::{queries, Persistent};
20    /// #[derive(Persistent)]
21    /// struct Basic {
22    ///     name: String,
23    /// }
24    /// impl Basic {
25    ///     fn new(name: &str) -> Basic {
26    ///         Basic { name: name.to_string() }
27    ///     }
28    /// }
29    ///
30    /// #[queries(Basic)]
31    /// trait BasicQuery {
32    ///     fn by_name(self, name: String) -> Self;
33    /// }
34    ///
35    ///
36    /// fn basic_query() -> Result<(), StructsyError> {
37    ///     let structsy = Structsy::open("file.structsy")?;
38    ///     structsy.define::<Basic>()?;
39    ///     let mut tx = structsy.begin()?;
40    ///     tx.insert(&Basic::new("aaa"))?;
41    ///     let count = tx.query::<Basic>().by_name("aaa".to_string()).fetch().count();
42    ///     assert_eq!(count, 1);
43    ///     tx.commit()?;
44    ///     Ok(())
45    /// }
46    /// ```
47    ///
48    pub fn query<T: Persistent>(&mut self) -> StructsyQueryTx<T> {
49        StructsyQueryTx {
50            tx: self,
51            builder: FilterBuilder::new(),
52        }
53    }
54
55    pub fn into_iter<R: Fetch<T>, T>(&mut self, filter: R) -> StructsyIter<T> {
56        filter.fetch_tx(self)
57    }
58    pub(crate) fn reference(&mut self) -> RefSytx {
59        RefSytx {
60            trans: &mut self.trans,
61            structsy_impl: self.structsy_impl.clone(),
62        }
63    }
64}
65
66/// Reference transaction to use with [`StructsyTx`] trait
67///
68/// [`StructsyTx`]: trait.StructsyTx.html
69pub struct RefSytx<'a> {
70    pub(crate) structsy_impl: Arc<StructsyImpl>,
71    pub(crate) trans: &'a mut Transaction,
72}
73
74/// Internal use transaction reference
75pub struct TxRef<'a> {
76    pub(crate) trans: &'a mut Transaction,
77}
78
79/// Internal use implementation reference
80pub struct ImplRef {
81    pub(crate) structsy_impl: Arc<StructsyImpl>,
82}
83
84pub trait Sytx {
85    /// Internal Use Only
86    ///
87    #[doc(hidden)]
88    fn tx(&mut self) -> TxRef;
89    /// Internal Use Only
90    ///
91    #[doc(hidden)]
92    fn structsy(&self) -> ImplRef;
93}
94
95impl Sytx for OwnedSytx {
96    fn tx(&mut self) -> TxRef {
97        TxRef { trans: &mut self.trans }
98    }
99    fn structsy(&self) -> ImplRef {
100        ImplRef {
101            structsy_impl: self.structsy_impl.clone(),
102        }
103    }
104}
105impl StructsyTx for OwnedSytx {
106    fn commit(self) -> SRes<()> {
107        let prepared = self.trans.prepare()?;
108        prepared.commit()?;
109        Ok(())
110    }
111
112    fn prepare_commit(self) -> SRes<Prepared> {
113        Ok(Prepared {
114            prepared: self.trans.prepare()?,
115        })
116    }
117}
118
119impl<'a> Sytx for RefSytx<'a> {
120    fn tx(&mut self) -> TxRef {
121        TxRef { trans: self.trans }
122    }
123    fn structsy(&self) -> ImplRef {
124        ImplRef {
125            structsy_impl: self.structsy_impl.clone(),
126        }
127    }
128}
129impl<'a> StructsyTx for RefSytx<'a> {
130    fn commit(self) -> SRes<()> {
131        unreachable!();
132    }
133    fn prepare_commit(self) -> SRes<Prepared> {
134        unreachable!();
135    }
136}
137
138///
139/// Transaction prepared state ready to be committed if the second phase is considered successful
140///
141pub struct Prepared {
142    prepared: persy::TransactionFinalize,
143}
144impl Prepared {
145    /// Commit all the prepared changes
146    pub fn commit(self) -> SRes<()> {
147        self.prepared.commit()?;
148        Ok(())
149    }
150    /// Rollback all the prepared changes
151    pub fn rollback(self) -> SRes<()> {
152        self.prepared.rollback()?;
153        Ok(())
154    }
155}
156
157/// Transaction behaviour trait.
158pub trait StructsyTx: Sytx + Sized {
159    /// Persist a new struct instance.
160    ///
161    /// # Example
162    /// ```
163    /// use structsy::{Structsy,StructsyTx};
164    /// use structsy_derive::Persistent;
165    /// #[derive(Persistent)]
166    /// struct Example {
167    ///     value:u8,
168    /// }
169    /// # use structsy::SRes;
170    /// # fn example() -> SRes<()> {
171    /// # let structsy = Structsy::open("path/to/file.stry")?;
172    /// //.. open structsy etc.
173    /// let mut tx = structsy.begin()?;
174    /// tx.insert(&Example{value:10})?;
175    /// tx.commit()?;
176    /// # Ok(())
177    /// # }
178    /// ```
179    fn insert<T: Persistent>(&mut self, sct: &T) -> SRes<Ref<T>> {
180        let def = self.structsy().structsy_impl.check_defined::<T>()?;
181        let mut buff = Vec::new();
182        sct.write(&mut buff)?;
183        let id = self.tx().trans.insert(def.segment_name(), &buff)?;
184        let id_ref = Ref::new(id);
185        sct.put_indexes(self, &id_ref)?;
186        Ok(id_ref)
187    }
188
189    /// Update a persistent instance with a new value.
190    ///
191    /// # Example
192    /// ```
193    /// use structsy::{Structsy,StructsyTx};
194    /// use structsy_derive::Persistent;
195    /// #[derive(Persistent)]
196    /// struct Example {
197    ///     value:u8,
198    /// }
199    /// # use structsy::SRes;
200    /// # fn example() -> SRes<()> {
201    /// # let structsy = Structsy::open("path/to/file.stry")?;
202    /// //.. open structsy etc.
203    /// let mut tx = structsy.begin()?;
204    /// let id = tx.insert(&Example{value:10})?;
205    /// tx.update(&id, &Example{value:20})?;
206    /// tx.commit()?;
207    /// # Ok(())
208    /// # }
209    /// ```
210    fn update<T: Persistent>(&mut self, sref: &Ref<T>, sct: &T) -> SRes<()> {
211        let def = self.structsy().structsy_impl.check_defined::<T>()?;
212        let mut buff = Vec::new();
213        sct.write(&mut buff)?;
214        let old = self.read::<T>(sref)?;
215        if let Some(old_rec) = old {
216            old_rec.remove_indexes(self, sref)?;
217        }
218        self.tx().trans.update(def.segment_name(), &sref.raw_id, &buff)?;
219        sct.put_indexes(self, sref)?;
220        Ok(())
221    }
222
223    /// Delete a persistent instance.
224    ///
225    /// # Example
226    /// ```
227    /// use structsy::{Structsy,StructsyTx};
228    /// use structsy_derive::Persistent;
229    /// #[derive(Persistent)]
230    /// struct Example {
231    ///     value:u8,
232    /// }
233    /// # use structsy::SRes;
234    /// # fn example() -> SRes<()> {
235    /// # let structsy = Structsy::open("path/to/file.stry")?;
236    /// //.. open structsy etc.
237    /// let mut tx = structsy.begin()?;
238    /// let id = tx.insert(&Example{value:10})?;
239    /// tx.delete(&id)?;
240    /// tx.commit()?;
241    /// # Ok(())
242    /// # }
243    /// ```
244    fn delete<T: Persistent>(&mut self, sref: &Ref<T>) -> SRes<()> {
245        let def = self.structsy().structsy_impl.check_defined::<T>()?;
246        let old = self.read::<T>(sref)?;
247        if let Some(old_rec) = old {
248            old_rec.remove_indexes(self, sref)?;
249        }
250        self.tx().trans.delete(def.segment_name(), &sref.raw_id)?;
251        Ok(())
252    }
253
254    /// Read a persistent instance considering changes in transaction.
255    ///
256    /// # Example
257    /// ```
258    /// use structsy::{Structsy,StructsyTx};
259    /// use structsy_derive::Persistent;
260    /// #[derive(Persistent)]
261    /// struct Example {
262    ///     value:u8,
263    /// }
264    /// # use structsy::SRes;
265    /// # fn example() -> SRes<()> {
266    /// # let structsy = Structsy::open("path/to/file.stry")?;
267    /// //.. open structsy etc.
268    /// let mut tx = structsy.begin()?;
269    /// let id = tx.insert(&Example{value:10})?;
270    /// let read = tx.read(&id)?;
271    /// assert_eq!(10,read.unwrap().value);
272    /// tx.commit()?;
273    /// # Ok(())
274    /// # }
275    /// ```
276    fn read<T: Persistent>(&mut self, sref: &Ref<T>) -> SRes<Option<T>> {
277        let def = self.structsy().structsy_impl.check_defined::<T>()?;
278        crate::structsy::tx_read(def.segment_name(), &mut self.tx().trans, &sref.raw_id)
279    }
280
281    /// Scan persistent instances of a struct considering changes in transaction.
282    ///
283    /// # Example
284    /// ```
285    /// use structsy::{Structsy,StructsyTx};
286    /// use structsy_derive::Persistent;
287    /// #[derive(Persistent)]
288    /// struct Example {
289    ///     value:u8,
290    /// }
291    /// # use structsy::SRes;
292    /// # fn example() -> SRes<()> {
293    /// # let structsy = Structsy::open("path/to/file.stry")?;
294    /// //.. open structsy etc.
295    /// let mut tx = structsy.begin()?;
296    /// for (id, inst) in tx.scan::<Example>()? {
297    ///     // logic
298    /// }
299    /// tx.commit()?;
300    /// # Ok(())
301    /// # }
302    /// ```
303    fn scan<T: Persistent>(&mut self) -> SRes<TxRecordIter<T>> {
304        raw_tx_scan(self.structsy().structsy_impl, self.tx().trans)
305    }
306
307    /// Commit a transaction
308    ///
309    ///
310    /// # Example
311    /// ```
312    /// use structsy::{Structsy,StructsyTx};
313    /// # use structsy::SRes;
314    /// # fn example() -> SRes<()> {
315    /// let stry = Structsy::open("path/to/file.stry")?;
316    /// //....
317    /// let mut tx = stry.begin()?;
318    /// // ... operate on tx.
319    /// tx.commit()?;
320    /// # Ok(())
321    /// # }
322    /// ```
323    fn commit(self) -> SRes<()>;
324
325    /// Prepare Commit a transaction
326    ///
327    ///
328    /// # Example
329    /// ```
330    /// use structsy::{Structsy,StructsyTx};
331    /// # use structsy::SRes;
332    /// # fn example() -> SRes<()> {
333    /// let stry = Structsy::open("path/to/file.stry")?;
334    /// //....
335    /// let mut tx = stry.begin()?;
336    /// // ... operate on tx.
337    /// let prepared = tx.prepare_commit()?;
338    /// prepared.commit()?;
339    /// # Ok(())
340    /// # }
341    /// ```
342    fn prepare_commit(self) -> SRes<Prepared>;
343}
344
345pub(crate) fn raw_tx_scan<'a, T: Persistent>(
346    structsy: Arc<StructsyImpl>,
347    trans: &'a mut Transaction,
348) -> SRes<TxRecordIter<'a, T>> {
349    let def = structsy.check_defined::<T>()?;
350    let iter = trans.scan(def.segment_name())?;
351    Ok(TxRecordIter::new(iter, structsy))
352}
353
354pub trait TxIterator<'a>: Iterator {
355    fn tx(&mut self) -> RefSytx;
356}
357
358impl<'a, T: Persistent> TxIterator<'a> for TxRecordIter<'a, T> {
359    fn tx(&mut self) -> RefSytx {
360        self.tx()
361    }
362}
363
364/// Iterator for record instances aware of transactions changes
365pub struct TxRecordIter<'a, T> {
366    iter: persy::TxSegmentIter<'a>,
367    marker: PhantomData<T>,
368    structsy_impl: Arc<StructsyImpl>,
369}
370
371impl<'a, T> TxRecordIter<'a, T> {
372    fn new(iter: persy::TxSegmentIter<'a>, structsy_impl: Arc<StructsyImpl>) -> TxRecordIter<'a, T> {
373        TxRecordIter {
374            iter,
375            marker: PhantomData,
376            structsy_impl,
377        }
378    }
379
380    pub fn tx(&mut self) -> RefSytx {
381        RefSytx {
382            trans: self.iter.tx(),
383            structsy_impl: self.structsy_impl.clone(),
384        }
385    }
386}
387
388impl<'a, T: Persistent> TxRecordIter<'a, T> {
389    pub fn next_tx(&mut self) -> Option<(Ref<T>, T, RefSytx)> {
390        if let Some((id, buff, tx)) = self.iter.next_tx() {
391            if let Ok(x) = T::read(&mut Cursor::new(buff)) {
392                let stx = RefSytx {
393                    trans: tx,
394                    structsy_impl: self.structsy_impl.clone(),
395                };
396                Some((Ref::new(id), x, stx))
397            } else {
398                None
399            }
400        } else {
401            None
402        }
403    }
404}
405
406impl<'a, T: Persistent> Iterator for TxRecordIter<'a, T> {
407    type Item = (Ref<T>, T);
408    fn next(&mut self) -> Option<Self::Item> {
409        if let Some((id, buff)) = self.iter.next() {
410            if let Ok(x) = T::read(&mut Cursor::new(buff)) {
411                Some((Ref::new(id), x))
412            } else {
413                None
414            }
415        } else {
416            None
417        }
418    }
419}