Skip to main content

sentinel_driver/
transaction.rs

1/// Transaction isolation levels.
2#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3pub enum IsolationLevel {
4    ReadUncommitted,
5    ReadCommitted,
6    RepeatableRead,
7    Serializable,
8}
9
10impl IsolationLevel {
11    pub fn as_sql(&self) -> &'static str {
12        match self {
13            IsolationLevel::ReadUncommitted => "READ UNCOMMITTED",
14            IsolationLevel::ReadCommitted => "READ COMMITTED",
15            IsolationLevel::RepeatableRead => "REPEATABLE READ",
16            IsolationLevel::Serializable => "SERIALIZABLE",
17        }
18    }
19}
20
21/// Transaction access mode.
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub enum AccessMode {
24    ReadWrite,
25    ReadOnly,
26}
27
28/// Configuration for beginning a transaction.
29#[derive(Debug, Clone)]
30pub struct TransactionConfig {
31    pub(crate) isolation: Option<IsolationLevel>,
32    pub(crate) access_mode: Option<AccessMode>,
33    pub(crate) deferrable: bool,
34}
35
36impl Default for TransactionConfig {
37    fn default() -> Self {
38        Self::new()
39    }
40}
41
42impl TransactionConfig {
43    pub fn new() -> Self {
44        Self {
45            isolation: None,
46            access_mode: None,
47            deferrable: false,
48        }
49    }
50
51    pub fn isolation(mut self, level: IsolationLevel) -> Self {
52        self.isolation = Some(level);
53        self
54    }
55
56    pub fn read_only(mut self) -> Self {
57        self.access_mode = Some(AccessMode::ReadOnly);
58        self
59    }
60
61    pub fn read_write(mut self) -> Self {
62        self.access_mode = Some(AccessMode::ReadWrite);
63        self
64    }
65
66    pub fn deferrable(mut self, deferrable: bool) -> Self {
67        self.deferrable = deferrable;
68        self
69    }
70
71    /// Build the BEGIN statement SQL.
72    pub fn begin_sql(&self) -> String {
73        let mut sql = String::from("BEGIN");
74        let mut has_option = false;
75
76        if let Some(isolation) = &self.isolation {
77            sql.push_str(" ISOLATION LEVEL ");
78            sql.push_str(isolation.as_sql());
79            has_option = true;
80        }
81
82        if let Some(access) = &self.access_mode {
83            if has_option {
84                sql.push(',');
85            }
86            match access {
87                AccessMode::ReadWrite => sql.push_str(" READ WRITE"),
88                AccessMode::ReadOnly => sql.push_str(" READ ONLY"),
89            }
90            has_option = true;
91        }
92
93        if self.deferrable {
94            if has_option {
95                sql.push(',');
96            }
97            sql.push_str(" DEFERRABLE");
98        }
99
100        sql
101    }
102}