Skip to content

Commit

Permalink
add query_s delete_records_s
Browse files Browse the repository at this point in the history
  • Loading branch information
Jacyking committed Feb 20, 2024
1 parent d4b4606 commit 2b2c473
Show file tree
Hide file tree
Showing 6 changed files with 394 additions and 99 deletions.
16 changes: 9 additions & 7 deletions ormpp/dbng.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,21 +74,23 @@ class dbng {
}

template <typename T, typename... Args>
bool delete_records(Args &&...where_condition) {
return db_.template delete_records<T>(
std::forward<Args>(where_condition)...);
bool delete_records_s(const std::string &str = "", Args &&...args) {
return db_.template delete_records_s<T>(str, std::forward<Args>(args)...);
}

template <typename T, typename... Args>
bool delete_records0(const std::string &str = "", Args &&...args) {
return db_.template delete_records0<T>(str, std::forward<Args>(args)...);
std::vector<T> query_s(const std::string &str = "", Args &&...args) {
return db_.template query_s<T>(str, std::forward<Args>(args)...);
}

// deprecated
template <typename T, typename... Args>
std::vector<T> query0(const std::string &str = "", Args &&...args) {
return db_.template query0<T>(str, std::forward<Args>(args)...);
bool delete_records(Args &&...where_condition) {
return db_.template delete_records<T>(
std::forward<Args>(where_condition)...);
}

// deprecated
// restriction, all the args are string, the first is the where condition,
// rest are append conditions
template <typename T, typename... Args>
Expand Down
147 changes: 137 additions & 10 deletions ormpp/mysql.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,11 +279,8 @@ class mysql {
}

template <typename T, typename... Args>
bool delete_records0(const std::string &str, Args &&...args) {
auto sql = generate_delete_sql<T>();
if (!str.empty()) {
sql += "where " + str;
}
bool delete_records_s(const std::string &str, Args &&...args) {
auto sql = generate_delete_sql<T>(str);
#ifdef ORMPP_ENABLE_LOG
std::cout << sql << std::endl;
#endif
Expand Down Expand Up @@ -318,12 +315,9 @@ class mysql {
}

template <typename T, typename... Args>
std::enable_if_t<iguana::is_reflection_v<T>, std::vector<T>> query0(
std::enable_if_t<iguana::is_reflection_v<T>, std::vector<T>> query_s(
const std::string &str, Args &&...args) {
std::string sql = generate_query_sql<T>();
if (!str.empty()) {
sql += "where " + str;
}
std::string sql = generate_query_sql<T>(str);
#ifdef ORMPP_ENABLE_LOG
std::cout << sql << std::endl;
#endif
Expand Down Expand Up @@ -407,6 +401,139 @@ class mysql {
return v;
}

template <typename T, typename... Args>
std::enable_if_t<!iguana::is_reflection_v<T>, std::vector<T>> query_s(
const std::string &sql, Args &&...args) {
static_assert(iguana::is_tuple<T>::value);
constexpr auto SIZE = std::tuple_size_v<T>;
#ifdef ORMPP_ENABLE_LOG
std::cout << sql << std::endl;
#endif
stmt_ = mysql_stmt_init(con_);
if (!stmt_) {
set_last_error(mysql_error(con_));
return {};
}

auto guard = guard_statment(stmt_);

if (mysql_stmt_prepare(stmt_, sql.c_str(), (int)sql.size())) {
set_last_error(mysql_stmt_error(stmt_));
return {};
}

if constexpr (sizeof...(Args) > 0) {
size_t index = 0;
using expander = int[];
std::vector<MYSQL_BIND> param_binds;
expander{0, (set_param_bind(param_binds, args), 0)...};
if (mysql_stmt_bind_param(stmt_, &param_binds[0])) {
set_last_error(mysql_stmt_error(stmt_));
return {};
}
}

std::array<decltype(std::declval<MYSQL_BIND>().is_null),
result_size<T>::value>
nulls = {};
std::array<MYSQL_BIND, result_size<T>::value> param_binds = {};
std::map<size_t, std::vector<char>> mp;

std::vector<T> v;
T tp{};

int index = 0;
iguana::for_each(
tp,
[&param_binds, &index, &nulls, &mp, &tp, this](auto &t, auto /*i*/) {
using U = std::remove_reference_t<decltype(t)>;
if constexpr (iguana::is_reflection_v<U>) {
iguana::for_each(t, [&param_binds, &index, &nulls, &mp, &t, this](
auto &item, auto /*i*/) {
set_param_bind(param_binds[index], t.*item, index, mp,
nulls[index]);
index++;
});
}
else {
set_param_bind(param_binds[index], t, index, mp, nulls[index]);
index++;
}
},
std::make_index_sequence<std::tuple_size_v<T>>{});

if (index == 0) {
return {};
}

if (mysql_stmt_bind_result(stmt_, &param_binds[0])) {
set_last_error(mysql_stmt_error(stmt_));
return {};
}

if (mysql_stmt_execute(stmt_)) {
set_last_error(mysql_stmt_error(stmt_));
return {};
}

while (mysql_stmt_fetch(stmt_) == 0) {
index = 0;
iguana::for_each(
tp,
[&param_binds, &index, &mp, &tp, this](auto &t, auto /*i*/) {
using U = std::remove_reference_t<decltype(t)>;
if constexpr (iguana::is_reflection_v<U>) {
iguana::for_each(t, [&param_binds, &index, &mp, &t, this](
auto ele, auto /*i*/) {
set_value(param_binds.at(index), t.*ele, index, mp);
index++;
});
}
else {
set_value(param_binds.at(index), t, index, mp);
index++;
}
},
std::make_index_sequence<SIZE>{});

for (auto &p : mp) {
p.second.assign(p.second.size(), 0);
}

index = 0;
iguana::for_each(
tp,
[&index, nulls, &tp](auto &t, auto /*i*/) {
using U = std::remove_reference_t<decltype(t)>;
if constexpr (iguana::is_reflection_v<U>) {
iguana::for_each(t, [&index, nulls, &t](auto ele, auto /*i*/) {
if (nulls.at(index++)) {
using W =
std::remove_reference_t<decltype(std::declval<U>().*ele)>;
if constexpr (is_optional_v<W>::value ||
std::is_arithmetic_v<W>) {
t.*ele = {};
}
}
});
}
else {
if (nulls.at(index++)) {
if constexpr (is_optional_v<U>::value ||
std::is_arithmetic_v<U>) {
t = {};
}
}
}
},
std::make_index_sequence<SIZE>{});

v.push_back(std::move(tp));
}

return v;
}

// if there is a sql error, how to tell the user? throw exception?
template <typename T, typename... Args>
std::enable_if_t<iguana::is_reflection_v<T>, std::vector<T>> query(
Expand Down
78 changes: 67 additions & 11 deletions ormpp/postgresql.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,8 @@ class postgresql {
}

template <typename T, typename... Args>
bool delete_records0(const std::string &str, Args &&...args) {
auto sql = generate_delete_sql<T>();
if (!str.empty()) {
sql += "where " + str;
}
bool delete_records_s(const std::string &str, Args &&...args) {
auto sql = generate_delete_sql<T>(str);
#ifdef ORMPP_ENABLE_LOG
std::cout << sql << std::endl;
#endif
Expand Down Expand Up @@ -160,12 +157,9 @@ class postgresql {
}

template <typename T, typename... Args>
std::enable_if_t<iguana::is_reflection_v<T>, std::vector<T>> query0(
std::enable_if_t<iguana::is_reflection_v<T>, std::vector<T>> query_s(
const std::string &str, Args &&...args) {
std::string sql = generate_query_sql<T>();
if (!str.empty()) {
sql += "where " + str;
}
std::string sql = generate_query_sql<T>(str);
#ifdef ORMPP_ENABLE_LOG
std::cout << sql << std::endl;
#endif
Expand Down Expand Up @@ -207,11 +201,73 @@ class postgresql {
return v;
}

template <typename T, typename... Args>
constexpr std::enable_if_t<!iguana::is_reflection_v<T>, std::vector<T>>
query_s(const std::string &sql, Args &&...args) {
static_assert(iguana::is_tuple<T>::value);
#ifdef ORMPP_ENABLE_LOG
std::cout << sql << std::endl;
#endif
if (!prepare<T>(sql))
return {};

if constexpr (sizeof...(Args) > 0) {
size_t index = 0;
using expander = int[];
std::vector<const char *> param_values_buf;
std::vector<std::vector<char>> param_values;
expander{0, (set_param_values(param_values, args), 0)...};
for (auto &item : param_values) {
param_values_buf.push_back(item.data());
}
res_ = PQexecPrepared(con_, "", (int)param_values.size(),
param_values_buf.data(), NULL, NULL, 0);
}
else {
res_ = PQexec(con_, sql.data());
}

auto guard = guard_statment(res_);
if (PQresultStatus(res_) != PGRES_TUPLES_OK) {
return {};
}

std::vector<T> v;
auto ntuples = PQntuples(res_);

for (auto i = 0; i < ntuples; i++) {
T tp = {};
int index = 0;
iguana::for_each(
tp,
[this, i, &index](auto &item, auto I) {
if constexpr (iguana::is_reflection_v<decltype(item)>) {
std::remove_reference_t<decltype(item)> t = {};
iguana::for_each(t, [this, &index, &t, i](auto ele, auto /*i*/) {
assign(t.*ele, (int)i, index++);
});
item = std::move(t);
}
else {
assign(item, (int)i, index++);
}
},
std::make_index_sequence<std::tuple_size_v<T>>{});

if (index > 0)
v.push_back(std::move(tp));
}

return v;
}

template <typename T, typename... Args>
std::enable_if_t<iguana::is_reflection_v<T>, std::vector<T>> query(
Args &&...args) {
std::string sql = generate_query_sql<T>(args...);

#ifdef ORMPP_ENABLE_LOG
std::cout << sql << std::endl;
#endif
if (!prepare<T>(sql))
return {};

Expand Down
Loading

0 comments on commit 2b2c473

Please sign in to comment.