indexed_db_futures/
transaction.rs1use crate::database::Database;
4use crate::error::Error;
5use crate::internal_utils::{StructName, SystemRepr};
6pub use base::TransactionRef;
7use listeners::TxListeners;
8pub(crate) use options::TransactionOptionsSys;
9pub use options::{TransactionDurability, TransactionOptions};
10use std::fmt::{Debug, Formatter};
11use std::ops::Deref;
12pub(crate) use tx_sys::TransactionSys;
13pub use web_sys::IdbTransactionMode as TransactionMode;
14
15mod base;
16mod listeners;
17mod options;
18mod tx_sys;
19
20iffeat! {
21 #[cfg(feature = "tx-done")]
22 mod on_done;
23 pub use on_done::{TransactionDone, TransactionFinishKind};
24}
25
26#[derive(StructName)]
33#[must_use]
34pub struct Transaction<'a> {
35 listeners: TxListeners<'a>,
36
37 done: bool,
38}
39
40#[derive(Debug, PartialEq, derive_more::From)]
42enum TransactionResult {
43 Ok,
45
46 Err(Error),
48
49 Abort,
51}
52
53macro_rules! map_result {
54 ($expr: expr, ok: $ok: ident, unexpected: $unexpect: ident => $err: ident) => {
55 match $expr {
56 TransactionResult::$ok => Ok(()),
57 TransactionResult::Err(e) => Err(e),
58 TransactionResult::$unexpect => Err(crate::error::UnexpectedDataError::$err.into()),
59 }
60 };
61}
62
63impl<'a> Transaction<'a> {
64 pub(crate) fn new(db: &'a Database, inner: web_sys::IdbTransaction) -> Self {
65 Self {
66 listeners: TxListeners::new(db, inner),
67 done: false,
68 }
69 }
70
71 #[allow(clippy::missing_errors_doc)]
80 pub async fn abort(mut self) -> crate::Result<()> {
81 self.done = true;
82 self.as_sys().abort()?;
83
84 map_result!(self.listeners.recv().await, ok: Abort, unexpected: Ok => TransactionCommitted)
85 }
86
87 #[allow(clippy::missing_errors_doc)]
89 pub async fn commit(mut self) -> crate::Result<()> {
90 self.done = true;
91 self.as_sys().do_commit()?;
92
93 map_result!(self.listeners.recv().await, ok: Ok, unexpected: Abort => TransactionAborted)
94 }
95}
96
97#[::sealed::sealed]
98#[allow(unused_qualifications)]
99impl crate::internal_utils::SystemRepr for Transaction<'_> {
100 type Repr = TransactionSys;
101
102 #[inline]
103 fn as_sys(&self) -> &Self::Repr {
104 self.transaction()
105 }
106
107 #[inline]
108 fn into_sys(self) -> Self::Repr {
109 self.as_sys().clone()
110 }
111}
112
113impl Drop for Transaction<'_> {
114 fn drop(&mut self) {
115 self.listeners.free_listeners();
116
117 if !self.done {
118 let _ = self.as_sys().abort();
119 }
120 }
121}
122
123impl Debug for Transaction<'_> {
124 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
125 f.debug_struct(Self::TYPE_NAME)
126 .field("transaction", self.as_sys())
127 .field("db", self.db())
128 .field("done", &self.done)
129 .finish()
130 }
131}
132
133impl<'a> Deref for Transaction<'a> {
134 type Target = TransactionRef<'a>;
135
136 #[inline]
137 fn deref(&self) -> &Self::Target {
138 self.listeners.tx_ref()
139 }
140}