mirror of https://github.com/sipwise/sems.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
137 lines
4.9 KiB
137 lines
4.9 KiB
#pragma once
|
|
#include <string>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
#include <variant>
|
|
#include <initializer_list>
|
|
#include <memory>
|
|
#include <mysql++/mysql++.h>
|
|
#include "log.h"
|
|
/*
|
|
Utilization examples:
|
|
With list of arguments:
|
|
```
|
|
std::initializer_list<DBArgOption> args = {
|
|
dbReconnectOption,
|
|
dbConnectTimeoutOption(5),
|
|
dbReadTimeoutOption(5),
|
|
dbWriteTimeoutOption(5),
|
|
dbFoundRowsOption
|
|
};
|
|
apply_mysql_options(conn1, args);
|
|
apply_mysql_options(conn2, args);
|
|
apply_mysql_options(conn3, args);
|
|
```
|
|
As a variadic function:
|
|
```
|
|
apply_mysql_options(conn, dbConnectTimeoutOption(5), dbReadTimeoutOption(5));
|
|
```
|
|
Variadic function, only setting reconnectionOption:
|
|
```
|
|
apply_mysql_options(conn, dbReconnectOption);
|
|
```
|
|
Variadic function, no time set(default: 5) and out of order:
|
|
```
|
|
apply_mysql_options(conn, dbFoundRowsOption, dbConnectTimeoutOption);
|
|
```
|
|
Note that ```apply_mysql_options(conn)``` should do nothing.
|
|
*/
|
|
enum class DbOptionId { Reconnect, ConnectTimeout, ReadTimeout, WriteTimeout, FoundRows };
|
|
using Value = std::variant<int, bool, std::string>;
|
|
using Kv = std::pair<DbOptionId, Value>;
|
|
struct Key
|
|
{
|
|
DbOptionId id;
|
|
template <class T>
|
|
auto operator()(T&& v) const {
|
|
return Kv{ id, Value{std::forward<T>(v)} };
|
|
}
|
|
};
|
|
inline constexpr int defaultTimeoutSec = 5;
|
|
inline constexpr Key dbReconnectOption{DbOptionId::Reconnect};
|
|
inline constexpr Key dbConnectTimeoutOption{DbOptionId::ConnectTimeout};
|
|
inline constexpr Key dbReadTimeoutOption{DbOptionId::ReadTimeout};
|
|
inline constexpr Key dbWriteTimeoutOption{DbOptionId::WriteTimeout};
|
|
inline constexpr Key dbFoundRowsOption{DbOptionId::FoundRows};
|
|
using DBArgOption = std::variant<Key, Kv>;
|
|
template<class T>
|
|
concept ArgLike = std::is_same_v<std::decay_t<T>, Key> || std::is_same_v<std::decay_t<T>, Kv>;
|
|
template<typename Opt, typename... Args>
|
|
inline void set_opt(mysqlpp::Connection& conn, Args&&... args) {
|
|
auto p = std::make_unique<Opt>(std::forward<Args>(args)...);
|
|
conn.set_option(p.release());
|
|
}
|
|
// Flags (no value). Example: passing `dbReconnectOption` alone sets reconnect=true.
|
|
inline void process_arg(mysqlpp::Connection& conn, const Key& k) {
|
|
DbOptionId id = k.id;
|
|
switch(id) {
|
|
case DbOptionId::Reconnect:
|
|
set_opt<mysqlpp::ReconnectOption>(conn, true);
|
|
break;
|
|
case DbOptionId::FoundRows:
|
|
set_opt<mysqlpp::FoundRowsOption>(conn, true);
|
|
break;
|
|
case DbOptionId::ConnectTimeout:
|
|
set_opt<mysqlpp::ConnectTimeoutOption>(conn, defaultTimeoutSec);
|
|
break;
|
|
case DbOptionId::ReadTimeout:
|
|
set_opt<mysqlpp::ReadTimeoutOption>(conn, defaultTimeoutSec);
|
|
break;
|
|
case DbOptionId::WriteTimeout:
|
|
set_opt<mysqlpp::WriteTimeoutOption>(conn, defaultTimeoutSec);
|
|
break;
|
|
default:
|
|
ERROR("Unknown DB id(%d) Option without value.\n", static_cast<int>(id));
|
|
break;
|
|
}
|
|
}
|
|
template<class T, class MakeUnique>
|
|
inline void set_as(mysqlpp::Connection& conn, const Value& val, MakeUnique make_unique) {
|
|
if (const T* p = std::get_if<T>(&val)) {
|
|
conn.set_option(make_unique(*p).release());
|
|
}
|
|
}
|
|
// Key/value pairs. Example: dbConnectTimeoutOption(5) sets a 5s connect timeout.
|
|
inline void process_arg(mysqlpp::Connection& conn, const Kv& kv) {
|
|
const auto& [id, val] = kv;
|
|
switch(id) {
|
|
case DbOptionId::ConnectTimeout:
|
|
set_as<int>(conn, val, [&](int x) { return std::make_unique<mysqlpp::ConnectTimeoutOption>(x); });
|
|
break;
|
|
case DbOptionId::ReadTimeout:
|
|
set_as<int>(conn, val, [&](int x) { return std::make_unique<mysqlpp::ReadTimeoutOption>(x); });
|
|
break;
|
|
case DbOptionId::WriteTimeout:
|
|
set_as<int>(conn, val, [&](int x) { return std::make_unique<mysqlpp::WriteTimeoutOption>(x); });
|
|
break;
|
|
case DbOptionId::Reconnect:
|
|
set_as<bool>(conn, val, [&](bool x) { return std::make_unique<mysqlpp::ReconnectOption>(x); });
|
|
break;
|
|
case DbOptionId::FoundRows:
|
|
set_as<bool>(conn, val, [&](bool x) { return std::make_unique<mysqlpp::FoundRowsOption>(x); });
|
|
break;
|
|
default:
|
|
std::string valueStr;
|
|
if (auto p = std::get_if<std::string>(&val)) {
|
|
valueStr = *p;
|
|
} else if (auto p = std::get_if<int>(&val)) {
|
|
valueStr = std::to_string(*p);
|
|
} else if (auto p = std::get_if<bool>(&val)) {
|
|
valueStr = *p ? "true" : "false";
|
|
} else {
|
|
valueStr = "<unknown type>";
|
|
}
|
|
ERROR("Unknown DB id(%d) Option with value (%s).\n", static_cast<int>(id), valueStr.c_str());
|
|
break;
|
|
}
|
|
}
|
|
template<ArgLike... Args>
|
|
inline void apply_mysql_options(mysqlpp::Connection& conn, Args&&... args) {
|
|
(process_arg(conn, std::forward<Args>(args)), ...);
|
|
}
|
|
inline void apply_mysql_options(mysqlpp::Connection& conn,
|
|
std::initializer_list<DBArgOption> args) {
|
|
for (const auto& a : args) {
|
|
std::visit([&](const auto& x) { process_arg(conn, x); }, a);
|
|
}
|
|
} |