relx 0.1.0
A Modern C++23 Type-Safe SQL Query Builder
Loading...
Searching...
No Matches
transaction_guard.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "connection.hpp"
4
5#include <stdexcept>
6#include <string_view>
7#include <utility>
8
9namespace relx::connection {
10
12class TransactionException : public std::runtime_error {
13public:
15 : std::runtime_error(error.message), error_code_(error.error_code) {}
16
17 explicit TransactionException(const std::string& message)
18 : std::runtime_error(message), error_code_(0) {}
19
22 int error_code() const noexcept { return error_code_; }
23
24private:
25 int error_code_;
26};
27
32public:
37 explicit TransactionGuard(Connection& connection,
39 : connection_(connection), committed_(false), rolled_back_(false) {
40 auto result = connection_.get().begin_transaction(isolation_level);
41 if (!result) {
42 throw TransactionException(result.error());
43 }
44 }
45
47 ~TransactionGuard() noexcept {
48 if (!committed_ && !rolled_back_ && connection_.get().in_transaction()) {
49 try {
50 rollback();
51 } catch (...) {
52 // Suppress any exceptions from rollback in destructor
53 }
54 }
55 }
56
57 // Delete copy constructor and assignment operator
60
61 // Allow move operations
63 : connection_(other.connection_), committed_(other.committed_),
64 rolled_back_(other.rolled_back_) {
65 // Mark the other transaction as rolled back to prevent double-rollback
66 other.rolled_back_ = true;
67 }
68
70 if (this != &other) {
71 // Rollback the current transaction if needed
72 if (!committed_ && !rolled_back_ && connection_.get().in_transaction()) {
73 try {
74 rollback();
75 } catch (...) {
76 // Suppress any exceptions from rollback
77 }
78 }
79
80 connection_ = other.connection_;
81 committed_ = other.committed_;
82 rolled_back_ = other.rolled_back_;
83
84 // Mark the other transaction as rolled back to prevent double-rollback
85 other.rolled_back_ = true;
86 }
87 return *this;
88 }
89
92 void commit() {
93 if (committed_ || rolled_back_) {
94 throw TransactionException("Transaction already committed or rolled back");
95 }
96
97 auto result = connection_.get().commit_transaction();
98 if (!result) {
99 throw TransactionException(result.error());
100 }
101
102 committed_ = true;
103 }
104
107 void rollback() {
108 if (committed_ || rolled_back_) {
109 throw TransactionException("Transaction already committed or rolled back");
110 }
111
112 auto result = connection_.get().rollback_transaction();
113 if (!result) {
114 throw TransactionException(result.error());
115 }
116
117 rolled_back_ = true;
118 }
119
122 bool is_committed() const noexcept { return committed_; }
123
126 bool is_rolled_back() const noexcept { return rolled_back_; }
127
132 template <typename Func>
133 static void with_transaction(Connection& connection, Func&& func,
135 TransactionGuard guard(connection, isolation_level);
136 func(connection);
137 guard.commit();
138 }
139
140private:
141 std::reference_wrapper<Connection> connection_;
142 bool committed_;
143 bool rolled_back_;
144};
145
146} // namespace relx::connection
147
148// Convenient imports from the connection namespace
Abstract base class for database connections.
Exception thrown when transaction operations fail.
int error_code() const noexcept
Get the error code associated with this exception.
TransactionException(const ConnectionError &error)
TransactionException(const std::string &message)
RAII wrapper for database transactions.
TransactionGuard(Connection &connection, IsolationLevel isolation_level=IsolationLevel::ReadCommitted)
Constructor that begins a transaction.
TransactionGuard & operator=(TransactionGuard &&other) noexcept
void rollback()
Roll back the transaction.
~TransactionGuard() noexcept
Destructor that rolls back the transaction if it wasn't committed or rolled back.
TransactionGuard & operator=(const TransactionGuard &)=delete
void commit()
Commit the transaction.
static void with_transaction(Connection &connection, Func &&func, IsolationLevel isolation_level=IsolationLevel::ReadCommitted)
Execute a query within the transaction and commit on success.
bool is_rolled_back() const noexcept
Check if the transaction has been rolled back.
TransactionGuard(TransactionGuard &&other) noexcept
bool is_committed() const noexcept
Check if the transaction has been committed.
TransactionGuard(const TransactionGuard &)=delete
IsolationLevel
Transaction isolation levels.
@ ReadCommitted
Prevents dirty reads.
STL namespace.
Error type for database connection operations.