Line data Source code
1 : use crate::{Client, Error, Transaction};
2 :
3 : /// The isolation level of a database transaction.
4 : #[derive(Debug, Copy, Clone)]
5 : #[non_exhaustive]
6 : pub enum IsolationLevel {
7 : /// Equivalent to `ReadCommitted`.
8 : ReadUncommitted,
9 :
10 : /// An individual statement in the transaction will see rows committed before it began.
11 : ReadCommitted,
12 :
13 : /// All statements in the transaction will see the same view of rows committed before the first query in the
14 : /// transaction.
15 : RepeatableRead,
16 :
17 : /// The reads and writes in this transaction must be able to be committed as an atomic "unit" with respect to reads
18 : /// and writes of all other concurrent serializable transactions without interleaving.
19 : Serializable,
20 : }
21 :
22 : /// A builder for database transactions.
23 : pub struct TransactionBuilder<'a> {
24 : client: &'a mut Client,
25 : isolation_level: Option<IsolationLevel>,
26 : read_only: Option<bool>,
27 : deferrable: Option<bool>,
28 : }
29 :
30 : impl<'a> TransactionBuilder<'a> {
31 0 : pub(crate) fn new(client: &'a mut Client) -> TransactionBuilder<'a> {
32 0 : TransactionBuilder {
33 0 : client,
34 0 : isolation_level: None,
35 0 : read_only: None,
36 0 : deferrable: None,
37 0 : }
38 0 : }
39 :
40 : /// Sets the isolation level of the transaction.
41 0 : pub fn isolation_level(mut self, isolation_level: IsolationLevel) -> Self {
42 0 : self.isolation_level = Some(isolation_level);
43 0 : self
44 0 : }
45 :
46 : /// Sets the access mode of the transaction.
47 0 : pub fn read_only(mut self, read_only: bool) -> Self {
48 0 : self.read_only = Some(read_only);
49 0 : self
50 0 : }
51 :
52 : /// Sets the deferrability of the transaction.
53 : ///
54 : /// If the transaction is also serializable and read only, creation of the transaction may block, but when it
55 : /// completes the transaction is able to run with less overhead and a guarantee that it will not be aborted due to
56 : /// serialization failure.
57 0 : pub fn deferrable(mut self, deferrable: bool) -> Self {
58 0 : self.deferrable = Some(deferrable);
59 0 : self
60 0 : }
61 :
62 : /// Begins the transaction.
63 : ///
64 : /// The transaction will roll back by default - use the `commit` method to commit it.
65 0 : pub async fn start(self) -> Result<Transaction<'a>, Error> {
66 0 : let mut query = "START TRANSACTION".to_string();
67 0 : let mut first = true;
68 :
69 0 : if let Some(level) = self.isolation_level {
70 0 : first = false;
71 0 :
72 0 : query.push_str(" ISOLATION LEVEL ");
73 0 : let level = match level {
74 0 : IsolationLevel::ReadUncommitted => "READ UNCOMMITTED",
75 0 : IsolationLevel::ReadCommitted => "READ COMMITTED",
76 0 : IsolationLevel::RepeatableRead => "REPEATABLE READ",
77 0 : IsolationLevel::Serializable => "SERIALIZABLE",
78 : };
79 0 : query.push_str(level);
80 0 : }
81 :
82 0 : if let Some(read_only) = self.read_only {
83 0 : if !first {
84 0 : query.push(',');
85 0 : }
86 0 : first = false;
87 :
88 0 : let s = if read_only {
89 0 : " READ ONLY"
90 : } else {
91 0 : " READ WRITE"
92 : };
93 0 : query.push_str(s);
94 0 : }
95 :
96 0 : if let Some(deferrable) = self.deferrable {
97 0 : if !first {
98 0 : query.push(',');
99 0 : }
100 :
101 0 : let s = if deferrable {
102 0 : " DEFERRABLE"
103 : } else {
104 0 : " NOT DEFERRABLE"
105 : };
106 0 : query.push_str(s);
107 0 : }
108 :
109 0 : self.client.batch_execute(&query).await?;
110 :
111 0 : Ok(Transaction::new(self.client))
112 0 : }
113 : }
|