Modify Mapper and CoroMapper templates (#722)
This commit is contained in:
parent
fd720d55d9
commit
ffda84627b
|
@ -27,7 +27,7 @@ struct MapperAwaiter : public CallbackAwaiter<ReturnType>
|
|||
{
|
||||
using MapperFunction =
|
||||
std::function<void(std::function<void(ReturnType result)> &&,
|
||||
std::function<void(const DrogonDbException &)> &&)>;
|
||||
std::function<void(const std::exception_ptr &)> &&)>;
|
||||
MapperAwaiter(MapperFunction &&function) : function_(std::move(function))
|
||||
{
|
||||
}
|
||||
|
@ -38,8 +38,8 @@ struct MapperAwaiter : public CallbackAwaiter<ReturnType>
|
|||
this->setValue(std::move(result));
|
||||
handle.resume();
|
||||
},
|
||||
[handle, this](const DrogonDbException &e) {
|
||||
this->setException(std::make_exception_ptr(e));
|
||||
[handle, this](const std::exception_ptr &e) {
|
||||
this->setException(e);
|
||||
handle.resume();
|
||||
});
|
||||
}
|
||||
|
@ -66,36 +66,86 @@ class CoroMapper : public Mapper<T>
|
|||
using TraitsPKType = typename Mapper<T>::TraitsPKType;
|
||||
inline const Task<T> findByPrimaryKey(const TraitsPKType &key)
|
||||
{
|
||||
auto lb =
|
||||
[this, key](
|
||||
std::function<void(T)> &&callback,
|
||||
std::function<void(const DrogonDbException &)> &&errCallback) {
|
||||
Mapper<T>::findByPrimaryKey(key,
|
||||
std::move(callback),
|
||||
std::move(errCallback));
|
||||
if constexpr (!std::is_same<typename T::PrimaryKeyType, void>::value)
|
||||
{
|
||||
auto lb = [this,
|
||||
key](std::function<void(T)> &&callback,
|
||||
std::function<void(const std::exception_ptr &)>
|
||||
&&errCallback) mutable {
|
||||
static_assert(
|
||||
!std::is_same<typename T::PrimaryKeyType, void>::value,
|
||||
"No primary key in the table!");
|
||||
static_assert(
|
||||
internal::has_sqlForFindingByPrimaryKey<T>::value,
|
||||
"No function member named sqlForFindingByPrimaryKey, "
|
||||
"please "
|
||||
"make sure that the model class is generated by the latest "
|
||||
"version of drogon_ctl");
|
||||
// return findFutureOne(Criteria(T::primaryKeyName, key));
|
||||
std::string sql = T::sqlForFindingByPrimaryKey();
|
||||
if (this->forUpdate_)
|
||||
{
|
||||
sql += " for update";
|
||||
}
|
||||
this->clear();
|
||||
auto binder = *(this->client_) << std::move(sql);
|
||||
this->outputPrimeryKeyToBinder(key, binder);
|
||||
|
||||
binder >> [callback = std::move(callback),
|
||||
errCallback](const Result &r) {
|
||||
if (r.size() == 0)
|
||||
{
|
||||
errCallback(std::make_exception_ptr(
|
||||
UnexpectedRows("0 rows found")));
|
||||
}
|
||||
else if (r.size() > 1)
|
||||
{
|
||||
errCallback(std::make_exception_ptr(
|
||||
UnexpectedRows("Found more than one row")));
|
||||
}
|
||||
else
|
||||
{
|
||||
callback(T(r[0]));
|
||||
}
|
||||
};
|
||||
binder >> std::move(errCallback);
|
||||
binder.exec();
|
||||
};
|
||||
co_return co_await internal::MapperAwaiter<T>(std::move(lb));
|
||||
co_return co_await internal::MapperAwaiter<T>(std::move(lb));
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_FATAL << "The table must have a primary key";
|
||||
abort();
|
||||
}
|
||||
}
|
||||
inline const Task<std::vector<T>> findAll()
|
||||
{
|
||||
auto lb =
|
||||
[this](
|
||||
std::function<void(std::vector<T>)> &&callback,
|
||||
std::function<void(const DrogonDbException &)> &&errCallback) {
|
||||
Mapper<T>::findAll(std::move(callback), std::move(errCallback));
|
||||
};
|
||||
co_return co_await internal::MapperAwaiter<std::vector<T>>(
|
||||
std::move(lb));
|
||||
co_return co_await findBy(Criteria());
|
||||
}
|
||||
inline const Task<size_t> count(const Criteria &criteria = Criteria())
|
||||
{
|
||||
auto lb =
|
||||
[this, criteria](
|
||||
std::function<void(const size_t)> &&callback,
|
||||
std::function<void(const DrogonDbException &)> &&errCallback) {
|
||||
Mapper<T>::count(criteria,
|
||||
std::move(callback),
|
||||
std::move(errCallback));
|
||||
std::function<void(const std::exception_ptr &)> &&errCallback) {
|
||||
std::string sql = "select count(*) from ";
|
||||
sql += T::tableName;
|
||||
if (criteria)
|
||||
{
|
||||
sql += " where ";
|
||||
sql += criteria.criteriaString();
|
||||
sql = this->replaceSqlPlaceHolder(sql, "$?");
|
||||
}
|
||||
this->clear();
|
||||
auto binder = *(this->client_) << std::move(sql);
|
||||
if (criteria)
|
||||
criteria.outputArgs(binder);
|
||||
binder >> [callback = std::move(callback)](const Result &r) {
|
||||
assert(r.size() == 1);
|
||||
callback(r[0][(Row::SizeType)0].as<size_t>());
|
||||
};
|
||||
binder >> std::move(errCallback);
|
||||
};
|
||||
co_return co_await internal::MapperAwaiter<size_t>(std::move(lb));
|
||||
}
|
||||
|
@ -104,10 +154,59 @@ class CoroMapper : public Mapper<T>
|
|||
auto lb =
|
||||
[this, criteria](
|
||||
std::function<void(T)> &&callback,
|
||||
std::function<void(const DrogonDbException &)> &&errCallback) {
|
||||
Mapper<T>::findOne(criteria,
|
||||
std::move(callback),
|
||||
std::move(errCallback));
|
||||
std::function<void(const std::exception_ptr &)> &&errCallback) {
|
||||
std::string sql = "select * from ";
|
||||
sql += T::tableName;
|
||||
bool hasParameters = false;
|
||||
if (criteria)
|
||||
{
|
||||
sql += " where ";
|
||||
sql += criteria.criteriaString();
|
||||
hasParameters = true;
|
||||
}
|
||||
sql.append(this->orderByString_);
|
||||
if (this->limit_ > 0)
|
||||
{
|
||||
hasParameters = true;
|
||||
sql.append(" limit $?");
|
||||
}
|
||||
if (this->offset_ > 0)
|
||||
{
|
||||
hasParameters = true;
|
||||
sql.append(" offset $?");
|
||||
}
|
||||
if (hasParameters)
|
||||
sql = this->replaceSqlPlaceHolder(sql, "$?");
|
||||
if (this->forUpdate_)
|
||||
{
|
||||
sql += " for update";
|
||||
}
|
||||
auto binder = *(this->client_) << std::move(sql);
|
||||
if (criteria)
|
||||
criteria.outputArgs(binder);
|
||||
if (this->limit_ > 0)
|
||||
binder << this->limit_;
|
||||
if (this->offset_)
|
||||
binder << this->offset_;
|
||||
this->clear();
|
||||
binder >> [errCallback,
|
||||
callback = std::move(callback)](const Result &r) {
|
||||
if (r.size() == 0)
|
||||
{
|
||||
errCallback(std::make_exception_ptr(
|
||||
UnexpectedRows("0 rows found")));
|
||||
}
|
||||
else if (r.size() > 1)
|
||||
{
|
||||
errCallback(std::make_exception_ptr(
|
||||
UnexpectedRows("Found more than one row")));
|
||||
}
|
||||
else
|
||||
{
|
||||
callback(T(r[0]));
|
||||
}
|
||||
};
|
||||
binder >> std::move(errCallback);
|
||||
};
|
||||
co_return co_await internal::MapperAwaiter<T>(std::move(lb));
|
||||
}
|
||||
|
@ -116,30 +215,141 @@ class CoroMapper : public Mapper<T>
|
|||
auto lb =
|
||||
[this, criteria](
|
||||
std::function<void(std::vector<T>)> &&callback,
|
||||
std::function<void(const DrogonDbException &)> &&errCallback) {
|
||||
Mapper<T>::findBy(criteria,
|
||||
std::move(callback),
|
||||
std::move(errCallback));
|
||||
std::function<void(const std::exception_ptr &)> &&errCallback) {
|
||||
std::string sql = "select * from ";
|
||||
sql += T::tableName;
|
||||
bool hasParameters = false;
|
||||
if (criteria)
|
||||
{
|
||||
hasParameters = true;
|
||||
sql += " where ";
|
||||
sql += criteria.criteriaString();
|
||||
}
|
||||
sql.append(this->orderByString_);
|
||||
if (this->limit_ > 0)
|
||||
{
|
||||
hasParameters = true;
|
||||
sql.append(" limit $?");
|
||||
}
|
||||
if (this->offset_ > 0)
|
||||
{
|
||||
hasParameters = true;
|
||||
sql.append(" offset $?");
|
||||
}
|
||||
if (hasParameters)
|
||||
sql = this->replaceSqlPlaceHolder(sql, "$?");
|
||||
if (this->forUpdate_)
|
||||
{
|
||||
sql += " for update";
|
||||
}
|
||||
auto binder = *(this->client_) << std::move(sql);
|
||||
if (criteria)
|
||||
criteria.outputArgs(binder);
|
||||
if (this->limit_ > 0)
|
||||
binder << this->limit_;
|
||||
if (this->offset_)
|
||||
binder << this->offset_;
|
||||
this->clear();
|
||||
binder >> [callback = std::move(callback)](const Result &r) {
|
||||
std::vector<T> ret;
|
||||
for (auto const &row : r)
|
||||
{
|
||||
ret.push_back(T(row));
|
||||
}
|
||||
callback(ret);
|
||||
};
|
||||
binder >> std::move(errCallback);
|
||||
};
|
||||
co_return co_await internal::MapperAwaiter<std::vector<T>>(
|
||||
std::move(lb));
|
||||
}
|
||||
inline const Task<T> insert(const T &obj)
|
||||
{
|
||||
auto lb = [this, obj](std::function<void(T)> &&callback,
|
||||
std::function<void(const DrogonDbException &)>
|
||||
&&errCallback) {
|
||||
Mapper<T>::insert(obj, std::move(callback), std::move(errCallback));
|
||||
};
|
||||
auto lb =
|
||||
[this, obj](
|
||||
std::function<void(T)> &&callback,
|
||||
std::function<void(const std::exception_ptr &)> &&errCallback) {
|
||||
this->clear();
|
||||
bool needSelection = false;
|
||||
auto binder = *(this->client_)
|
||||
<< obj.sqlForInserting(needSelection);
|
||||
obj.outputArgs(binder);
|
||||
auto client = this->client_;
|
||||
binder >> [client,
|
||||
callback = std::move(callback),
|
||||
obj,
|
||||
needSelection,
|
||||
errCallback](const Result &r) {
|
||||
assert(r.affectedRows() == 1);
|
||||
if (client->type() == ClientType::PostgreSQL)
|
||||
{
|
||||
if (needSelection)
|
||||
{
|
||||
assert(r.size() == 1);
|
||||
callback(T(r[0]));
|
||||
}
|
||||
else
|
||||
{
|
||||
callback(obj);
|
||||
}
|
||||
}
|
||||
else // Mysql or Sqlite3
|
||||
{
|
||||
auto id = r.insertId();
|
||||
auto newObj = obj;
|
||||
newObj.updateId(id);
|
||||
if (needSelection)
|
||||
{
|
||||
auto tmp = Mapper<T>(client);
|
||||
tmp.findByPrimaryKey(
|
||||
newObj.getPrimaryKey(),
|
||||
callback,
|
||||
[errCallback](const DrogonDbException &err) {
|
||||
errCallback(std::make_exception_ptr(
|
||||
Failure(err.base().what())));
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
callback(newObj);
|
||||
}
|
||||
}
|
||||
};
|
||||
binder >> std::move(errCallback);
|
||||
};
|
||||
co_return co_await internal::MapperAwaiter<T>(std::move(lb));
|
||||
}
|
||||
inline const Task<size_t> update(const T &obj)
|
||||
{
|
||||
auto lb = [this, obj](std::function<void(const size_t)> &&callback,
|
||||
std::function<void(const DrogonDbException &)>
|
||||
&&errCallback) {
|
||||
Mapper<T>::update(obj, std::move(callback), std::move(errCallback));
|
||||
};
|
||||
auto lb =
|
||||
[this, obj](
|
||||
std::function<void(const size_t)> &&callback,
|
||||
std::function<void(const std::exception_ptr &)> &&errCallback) {
|
||||
this->clear();
|
||||
static_assert(
|
||||
!std::is_same<typename T::PrimaryKeyType, void>::value,
|
||||
"No primary key in the table!");
|
||||
std::string sql = "update ";
|
||||
sql += T::tableName;
|
||||
sql += " set ";
|
||||
for (auto const &colName : obj.updateColumns())
|
||||
{
|
||||
sql += colName;
|
||||
sql += " = $?,";
|
||||
}
|
||||
sql[sql.length() - 1] = ' '; // Replace the last ','
|
||||
|
||||
this->makePrimaryKeyCriteria(sql);
|
||||
|
||||
sql = this->replaceSqlPlaceHolder(sql, "$?");
|
||||
auto binder = *(this->client_) << std::move(sql);
|
||||
obj.updateArgs(binder);
|
||||
this->outputPrimeryKeyToBinder(obj.getPrimaryKey(), binder);
|
||||
binder >> [callback = std::move(callback)](const Result &r) {
|
||||
callback(r.affectedRows());
|
||||
};
|
||||
binder >> std::move(errCallback);
|
||||
};
|
||||
co_return co_await internal::MapperAwaiter<size_t>(std::move(lb));
|
||||
}
|
||||
inline const Task<size_t> deleteOne(const T &obj)
|
||||
|
@ -147,10 +357,24 @@ class CoroMapper : public Mapper<T>
|
|||
auto lb =
|
||||
[this, obj](
|
||||
std::function<void(const size_t)> &&callback,
|
||||
std::function<void(const DrogonDbException &)> &&errCallback) {
|
||||
Mapper<T>::deleteOne(obj,
|
||||
std::move(callback),
|
||||
std::move(errCallback));
|
||||
std::function<void(const std::exception_ptr &)> &&errCallback) {
|
||||
this->clear();
|
||||
static_assert(
|
||||
!std::is_same<typename T::PrimaryKeyType, void>::value,
|
||||
"No primary key in the table!");
|
||||
std::string sql = "delete from ";
|
||||
sql += T::tableName;
|
||||
sql += " ";
|
||||
|
||||
this->makePrimaryKeyCriteria(sql);
|
||||
|
||||
sql = this->replaceSqlPlaceHolder(sql, "$?");
|
||||
auto binder = *(this->client_) << std::move(sql);
|
||||
this->outputPrimeryKeyToBinder(obj.getPrimaryKey(), binder);
|
||||
binder >> [callback = std::move(callback)](const Result &r) {
|
||||
callback(r.affectedRows());
|
||||
};
|
||||
binder >> std::move(errCallback);
|
||||
};
|
||||
co_return co_await internal::MapperAwaiter<size_t>(std::move(lb));
|
||||
}
|
||||
|
@ -159,23 +383,53 @@ class CoroMapper : public Mapper<T>
|
|||
auto lb =
|
||||
[this, criteria](
|
||||
std::function<void(const size_t)> &&callback,
|
||||
std::function<void(const DrogonDbException &)> &&errCallback) {
|
||||
Mapper<T>::deleteBy(criteria,
|
||||
std::move(callback),
|
||||
std::move(errCallback));
|
||||
std::function<void(const std::exception_ptr &)> &&errCallback) {
|
||||
this->clear();
|
||||
static_assert(
|
||||
!std::is_same<typename T::PrimaryKeyType, void>::value,
|
||||
"No primary key in the table!");
|
||||
std::string sql = "delete from ";
|
||||
sql += T::tableName;
|
||||
|
||||
if (criteria)
|
||||
{
|
||||
sql += " where ";
|
||||
sql += criteria.criteriaString();
|
||||
sql = this->replaceSqlPlaceHolder(sql, "$?");
|
||||
}
|
||||
|
||||
auto binder = *(this->client_) << std::move(sql);
|
||||
if (criteria)
|
||||
{
|
||||
criteria.outputArgs(binder);
|
||||
}
|
||||
binder >> [callback = std::move(callback)](const Result &r) {
|
||||
callback(r.affectedRows());
|
||||
};
|
||||
binder >> std::move(errCallback);
|
||||
};
|
||||
co_return co_await internal::MapperAwaiter<size_t>(std::move(lb));
|
||||
}
|
||||
inline const Task<size_t> deleteByPrimaryKey(const TraitsPKType &key)
|
||||
{
|
||||
auto lb =
|
||||
[this, key](
|
||||
std::function<void(const size_t)> &&callback,
|
||||
std::function<void(const DrogonDbException &)> &&errCallback) {
|
||||
Mapper<T>::deleteByPrimaryKey(key,
|
||||
std::move(callback),
|
||||
std::move(errCallback));
|
||||
static_assert(!std::is_same<typename T::PrimaryKeyType, void>::value,
|
||||
"No primary key in the table!");
|
||||
static_assert(
|
||||
internal::has_sqlForDeletingByPrimaryKey<T>::value,
|
||||
"No function member named sqlForDeletingByPrimaryKey, please "
|
||||
"make sure that the model class is generated by the latest "
|
||||
"version of drogon_ctl");
|
||||
auto lb = [this, key](std::function<void(const size_t)> &&callback,
|
||||
std::function<void(const std::exception_ptr &)>
|
||||
&&errCallback) {
|
||||
this->clear();
|
||||
auto binder = *(this->client_) << T::sqlForDeletingByPrimaryKey();
|
||||
this->outputPrimeryKeyToBinder(key, binder);
|
||||
binder >> [callback = std::move(callback)](const Result &r) {
|
||||
callback(r.affectedRows());
|
||||
};
|
||||
binder >> std::move(errCallback);
|
||||
};
|
||||
co_return co_await internal::MapperAwaiter<size_t>(std::move(lb));
|
||||
}
|
||||
};
|
||||
|
|
|
@ -326,25 +326,13 @@ class Mapper
|
|||
binder >> [prom](const Result &r) {
|
||||
if (r.size() == 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
throw UnexpectedRows("0 rows found");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
prom->set_exception(std::current_exception());
|
||||
}
|
||||
prom->set_exception(
|
||||
std::make_exception_ptr(UnexpectedRows("0 rows found")));
|
||||
}
|
||||
else if (r.size() > 1)
|
||||
{
|
||||
try
|
||||
{
|
||||
throw UnexpectedRows("Found more than one row");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
prom->set_exception(std::current_exception());
|
||||
}
|
||||
prom->set_exception(std::make_exception_ptr(
|
||||
UnexpectedRows("Found more than one row")));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -633,7 +621,7 @@ class Mapper
|
|||
std::future<size_t> deleteFutureByPrimaryKey(
|
||||
const TraitsPKType &key) noexcept;
|
||||
|
||||
private:
|
||||
protected:
|
||||
DbClientPtr client_;
|
||||
size_t limit_{0};
|
||||
size_t offset_{0};
|
||||
|
@ -863,25 +851,13 @@ inline std::future<T> Mapper<T>::findFutureOne(
|
|||
binder >> [prom](const Result &r) {
|
||||
if (r.size() == 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
throw UnexpectedRows("0 rows found");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
prom->set_exception(std::current_exception());
|
||||
}
|
||||
prom->set_exception(
|
||||
std::make_exception_ptr(UnexpectedRows("0 rows found")));
|
||||
}
|
||||
else if (r.size() > 1)
|
||||
{
|
||||
try
|
||||
{
|
||||
throw UnexpectedRows("Found more than one row");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
prom->set_exception(std::current_exception());
|
||||
}
|
||||
prom->set_exception(std::make_exception_ptr(
|
||||
UnexpectedRows("Found more than one row")));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1244,14 +1220,8 @@ inline std::future<T> Mapper<T>::insertFuture(const T &obj) noexcept
|
|||
newObj.getPrimaryKey(),
|
||||
[prom](T selObj) { prom->set_value(selObj); },
|
||||
[prom](const DrogonDbException &e) {
|
||||
try
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
prom->set_exception(std::current_exception());
|
||||
}
|
||||
prom->set_exception(
|
||||
std::make_exception_ptr(Failure(e.base().what())));
|
||||
});
|
||||
}
|
||||
else
|
||||
|
|
|
@ -36,7 +36,7 @@ using namespace drogon::orm;
|
|||
#ifdef __cpp_impl_coroutine
|
||||
constexpr int postgre_tests = 50;
|
||||
constexpr int mysql_tests = 47;
|
||||
constexpr int sqlite_tests = 51;
|
||||
constexpr int sqlite_tests = 52;
|
||||
#else
|
||||
constexpr int postgre_tests = 44;
|
||||
constexpr int mysql_tests = 45;
|
||||
|
@ -2177,6 +2177,17 @@ void doSqliteTest(const drogon::orm::DbClientPtr &clientPtr)
|
|||
std::cerr << e.base().what() << std::endl;
|
||||
testOutput(false, "sqlite3 - CoroMapper coroutine interface(1)");
|
||||
}
|
||||
try
|
||||
{
|
||||
auto mapper = CoroMapper<Users>(clientPtr);
|
||||
auto n = co_await mapper.deleteByPrimaryKey(1);
|
||||
testOutput(n == 1, "sqlite3 - CoroMapper coroutine interface(2)");
|
||||
}
|
||||
catch (const DrogonDbException &e)
|
||||
{
|
||||
std::cerr << e.base().what() << std::endl;
|
||||
testOutput(false, "sqlite3 - CoroMapper coroutine interface(2)");
|
||||
}
|
||||
co_await drogon::sleepCoro(
|
||||
trantor::EventLoop::getEventLoopOfCurrentThread(), 1.0s);
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue