userver: userver/storages/sqlite/transaction.hpp Source File
Loading...
Searching...
No Matches
transaction.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/storages/sqlite/transaction.hpp
4
5#include <userver/utils/fast_pimpl.hpp>
6#include <userver/utils/trx_tracker.hpp>
7
8#include <userver/storages/sqlite/cursor_result_set.hpp>
9#include <userver/storages/sqlite/impl/binder_help.hpp>
10#include <userver/storages/sqlite/options.hpp>
11#include <userver/storages/sqlite/query.hpp>
12#include <userver/storages/sqlite/result_set.hpp>
13#include <userver/storages/sqlite/savepoint.hpp>
14#include <userver/storages/sqlite/sqlite_fwd.hpp>
15
16USERVER_NAMESPACE_BEGIN
17
18namespace storages::sqlite {
19
20/// @brief RAII transaction wrapper, auto-<b>ROLLBACK</b>s on destruction if no
21/// prior `Commit`/`Rollback` call was made.
22///
23/// This type can't be constructed in user code and is always retrieved from
24/// storages::sqlite::Client
25class Transaction final {
26public:
27 Transaction(std::shared_ptr<infra::ConnectionPtr> connection, const settings::TransactionOptions& options);
28 ~Transaction();
29 Transaction(const Transaction& other) = delete;
30 Transaction(Transaction&& other) noexcept;
31 Transaction& operator=(Transaction&&) noexcept;
32
33 /// @brief Executes a statement.
34 ///
35 /// Fills placeholders of the statement with args..., `Args` are expected to
36 /// be of supported types.
37 /// See @ref scripts/docs/en/userver/sqlite/supported_types.md for better understanding of `Args`
38 /// requirements.
39 ///
40 /// @tparam Args Types of parameters to bind
41 /// @param query SQL query to execute
42 /// @param args Parameters to bind to the query
43 /// @return ResultSet containing the results of the query
44 template <typename... Args>
45 ResultSet Execute(const Query& query, const Args&... args) const;
46
47 /// @brief Executes a statement, decomposing the row.
48 ///
49 /// Decomposes the fields of the row and binds them as parameters to the query.
50 /// See @ref scripts/docs/en/userver/sqlite/supported_types.md for better understanding of `T` requirements.
51 ///
52 /// @tparam T Type of the row to decompose
53 /// @param query SQL query to execute
54 /// @param row Row object to decompose and bind
55 /// @return ResultSet containing the results of the query
56 template <typename T>
57 ResultSet ExecuteDecompose(const Query& query, const T& row) const;
58
59 /// @brief Executes a statement multiple times.
60 ///
61 /// Iterates over the container and executes the query for each element.
62 /// Container is expected to be a std::Container, Container::value_type is
63 /// expected to be an aggregate of supported types.
64 /// See @ref scripts/docs/en/userver/mysql/supported_types.md for better understanding of
65 /// `Container::value_type` requirements.
66 ///
67 /// @tparam Container Type of the container holding rows
68 /// @param query SQL query to execute
69 /// @param params Container of rows to bind and execute
70 template <typename Container>
71 void ExecuteMany(const Query& query, const Container& params) const;
72
73 /// @brief Executes a statement and returns a cursor for iterating over results.
74 ///
75 /// Fills placeholders of the statement with args..., `Args` are expected to
76 /// be of supported types.
77 /// See @ref scripts/docs/en/userver/sqlite/supported_types.md for better understanding of `Args`
78 /// requirements.
79 ///
80 /// @tparam T Type of the result rows
81 /// @tparam Args Types of parameters to bind
82 /// @param batch_size Number of rows to fetch per batch
83 /// @param query SQL query to execute
84 /// @param args Parameters to bind to the query
85 /// @return CursorResultSet for iterating over the results
86 template <typename T, typename... Args>
87 CursorResultSet<T> GetCursor(std::size_t batch_size, const Query& query, const Args&... args) const;
88
89 /// @brief Creates a savepoint with specified name.
90 ///
91 /// @param name Name of the savepoint
92 /// @return Savepoint object representing the created savepoint
93 Savepoint Save(std::string name) const;
94
95 /// @brief Commit the transaction
96 void Commit();
97
98 /// @brief Rollback the transaction
99 void Rollback();
100
101private:
102 ResultSet DoExecute(impl::io::ParamsBinderBase& params) const;
103 void AssertValid() const;
104
105 void AccountQueryExecute() const noexcept;
106 void AccountQueryFailed() const noexcept;
107
108 std::shared_ptr<infra::ConnectionPtr> connection_;
109 utils::trx_tracker::TransactionLock trx_lock_;
110};
111
112template <typename... Args>
113ResultSet Transaction::Execute(const Query& query, const Args&... args) const {
114 AssertValid();
115 AccountQueryExecute();
116 try {
117 auto params_binder = impl::BindHelper::UpdateParamsBindings(query, *connection_, args...);
118 return DoExecute(params_binder);
119 } catch (const std::exception& err) {
120 AccountQueryFailed();
121 throw;
122 }
123}
124
125template <typename T>
126ResultSet Transaction::ExecuteDecompose(const Query& query, const T& row) const {
127 AssertValid();
128 AccountQueryExecute();
129 try {
130 auto params_binder = impl::BindHelper::UpdateRowAsParamsBindings(query, *connection_, row);
131 return DoExecute(params_binder);
132 } catch (const std::exception& err) {
133 AccountQueryFailed();
134 throw;
135 }
136}
137
138template <typename Container>
139void Transaction::ExecuteMany(const Query& query, const Container& params) const {
140 AssertValid();
141 AccountQueryExecute();
142 for (const auto& row : params) {
143 try {
144 auto params_binder = impl::BindHelper::UpdateRowAsParamsBindings(query, *connection_, row);
145 DoExecute(params_binder);
146 } catch (const std::exception& err) {
147 AccountQueryFailed();
148 throw;
149 }
150 }
151}
152
153template <typename T, typename... Args>
154CursorResultSet<T> Transaction::GetCursor(std::size_t batch_size, const Query& query, const Args&... args) const {
155 AssertValid();
156 AccountQueryExecute();
157 try {
158 auto params_binder = impl::BindHelper::UpdateParamsBindings(query, *connection_, args...);
159 return CursorResultSet<T>{DoExecute(params_binder, connection_), batch_size};
160 } catch (const std::exception& err) {
161 AccountQueryFailed();
162 throw;
163 }
164}
165
166} // namespace storages::sqlite
167
168USERVER_NAMESPACE_END