Skip to main content

nimiq_database/mdbx/transaction/
wrapper.rs

1use std::ops::Deref;
2
3use libmdbx::{NoWriteMap, RO, RW};
4use nimiq_database_value::IntoDatabaseValue;
5
6use super::MdbxTransaction;
7use crate::{
8    mdbx::{CursorProxy, MdbxCursor},
9    traits::{DupTable, ReadTransaction, RegularTable, Table, WriteTransaction},
10};
11
12/// A proxy object that can be either a read or a write transaction.
13/// This is used to the outside to hide the transaction kind generic.
14pub enum MdbxReadTransaction<'db> {
15    Read(MdbxTransaction<'db, RO>),
16    Write(MdbxTransaction<'db, RW>),
17}
18
19impl<'db> AsRef<MdbxReadTransaction<'db>> for MdbxReadTransaction<'db> {
20    fn as_ref(&self) -> &MdbxReadTransaction<'db> {
21        self
22    }
23}
24
25impl<'db> MdbxReadTransaction<'db> {
26    pub(crate) fn new_read(txn: libmdbx::Transaction<'db, RO, NoWriteMap>) -> Self {
27        MdbxReadTransaction::Read(MdbxTransaction::new(txn))
28    }
29}
30
31impl<'db> ReadTransaction<'db> for MdbxReadTransaction<'db> {
32    type Cursor<'txn, T: Table>
33        = CursorProxy<'txn, T>
34    where
35        Self: 'txn;
36
37    type DupCursor<'txn, T: DupTable>
38        = CursorProxy<'txn, T>
39    where
40        Self: 'txn;
41
42    fn get<T: Table>(&self, table: &T, key: &T::Key) -> Option<T::Value> {
43        match self {
44            MdbxReadTransaction::Read(txn) => txn.get(table, key),
45            MdbxReadTransaction::Write(txn) => txn.get(table, key),
46        }
47    }
48
49    fn cursor<'txn, T: RegularTable>(&'txn self, table: &T) -> Self::Cursor<'txn, T> {
50        match self {
51            MdbxReadTransaction::Read(txn) => CursorProxy::Read(txn.cursor(table)),
52            MdbxReadTransaction::Write(txn) => {
53                CursorProxy::Write(ReadTransaction::cursor(txn, table))
54            }
55        }
56    }
57
58    fn dup_cursor<'txn, T: DupTable>(&'txn self, table: &T) -> Self::DupCursor<'txn, T> {
59        match self {
60            MdbxReadTransaction::Read(txn) => CursorProxy::Read(txn.dup_cursor(table)),
61            MdbxReadTransaction::Write(txn) => {
62                CursorProxy::Write(ReadTransaction::dup_cursor(txn, table))
63            }
64        }
65    }
66}
67
68pub struct MdbxWriteTransaction<'db> {
69    txn: MdbxReadTransaction<'db>,
70}
71
72impl<'db> MdbxWriteTransaction<'db> {
73    pub(crate) fn new(txn: libmdbx::Transaction<'db, RW, NoWriteMap>) -> Self {
74        Self {
75            txn: MdbxReadTransaction::Write(MdbxTransaction::new(txn)),
76        }
77    }
78}
79
80impl<'db> ReadTransaction<'db> for MdbxWriteTransaction<'db> {
81    type Cursor<'txn, T: Table>
82        = CursorProxy<'txn, T>
83    where
84        Self: 'txn;
85
86    type DupCursor<'txn, T: DupTable>
87        = CursorProxy<'txn, T>
88    where
89        Self: 'txn;
90
91    fn get<T: Table>(&self, table: &T, key: &T::Key) -> Option<T::Value> {
92        self.txn.get(table, key)
93    }
94
95    fn cursor<'txn, T: RegularTable>(&'txn self, table: &T) -> Self::Cursor<'txn, T> {
96        self.txn.cursor(table)
97    }
98
99    fn dup_cursor<'txn, T: DupTable>(&'txn self, table: &T) -> Self::DupCursor<'txn, T> {
100        self.txn.dup_cursor(table)
101    }
102}
103
104impl<'db> WriteTransaction<'db> for MdbxWriteTransaction<'db> {
105    type WriteCursor<'txn, T: Table>
106        = MdbxCursor<'txn, RW, T>
107    where
108        Self: 'txn;
109
110    type DupWriteCursor<'txn, T: DupTable>
111        = MdbxCursor<'txn, RW, T>
112    where
113        Self: 'txn;
114
115    fn put_reserve<T: RegularTable>(&mut self, table: &T, key: &T::Key, value: &T::Value)
116    where
117        T::Value: IntoDatabaseValue,
118    {
119        match self.txn {
120            MdbxReadTransaction::Write(ref mut txn) => txn.put_reserve(table, key, value),
121            _ => unreachable!(),
122        }
123    }
124
125    fn put<T: Table>(&mut self, table: &T, key: &T::Key, value: &T::Value) {
126        match self.txn {
127            MdbxReadTransaction::Write(ref mut txn) => txn.put(table, key, value),
128            _ => unreachable!(),
129        }
130    }
131
132    fn append<T: Table>(&mut self, table: &T, key: &T::Key, value: &T::Value) {
133        match self.txn {
134            MdbxReadTransaction::Write(ref mut txn) => txn.append(table, key, value),
135            _ => unreachable!(),
136        }
137    }
138
139    fn remove<T: Table>(&mut self, table: &T, key: &T::Key) {
140        match self.txn {
141            MdbxReadTransaction::Write(ref mut txn) => txn.remove(table, key),
142            _ => unreachable!(),
143        }
144    }
145
146    fn remove_item<T: Table>(&mut self, table: &T, key: &T::Key, value: &T::Value) {
147        match self.txn {
148            MdbxReadTransaction::Write(ref mut txn) => txn.remove_item(table, key, value),
149            _ => unreachable!(),
150        }
151    }
152
153    fn commit(self) {
154        match self.txn {
155            MdbxReadTransaction::Write(txn) => txn.commit(),
156            _ => unreachable!(),
157        }
158    }
159
160    fn cursor<'txn, T: RegularTable>(&'txn self, table: &T) -> Self::WriteCursor<'txn, T> {
161        match self.txn {
162            MdbxReadTransaction::Write(ref txn) => WriteTransaction::cursor(txn, table),
163            _ => unreachable!(),
164        }
165    }
166
167    fn dup_cursor<'txn, T: DupTable>(&'txn self, table: &T) -> Self::DupWriteCursor<'txn, T> {
168        match self.txn {
169            MdbxReadTransaction::Write(ref txn) => WriteTransaction::dup_cursor(txn, table),
170            _ => unreachable!(),
171        }
172    }
173
174    fn clear_table<T: Table>(&mut self, table: &T) {
175        match self.txn {
176            MdbxReadTransaction::Write(ref mut txn) => txn.clear_table(table),
177            _ => unreachable!(),
178        }
179    }
180}
181
182impl<'db> Deref for MdbxWriteTransaction<'db> {
183    type Target = MdbxReadTransaction<'db>;
184
185    fn deref(&self) -> &Self::Target {
186        &self.txn
187    }
188}
189
190impl<'db> AsRef<MdbxReadTransaction<'db>> for MdbxWriteTransaction<'db> {
191    fn as_ref(&self) -> &MdbxReadTransaction<'db> {
192        &self.txn
193    }
194}