rsfbclient_diesel/fb/
transaction.rs1use super::connection::FbConnection;
4use diesel::connection::TransactionManagerStatus;
5use diesel::result::DatabaseErrorKind;
6use diesel::result::Error::DatabaseError;
7use diesel::QueryResult;
8use diesel::{connection::*, RunQueryDsl};
9
10pub struct FbTransactionManager {
12 status: TransactionManagerStatus,
13}
14
15impl FbTransactionManager {
16 pub fn new() -> Self {
17 FbTransactionManager {
18 status: Default::default(),
19 }
20 }
21
22 fn get_transaction_state(
23 conn: &mut FbConnection,
24 ) -> QueryResult<&mut ValidTransactionManagerStatus> {
25 match FbTransactionManager::transaction_manager_status_mut(conn) {
26 TransactionManagerStatus::Valid(v) => Ok(v),
27 TransactionManagerStatus::InError => {
28 Err(diesel::result::Error::BrokenTransactionManager)
29 }
30 }
31 }
32}
33
34impl Default for FbTransactionManager {
35 fn default() -> Self {
36 FbTransactionManager::new()
37 }
38}
39
40impl TransactionManager<FbConnection> for FbTransactionManager {
41 type TransactionStateData = Self;
42
43 fn begin_transaction(conn: &mut FbConnection) -> QueryResult<()> {
44 let state = Self::transaction_manager_status_mut(conn);
45 let depth = state.transaction_depth()?;
46 if let Some(depth) = depth {
47 diesel::sql_query(&format!("savepoint sp_diesel_{}", u32::from(depth) + 1))
50 .execute(conn)?;
51 } else {
52 conn.raw
53 .begin_transaction()
54 .map_err(|e| DatabaseError(DatabaseErrorKind::Unknown, Box::new(e.to_string())))?;
55 }
56 if let TransactionManagerStatus::Valid(s) = Self::transaction_manager_status_mut(conn) {
57 s.change_transaction_depth(TransactionDepthChange::IncreaseDepth)?;
58 }
59 Ok(())
60 }
61
62 fn rollback_transaction(conn: &mut FbConnection) -> QueryResult<()> {
63 let transaction_state = Self::get_transaction_state(conn)?;
64
65 let rollback_result = match transaction_state.transaction_depth().map(|d| d.get()) {
66 Some(1) => conn
67 .raw
68 .rollback()
69 .map_err(|e| DatabaseError(DatabaseErrorKind::Unknown, Box::new(e.to_string()))),
70 Some(depth_gt1) => {
71 diesel::sql_query(&format!("rollback to savepoint sp_diesel_{}", depth_gt1))
72 .execute(conn)
73 .map(|_| ())
74 }
75 None => return Err(diesel::result::Error::NotInTransaction),
76 };
77
78 match rollback_result {
79 Ok(()) => {
80 Self::get_transaction_state(conn)?
81 .change_transaction_depth(TransactionDepthChange::DecreaseDepth)?;
82 Ok(())
83 }
84 Err(rollback_error) => {
85 let tm_status = Self::transaction_manager_status_mut(conn);
86 tm_status.set_in_error();
87 Err(rollback_error)
88 }
89 }
90 }
91
92 fn commit_transaction(conn: &mut FbConnection) -> QueryResult<()> {
93 let transaction_state = Self::get_transaction_state(conn)?;
94 let transaction_depth = transaction_state.transaction_depth();
95 let commit_result = match transaction_depth {
96 None => return Err(diesel::result::Error::NotInTransaction),
97 Some(transaction_depth) if transaction_depth.get() == 1 => conn
98 .raw
99 .commit()
100 .map_err(|e| DatabaseError(DatabaseErrorKind::Unknown, Box::new(e.to_string()))),
101 Some(_transaction_depth) => Ok(()),
102 };
103 match commit_result {
104 Ok(()) => {
105 Self::get_transaction_state(conn)?
106 .change_transaction_depth(TransactionDepthChange::DecreaseDepth)?;
107 Ok(())
108 }
109 Err(commit_error) => {
110 if let TransactionManagerStatus::Valid(ref mut s) = conn.transaction_state().status
111 {
112 match s.transaction_depth().map(|p| p.get()) {
113 Some(1) => match Self::rollback_transaction(conn) {
114 Ok(()) => {}
115 Err(rollback_error) => {
116 conn.transaction_state().status.set_in_error();
117 return Err(diesel::result::Error::RollbackErrorOnCommit {
118 rollback_error: Box::new(rollback_error),
119 commit_error: Box::new(commit_error),
120 });
121 }
122 },
123 Some(_depth_gt1) => {
124 s.change_transaction_depth(TransactionDepthChange::DecreaseDepth)?;
134 }
135 None => {}
136 }
137 }
138 Err(commit_error)
139 }
140 }
141 }
142
143 fn transaction_manager_status_mut(conn: &mut FbConnection) -> &mut TransactionManagerStatus {
144 &mut conn.transaction_state().status
145 }
146}