drogon
C++14/17-based HTTP application framework
Loading...
Searching...
No Matches
DbClient.h
Go to the documentation of this file.
1
14
15#pragma once
16
17#include <drogon/exports.h>
19#include <drogon/orm/Field.h>
20#include <drogon/orm/Result.h>
21#include <drogon/orm/ResultIterator.h>
22#include <drogon/orm/Row.h>
23#include <drogon/orm/RowIterator.h>
25#include <exception>
26#include <functional>
27#include <future>
28#include <string>
29#include <trantor/utils/Logger.h>
30#include <trantor/utils/NonCopyable.h>
31
32#ifdef __cpp_impl_coroutine
34#endif
35
36namespace drogon
37{
38namespace orm
39{
40using ResultCallback = std::function<void(const Result &)>;
41using ExceptionCallback = std::function<void(const DrogonDbException &)>;
42
43class Transaction;
44class DbClient;
45
54
55namespace internal
56{
57#ifdef __cpp_impl_coroutine
58struct [[nodiscard]] SqlAwaiter : public CallbackAwaiter<Result>
59{
60 explicit SqlAwaiter(internal::SqlBinder &&binder)
61 : binder_(std::move(binder))
62 {
63 }
64
65 void await_suspend(std::coroutine_handle<> handle)
66 {
67 binder_ >> [handle, this](const drogon::orm::Result &result) {
68 setValue(result);
69 handle.resume();
70 };
71 binder_ >> [handle, this](const std::exception_ptr &e) {
72 setException(e);
73 handle.resume();
74 };
75 binder_.exec();
76 }
77
78 private:
79 internal::SqlBinder binder_;
80};
81
82struct [[nodiscard]] TransactionAwaiter
83 : public CallbackAwaiter<std::shared_ptr<Transaction> >
84{
85 explicit TransactionAwaiter(
86 DbClient *client,
87 TransactionType transType = TransactionType::Deferred)
88 : client_(client), transType_(transType)
89 {
90 }
91
92 void await_suspend(std::coroutine_handle<> handle);
93
94 private:
95 DbClient *client_;
96 TransactionType transType_;
97};
98
99#endif
100
101} // namespace internal
102
104class DROGON_EXPORT DbClient : public trantor::NonCopyable
105{
106 public:
107 virtual ~DbClient();
109
134 static std::shared_ptr<DbClient> newPgClient(const std::string &connInfo,
135 size_t connNum,
136 bool autoBatch = false);
137 static std::shared_ptr<DbClient> newMysqlClient(const std::string &connInfo,
138 size_t connNum);
139 static std::shared_ptr<DbClient> newSqlite3Client(
140 const std::string &connInfo,
141 size_t connNum);
142
144
171 template <typename FUNCTION1, typename FUNCTION2, typename... Arguments>
172 void execSqlAsync(const std::string &sql,
173 FUNCTION1 &&rCallback,
174 FUNCTION2 &&exceptCallback,
175 Arguments &&...args) noexcept
176 {
177 auto binder = *this << sql;
178 (void)std::initializer_list<int>{
179 (binder << std::forward<Arguments>(args), 0)...};
180 binder >> std::forward<FUNCTION1>(rCallback);
181 binder >> std::forward<FUNCTION2>(exceptCallback);
182 }
183
185 template <typename... Arguments>
186 std::future<Result> execSqlAsyncFuture(const std::string &sql,
187 Arguments &&...args) noexcept
188 {
189 auto binder = *this << sql;
190 (void)std::initializer_list<int>{
191 (binder << std::forward<Arguments>(args), 0)...};
192 std::shared_ptr<std::promise<Result> > prom =
193 std::make_shared<std::promise<Result> >();
194 binder >> [prom](const Result &r) { prom->set_value(r); };
195 binder >>
196 [prom](const std::exception_ptr &e) { prom->set_exception(e); };
197 binder.exec();
198 return prom->get_future();
199 }
200
201 // Sync and blocking method
202 template <typename... Arguments>
203 Result execSqlSync(const std::string &sql,
204 Arguments &&...args) noexcept(false)
205 {
206 Result r(nullptr);
207 {
208 auto binder = *this << sql;
209 (void)std::initializer_list<int>{
210 (binder << std::forward<Arguments>(args), 0)...};
211 // Use blocking mode
212 binder << Mode::Blocking;
213
214 binder >> [&r](const Result &result) { r = result; };
215 binder.exec(); // exec may be throw exception;
216 }
217 return r;
218 }
219
220#ifdef __cpp_impl_coroutine
221 template <typename... Arguments>
222 internal::SqlAwaiter execSqlCoro(const std::string &sql,
223 Arguments &&...args) noexcept
224 {
225 auto binder = *this << sql;
226 (void)std::initializer_list<int>{
227 (binder << std::forward<Arguments>(args), 0)...};
228 return internal::SqlAwaiter(std::move(binder));
229 }
230
241 template <typename T>
242 internal::SqlAwaiter execSqlCoro(const std::string &sql,
243 const std::vector<T> &args) noexcept
244 {
245 auto binder = *this << sql;
246 for (const auto &arg : args)
247 {
248 binder << arg;
249 }
250 return internal::SqlAwaiter(std::move(binder));
251 }
252#endif
253
256 internal::SqlBinder operator<<(const std::string &sql);
257 internal::SqlBinder operator<<(std::string &&sql);
258
259 template <int N>
260 internal::SqlBinder operator<<(const char (&sql)[N])
261 {
262 return internal::SqlBinder(sql, N - 1, *this, type_);
263 }
264
265 internal::SqlBinder operator<<(const std::string_view &sql)
266 {
267 return internal::SqlBinder(sql.data(), sql.length(), *this, type_);
268 }
269
271
283 virtual std::shared_ptr<Transaction> newTransaction(
284 const std::function<void(bool)> &commitCallback =
285 std::function<void(bool)>(),
286 TransactionType transType =
287 TransactionType::Deferred) noexcept(false) = 0;
288
290 std::shared_ptr<Transaction> newTransaction(
291 TransactionType transType) noexcept(false)
292 {
293 return newTransaction(std::function<void(bool)>(), transType);
294 }
295
297
302 const std::function<void(const std::shared_ptr<Transaction> &)>
303 &callback,
305
309 TransactionType transType,
310 const std::function<void(const std::shared_ptr<Transaction> &)>
311 &callback)
312 {
313 newTransactionAsync(callback, transType);
314 }
315
316#ifdef __cpp_impl_coroutine
317 orm::internal::TransactionAwaiter newTransactionCoro(
319 {
320 return orm::internal::TransactionAwaiter(this, transType);
321 }
322#endif
323
330 virtual bool hasAvailableConnections() const noexcept = 0;
331
332 ClientType type() const
333 {
334 return type_;
335 }
336
337 const std::string &connectionInfo() const
338 {
339 return connectionInfo_;
340 }
341
352 virtual void setTimeout(double timeout) = 0;
357 virtual void closeAll() = 0;
358
398 // virtual void enableAutoBatch() = 0;
399
400 private:
401 friend internal::SqlBinder;
402 virtual void execSql(
403 const char *sql,
404 size_t sqlLength,
405 size_t paraNum,
406 std::vector<const char *> &&parameters,
407 std::vector<int> &&length,
408 std::vector<int> &&format,
409 ResultCallback &&rcb,
410 std::function<void(const std::exception_ptr &)> &&exceptCallback) = 0;
411
412 protected:
413 ClientType type_;
414 std::string connectionInfo_;
415};
416
417using DbClientPtr = std::shared_ptr<DbClient>;
418
419class Transaction : public DbClient
420{
421 public:
422 virtual void rollback() = 0;
423 // virtual void commit() = 0;
424 virtual void setCommitCallback(
425 const std::function<void(bool)> &commitCallback) = 0;
426
427 void closeAll() override
428 {
429 }
430};
431
432#ifdef __cpp_impl_coroutine
433inline void internal::TransactionAwaiter::await_suspend(
434 std::coroutine_handle<> handle)
435{
436 assert(client_ != nullptr);
437 client_->newTransactionAsync(
438 [this, handle](const std::shared_ptr<Transaction> &transaction) {
439 if (transaction == nullptr)
440 setException(std::make_exception_ptr(TimeoutError(
441 "Timeout, no connection available for transaction")));
442 else
443 setValue(transaction);
444 handle.resume();
445 },
446 transType_);
447}
448#endif
449
450} // namespace orm
451} // namespace drogon
TransactionType
Transaction locking mode.
Definition DbClient.h:48
@ Exclusive
Definition DbClient.h:51
@ Immediate
BEGIN IMMEDIATE — write lock acquired upfront (SQLite only).
Definition DbClient.h:50
@ Deferred
BEGIN — lock acquired on first write (default).
Definition DbClient.h:49
Database client abstract class.
Definition DbClient.h:105
virtual bool hasAvailableConnections() const noexcept=0
Check if there is a connection successfully established.
std::shared_ptr< Transaction > newTransaction(TransactionType transType) noexcept(false)
Convenience overload: create a transaction with a specific locking mode.
Definition DbClient.h:290
virtual void setTimeout(double timeout)=0
Set the Timeout value of execution of a SQL.
void execSqlAsync(const std::string &sql, FUNCTION1 &&rCallback, FUNCTION2 &&exceptCallback, Arguments &&...args) noexcept
Async and nonblocking method.
Definition DbClient.h:172
std::future< Result > execSqlAsyncFuture(const std::string &sql, Arguments &&...args) noexcept
Async and nonblocking method.
Definition DbClient.h:186
static std::shared_ptr< DbClient > newPgClient(const std::string &connInfo, size_t connNum, bool autoBatch=false)
Create a new database client with multiple connections;.
virtual void closeAll()=0
Close all connections in the client. usually used by Drogon in the quit() method.
virtual std::shared_ptr< Transaction > newTransaction(const std::function< void(bool)> &commitCallback=std::function< void(bool)>(), TransactionType transType=TransactionType::Deferred) noexcept(false)=0
Create a transaction object.
void newTransactionAsync(TransactionType transType, const std::function< void(const std::shared_ptr< Transaction > &)> &callback)
Definition DbClient.h:308
virtual void newTransactionAsync(const std::function< void(const std::shared_ptr< Transaction > &)> &callback, TransactionType transType=TransactionType::Deferred)=0
Create a transaction object in asynchronous mode.
internal::SqlBinder operator<<(const std::string &sql)
Mixin base class to identify drogon-db-specific exception types.
Definition Exception.h:51
Result set containing data returned by a query or command.
Definition Result.h:58
Definition DbClient.h:420
void closeAll() override
Close all connections in the client. usually used by Drogon in the quit() method.
Definition DbClient.h:427
Definition SqlBinder.h:293
Drogon Test is a minimal effort test framework developed because the major C++ test frameworks doesn'...
Definition Attribute.h:23
Definition coroutine.h:421