25using ssize_t = std::intptr_t;
40template <
typename T,
bool hasPrimaryKey = true>
43 using type =
typename T::PrimaryKeyType;
56 using yes = std::true_type;
57 using no = std::false_type;
60 static auto test(
int) ->
decltype(U::sqlForFindingByPrimaryKey(), yes());
66 static constexpr bool value = std::is_same_v<decltype(test<T>(0)), yes>;
73 using yes = std::true_type;
74 using no = std::false_type;
78 ->
decltype(U::sqlForDeletingByPrimaryKey().length(), yes());
84 static constexpr bool value = std::is_same_v<decltype(test<T>(0)), yes>;
124 explicit Mapper(DbClientPtr client) : client_(
std::move(client))
152 const SortOrder &order = SortOrder::ASC);
162 const SortOrder &order = SortOrder::ASC);
191 const std::string &onLeft,
192 const std::string &onRight)
197 joinString_ +=
" INNER JOIN ";
198 joinString_ += table;
199 joinString_ +=
" ON ";
200 joinString_ += onLeft;
201 joinString_ +=
" = ";
202 joinString_ += onRight;
215 const std::string &onLeft,
216 const std::string &onRight)
221 joinString_ +=
" LEFT JOIN ";
222 joinString_ += table;
223 joinString_ +=
" ON ";
224 joinString_ += onLeft;
225 joinString_ +=
" = ";
226 joinString_ += onRight;
239 const std::string &onLeft,
240 const std::string &onRight)
245 joinString_ +=
" RIGHT JOIN ";
246 joinString_ += table;
247 joinString_ +=
" ON ";
248 joinString_ += onLeft;
249 joinString_ +=
" = ";
250 joinString_ += onRight;
254 using SingleRowCallback = std::function<void(T)>;
255 using MultipleRowsCallback = std::function<void(std::vector<T>)>;
256 using CountCallback = std::function<void(
const size_t)>;
258 using TraitsPKType =
typename internal::
259 Traits<T, !std::is_same_v<typename T::PrimaryKeyType, void>>::type;
269 template <
typename U = T>
272 if constexpr (!std::is_same_v<typename U::PrimaryKeyType, void>)
274 static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
275 "No primary key in the table!");
277 internal::has_sqlForFindingByPrimaryKey<T>::value,
278 "No function member named sqlForFindingByPrimaryKey, please "
279 "make sure that the model class is generated by the latest "
280 "version of drogon_ctl");
282 std::string sql = T::sqlForFindingByPrimaryKey();
285 sql +=
" for update";
290 auto binder = *client_ << std::move(sql);
291 outputPrimaryKeyToBinder(key, binder);
292 binder << Mode::Blocking;
293 binder >> [&r](
const Result &result) { r = result; };
300 else if (r.size() > 1)
309 LOG_FATAL <<
"The table must have a primary key";
321 template <
typename U = T>
323 const SingleRowCallback &rcb,
324 const ExceptionCallback &ecb)
noexcept
326 if constexpr (!std::is_same_v<typename U::PrimaryKeyType, void>)
328 static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
329 "No primary key in the table!");
331 internal::has_sqlForFindingByPrimaryKey<T>::value,
332 "No function member named sqlForFindingByPrimaryKey, please "
333 "make sure that the model class is generated by the latest "
334 "version of drogon_ctl");
336 std::string sql = T::sqlForFindingByPrimaryKey();
339 sql +=
" for update";
342 auto binder = *client_ << std::move(sql);
343 outputPrimaryKeyToBinder(key, binder);
344 binder >> [ecb, rcb](
const Result &r) {
349 else if (r.size() > 1)
362 LOG_FATAL <<
"The table must have a primary key";
376 template <
typename U = T>
378 const TraitsPKType &key)
noexcept
380 if constexpr (!std::is_same_v<typename U::PrimaryKeyType, void>)
382 static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
383 "No primary key in the table!");
385 internal::has_sqlForFindingByPrimaryKey<T>::value,
386 "No function member named sqlForFindingByPrimaryKey, please "
387 "make sure that the model class is generated by the latest "
388 "version of drogon_ctl");
390 std::string sql = T::sqlForFindingByPrimaryKey();
393 sql +=
" for update";
396 auto binder = *client_ << std::move(sql);
397 outputPrimaryKeyToBinder(key, binder);
399 std::shared_ptr<std::promise<T>> prom =
400 std::make_shared<std::promise<T>>();
401 binder >> [prom](
const Result &r) {
404 prom->set_exception(std::make_exception_ptr(
407 else if (r.size() > 1)
409 prom->set_exception(std::make_exception_ptr(
414 prom->set_value(T(r[0]));
418 [prom](
const std::exception_ptr &e) { prom->set_exception(e); };
420 return prom->get_future();
424 LOG_FATAL <<
"The table must have a primary key";
434 std::vector<T>
findAll() noexcept(false);
442 void findAll(const MultipleRowsCallback &rcb,
443 const ExceptionCallback &ecb) noexcept;
470 const CountCallback &rcb,
471 const ExceptionCallback &ecb) noexcept;
502 const SingleRowCallback &rcb,
503 const ExceptionCallback &ecb) noexcept;
533 const MultipleRowsCallback &rcb,
534 const ExceptionCallback &ecb) noexcept;
552 void insert(T &obj) noexcept(false);
563 const SingleRowCallback &rcb,
564 const ExceptionCallback &ecb) noexcept;
581 size_t update(const T &obj) noexcept(false);
592 const CountCallback &rcb,
593 const ExceptionCallback &ecb) noexcept;
615 template <typename... Arguments>
618 Arguments &&...args) noexcept(false);
630 template <typename... Arguments>
632 const CountCallback &rcb,
633 const ExceptionCallback &ecb,
635 Arguments &&...args) noexcept;
648 template <typename... Arguments>
651 Arguments &&...args) noexcept;
662 template <typename... Arguments>
665 Arguments... args) noexcept(false);
677 template <typename... Arguments>
679 const CountCallback &rcb,
680 const ExceptionCallback &ecb,
682 Arguments... args) noexcept;
694 template <typename... Arguments>
696 const
std::vector<
std::
string> &colNames,
698 Arguments... args) noexcept;
707 size_t deleteOne(const T &obj) noexcept(false);
718 const CountCallback &rcb,
719 const ExceptionCallback &ecb) noexcept;
747 const CountCallback &rcb,
748 const ExceptionCallback &ecb) noexcept;
776 const CountCallback &rcb,
777 const ExceptionCallback &ecb) noexcept;
788 const TraitsPKType &key) noexcept;
794 std::string orderByString_;
795 std::string joinString_;
796 bool forUpdate_{
false};
802 orderByString_.clear();
807 template <
typename PKType = decltype(T::primaryKeyName)>
808 void makePrimaryKeyCriteria(std::string &sql)
810 if constexpr (std::is_same_v<const std::string, PKType>)
813 sql += T::primaryKeyName;
816 else if constexpr (std::is_same_v<const std::vector<std::string>,
820 for (
size_t i = 0; i < T::primaryKeyName.size(); ++i)
822 sql += T::primaryKeyName[i];
824 if (i < (T::primaryKeyName.size() - 1))
832 template <
typename PKType = decltype(T::primaryKeyName)>
833 void outputPrimaryKeyToBinder(
const TraitsPKType &pk,
834 internal::SqlBinder &binder)
836 if constexpr (std::is_same_v<const std::string, PKType>)
840 else if constexpr (std::is_same_v<const std::vector<std::string>,
843 tupleToBinder<typename T::PrimaryKeyType>(pk, binder);
847 template <typename TP, ssize_t N = std::tuple_size<TP>::value>
848 void tupleToBinder(
const TP &t, internal::SqlBinder &binder)
852 tupleToBinder<TP, N - 1>(t, binder);
853 binder << std::get<N - 1>(t);
855 else if constexpr (N == 1)
857 binder << std::get<0>(t);
861 std::string replaceSqlPlaceHolder(
const std::string &sqlStr,
862 const std::string &holderStr)
const;
868 std::string sql =
"select * from ";
871 bool hasParameters =
false;
875 sql += criteria.criteriaString();
876 hasParameters =
true;
878 sql.append(orderByString_);
881 hasParameters =
true;
882 sql.append(
" limit $?");
886 hasParameters =
true;
887 sql.append(
" offset $?");
890 sql = replaceSqlPlaceHolder(sql,
"$?");
893 sql +=
" for update";
897 auto binder = *client_ << std::move(sql);
899 criteria.outputArgs(binder);
905 binder << Mode::Blocking;
906 binder >> [&r](
const Result &result) { r = result; };
913 else if (r.size() > 1)
923 const SingleRowCallback &rcb,
924 const ExceptionCallback &ecb)
noexcept
926 std::string sql =
"select * from ";
929 bool hasParameters =
false;
933 sql += criteria.criteriaString();
934 hasParameters =
true;
936 sql.append(orderByString_);
939 hasParameters =
true;
940 sql.append(
" limit $?");
944 hasParameters =
true;
945 sql.append(
" offset $?");
948 sql = replaceSqlPlaceHolder(sql,
"$?");
951 sql +=
" for update";
953 auto binder = *client_ << std::move(sql);
955 criteria.outputArgs(binder);
961 binder >> [ecb, rcb](
const Result &r) {
966 else if (r.size() > 1)
982 std::string sql =
"select * from ";
985 bool hasParameters =
false;
989 sql += criteria.criteriaString();
990 hasParameters =
true;
992 sql.append(orderByString_);
995 hasParameters =
true;
996 sql.append(
" limit $?");
1000 hasParameters =
true;
1001 sql.append(
" offset $?");
1004 sql = replaceSqlPlaceHolder(sql,
"$?");
1007 sql +=
" for update";
1009 auto binder = *client_ << std::move(sql);
1011 criteria.outputArgs(binder);
1017 std::shared_ptr<std::promise<T>> prom = std::make_shared<std::promise<T>>();
1018 binder >> [prom](
const Result &r) {
1021 prom->set_exception(
1024 else if (r.size() > 1)
1026 prom->set_exception(std::make_exception_ptr(
1031 prom->set_value(T(r[0]));
1034 binder >> [prom](
const std::exception_ptr &e) { prom->set_exception(e); };
1036 return prom->get_future();
1039template <
typename T>
1043 std::string sql =
"select * from ";
1044 sql += T::tableName;
1046 bool hasParameters =
false;
1049 hasParameters =
true;
1051 sql += criteria.criteriaString();
1053 sql.append(orderByString_);
1056 hasParameters =
true;
1057 sql.append(
" limit $?");
1061 hasParameters =
true;
1062 sql.append(
" offset $?");
1065 sql = replaceSqlPlaceHolder(sql,
"$?");
1068 sql +=
" for update";
1072 auto binder = *client_ << std::move(sql);
1074 criteria.outputArgs(binder);
1080 binder << Mode::Blocking;
1081 binder >> [&r](
const Result &result) { r = result; };
1085 ret.reserve(r.size());
1086 for (
auto const &row : r)
1088 ret.emplace_back(row);
1093template <
typename T>
1095 const MultipleRowsCallback &rcb,
1096 const ExceptionCallback &ecb)
noexcept
1098 std::string sql =
"select * from ";
1099 sql += T::tableName;
1101 bool hasParameters =
false;
1104 hasParameters =
true;
1106 sql += criteria.criteriaString();
1108 sql.append(orderByString_);
1111 hasParameters =
true;
1112 sql.append(
" limit $?");
1116 hasParameters =
true;
1117 sql.append(
" offset $?");
1120 sql = replaceSqlPlaceHolder(sql,
"$?");
1123 sql +=
" for update";
1125 auto binder = *client_ << std::move(sql);
1127 criteria.outputArgs(binder);
1133 binder >> [rcb](
const Result &r) {
1135 ret.reserve(r.size());
1136 for (
auto const &row : r)
1138 ret.emplace_back(row);
1140 rcb(std::move(ret));
1145template <
typename T>
1149 std::string sql =
"select * from ";
1150 sql += T::tableName;
1152 bool hasParameters =
false;
1155 hasParameters =
true;
1157 sql += criteria.criteriaString();
1159 sql.append(orderByString_);
1162 hasParameters =
true;
1163 sql.append(
" limit $?");
1167 hasParameters =
true;
1168 sql.append(
" offset $?");
1171 sql = replaceSqlPlaceHolder(sql,
"$?");
1174 sql +=
" for update";
1176 auto binder = *client_ << std::move(sql);
1178 criteria.outputArgs(binder);
1184 std::shared_ptr<std::promise<std::vector<T>>> prom =
1185 std::make_shared<std::promise<std::vector<T>>>();
1186 binder >> [prom](
const Result &r) {
1188 ret.reserve(r.size());
1189 for (
auto const &row : r)
1191 ret.emplace_back(row);
1193 prom->set_value(std::move(ret));
1195 binder >> [prom](
const std::exception_ptr &e) { prom->set_exception(e); };
1197 return prom->get_future();
1200template <
typename T>
1206template <
typename T>
1208 const ExceptionCallback &ecb)
noexcept
1213template <
typename T>
1219template <
typename T>
1222 std::string sql =
"select count(*) from ";
1223 sql += T::tableName;
1228 sql += criteria.criteriaString();
1229 sql = replaceSqlPlaceHolder(sql,
"$?");
1234 auto binder = *client_ << std::move(sql);
1236 criteria.outputArgs(binder);
1237 binder << Mode::Blocking;
1238 binder >> [&r](
const Result &result) { r = result; };
1241 assert(r.size() == 1);
1242 return r[0][(Row::SizeType)0].as<size_t>();
1245template <
typename T>
1247 const CountCallback &rcb,
1248 const ExceptionCallback &ecb)
noexcept
1250 std::string sql =
"select count(*) from ";
1251 sql += T::tableName;
1256 sql += criteria.criteriaString();
1257 sql = replaceSqlPlaceHolder(sql,
"$?");
1260 auto binder = *client_ << std::move(sql);
1262 criteria.outputArgs(binder);
1263 binder >> [rcb](
const Result &r) {
1264 assert(r.size() == 1);
1265 rcb(r[0][(Row::SizeType)0].as<size_t>());
1270template <
typename T>
1274 std::string sql =
"select count(*) from ";
1275 sql += T::tableName;
1280 sql += criteria.criteriaString();
1281 sql = replaceSqlPlaceHolder(sql,
"$?");
1284 auto binder = *client_ << std::move(sql);
1286 criteria.outputArgs(binder);
1288 std::shared_ptr<std::promise<size_t>> prom =
1289 std::make_shared<std::promise<size_t>>();
1290 binder >> [prom](
const Result &r) {
1291 assert(r.size() == 1);
1292 prom->set_value(r[0][(Row::SizeType)0].as<size_t>());
1294 binder >> [prom](
const std::exception_ptr &e) { prom->set_exception(e); };
1296 return prom->get_future();
1299template <
typename T>
1304 bool needSelection =
false;
1306 auto binder = *client_ << obj.sqlForInserting(needSelection);
1307 obj.outputArgs(binder);
1308 binder << Mode::Blocking;
1309 binder >> [&r](
const Result &result) { r = result; };
1313 if (client_->type() == ClientType::PostgreSQL)
1317 assert(r.size() == 1);
1332template <
typename T>
1334 const SingleRowCallback &rcb,
1335 const ExceptionCallback &ecb)
noexcept
1338 bool needSelection =
false;
1339 auto binder = *client_ << obj.sqlForInserting(needSelection);
1340 obj.outputArgs(binder);
1341 auto client = client_;
1342 binder >> [client, rcb, obj, needSelection, ecb](
const Result &r) {
1343 assert(r.affectedRows() == 1);
1344 if (client->type() == ClientType::PostgreSQL)
1348 assert(r.size() == 1);
1358 auto id = r.insertId();
1360 newObj.updateId(
id);
1364 tmp.findByPrimaryKey(newObj.getPrimaryKey(), rcb, ecb);
1375template <
typename T>
1379 bool needSelection =
false;
1380 auto binder = *client_ << obj.sqlForInserting(needSelection);
1381 obj.outputArgs(binder);
1383 std::shared_ptr<std::promise<T>> prom = std::make_shared<std::promise<T>>();
1384 auto client = client_;
1385 binder >> [client, prom, obj, needSelection](
const Result &r) {
1386 assert(r.affectedRows() == 1);
1387 if (client->type() == ClientType::PostgreSQL)
1391 assert(r.size() == 1);
1392 prom->set_value(T(r[0]));
1396 prom->set_value(obj);
1401 auto id = r.insertId();
1403 newObj.updateId(
id);
1407 tmp.findByPrimaryKey(
1408 newObj.getPrimaryKey(),
1409 [prom](T selObj) { prom->set_value(selObj); },
1411 prom->set_exception(
1412 std::make_exception_ptr(Failure(e.base().what())));
1417 prom->set_value(newObj);
1421 binder >> [prom](
const std::exception_ptr &e) { prom->set_exception(e); };
1423 return prom->get_future();
1426template <
typename T>
1430 static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
1431 "No primary key in the table!");
1432 std::vector<std::string> colNames = obj.updateColumns();
1433 if (colNames.empty())
1437 std::string sql =
"update ";
1438 sql += T::tableName;
1440 for (
auto const &colName : colNames)
1445 sql[sql.length() - 1] =
' ';
1447 makePrimaryKeyCriteria(sql);
1449 sql = replaceSqlPlaceHolder(sql,
"$?");
1452 auto binder = *client_ << std::move(sql);
1453 obj.updateArgs(binder);
1454 outputPrimaryKeyToBinder(obj.getPrimaryKey(), binder);
1455 binder << Mode::Blocking;
1456 binder >> [&r](
const Result &result) { r = result; };
1462template <
typename T>
1463template <
typename... Arguments>
1466 Arguments &&...args)
noexcept(
false)
1468 static_assert(
sizeof...(args) > 0);
1469 assert(colNames.size() ==
sizeof...(args));
1471 std::string sql =
"update ";
1472 sql += T::tableName;
1474 for (
auto const &colName : colNames)
1479 sql[sql.length() - 1] =
' ';
1484 sql += criteria.criteriaString();
1487 sql = replaceSqlPlaceHolder(sql,
"$?");
1490 auto binder = *client_ << std::move(sql);
1491 (void)std::initializer_list<int>{
1492 (binder << std::forward<Arguments>(args), 0)...};
1494 criteria.outputArgs(binder);
1495 binder << Mode::Blocking;
1496 binder >> [&r](
const Result &result) { r = result; };
1502template <
typename T>
1504 const CountCallback &rcb,
1505 const ExceptionCallback &ecb)
noexcept
1508 static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
1509 "No primary key in the table!");
1511 std::vector<std::string> colNames = obj.updateColumns();
1512 if (colNames.empty())
1517 std::string sql =
"update ";
1518 sql += T::tableName;
1520 for (
auto const &colName : colNames)
1525 sql[sql.length() - 1] =
' ';
1527 makePrimaryKeyCriteria(sql);
1529 sql = replaceSqlPlaceHolder(sql,
"$?");
1530 auto binder = *client_ << std::move(sql);
1531 obj.updateArgs(binder);
1532 outputPrimaryKeyToBinder(obj.getPrimaryKey(), binder);
1533 binder >> [rcb](
const Result &r) { rcb(r.affectedRows()); };
1537template <
typename T>
1538template <
typename... Arguments>
1540 const CountCallback &rcb,
1541 const ExceptionCallback &ecb,
1543 Arguments &&...args)
noexcept
1545 static_assert(
sizeof...(args) > 0);
1546 assert(colNames.size() ==
sizeof...(args));
1548 std::string sql =
"update ";
1549 sql += T::tableName;
1551 for (
auto const &colName : colNames)
1556 sql[sql.length() - 1] =
' ';
1561 sql += criteria.criteriaString();
1564 sql = replaceSqlPlaceHolder(sql,
"$?");
1565 auto binder = *client_ << std::move(sql);
1566 (void)std::initializer_list<int>{
1567 (binder << std::forward<Arguments>(args), 0)...};
1569 criteria.outputArgs(binder);
1570 binder >> [rcb](
const Result &r) { rcb(r.affectedRows()); };
1574template <
typename T>
1578 static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
1579 "No primary key in the table!");
1580 std::vector<std::string> colNames = obj.updateColumns();
1581 if (colNames.empty())
1583 std::shared_ptr<std::promise<size_t>> prom =
1584 std::make_shared<std::promise<size_t>>();
1586 return prom->get_future();
1588 std::string sql =
"update ";
1589 sql += T::tableName;
1591 for (
auto const &colName : colNames)
1596 sql[sql.length() - 1] =
' ';
1598 makePrimaryKeyCriteria(sql);
1600 sql = replaceSqlPlaceHolder(sql,
"$?");
1601 auto binder = *client_ << std::move(sql);
1602 obj.updateArgs(binder);
1603 outputPrimaryKeyToBinder(obj.getPrimaryKey(), binder);
1605 std::shared_ptr<std::promise<size_t>> prom =
1606 std::make_shared<std::promise<size_t>>();
1607 binder >> [prom](
const Result &r) { prom->set_value(r.affectedRows()); };
1608 binder >> [prom](
const std::exception_ptr &e) { prom->set_exception(e); };
1610 return prom->get_future();
1613template <
typename T>
1614template <
typename... Arguments>
1616 const std::vector<std::string> &colNames,
1618 Arguments &&...args)
noexcept
1620 static_assert(
sizeof...(args) > 0);
1621 assert(colNames.size() ==
sizeof...(args));
1623 std::string sql =
"update ";
1624 sql += T::tableName;
1626 for (
auto const &colName : colNames)
1631 sql[sql.length() - 1] =
' ';
1636 sql += criteria.criteriaString();
1639 sql = replaceSqlPlaceHolder(sql,
"$?");
1640 auto binder = *client_ << std::move(sql);
1641 (void)std::initializer_list<int>{
1642 (binder << std::forward<Arguments>(args), 0)...};
1644 criteria.outputArgs(binder);
1646 std::shared_ptr<std::promise<size_t>> prom =
1647 std::make_shared<std::promise<size_t>>();
1648 binder >> [prom](
const Result &r) { prom->set_value(r.affectedRows()); };
1649 binder >> [prom](
const std::exception_ptr &e) { prom->set_exception(e); };
1651 return prom->get_future();
1654template <
typename T>
1655template <
typename... Arguments>
1658 Arguments... args)
noexcept(
false)
1660 static_assert(
sizeof...(args) > 0);
1661 assert(colNames.size() ==
sizeof...(args));
1663 std::string sql =
"update ";
1664 sql += T::tableName;
1667 std::vector<const char *> temps;
1668 (void)std::initializer_list<int>{(
1670 args = (args < 0) ? (temps.push_back(
" - $?,"), -args)
1671 : (temps.push_back(
" + $?,"), args);
1675 for (
int i = 0; i <
sizeof...(args); ++i)
1677 const auto &colName = colNames[i];
1683 sql[sql.length() - 1] =
' ';
1688 sql += criteria.criteriaString();
1691 sql = replaceSqlPlaceHolder(sql,
"$?");
1694 auto binder = *client_ << std::move(sql);
1695 (void)std::initializer_list<int>{
1696 (binder << std::forward<Arguments>(args), 0)...};
1698 criteria.outputArgs(binder);
1699 binder << Mode::Blocking;
1700 binder >> [&r](
const Result &result) { r = result; };
1706template <
typename T>
1707template <
typename... Arguments>
1709 const CountCallback &rcb,
1710 const ExceptionCallback &ecb,
1712 Arguments... args)
noexcept
1714 static_assert(
sizeof...(args) > 0);
1715 assert(colNames.size() ==
sizeof...(args));
1717 std::string sql =
"update ";
1718 sql += T::tableName;
1721 std::vector<const char *> temps;
1722 (void)std::initializer_list<int>{(
1724 args = args < 0 ? (temps.push_back(
" - $?,"), -args)
1725 : (temps.push_back(
" + $?,"), args);
1729 for (
int i = 0; i <
sizeof...(args); ++i)
1731 const auto &colName = colNames[i];
1737 sql[sql.length() - 1] =
' ';
1742 sql += criteria.criteriaString();
1745 sql = replaceSqlPlaceHolder(sql,
"$?");
1746 auto binder = *client_ << std::move(sql);
1747 (void)std::initializer_list<int>{
1748 (binder << std::forward<Arguments>(args), 0)...};
1750 criteria.outputArgs(binder);
1751 binder >> [rcb](
const Result &r) { rcb(r.affectedRows()); };
1755template <
typename T>
1756template <
typename... Arguments>
1758 const std::vector<std::string> &colNames,
1760 Arguments... args)
noexcept
1762 static_assert(
sizeof...(args) > 0);
1763 assert(colNames.size() ==
sizeof...(args));
1765 std::string sql =
"update ";
1766 sql += T::tableName;
1769 std::vector<const char *> temps;
1770 (void)std::initializer_list<int>{(
1772 args = args < 0 ? (temps.push_back(
" - $?,"), -args)
1773 : (temps.push_back(
" + $?,"), args);
1777 for (
int i = 0; i <
sizeof...(args); ++i)
1779 const auto &colName = colNames[i];
1785 sql[sql.length() - 1] =
' ';
1790 sql += criteria.criteriaString();
1793 sql = replaceSqlPlaceHolder(sql,
"$?");
1794 auto binder = *client_ << std::move(sql);
1795 (void)std::initializer_list<int>{
1796 (binder << std::forward<Arguments>(args), 0)...};
1798 criteria.outputArgs(binder);
1800 std::shared_ptr<std::promise<size_t>> prom =
1801 std::make_shared<std::promise<size_t>>();
1802 binder >> [prom](
const Result &r) { prom->set_value(r.affectedRows()); };
1803 binder >> [prom](
const std::exception_ptr &e) { prom->set_exception(e); };
1805 return prom->get_future();
1808template <
typename T>
1812 static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
1813 "No primary key in the table!");
1814 std::string sql =
"delete from ";
1815 sql += T::tableName;
1819 makePrimaryKeyCriteria(sql);
1821 sql = replaceSqlPlaceHolder(sql,
"$?");
1824 auto binder = *client_ << std::move(sql);
1825 outputPrimaryKeyToBinder(obj.getPrimaryKey(), binder);
1826 binder << Mode::Blocking;
1827 binder >> [&r](
const Result &result) { r = result; };
1833template <
typename T>
1835 const CountCallback &rcb,
1836 const ExceptionCallback &ecb)
noexcept
1839 static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
1840 "No primary key in the table!");
1841 std::string sql =
"delete from ";
1842 sql += T::tableName;
1845 makePrimaryKeyCriteria(sql);
1847 sql = replaceSqlPlaceHolder(sql,
"$?");
1848 auto binder = *client_ << std::move(sql);
1849 outputPrimaryKeyToBinder(obj.getPrimaryKey(), binder);
1850 binder >> [rcb](
const Result &r) { rcb(r.affectedRows()); };
1854template <
typename T>
1858 static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
1859 "No primary key in the table!");
1860 std::string sql =
"delete from ";
1861 sql += T::tableName;
1864 makePrimaryKeyCriteria(sql);
1866 sql = replaceSqlPlaceHolder(sql,
"$?");
1867 auto binder = *client_ << std::move(sql);
1868 outputPrimaryKeyToBinder(obj.getPrimaryKey(), binder);
1870 std::shared_ptr<std::promise<size_t>> prom =
1871 std::make_shared<std::promise<size_t>>();
1872 binder >> [prom](
const Result &r) { prom->set_value(r.affectedRows()); };
1873 binder >> [prom](
const std::exception_ptr &e) { prom->set_exception(e); };
1875 return prom->get_future();
1878template <
typename T>
1882 static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
1883 "No primary key in the table!");
1884 std::string sql =
"delete from ";
1885 sql += T::tableName;
1890 sql += criteria.criteriaString();
1891 sql = replaceSqlPlaceHolder(sql,
"$?");
1896 auto binder = *client_ << std::move(sql);
1899 criteria.outputArgs(binder);
1901 binder << Mode::Blocking;
1902 binder >> [&r](
const Result &result) { r = result; };
1908template <
typename T>
1910 const CountCallback &rcb,
1911 const ExceptionCallback &ecb)
noexcept
1914 static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
1915 "No primary key in the table!");
1916 std::string sql =
"delete from ";
1917 sql += T::tableName;
1922 sql += criteria.criteriaString();
1923 sql = replaceSqlPlaceHolder(sql,
"$?");
1926 auto binder = *client_ << std::move(sql);
1929 criteria.outputArgs(binder);
1931 binder >> [rcb](
const Result &r) { rcb(r.affectedRows()); };
1935template <
typename T>
1940 static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
1941 "No primary key in the table!");
1942 std::string sql =
"delete from ";
1943 sql += T::tableName;
1947 sql += criteria.criteriaString();
1948 sql = replaceSqlPlaceHolder(sql,
"$?");
1950 auto binder = *client_ << std::move(sql);
1953 criteria.outputArgs(binder);
1956 std::shared_ptr<std::promise<size_t>> prom =
1957 std::make_shared<std::promise<size_t>>();
1958 binder >> [prom](
const Result &r) { prom->set_value(r.affectedRows()); };
1959 binder >> [prom](
const std::exception_ptr &e) { prom->set_exception(e); };
1961 return prom->get_future();
1964template <
typename T>
1972template <
typename T>
1979template <
typename T>
1981 const SortOrder &order)
1983 if (orderByString_.empty())
1987 if (order == SortOrder::DESC)
1989 orderByString_ +=
" desc";
1994 orderByString_ +=
",";
1995 orderByString_ += colName;
1996 if (order == SortOrder::DESC)
1998 orderByString_ +=
" desc";
2004template <
typename T>
2007 std::string colName = T::getColumnName(colIndex);
2008 assert(!colName.empty());
2009 return orderBy(colName, order);
2012template <
typename T>
2015 assert(page > 0 && perPage > 0);
2016 return limit(perPage).offset((page - 1) * perPage);
2019template <
typename T>
2026template <
typename T>
2027inline std::string Mapper<T>::replaceSqlPlaceHolder(
2028 const std::string &sqlStr,
2029 const std::string &holderStr)
const
2031 if (client_->type() == ClientType::PostgreSQL)
2033 std::string::size_type startPos = 0;
2034 std::string::size_type pos;
2035 std::stringstream ret;
2039 pos = sqlStr.find(holderStr, startPos);
2040 if (pos == std::string::npos)
2042 ret << sqlStr.substr(startPos);
2045 ret << sqlStr.substr(startPos, pos - startPos);
2048 startPos = pos + holderStr.length();
2051 else if (client_->type() == ClientType::Mysql ||
2052 client_->type() == ClientType::Sqlite3)
2054 std::string::size_type startPos = 0;
2055 std::string::size_type pos;
2056 std::stringstream ret;
2059 pos = sqlStr.find(holderStr, startPos);
2060 if (pos == std::string::npos)
2062 ret << sqlStr.substr(startPos);
2065 ret << sqlStr.substr(startPos, pos - startPos);
2067 startPos = pos + holderStr.length();
2076template <
typename T>
2078 const typename Mapper<T>::TraitsPKType &key)
noexcept(
false)
2080 static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
2081 "No primary key in the table!");
2082 static_assert(internal::has_sqlForDeletingByPrimaryKey<T>::value,
2083 "No function member named sqlForDeletingByPrimaryKey, please "
2084 "make sure that the model class is generated by the latest "
2085 "version of drogon_ctl");
2089 auto binder = *client_ << T::sqlForDeletingByPrimaryKey();
2090 outputPrimaryKeyToBinder(key, binder);
2091 binder << Mode::Blocking;
2092 binder >> [&r](
const Result &result) { r = result; };
2095 return r.affectedRows();
2098template <
typename T>
2100 const typename Mapper<T>::TraitsPKType &key,
2101 const CountCallback &rcb,
2102 const ExceptionCallback &ecb)
noexcept
2104 static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
2105 "No primary key in the table!");
2106 static_assert(internal::has_sqlForDeletingByPrimaryKey<T>::value,
2107 "No function member named sqlForDeletingByPrimaryKey, please "
2108 "make sure that the model class is generated by the latest "
2109 "version of drogon_ctl");
2111 auto binder = *client_ << T::sqlForDeletingByPrimaryKey();
2112 outputPrimaryKeyToBinder(key, binder);
2114 [rcb = std::move(rcb)](
const Result &r) { rcb(r.affectedRows()); };
2118template <
typename T>
2120 const typename Mapper<T>::TraitsPKType &key)
noexcept
2122 static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
2123 "No primary key in the table!");
2124 static_assert(internal::has_sqlForDeletingByPrimaryKey<T>::value,
2125 "No function member named sqlForDeletingByPrimaryKey, please "
2126 "make sure that the model class is generated by the latest "
2127 "version of drogon_ctl");
2129 auto binder = *client_ << T::sqlForDeletingByPrimaryKey();
2130 outputPrimaryKeyToBinder(key, binder);
2132 std::shared_ptr<std::promise<size_t>> prom =
2133 std::make_shared<std::promise<size_t>>();
2134 binder >> [prom](
const Result &r) { prom->set_value(r.affectedRows()); };
2135 binder >> [prom](
const std::exception_ptr &e) { prom->set_exception(e); };
2137 return prom->get_future();
2146template <
typename Value>
2147inline Json::Value
toJson(
const std::vector<Value> &container)
2149 Json::Value values(Json::arrayValue);
2150 for (
const Value &c : container)
2152 values.append(c.toJson());
bool isValidSqlIdentifier(const std::string &identifier)
Validate that a string is a safe SQL identifier.
Definition BaseBuilder.h:116
Json::Value toJson(const std::vector< Value > &container)
Convert std::vector<Value> where Value can be JSON to JSON.
Definition Mapper.h:2147
DROGON_EXPORT std::string formattedString(const char *format,...)
Get a formatted string.
this class represents a comparison condition.
Definition Criteria.h:74
Mixin base class to identify drogon-db-specific exception types.
Definition Exception.h:51
The mapper template.
Definition Mapper.h:117
std::future< size_t > deleteFutureBy(const Criteria &criteria) noexcept
Delete records that match the given criteria asynchronously.
Definition Mapper.h:1936
Mapper< T > & rightJoin(const std::string &table, const std::string &onLeft, const std::string &onRight)
Add a RIGHT JOIN clause to the query.
Definition Mapper.h:238
std::vector< T > findBy(const Criteria &criteria) noexcept(false)
Select the rows that match the given criteria.
Definition Mapper.h:1040
Mapper< T > & paginate(size_t page, size_t perPage)
Set limit and offset to achieve pagination. This method will override limit() and offset(),...
Definition Mapper.h:2013
void findByPrimaryKey(const TraitsPKType &key, const SingleRowCallback &rcb, const ExceptionCallback &ecb) noexcept
Asynchronously find a record by the primary key.
Definition Mapper.h:322
size_t updateBy(const std::vector< std::string > &colNames, const Criteria &criteria, Arguments &&...args) noexcept(false)
Update a record that match both the primary key and the given criteria.
Definition Mapper.h:1464
size_t deleteBy(const Criteria &criteria) noexcept(false)
Delete records that satisfy the given criteria.
Definition Mapper.h:1879
std::future< std::vector< T > > findFutureAll() noexcept
Asynchronously find all the records in the table.
Definition Mapper.h:1214
Mapper< T > & offset(size_t offset)
Add a offset to the query.
Definition Mapper.h:1973
Mapper< T > & limit(size_t limit)
Add a limit to the query.
Definition Mapper.h:1965
std::future< size_t > deleteFutureOne(const T &obj) noexcept
Asynchronously delete a record from the table.
Definition Mapper.h:1855
T findOne(const Criteria &criteria) noexcept(false)
Find one record that matches the given criteria.
Definition Mapper.h:866
std::future< size_t > incrementFuture(const std::vector< std::string > &colNames, const Criteria &criteria, Arguments... args) noexcept
Asynchronously update some records that match the given criteria.
Definition Mapper.h:1757
size_t deleteOne(const T &obj) noexcept(false)
Delete a record from the table.
Definition Mapper.h:1809
Mapper< T > & orderBy(const std::string &colName, const SortOrder &order=SortOrder::ASC)
Set the order of the results.
Definition Mapper.h:1980
std::vector< T > findAll() noexcept(false)
Find all the records in the table.
Definition Mapper.h:1201
std::future< std::vector< T > > findFutureBy(const Criteria &criteria) noexcept
Asynchronously select the rows that match the given criteria.
Definition Mapper.h:1146
size_t count(const Criteria &criteria=Criteria()) noexcept(false)
Get the count of rows that match the given criteria.
Definition Mapper.h:1220
size_t deleteByPrimaryKey(const TraitsPKType &key) noexcept(false)
Delete the record that matches the given primary key.
std::future< size_t > updateFuture(const T &obj) noexcept
Asynchronously update a record.
Definition Mapper.h:1575
std::future< T > findFutureOne(const Criteria &criteria) noexcept
Asynchronously find one record that matches the given criteria.
Definition Mapper.h:979
Mapper< T > & leftJoin(const std::string &table, const std::string &onLeft, const std::string &onRight)
Add a LEFT JOIN clause to the query.
Definition Mapper.h:214
size_t increment(const std::vector< std::string > &colNames, const Criteria &criteria, Arguments... args) noexcept(false)
Update some records that match the given criteria.
Definition Mapper.h:1656
Mapper(DbClientPtr client)
Construct a new Mapper object.
Definition Mapper.h:124
std::future< T > findFutureByPrimaryKey(const TraitsPKType &key) noexcept
Asynchronously find a record by the primary key.
Definition Mapper.h:377
size_t update(const T &obj) noexcept(false)
Update a record.
Definition Mapper.h:1427
std::future< size_t > updateFutureBy(const std::vector< std::string > &colNames, const Criteria &criteria, Arguments &&...args) noexcept
Asynchronously update a record that match both the primary key and the given criteria.
Definition Mapper.h:1615
void insert(T &obj) noexcept(false)
Insert a row into the table.
Definition Mapper.h:1300
Mapper< T > & forUpdate()
Lock the result for updating.
Definition Mapper.h:2020
T findByPrimaryKey(const TraitsPKType &key) noexcept(false)
Find a record by the primary key.
Definition Mapper.h:270
std::future< size_t > deleteFutureByPrimaryKey(const TraitsPKType &key) noexcept
Delete the record that matches the given primary key asynchronously.
Definition Mapper.h:2119
std::future< size_t > countFuture(const Criteria &criteria=Criteria()) noexcept
Asynchronously get the number of rows that match the given criteria.
Definition Mapper.h:1271
std::future< T > insertFuture(const T &) noexcept
Asynchronously insert a row into the table.
Definition Mapper.h:1376
Mapper< T > & innerJoin(const std::string &table, const std::string &onLeft, const std::string &onRight)
Add an INNER JOIN clause to the query.
Definition Mapper.h:190
Result set containing data returned by a query or command.
Definition Result.h:58
unsigned long long insertId() const noexcept
SizeType affectedRows() const noexcept
Query returned an unexpected number of rows.
Definition Exception.h:283
Drogon Test is a minimal effort test framework developed because the major C++ test frameworks doesn'...
Definition Attribute.h:23