Skip to main content

noxu_db/
transaction_config.rs

1//! Transaction configuration.
2//!
3
4use crate::durability::Durability;
5
6/// Configuration for transactions.
7///
8/// Specifies the configuration parameters used when beginning a transaction.
9///
10///
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct TransactionConfig {
13    /// Durability for this transaction.
14    pub durability: Durability,
15
16    /// Use read-committed isolation.
17    pub read_committed: bool,
18
19    /// Use read-uncommitted isolation (dirty reads).
20    pub read_uncommitted: bool,
21
22    /// The transaction is read-only.
23    pub read_only: bool,
24
25    /// Don't wait for locks (fail immediately if lock unavailable).
26    pub no_wait: bool,
27
28    /// Lock timeout in milliseconds (0 = use environment default).
29    pub lock_timeout_ms: u64,
30
31    /// Transaction timeout in milliseconds (0 = no timeout).
32    pub txn_timeout_ms: u64,
33
34    /// Use serializable (repeatable-read) isolation.
35    /// Read locks are retained through commit/abort.
36    pub serializable_isolation: bool,
37
38    /// Importunate transactions can steal locks from other lockers
39    /// rather than waiting.
40    pub importunate: bool,
41
42    /// Writes stay local (used on read-only replicas for local modifications
43    /// that are not replicated).
44    pub local_write: bool,
45}
46
47impl TransactionConfig {
48    /// Creates a new TransactionConfig with default settings.
49    pub fn new() -> Self {
50        Self {
51            durability: Durability::default(),
52            read_committed: false,
53            read_uncommitted: false,
54            read_only: false,
55            no_wait: false,
56            lock_timeout_ms: 0,
57            txn_timeout_ms: 0,
58            serializable_isolation: false,
59            importunate: false,
60            local_write: false,
61        }
62    }
63
64    /// Sets the durability for this transaction.
65    pub fn set_durability(&mut self, durability: Durability) -> &mut Self {
66        self.durability = durability;
67        self
68    }
69
70    /// Sets read-committed isolation.
71    pub fn set_read_committed(&mut self, read_committed: bool) -> &mut Self {
72        self.read_committed = read_committed;
73        if read_committed {
74            self.read_uncommitted = false;
75        }
76        self
77    }
78
79    /// Sets read-uncommitted isolation.
80    pub fn set_read_uncommitted(
81        &mut self,
82        read_uncommitted: bool,
83    ) -> &mut Self {
84        self.read_uncommitted = read_uncommitted;
85        if read_uncommitted {
86            self.read_committed = false;
87        }
88        self
89    }
90
91    /// Sets whether the transaction is read-only.
92    pub fn set_read_only(&mut self, read_only: bool) -> &mut Self {
93        self.read_only = read_only;
94        self
95    }
96
97    /// Sets whether to fail immediately if a lock is unavailable.
98    pub fn set_no_wait(&mut self, no_wait: bool) -> &mut Self {
99        self.no_wait = no_wait;
100        self
101    }
102
103    /// Sets the lock timeout in milliseconds (0 = use environment default).
104    pub fn set_lock_timeout_ms(&mut self, ms: u64) -> &mut Self {
105        self.lock_timeout_ms = ms;
106        self
107    }
108
109    /// Sets the transaction timeout in milliseconds (0 = no timeout).
110    pub fn set_txn_timeout_ms(&mut self, ms: u64) -> &mut Self {
111        self.txn_timeout_ms = ms;
112        self
113    }
114
115    /// Sets serializable isolation (read locks retained through commit).
116    pub fn set_serializable_isolation(&mut self, v: bool) -> &mut Self {
117        self.serializable_isolation = v;
118        self
119    }
120
121    /// Sets importunate mode (steal locks rather than wait).
122    pub fn set_importunate(&mut self, v: bool) -> &mut Self {
123        self.importunate = v;
124        self
125    }
126
127    /// Sets local-write mode (writes not replicated).
128    pub fn set_local_write(&mut self, v: bool) -> &mut Self {
129        self.local_write = v;
130        self
131    }
132
133    /// Builder-style method to set durability.
134    pub fn with_durability(mut self, durability: Durability) -> Self {
135        self.durability = durability;
136        self
137    }
138
139    /// Builder-style method to set read_committed.
140    pub fn with_read_committed(mut self, read_committed: bool) -> Self {
141        self.set_read_committed(read_committed);
142        self
143    }
144
145    /// Builder-style method to set read_uncommitted.
146    pub fn with_read_uncommitted(mut self, read_uncommitted: bool) -> Self {
147        self.set_read_uncommitted(read_uncommitted);
148        self
149    }
150
151    /// Builder-style method to set read_only.
152    pub fn with_read_only(mut self, read_only: bool) -> Self {
153        self.read_only = read_only;
154        self
155    }
156
157    /// Builder-style method to set no_wait.
158    pub fn with_no_wait(mut self, no_wait: bool) -> Self {
159        self.no_wait = no_wait;
160        self
161    }
162
163    /// Builder-style method to set lock timeout.
164    pub fn with_lock_timeout_ms(mut self, ms: u64) -> Self {
165        self.lock_timeout_ms = ms;
166        self
167    }
168
169    /// Builder-style method to set transaction timeout.
170    pub fn with_txn_timeout_ms(mut self, ms: u64) -> Self {
171        self.txn_timeout_ms = ms;
172        self
173    }
174
175    /// Builder-style method to set serializable isolation.
176    pub fn with_serializable_isolation(mut self, v: bool) -> Self {
177        self.serializable_isolation = v;
178        self
179    }
180
181    /// Builder-style method to set importunate mode.
182    pub fn with_importunate(mut self, v: bool) -> Self {
183        self.importunate = v;
184        self
185    }
186
187    /// Builder-style method to set local-write mode.
188    pub fn with_local_write(mut self, v: bool) -> Self {
189        self.local_write = v;
190        self
191    }
192
193    /// Creates a TransactionConfig for read-committed isolation.
194    pub fn read_committed() -> Self {
195        Self::new().with_read_committed(true)
196    }
197
198    /// Creates a TransactionConfig for read-uncommitted isolation.
199    pub fn read_uncommitted() -> Self {
200        Self::new().with_read_uncommitted(true)
201    }
202
203    /// Creates a TransactionConfig for read-only transactions.
204    pub fn read_only() -> Self {
205        Self::new().with_read_only(true)
206    }
207}
208
209impl Default for TransactionConfig {
210    fn default() -> Self {
211        Self::new()
212    }
213}
214
215#[cfg(test)]
216mod tests {
217    use super::*;
218
219    #[test]
220    fn test_new() {
221        let config = TransactionConfig::new();
222        assert_eq!(config.durability, Durability::default());
223        assert!(!config.read_committed);
224        assert!(!config.read_uncommitted);
225        assert!(!config.read_only);
226        assert!(!config.no_wait);
227    }
228
229    #[test]
230    fn test_set_durability() {
231        let mut config = TransactionConfig::new();
232        config.set_durability(Durability::COMMIT_NO_SYNC);
233        assert_eq!(config.durability, Durability::COMMIT_NO_SYNC);
234    }
235
236    #[test]
237    fn test_set_read_committed() {
238        let mut config = TransactionConfig::new();
239        config.set_read_committed(true);
240        assert!(config.read_committed);
241        assert!(!config.read_uncommitted);
242    }
243
244    #[test]
245    fn test_set_read_uncommitted() {
246        let mut config = TransactionConfig::new();
247        config.set_read_uncommitted(true);
248        assert!(config.read_uncommitted);
249        assert!(!config.read_committed);
250    }
251
252    #[test]
253    fn test_isolation_mutual_exclusion() {
254        let mut config = TransactionConfig::new();
255        config.set_read_committed(true);
256        assert!(config.read_committed);
257
258        config.set_read_uncommitted(true);
259        assert!(config.read_uncommitted);
260        assert!(!config.read_committed);
261
262        config.set_read_committed(true);
263        assert!(config.read_committed);
264        assert!(!config.read_uncommitted);
265    }
266
267    #[test]
268    fn test_set_read_only() {
269        let mut config = TransactionConfig::new();
270        config.set_read_only(true);
271        assert!(config.read_only);
272    }
273
274    #[test]
275    fn test_set_no_wait() {
276        let mut config = TransactionConfig::new();
277        config.set_no_wait(true);
278        assert!(config.no_wait);
279    }
280
281    #[test]
282    fn test_with_durability() {
283        let config = TransactionConfig::new()
284            .with_durability(Durability::COMMIT_WRITE_NO_SYNC);
285        assert_eq!(config.durability, Durability::COMMIT_WRITE_NO_SYNC);
286    }
287
288    #[test]
289    fn test_with_read_committed() {
290        let config = TransactionConfig::new().with_read_committed(true);
291        assert!(config.read_committed);
292    }
293
294    #[test]
295    fn test_with_read_uncommitted() {
296        let config = TransactionConfig::new().with_read_uncommitted(true);
297        assert!(config.read_uncommitted);
298    }
299
300    #[test]
301    fn test_with_read_only() {
302        let config = TransactionConfig::new().with_read_only(true);
303        assert!(config.read_only);
304    }
305
306    #[test]
307    fn test_with_no_wait() {
308        let config = TransactionConfig::new().with_no_wait(true);
309        assert!(config.no_wait);
310    }
311
312    #[test]
313    fn test_read_committed_factory() {
314        let config = TransactionConfig::read_committed();
315        assert!(config.read_committed);
316        assert!(!config.read_uncommitted);
317    }
318
319    #[test]
320    fn test_read_uncommitted_factory() {
321        let config = TransactionConfig::read_uncommitted();
322        assert!(config.read_uncommitted);
323        assert!(!config.read_committed);
324    }
325
326    #[test]
327    fn test_read_only_factory() {
328        let config = TransactionConfig::read_only();
329        assert!(config.read_only);
330    }
331
332    #[test]
333    fn test_default() {
334        let config = TransactionConfig::default();
335        assert!(!config.read_committed);
336        assert!(!config.read_uncommitted);
337    }
338
339    #[test]
340    fn test_clone() {
341        let config1 = TransactionConfig::read_committed();
342        let config2 = config1.clone();
343        assert_eq!(config1, config2);
344    }
345
346    #[test]
347    fn test_equality() {
348        let config1 = TransactionConfig::new();
349        let config2 = TransactionConfig::default();
350        assert_eq!(config1, config2);
351
352        let config3 = TransactionConfig::read_only();
353        assert_ne!(config1, config3);
354    }
355
356    #[test]
357    fn test_builder_chain() {
358        let config = TransactionConfig::new()
359            .with_durability(Durability::COMMIT_NO_SYNC)
360            .with_read_committed(true)
361            .with_no_wait(true);
362        assert_eq!(config.durability, Durability::COMMIT_NO_SYNC);
363        assert!(config.read_committed);
364        assert!(config.no_wait);
365    }
366
367    #[test]
368    fn test_debug() {
369        let config = TransactionConfig::read_only();
370        let debug = format!("{:?}", config);
371        assert!(debug.contains("read_only"));
372    }
373}