Add Criteria class
This commit is contained in:
parent
2dcb924c81
commit
054b0a2d68
|
@ -0,0 +1,164 @@
|
|||
/**
|
||||
*
|
||||
* Criteria.h
|
||||
* An Tao
|
||||
*
|
||||
* Copyright 2018, An Tao. All rights reserved.
|
||||
* Use of this source code is governed by a MIT license
|
||||
* that can be found in the License file.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <drogon/config.h>
|
||||
#include <drogon/orm/SqlBinder.h>
|
||||
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <assert.h>
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
namespace orm
|
||||
{
|
||||
|
||||
enum class CompareOperator
|
||||
{
|
||||
EQ,
|
||||
NE,
|
||||
GT,
|
||||
GE,
|
||||
LT,
|
||||
LE,
|
||||
IsNull,
|
||||
IsNotNull
|
||||
};
|
||||
class Criteria
|
||||
{
|
||||
public:
|
||||
explicit operator bool() const { return !_condString.empty(); }
|
||||
std::string criteriaString() { return _condString; }
|
||||
template <typename T>
|
||||
Criteria(const std::string &colName, const CompareOperator &opera, T &&arg)
|
||||
{
|
||||
static_assert(opera != CompareOperator::IsNotNull &&
|
||||
opera != CompareOperator::IsNull,
|
||||
"Invalid compare operator!");
|
||||
_condString = colName;
|
||||
switch (opera)
|
||||
{
|
||||
case CompareOperator::EQ:
|
||||
_condString += " = $?";
|
||||
break;
|
||||
case CompareOperator::NE:
|
||||
_condString += " != $?";
|
||||
break;
|
||||
case CompareOperator::GT:
|
||||
_condString += " > $?";
|
||||
break;
|
||||
case CompareOperator::GE:
|
||||
_condString += " >= $?";
|
||||
break;
|
||||
case CompareOperator::LT:
|
||||
_condString += " < $?";
|
||||
break;
|
||||
case CompareOperator::LE:
|
||||
_condString += " <= $?";
|
||||
break;
|
||||
case CompareOperator::IsNull:
|
||||
case CompareOperator::IsNotNull:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
_outputArgumentsFunc = [=](inner::SqlBinder &binder) {
|
||||
binder << arg;
|
||||
};
|
||||
}
|
||||
template <typename T>
|
||||
Criteria(const std::string &colName, T &&arg)
|
||||
: Criteria(colName, CompareOperator::EQ, arg)
|
||||
{
|
||||
}
|
||||
|
||||
Criteria(const std::string &colName, const CompareOperator &opera)
|
||||
{
|
||||
assert(opera == CompareOperator::IsNotNull ||
|
||||
opera == CompareOperator::IsNull);
|
||||
_condString = colName;
|
||||
switch (opera)
|
||||
{
|
||||
case CompareOperator::IsNull:
|
||||
_condString += " is null";
|
||||
break;
|
||||
case CompareOperator::IsNotNull:
|
||||
_condString += " is not null";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
Criteria() {}
|
||||
void outputArgs(internal::SqlBinder &binder)
|
||||
{
|
||||
if (_outputArgumentsFunc)
|
||||
_outputArgumentsFunc(binder);
|
||||
}
|
||||
|
||||
private:
|
||||
friend const Criteria operator&&(Criteria cond1, Criteria cond2);
|
||||
friend const Criteria operator||(Criteria cond1, Criteria cond2);
|
||||
std::string _condString;
|
||||
std::function<void(internal::SqlBinder &)> _outputArgumentsFunc;
|
||||
}; // namespace orm
|
||||
|
||||
const Criteria operator&&(Criteria cond1, Criteria cond2)
|
||||
{
|
||||
assert(cond1 && cond2);
|
||||
Criteria cond;
|
||||
cond._condString = "( ";
|
||||
cond._condString += cond1._condString;
|
||||
cond._condString += " ) and ( ";
|
||||
cond._condString += cond2._condString;
|
||||
cond._condString += " )";
|
||||
auto cond1Ptr = std::make_shared<Criteria>(std::move(cond1));
|
||||
auto cond2Ptr = std::make_shared<Criteria>(std::move(cond2));
|
||||
cond._outputArgumentsFunc = [=](internal::SqlBinder &binder) {
|
||||
if (cond1Ptr->_outputArgumentsFunc)
|
||||
{
|
||||
cond1Ptr->_outputArgumentsFunc(binder);
|
||||
}
|
||||
if (cond2Ptr->_outputArgumentsFunc)
|
||||
{
|
||||
cond2Ptr->_outputArgumentsFunc(binder);
|
||||
}
|
||||
};
|
||||
return cond;
|
||||
}
|
||||
const Criteria operator||(Criteria cond1, Criteria cond2)
|
||||
{
|
||||
assert(cond1 && cond2);
|
||||
Criteria cond;
|
||||
cond._condString = "( ";
|
||||
cond._condString += cond1._condString;
|
||||
cond._condString += " ) or ( ";
|
||||
cond._condString += cond2._condString;
|
||||
cond._condString += " )";
|
||||
auto cond1Ptr = std::make_shared<Criteria>(std::move(cond1));
|
||||
auto cond2Ptr = std::make_shared<Criteria>(std::move(cond2));
|
||||
cond._outputArgumentsFunc = [=](internal::SqlBinder &binder) {
|
||||
if (cond1Ptr->_outputArgumentsFunc)
|
||||
{
|
||||
cond1Ptr->_outputArgumentsFunc(binder);
|
||||
}
|
||||
if (cond2Ptr->_outputArgumentsFunc)
|
||||
{
|
||||
cond2Ptr->_outputArgumentsFunc(binder);
|
||||
}
|
||||
};
|
||||
return cond;
|
||||
}
|
||||
|
||||
} // namespace orm
|
||||
} // namespace drogon
|
|
@ -96,8 +96,9 @@ public:
|
|||
}
|
||||
|
||||
internal::SqlBinder operator<<(const std::string &sql);
|
||||
virtual std::string replaceSqlPlaceHolder(const std::string &sqlStr, const std::string &holderStr) const = 0;
|
||||
|
||||
private:
|
||||
private:
|
||||
friend internal::SqlBinder;
|
||||
virtual void execSql(const std::string &sql,
|
||||
size_t paraNum,
|
||||
|
|
|
@ -13,18 +13,31 @@
|
|||
|
||||
#pragma once
|
||||
#include <drogon/orm/DbClient.h>
|
||||
#include <drogon/orm/Criteria.h>
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
namespace orm
|
||||
{
|
||||
class Condition;
|
||||
|
||||
enum class SortOrder
|
||||
{
|
||||
ASC,
|
||||
DESC
|
||||
};
|
||||
template <typename T>
|
||||
class Mapper
|
||||
{
|
||||
public:
|
||||
Mapper<T> &limit(size_t limit);
|
||||
Mapper<T> &offset(size_t offset);
|
||||
Mapper<T> &orderBy(const std::string &colName, const SortOrder &order = SortOrder::ASC);
|
||||
Mapper<T> &orderBy(size_t colIndex, const SortOrder &order = SortOrder::ASC);
|
||||
|
||||
typedef std::function<void(T)> SingleRowCallback;
|
||||
typedef std::function<void(std::vector<T>)> MultipleRowsCallback;
|
||||
typedef std::function<void(const sise_t)> CountCallback;
|
||||
|
||||
Mapper(const DbClient &client) : _client(client) {}
|
||||
|
||||
T findByPrimaryKey(const T::PrimaryKeyType &key) noexcept(false);
|
||||
|
@ -38,18 +51,177 @@ class Mapper
|
|||
const ExceptionCallback &ecb) noexcept;
|
||||
std::future<std::vector<T>> findFutureAll() noexcept;
|
||||
|
||||
//find one
|
||||
//find by conditions
|
||||
//insert
|
||||
//update
|
||||
//update all
|
||||
//count
|
||||
//limit/offset/orderby
|
||||
//...
|
||||
size_t count(const Criteria &criteria) noexcept(false);
|
||||
void count(const Criteria &criteria,
|
||||
const CountCallback &rcb,
|
||||
const ExceptionCallback &ecb) noexcept;
|
||||
std::future<size_t> count(const Criteria &criteria) noexcept;
|
||||
|
||||
T findOne(const Criteria &criteria) noexcept(false);
|
||||
void findOne(const Criteria &criteria,
|
||||
const SingleRowCallback &rcb,
|
||||
const ExceptionCallback &ecb) noexcept;
|
||||
std::future<T> findFutureOne(const Criteria &criteria) noexcept;
|
||||
|
||||
std::vector<T> findBy(const Criteria &criteria) noexcept(false);
|
||||
void findBy(const Criteria &criteria,
|
||||
const MultipleRowsCallback &rcb,
|
||||
const ExceptionCallback &ecb) noexcept;
|
||||
std::future<std::vector<T>> findFutureBy(const Criteria &criteria) noexcept;
|
||||
|
||||
void insert(T &obj) noexcept(false);
|
||||
void insert(const T &obj,
|
||||
const SingleRowCallback &rcb,
|
||||
const ExceptionCallback &ecb) noexcept;
|
||||
std::future<T> insert(const T &) noexcept;
|
||||
|
||||
size_t update(T &obj) noexcept(false);
|
||||
void update(const T &obj,
|
||||
const CountCallback &rcb,
|
||||
const ExceptionCallback &ecb) noexcept;
|
||||
std::future<size_t> update(const T &obj) noexcept;
|
||||
|
||||
private:
|
||||
Dbclient &_client;
|
||||
std::string getSqlForFindingByPrimaryKey();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline T Mapper<T>::findByPrimaryKey(const T::PrimaryKeyType &key) noexcept(false)
|
||||
{
|
||||
static_assert(T::hasPrimaryKey, "No primary key in the table!");
|
||||
return findOne(Criteria(T::primaryKeyName, key));
|
||||
}
|
||||
template <typename T>
|
||||
inline void Mapper<T>::findByPrimaryKey(const T::PrimaryKeyType &key,
|
||||
const SingleRowCallback &rcb,
|
||||
const ExceptionCallback &ecb) noexcept
|
||||
{
|
||||
static_assert(T::hasPrimaryKey, "No primary key in the table!");
|
||||
findOne(Criteria(T::primaryKeyName, key), rcb, ecb);
|
||||
}
|
||||
template <typename T>
|
||||
inline std::future<T> Mapper<T>::findFutureByPrimaryKey(const T::PrimaryKeyType &key) noexcept
|
||||
{
|
||||
static_assert(T::hasPrimaryKey, "No primary key in the table!");
|
||||
return findFutureOne(Criteria(T::primaryKeyName, key));
|
||||
}
|
||||
template <typename T>
|
||||
inline T Mapper<T>::findOne(const Criteria &criteria) noexcept(false)
|
||||
{
|
||||
std::string sql = "select * from ";
|
||||
sql += T::tableName;
|
||||
if (criteria)
|
||||
{
|
||||
sql += " where ";
|
||||
sql += criteria.criteriaString();
|
||||
sql = _client.replaceSqlPlaceHolder(sql, "$?");
|
||||
}
|
||||
Result r(nullptr);
|
||||
{
|
||||
auto binder = _client << sql;
|
||||
if (criteria)
|
||||
criteria.outputArgs(binder);
|
||||
binder << Mode::Blocking;
|
||||
binder >> [&r](const Result &result) {
|
||||
r = result;
|
||||
};
|
||||
binder.exec(); //exec may be throw exception;
|
||||
}
|
||||
if (r.size() == 0)
|
||||
{
|
||||
throw Failure("No records found that meet the criteria");
|
||||
}
|
||||
else if (r.size() > 1)
|
||||
{
|
||||
throw Failure("More than one record found");
|
||||
}
|
||||
auto row = r[0];
|
||||
return T(row);
|
||||
}
|
||||
template <typename T>
|
||||
inline void Mapper<T>::findOne(const Criteria &criteria,
|
||||
const SingleRowCallback &rcb,
|
||||
const ExceptionCallback &ecb) noexcept
|
||||
{
|
||||
std::string sql = "select * from ";
|
||||
sql += T::tableName;
|
||||
if (criteria)
|
||||
{
|
||||
sql += " where ";
|
||||
sql += criteria.criteriaString();
|
||||
sql = _client.replaceSqlPlaceHolder(sql, "$?");
|
||||
}
|
||||
|
||||
auto binder = _client << sql;
|
||||
if (criteria)
|
||||
criteria.outputArgs(binder);
|
||||
binder >> [=](const Result &r) {
|
||||
if (r.size() == 0)
|
||||
{
|
||||
ecb(Failure("No records found that meet the criteria"));
|
||||
}
|
||||
else if (r.size() > 1)
|
||||
{
|
||||
ech(Failure("More than one record found"));
|
||||
}
|
||||
else
|
||||
{
|
||||
rcb(T(r[0]));
|
||||
}
|
||||
};
|
||||
binder >> ecb;
|
||||
}
|
||||
template <typename T>
|
||||
inline std::future<T> Mapper<T>::findFutureOne(const Criteria &criteria) noexcept
|
||||
{
|
||||
std::string sql = "select * from ";
|
||||
sql += T::tableName;
|
||||
if (criteria)
|
||||
{
|
||||
sql += " where ";
|
||||
sql += criteria.criteriaString();
|
||||
sql = _client.replaceSqlPlaceHolder(sql, "$?");
|
||||
}
|
||||
|
||||
auto binder = _client << sql;
|
||||
if (criteria)
|
||||
criteria.outputArgs(binder);
|
||||
|
||||
std::shared_ptr<std::promise<T>> prom = std::make_shared<std::promise<T>>();
|
||||
binder >> [=](const Result &r) {
|
||||
if (r.size() == 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
throw Failure("No records found that meet the criteria");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
prom->set_exception(std::current_exception());
|
||||
}
|
||||
}
|
||||
else if (r.size() > 1)
|
||||
{
|
||||
try
|
||||
{
|
||||
throw Failure("More than one record found");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
prom->set_exception(std::current_exception());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
prom->set_value(T(r[0]));
|
||||
}
|
||||
};
|
||||
binder >> [=](const std::exception_ptr &e) {
|
||||
prom->set_exception(e);
|
||||
};
|
||||
binder.exec();
|
||||
return prom->get_future();
|
||||
}
|
||||
} // namespace orm
|
||||
} // namespace drogon
|
||||
|
|
|
@ -23,6 +23,7 @@ class PgClient : public DbClient
|
|||
{
|
||||
public:
|
||||
PgClient(const std::string &connInfo, const size_t connNum);
|
||||
virtual std::string replaceSqlPlaceHolder(const std::string &sqlStr, const std::string &holderStr) const override;
|
||||
|
||||
private:
|
||||
virtual void execSql(const std::string &sql,
|
||||
|
|
|
@ -28,22 +28,12 @@ void PgClient::execSql(const std::string &sql,
|
|||
const ResultCallback &rcb,
|
||||
const std::function<void(const std::exception_ptr &)> &exceptCallback)
|
||||
{
|
||||
// std::thread _thread([=]() {
|
||||
// try
|
||||
// {
|
||||
// throw Failure("exception test!!!");
|
||||
// }
|
||||
// catch (...)
|
||||
// {
|
||||
// exceptCallback(std::current_exception());
|
||||
// }
|
||||
// });
|
||||
// _thread.detach();
|
||||
// rcb(Result());
|
||||
_clientPtr->execSql(sql,paraNum,parameters,length,format,rcb,exceptCallback);
|
||||
}
|
||||
|
||||
PgClient::PgClient(const std::string &connInfo, const size_t connNum):
|
||||
_clientPtr(new PgClientImpl(connInfo,connNum))
|
||||
std::string PgClient::replaceSqlPlaceHolder(const std::string &sqlStr, const std::string &holderStr) const {
|
||||
return _clientPtr->replaceSqlPlaceHolder(sqlStr, holderStr);
|
||||
}
|
||||
PgClient::PgClient(const std::string &connInfo, const size_t connNum) : _clientPtr(new PgClientImpl(connInfo, connNum))
|
||||
{
|
||||
}
|
|
@ -16,6 +16,8 @@
|
|||
#include <memory>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sstream>
|
||||
|
||||
using namespace drogon::orm;
|
||||
|
||||
DbConnectionPtr PgClientImpl::newConnection(trantor::EventLoop *loop)
|
||||
|
@ -34,7 +36,7 @@ DbConnectionPtr PgClientImpl::newConnection(trantor::EventLoop *loop)
|
|||
//std::cout<<"Conn closed!end"<<std::endl;
|
||||
});
|
||||
connPtr->setOkCallback([=](const DbConnectionPtr &okConnPtr) {
|
||||
LOG_TRACE << "postgreSQL connected!" ;
|
||||
LOG_TRACE << "postgreSQL connected!";
|
||||
std::lock_guard<std::mutex> guard(_connectionsMutex);
|
||||
_readyConnections.insert(okConnPtr);
|
||||
});
|
||||
|
@ -151,7 +153,7 @@ void PgClientImpl::execSql(const std::string &sql,
|
|||
{
|
||||
throw BrokenConnection("No connection to postgreSQL server");
|
||||
}
|
||||
catch(...)
|
||||
catch (...)
|
||||
{
|
||||
exceptCb(std::current_exception());
|
||||
}
|
||||
|
@ -200,3 +202,24 @@ void PgClientImpl::execSql(const std::string &sql,
|
|||
_sqlCmdBuffer.push_back(std::move(cmd));
|
||||
}
|
||||
}
|
||||
|
||||
std::string PgClientImpl::replaceSqlPlaceHolder(const std::string &sqlStr, const std::string &holderStr) const
|
||||
{
|
||||
std::string::size_type startPos = 0;
|
||||
std::string::size_type pos;
|
||||
std::stringstream ret;
|
||||
size_t phCount = 1;
|
||||
do
|
||||
{
|
||||
pos = sqlStr.find(holderStr, startPos);
|
||||
if (pos == std::string::npos)
|
||||
{
|
||||
ret << sqlStr.substr(startPos);
|
||||
return ret.str();
|
||||
}
|
||||
ret << sqlStr.substr(startPos, pos - startPos);
|
||||
ret << "$";
|
||||
ret << phCount++;
|
||||
startPos = pos + holderStr.length();
|
||||
} while (1);
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ class PgClientImpl : public trantor::NonCopyable
|
|||
const std::vector<int> &format,
|
||||
const ResultCallback &rcb,
|
||||
const std::function<void(const std::exception_ptr &)> &exceptCallback);
|
||||
std::string replaceSqlPlaceHolder(const std::string &sqlStr, const std::string &holderStr) const;
|
||||
|
||||
private:
|
||||
void ioLoop();
|
||||
|
|
Loading…
Reference in New Issue