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}