mirror of
https://github.com/drogonframework/drogon.git
synced 2025-07-25 00:00:40 -04:00
Compare commits
7 Commits
2f9d01f0c7
...
e3bc481a5e
Author | SHA1 | Date | |
---|---|---|---|
|
e3bc481a5e | ||
|
1f78acd89e | ||
|
26840aa056 | ||
|
01385f4f33 | ||
|
2000a4279e | ||
|
1ec3c96cbb | ||
|
0ec5b00f86 |
@ -6,9 +6,9 @@ add_executable(${PROJECT_NAME} test_main.cc)
|
|||||||
# ##############################################################################
|
# ##############################################################################
|
||||||
# If you include the drogon source code locally in your project, use this method
|
# If you include the drogon source code locally in your project, use this method
|
||||||
# to add drogon
|
# to add drogon
|
||||||
# target_link_libraries(${PROJECT_NAME}_test PRIVATE drogon)
|
# target_link_libraries(${PROJECT_NAME} PRIVATE drogon)
|
||||||
#
|
#
|
||||||
# and comment out the following lines
|
# and comment out the following lines
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE Drogon::Drogon)
|
target_link_libraries(${PROJECT_NAME} PRIVATE Drogon::Drogon)
|
||||||
|
|
||||||
ParseAndAddDrogonTests(${PROJECT_NAME})
|
ParseAndAddDrogonTests(${PROJECT_NAME})
|
||||||
|
@ -57,6 +57,26 @@ class DROGON_EXPORT DrObjectBase
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct isAutoCreationClass
|
||||||
|
{
|
||||||
|
template <class C>
|
||||||
|
static constexpr auto check(C *)
|
||||||
|
-> std::enable_if_t<std::is_same_v<decltype(C::isAutoCreation), bool>,
|
||||||
|
bool>
|
||||||
|
{
|
||||||
|
return C::isAutoCreation;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename>
|
||||||
|
static constexpr bool check(...)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr bool value = check<T>(nullptr);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* a class template to
|
* a class template to
|
||||||
* implement the reflection function of creating the class object by class name
|
* implement the reflection function of creating the class object by class name
|
||||||
@ -102,23 +122,22 @@ class DrObject : public virtual DrObjectBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename D>
|
template <typename D>
|
||||||
typename std::enable_if<std::is_default_constructible<D>::value,
|
void registerClass()
|
||||||
void>::type
|
|
||||||
registerClass()
|
|
||||||
{
|
|
||||||
DrClassMap::registerClass(
|
|
||||||
className(),
|
|
||||||
[]() -> DrObjectBase * { return new T; },
|
|
||||||
[]() -> std::shared_ptr<DrObjectBase> {
|
|
||||||
return std::make_shared<T>();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename D>
|
|
||||||
typename std::enable_if<!std::is_default_constructible<D>::value,
|
|
||||||
void>::type
|
|
||||||
registerClass()
|
|
||||||
{
|
{
|
||||||
|
if constexpr (std::is_default_constructible<D>::value)
|
||||||
|
{
|
||||||
|
DrClassMap::registerClass(
|
||||||
|
className(),
|
||||||
|
[]() -> DrObjectBase * { return new T; },
|
||||||
|
[]() -> std::shared_ptr<DrObjectBase> {
|
||||||
|
return std::make_shared<T>();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if constexpr (isAutoCreationClass<D>::value)
|
||||||
|
{
|
||||||
|
static_assert(std::is_default_constructible<D>::value,
|
||||||
|
"Class is not default constructable!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -70,6 +70,91 @@ struct BinderArgTypeTraits<const T &>
|
|||||||
static const bool isValid = true;
|
static const bool isValid = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T getHandlerArgumentValue(std::string &&p)
|
||||||
|
{
|
||||||
|
if constexpr (internal::CanConstructFromString<T>::value)
|
||||||
|
{
|
||||||
|
return T(std::move(p));
|
||||||
|
}
|
||||||
|
else if constexpr (internal::CanConvertFromStringStream<T>::value)
|
||||||
|
{
|
||||||
|
T value{T()};
|
||||||
|
if (!p.empty())
|
||||||
|
{
|
||||||
|
std::stringstream ss(std::move(p));
|
||||||
|
ss >> value;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
else if constexpr (internal::CanConvertFromString<T>::value)
|
||||||
|
{
|
||||||
|
T value;
|
||||||
|
value = p;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_ERROR << "Can't convert string to type " << typeid(T).name();
|
||||||
|
return T();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline std::string getHandlerArgumentValue<std::string>(std::string &&p)
|
||||||
|
{
|
||||||
|
return std::move(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline int getHandlerArgumentValue<int>(std::string &&p)
|
||||||
|
{
|
||||||
|
return std::stoi(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline long getHandlerArgumentValue<long>(std::string &&p)
|
||||||
|
{
|
||||||
|
return std::stol(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline long long getHandlerArgumentValue<long long>(std::string &&p)
|
||||||
|
{
|
||||||
|
return std::stoll(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline unsigned long getHandlerArgumentValue<unsigned long>(std::string &&p)
|
||||||
|
{
|
||||||
|
return std::stoul(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline unsigned long long getHandlerArgumentValue<unsigned long long>(
|
||||||
|
std::string &&p)
|
||||||
|
{
|
||||||
|
return std::stoull(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline float getHandlerArgumentValue<float>(std::string &&p)
|
||||||
|
{
|
||||||
|
return std::stof(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline double getHandlerArgumentValue<double>(std::string &&p)
|
||||||
|
{
|
||||||
|
return std::stod(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline long double getHandlerArgumentValue<long double>(std::string &&p)
|
||||||
|
{
|
||||||
|
return std::stold(p);
|
||||||
|
}
|
||||||
|
|
||||||
class HttpBinderBase
|
class HttpBinderBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -153,27 +238,22 @@ class HttpBinder : public HttpBinderBase
|
|||||||
|
|
||||||
template <bool isClassFunction = traits::isClassFunction,
|
template <bool isClassFunction = traits::isClassFunction,
|
||||||
bool isDrObjectClass = traits::isDrObjectClass>
|
bool isDrObjectClass = traits::isDrObjectClass>
|
||||||
typename std::enable_if<isDrObjectClass && isClassFunction, void>::type
|
void createHandlerInstance()
|
||||||
createHandlerInstance()
|
|
||||||
{
|
|
||||||
auto objPtr =
|
|
||||||
DrClassMap::getSingleInstance<typename traits::class_type>();
|
|
||||||
LOG_TRACE << "create handler class object: " << objPtr.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <bool isClassFunction = traits::isClassFunction,
|
|
||||||
bool isDrObjectClass = traits::isDrObjectClass>
|
|
||||||
typename std::enable_if<!isDrObjectClass && isClassFunction, void>::type
|
|
||||||
createHandlerInstance()
|
|
||||||
{
|
|
||||||
auto &obj = getControllerObj<typename traits::class_type>();
|
|
||||||
LOG_TRACE << "create handler class object: " << &obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <bool isClassFunction = traits::isClassFunction>
|
|
||||||
typename std::enable_if<!isClassFunction, void>::type
|
|
||||||
createHandlerInstance()
|
|
||||||
{
|
{
|
||||||
|
if constexpr (isClassFunction)
|
||||||
|
{
|
||||||
|
if constexpr (isDrObjectClass)
|
||||||
|
{
|
||||||
|
auto objPtr = DrClassMap::getSingleInstance<
|
||||||
|
typename traits::class_type>();
|
||||||
|
LOG_TRACE << "create handler class object: " << objPtr.get();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto &obj = getControllerObj<typename traits::class_type>();
|
||||||
|
LOG_TRACE << "create handler class object: " << &obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -184,276 +264,201 @@ class HttpBinder : public HttpBinderBase
|
|||||||
static const size_t argument_count = traits::arity;
|
static const size_t argument_count = traits::arity;
|
||||||
std::string handlerName_;
|
std::string handlerName_;
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
typename std::enable_if<internal::CanConvertFromStringStream<T>::value,
|
|
||||||
void>::type
|
|
||||||
getHandlerArgumentValue(T &value, std::string &&p)
|
|
||||||
{
|
|
||||||
if (!p.empty())
|
|
||||||
{
|
|
||||||
std::stringstream ss(std::move(p));
|
|
||||||
ss >> value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
typename std::enable_if<!(internal::CanConvertFromStringStream<T>::value),
|
|
||||||
void>::type
|
|
||||||
getHandlerArgumentValue(T &value, std::string &&p)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void getHandlerArgumentValue(std::string &value, std::string &&p)
|
|
||||||
{
|
|
||||||
value = std::move(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void getHandlerArgumentValue(int &value, std::string &&p)
|
|
||||||
{
|
|
||||||
value = std::stoi(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void getHandlerArgumentValue(long &value, std::string &&p)
|
|
||||||
{
|
|
||||||
value = std::stol(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void getHandlerArgumentValue(long long &value, std::string &&p)
|
|
||||||
{
|
|
||||||
value = std::stoll(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void getHandlerArgumentValue(unsigned long &value, std::string &&p)
|
|
||||||
{
|
|
||||||
value = std::stoul(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void getHandlerArgumentValue(unsigned long long &value, std::string &&p)
|
|
||||||
{
|
|
||||||
value = std::stoull(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void getHandlerArgumentValue(float &value, std::string &&p)
|
|
||||||
{
|
|
||||||
value = std::stof(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void getHandlerArgumentValue(double &value, std::string &&p)
|
|
||||||
{
|
|
||||||
value = std::stod(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void getHandlerArgumentValue(long double &value, std::string &&p)
|
|
||||||
{
|
|
||||||
value = std::stold(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename... Values, std::size_t Boundary = argument_count>
|
|
||||||
typename std::enable_if<(sizeof...(Values) < Boundary), void>::type run(
|
|
||||||
std::deque<std::string> &pathArguments,
|
|
||||||
const HttpRequestPtr &req,
|
|
||||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
|
||||||
Values &&...values)
|
|
||||||
{
|
|
||||||
// Call this function recursively until parameter's count equals to the
|
|
||||||
// count of target function parameters
|
|
||||||
static_assert(
|
|
||||||
BinderArgTypeTraits<nth_argument_type<sizeof...(Values)>>::isValid,
|
|
||||||
"your handler argument type must be value type or const left "
|
|
||||||
"reference type or right reference type");
|
|
||||||
using ValueType =
|
|
||||||
typename std::remove_cv<typename std::remove_reference<
|
|
||||||
nth_argument_type<sizeof...(Values)>>::type>::type;
|
|
||||||
ValueType value = ValueType();
|
|
||||||
if (!pathArguments.empty())
|
|
||||||
{
|
|
||||||
std::string v = std::move(pathArguments.front());
|
|
||||||
pathArguments.pop_front();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (v.empty() == false)
|
|
||||||
getHandlerArgumentValue(value, std::move(v));
|
|
||||||
}
|
|
||||||
catch (const std::exception &e)
|
|
||||||
{
|
|
||||||
handleException(e, req, std::move(callback));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
value = req->as<ValueType>();
|
|
||||||
}
|
|
||||||
catch (const std::exception &e)
|
|
||||||
{
|
|
||||||
handleException(e, req, std::move(callback));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
LOG_ERROR << "Exception not derived from std::exception";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
run(pathArguments,
|
|
||||||
req,
|
|
||||||
std::move(callback),
|
|
||||||
std::forward<Values>(values)...,
|
|
||||||
std::move(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename... Values,
|
template <typename... Values,
|
||||||
std::size_t Boundary = argument_count,
|
std::size_t Boundary = argument_count,
|
||||||
bool isCoroutine = traits::isCoroutine>
|
bool isCoroutine = traits::isCoroutine>
|
||||||
typename std::enable_if<(sizeof...(Values) == Boundary) && !isCoroutine,
|
void run(std::deque<std::string> &pathArguments,
|
||||||
void>::type
|
const HttpRequestPtr &req,
|
||||||
run(std::deque<std::string> &,
|
std::function<void(const HttpResponsePtr &)> &&callback,
|
||||||
const HttpRequestPtr &req,
|
Values &&...values)
|
||||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
|
||||||
Values &&...values)
|
|
||||||
{
|
{
|
||||||
try
|
if constexpr (sizeof...(Values) < Boundary)
|
||||||
{
|
{ // Call this function recursively until parameter's count equals to
|
||||||
// Explcit copy because `callFunction` moves it
|
// the count of target function parameters
|
||||||
auto cb = callback;
|
static_assert(
|
||||||
callFunction(req, cb, std::move(values)...);
|
BinderArgTypeTraits<
|
||||||
}
|
nth_argument_type<sizeof...(Values)>>::isValid,
|
||||||
catch (const std::exception &except)
|
"your handler argument type must be value type or const left "
|
||||||
{
|
"reference type or right reference type");
|
||||||
handleException(except, req, std::move(callback));
|
using ValueType = std::remove_cv_t<
|
||||||
}
|
std::remove_reference_t<nth_argument_type<sizeof...(Values)>>>;
|
||||||
catch (...)
|
if (!pathArguments.empty())
|
||||||
{
|
|
||||||
LOG_ERROR << "Exception not derived from std::exception";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef __cpp_impl_coroutine
|
|
||||||
template <typename... Values,
|
|
||||||
std::size_t Boundary = argument_count,
|
|
||||||
bool isCoroutine = traits::isCoroutine>
|
|
||||||
typename std::enable_if<(sizeof...(Values) == Boundary) && isCoroutine,
|
|
||||||
void>::type
|
|
||||||
run(std::deque<std::string> &,
|
|
||||||
const HttpRequestPtr &req,
|
|
||||||
std::function<void(const HttpResponsePtr &)> &&callback,
|
|
||||||
Values &&...values)
|
|
||||||
{
|
|
||||||
[this](HttpRequestPtr req,
|
|
||||||
std::function<void(const HttpResponsePtr &)> callback,
|
|
||||||
Values &&...values) -> AsyncTask {
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
if constexpr (std::is_same_v<AsyncTask,
|
std::string v{std::move(pathArguments.front())};
|
||||||
typename traits::return_type>)
|
pathArguments.pop_front();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!v.empty())
|
||||||
|
{
|
||||||
|
auto value =
|
||||||
|
getHandlerArgumentValue<ValueType>(std::move(v));
|
||||||
|
run(pathArguments,
|
||||||
|
req,
|
||||||
|
std::move(callback),
|
||||||
|
std::forward<Values>(values)...,
|
||||||
|
std::move(value));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
handleException(e, req, std::move(callback));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto value = req->as<ValueType>();
|
||||||
|
run(pathArguments,
|
||||||
|
req,
|
||||||
|
std::move(callback),
|
||||||
|
std::forward<Values>(values)...,
|
||||||
|
std::move(value));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (const std::exception &e)
|
||||||
|
{
|
||||||
|
handleException(e, req, std::move(callback));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
LOG_ERROR << "Exception not derived from std::exception";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
run(pathArguments,
|
||||||
|
req,
|
||||||
|
std::move(callback),
|
||||||
|
std::forward<Values>(values)...,
|
||||||
|
ValueType());
|
||||||
|
}
|
||||||
|
else if constexpr (sizeof...(Values) == Boundary)
|
||||||
|
{
|
||||||
|
if constexpr (!isCoroutine)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
// Explcit copy because `callFunction` moves it
|
// Explcit copy because `callFunction` moves it
|
||||||
auto cb = callback;
|
auto cb = callback;
|
||||||
callFunction(req, cb, std::move(values)...);
|
callFunction(req, cb, std::move(values)...);
|
||||||
}
|
}
|
||||||
else if constexpr (std::is_same_v<Task<>,
|
catch (const std::exception &except)
|
||||||
typename traits::return_type>)
|
|
||||||
{
|
{
|
||||||
// Explcit copy because `callFunction` moves it
|
handleException(except, req, std::move(callback));
|
||||||
auto cb = callback;
|
|
||||||
co_await callFunction(req, cb, std::move(values)...);
|
|
||||||
}
|
}
|
||||||
else if constexpr (std::is_same_v<Task<HttpResponsePtr>,
|
catch (...)
|
||||||
typename traits::return_type>)
|
|
||||||
{
|
{
|
||||||
auto resp =
|
LOG_ERROR << "Exception not derived from std::exception";
|
||||||
co_await callFunction(req, std::move(values)...);
|
return;
|
||||||
callback(std::move(resp));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (const std::exception &except)
|
#ifdef __cpp_impl_coroutine
|
||||||
|
else
|
||||||
{
|
{
|
||||||
handleException(except, req, std::move(callback));
|
[this](HttpRequestPtr req,
|
||||||
|
std::function<void(const HttpResponsePtr &)> callback,
|
||||||
|
Values &&...values) -> AsyncTask {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if constexpr (std::is_same_v<
|
||||||
|
AsyncTask,
|
||||||
|
typename traits::return_type>)
|
||||||
|
{
|
||||||
|
// Explcit copy because `callFunction` moves it
|
||||||
|
auto cb = callback;
|
||||||
|
callFunction(req, cb, std::move(values)...);
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<
|
||||||
|
Task<>,
|
||||||
|
typename traits::return_type>)
|
||||||
|
{
|
||||||
|
// Explcit copy because `callFunction` moves it
|
||||||
|
auto cb = callback;
|
||||||
|
co_await callFunction(req,
|
||||||
|
cb,
|
||||||
|
std::move(values)...);
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<
|
||||||
|
Task<HttpResponsePtr>,
|
||||||
|
typename traits::return_type>)
|
||||||
|
{
|
||||||
|
auto resp =
|
||||||
|
co_await callFunction(req,
|
||||||
|
std::move(values)...);
|
||||||
|
callback(std::move(resp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception &except)
|
||||||
|
{
|
||||||
|
handleException(except, req, std::move(callback));
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
LOG_ERROR
|
||||||
|
<< "Exception not derived from std::exception";
|
||||||
|
}
|
||||||
|
}(req, std::move(callback), std::move(values)...);
|
||||||
}
|
}
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
LOG_ERROR << "Exception not derived from std::exception";
|
|
||||||
}
|
|
||||||
}(req, std::move(callback), std::move(values)...);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
template <typename... Values,
|
}
|
||||||
bool isClassFunction = traits::isClassFunction,
|
|
||||||
bool isDrObjectClass = traits::isDrObjectClass,
|
|
||||||
bool isNormal = std::is_same<typename traits::first_param_type,
|
|
||||||
HttpRequestPtr>::value>
|
|
||||||
typename std::enable_if<isClassFunction && !isDrObjectClass && isNormal,
|
|
||||||
typename traits::return_type>::type
|
|
||||||
callFunction(const HttpRequestPtr &req, Values &&...values)
|
|
||||||
{
|
|
||||||
static auto &obj = getControllerObj<typename traits::class_type>();
|
|
||||||
return (obj.*func_)(req, std::move(values)...);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Values,
|
template <typename... Values,
|
||||||
bool isClassFunction = traits::isClassFunction,
|
bool isClassFunction = traits::isClassFunction,
|
||||||
bool isDrObjectClass = traits::isDrObjectClass,
|
bool isDrObjectClass = traits::isDrObjectClass,
|
||||||
bool isNormal = std::is_same<typename traits::first_param_type,
|
bool isNormal = std::is_same_v<typename traits::first_param_type,
|
||||||
HttpRequestPtr>::value>
|
HttpRequestPtr>>
|
||||||
typename std::enable_if<isClassFunction && isDrObjectClass && isNormal,
|
typename traits::return_type callFunction(const HttpRequestPtr &req,
|
||||||
typename traits::return_type>::type
|
Values &&...values)
|
||||||
callFunction(const HttpRequestPtr &req, Values &&...values)
|
|
||||||
{
|
{
|
||||||
static auto objPtr =
|
if constexpr (isNormal)
|
||||||
DrClassMap::getSingleInstance<typename traits::class_type>();
|
{
|
||||||
return (*objPtr.*func_)(req, std::move(values)...);
|
if constexpr (isClassFunction)
|
||||||
}
|
{
|
||||||
|
if constexpr (!isDrObjectClass)
|
||||||
template <typename... Values,
|
{
|
||||||
bool isClassFunction = traits::isClassFunction,
|
static auto &obj =
|
||||||
bool isNormal = std::is_same<typename traits::first_param_type,
|
getControllerObj<typename traits::class_type>();
|
||||||
HttpRequestPtr>::value>
|
return (obj.*func_)(req, std::move(values)...);
|
||||||
typename std::enable_if<!isClassFunction && isNormal,
|
}
|
||||||
typename traits::return_type>::type
|
else
|
||||||
callFunction(const HttpRequestPtr &req, Values &&...values)
|
{
|
||||||
{
|
static auto objPtr = DrClassMap::getSingleInstance<
|
||||||
return func_(req, std::move(values)...);
|
typename traits::class_type>();
|
||||||
}
|
return (*objPtr.*func_)(req, std::move(values)...);
|
||||||
|
}
|
||||||
template <typename... Values,
|
}
|
||||||
bool isClassFunction = traits::isClassFunction,
|
else
|
||||||
bool isDrObjectClass = traits::isDrObjectClass,
|
{
|
||||||
bool isNormal = std::is_same<typename traits::first_param_type,
|
return func_(req, std::move(values)...);
|
||||||
HttpRequestPtr>::value>
|
}
|
||||||
typename std::enable_if<isClassFunction && !isDrObjectClass && !isNormal,
|
}
|
||||||
typename traits::return_type>::type
|
else
|
||||||
callFunction(const HttpRequestPtr &req, Values &&...values)
|
{
|
||||||
{
|
if constexpr (isClassFunction)
|
||||||
static auto &obj = getControllerObj<typename traits::class_type>();
|
{
|
||||||
return (obj.*func_)((*req), std::move(values)...);
|
if constexpr (!isDrObjectClass)
|
||||||
}
|
{
|
||||||
|
static auto &obj =
|
||||||
template <typename... Values,
|
getControllerObj<typename traits::class_type>();
|
||||||
bool isClassFunction = traits::isClassFunction,
|
return (obj.*func_)((*req), std::move(values)...);
|
||||||
bool isDrObjectClass = traits::isDrObjectClass,
|
}
|
||||||
bool isNormal = std::is_same<typename traits::first_param_type,
|
else
|
||||||
HttpRequestPtr>::value>
|
{
|
||||||
typename std::enable_if<isClassFunction && isDrObjectClass && !isNormal,
|
static auto objPtr = DrClassMap::getSingleInstance<
|
||||||
typename traits::return_type>::type
|
typename traits::class_type>();
|
||||||
callFunction(const HttpRequestPtr &req, Values &&...values)
|
return (*objPtr.*func_)((*req), std::move(values)...);
|
||||||
{
|
}
|
||||||
static auto objPtr =
|
}
|
||||||
DrClassMap::getSingleInstance<typename traits::class_type>();
|
else
|
||||||
return (*objPtr.*func_)((*req), std::move(values)...);
|
{
|
||||||
}
|
return func_((*req), std::move(values)...);
|
||||||
|
}
|
||||||
template <typename... Values,
|
}
|
||||||
bool isClassFunction = traits::isClassFunction,
|
|
||||||
bool isNormal = std::is_same<typename traits::first_param_type,
|
|
||||||
HttpRequestPtr>::value>
|
|
||||||
typename std::enable_if<!isClassFunction && !isNormal,
|
|
||||||
typename traits::return_type>::type
|
|
||||||
callFunction(const HttpRequestPtr &req, Values &&...values)
|
|
||||||
{
|
|
||||||
return func_((*req), std::move(values)...);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ template <typename T, bool AutoCreation = true>
|
|||||||
class HttpController : public DrObject<T>, public HttpControllerBase
|
class HttpController : public DrObject<T>, public HttpControllerBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static const bool isAutoCreation = AutoCreation;
|
static constexpr bool isAutoCreation = AutoCreation;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
template <typename FUNCTION>
|
template <typename FUNCTION>
|
||||||
|
@ -69,11 +69,10 @@ struct is_printable : std::false_type
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename _Tp>
|
template <typename _Tp>
|
||||||
struct is_printable<_Tp,
|
struct is_printable<
|
||||||
typename std::enable_if<
|
_Tp,
|
||||||
std::is_same<decltype(std::cout << std::declval<_Tp>()),
|
std::enable_if_t<std::is_same_v<decltype(std::cout << std::declval<_Tp>()),
|
||||||
std::ostream &>::value>::type>
|
std::ostream &>>> : std::true_type
|
||||||
: std::true_type
|
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -167,10 +166,10 @@ inline std::string attemptPrint(T &&v)
|
|||||||
|
|
||||||
// Poor man's if constexpr because SFINAE don't disambiguate between
|
// Poor man's if constexpr because SFINAE don't disambiguate between
|
||||||
// possible resolutions
|
// possible resolutions
|
||||||
return typename std::conditional<
|
return
|
||||||
std::is_convertible<T, std::string_view>::value,
|
typename std::conditional_t<std::is_convertible_v<T, std::string_view>,
|
||||||
internal::StringPrinter,
|
internal::StringPrinter,
|
||||||
DefaultPrinter>::type()(v);
|
DefaultPrinter>()(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Specializations to reduce template construction
|
// Specializations to reduce template construction
|
||||||
@ -281,7 +280,7 @@ struct Lhs
|
|||||||
template <typename RhsType>
|
template <typename RhsType>
|
||||||
ComparsionResult operator&&(const RhsType &rhs)
|
ComparsionResult operator&&(const RhsType &rhs)
|
||||||
{
|
{
|
||||||
static_assert(!std::is_same<RhsType, void>::value,
|
static_assert(!std::is_same_v<RhsType, void>,
|
||||||
" && is not supported in expression decomposition");
|
" && is not supported in expression decomposition");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -289,7 +288,7 @@ struct Lhs
|
|||||||
template <typename RhsType>
|
template <typename RhsType>
|
||||||
ComparsionResult operator||(const RhsType &rhs)
|
ComparsionResult operator||(const RhsType &rhs)
|
||||||
{
|
{
|
||||||
static_assert(!std::is_same<RhsType, void>::value,
|
static_assert(!std::is_same_v<RhsType, void>,
|
||||||
" || is not supported in expression decomposition");
|
" || is not supported in expression decomposition");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -297,7 +296,7 @@ struct Lhs
|
|||||||
template <typename RhsType>
|
template <typename RhsType>
|
||||||
ComparsionResult operator|(const RhsType &rhs)
|
ComparsionResult operator|(const RhsType &rhs)
|
||||||
{
|
{
|
||||||
static_assert(!std::is_same<RhsType, void>::value,
|
static_assert(!std::is_same_v<RhsType, void>,
|
||||||
" | is not supported in expression decomposition");
|
" | is not supported in expression decomposition");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -305,7 +304,7 @@ struct Lhs
|
|||||||
template <typename RhsType>
|
template <typename RhsType>
|
||||||
ComparsionResult operator&(const RhsType &rhs)
|
ComparsionResult operator&(const RhsType &rhs)
|
||||||
{
|
{
|
||||||
static_assert(!std::is_same<RhsType, void>::value,
|
static_assert(!std::is_same_v<RhsType, void>,
|
||||||
" & is not supported in expression decomposition");
|
" & is not supported in expression decomposition");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -106,8 +106,7 @@ class DROGON_EXPORT PluginBase : public virtual DrObjectBase,
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
struct IsPlugin
|
struct IsPlugin
|
||||||
{
|
{
|
||||||
using TYPE =
|
using TYPE = std::remove_cv_t<typename std::remove_reference_t<T>>;
|
||||||
typename std::remove_cv<typename std::remove_reference<T>::type>::type;
|
|
||||||
|
|
||||||
static int test(void *)
|
static int test(void *)
|
||||||
{
|
{
|
||||||
|
@ -50,7 +50,7 @@ struct FunctionTraits;
|
|||||||
template <typename Function>
|
template <typename Function>
|
||||||
struct FunctionTraits
|
struct FunctionTraits
|
||||||
: public FunctionTraits<
|
: public FunctionTraits<
|
||||||
decltype(&std::remove_reference<Function>::type::operator())>
|
decltype(&std::remove_reference_t<Function>::operator())>
|
||||||
{
|
{
|
||||||
static const bool isClassFunction = false;
|
static const bool isClassFunction = false;
|
||||||
static const bool isDrObjectClass = false;
|
static const bool isDrObjectClass = false;
|
||||||
@ -190,7 +190,7 @@ struct FunctionTraits<ReturnType (*)(Arguments...)>
|
|||||||
|
|
||||||
template <std::size_t Index>
|
template <std::size_t Index>
|
||||||
using argument =
|
using argument =
|
||||||
typename std::tuple_element<Index, std::tuple<Arguments...>>::type;
|
typename std::tuple_element_t<Index, std::tuple<Arguments...>>;
|
||||||
|
|
||||||
static const std::size_t arity = sizeof...(Arguments);
|
static const std::size_t arity = sizeof...(Arguments);
|
||||||
using class_type = void;
|
using class_type = void;
|
||||||
|
@ -37,8 +37,7 @@ struct CanConvertToString
|
|||||||
static no test(...);
|
static no test(...);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static constexpr bool value =
|
static constexpr bool value = std::is_same_v<decltype(test<Type>(0)), yes>;
|
||||||
std::is_same<decltype(test<Type>(0)), yes>::value;
|
|
||||||
};
|
};
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
@ -53,21 +52,20 @@ class OStringStream
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::enable_if_t<!internal::CanConvertToString<T>::value, OStringStream &>
|
OStringStream &operator<<(T &&value)
|
||||||
operator<<(T &&value)
|
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
if constexpr (internal::CanConvertToString<T>::value)
|
||||||
ss << std::forward<T>(value);
|
{
|
||||||
buffer_.append(ss.str());
|
buffer_.append(std::to_string(std::forward<T>(value)));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
template <typename T>
|
{
|
||||||
std::enable_if_t<internal::CanConvertToString<T>::value, OStringStream &>
|
std::stringstream ss;
|
||||||
operator<<(T &&value)
|
ss << std::forward<T>(value);
|
||||||
{
|
buffer_.append(ss.str());
|
||||||
buffer_.append(std::to_string(std::forward<T>(value)));
|
return *this;
|
||||||
return *this;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <int N>
|
template <int N>
|
||||||
|
@ -53,9 +53,43 @@ struct CanConvertFromStringStream
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
static constexpr bool value =
|
static constexpr bool value =
|
||||||
std::is_same<decltype(test<T>(nullptr, std::stringstream())),
|
std::is_same_v<decltype(test<T>(nullptr, std::stringstream())), yes>;
|
||||||
yes>::value;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct CanConstructFromString
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
using yes = std::true_type;
|
||||||
|
using no = std::false_type;
|
||||||
|
|
||||||
|
template <typename U>
|
||||||
|
static auto test(U *p) -> decltype(U(std::string{}), yes());
|
||||||
|
|
||||||
|
template <typename>
|
||||||
|
static no test(...);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr bool value =
|
||||||
|
std::is_same_v<decltype(test<T>(nullptr)), yes>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct CanConvertFromString
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
using yes = std::true_type;
|
||||||
|
using no = std::false_type;
|
||||||
|
template <class U>
|
||||||
|
static auto test(U *p) -> decltype(*p = std::string(), yes());
|
||||||
|
template <class>
|
||||||
|
static no test(...);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr bool value =
|
||||||
|
std::is_same_v<decltype(test<T>(nullptr)), yes>;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
namespace utils
|
namespace utils
|
||||||
@ -79,7 +113,8 @@ DROGON_EXPORT std::string genRandomString(int length);
|
|||||||
|
|
||||||
/// Convert a binary string to hex format
|
/// Convert a binary string to hex format
|
||||||
DROGON_EXPORT std::string binaryStringToHex(const unsigned char *ptr,
|
DROGON_EXPORT std::string binaryStringToHex(const unsigned char *ptr,
|
||||||
size_t length);
|
size_t length,
|
||||||
|
bool lowerCase = false);
|
||||||
|
|
||||||
/// Get a binary string from hexadecimal format
|
/// Get a binary string from hexadecimal format
|
||||||
DROGON_EXPORT std::string hexToBinaryString(const char *ptr, size_t length);
|
DROGON_EXPORT std::string hexToBinaryString(const char *ptr, size_t length);
|
||||||
@ -88,6 +123,11 @@ DROGON_EXPORT std::string hexToBinaryString(const char *ptr, size_t length);
|
|||||||
DROGON_EXPORT std::vector<char> hexToBinaryVector(const char *ptr,
|
DROGON_EXPORT std::vector<char> hexToBinaryVector(const char *ptr,
|
||||||
size_t length);
|
size_t length);
|
||||||
|
|
||||||
|
DROGON_EXPORT void binaryStringToHex(const char *ptr,
|
||||||
|
size_t length,
|
||||||
|
char *out,
|
||||||
|
bool lowerCase = false);
|
||||||
|
|
||||||
/// Split the string into multiple separated strings.
|
/// Split the string into multiple separated strings.
|
||||||
/**
|
/**
|
||||||
* @param acceptEmptyString if true, empty strings are accepted in the
|
* @param acceptEmptyString if true, empty strings are accepted in the
|
||||||
@ -106,7 +146,7 @@ DROGON_EXPORT std::set<std::string> splitStringToSet(
|
|||||||
const std::string &separator);
|
const std::string &separator);
|
||||||
|
|
||||||
/// Get UUID string.
|
/// Get UUID string.
|
||||||
DROGON_EXPORT std::string getUuid();
|
DROGON_EXPORT std::string getUuid(bool lowercase = true);
|
||||||
|
|
||||||
/// Get the encoded length of base64.
|
/// Get the encoded length of base64.
|
||||||
constexpr size_t base64EncodedLength(size_t in_len, bool padded = true)
|
constexpr size_t base64EncodedLength(size_t in_len, bool padded = true)
|
||||||
@ -396,24 +436,22 @@ DROGON_EXPORT bool secureRandomBytes(void *ptr, size_t size);
|
|||||||
DROGON_EXPORT std::string secureRandomString(size_t size);
|
DROGON_EXPORT std::string secureRandomString(size_t size);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename std::enable_if<internal::CanConvertFromStringStream<T>::value, T>::type
|
T fromString(const std::string &p) noexcept(false)
|
||||||
fromString(const std::string &p) noexcept(false)
|
|
||||||
{
|
{
|
||||||
T value{};
|
if constexpr (internal::CanConvertFromStringStream<T>::value)
|
||||||
if (!p.empty())
|
|
||||||
{
|
{
|
||||||
std::stringstream ss(p);
|
T value{};
|
||||||
ss >> value;
|
if (!p.empty())
|
||||||
|
{
|
||||||
|
std::stringstream ss(p);
|
||||||
|
ss >> value;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Bad type conversion");
|
||||||
}
|
}
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
typename std::enable_if<!(internal::CanConvertFromStringStream<T>::value),
|
|
||||||
T>::type
|
|
||||||
fromString(const std::string &) noexcept(false)
|
|
||||||
{
|
|
||||||
throw std::runtime_error("Bad type conversion");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
@ -1375,7 +1375,6 @@ void Http2Transport::sendFrame(const internal::H2Frame &frame, int32_t streamId)
|
|||||||
|
|
||||||
void Http2Transport::sendBufferedData()
|
void Http2Transport::sendBufferedData()
|
||||||
{
|
{
|
||||||
LOG_WARN << "Sending buffered data. Size: " << batchedSendBuffer.size();
|
|
||||||
if (batchedSendBuffer.size() == 0)
|
if (batchedSendBuffer.size() == 0)
|
||||||
return;
|
return;
|
||||||
OByteStream buffer;
|
OByteStream buffer;
|
||||||
|
@ -777,14 +777,14 @@ void HttpAppFrameworkImpl::findSessionForRequest(const HttpRequestImplPtr &req)
|
|||||||
if (useSession_)
|
if (useSession_)
|
||||||
{
|
{
|
||||||
std::string sessionId = req->getCookie(sessionCookieKey_);
|
std::string sessionId = req->getCookie(sessionCookieKey_);
|
||||||
bool needSetJsessionid = false;
|
bool needSetSessionid = false;
|
||||||
if (sessionId.empty())
|
if (sessionId.empty())
|
||||||
{
|
{
|
||||||
sessionId = utils::getUuid();
|
sessionId = sessionIdGeneratorCallback_();
|
||||||
needSetJsessionid = true;
|
needSetSessionid = true;
|
||||||
}
|
}
|
||||||
req->setSession(
|
req->setSession(
|
||||||
sessionManagerPtr_->getSession(sessionId, needSetJsessionid));
|
sessionManagerPtr_->getSession(sessionId, needSetSessionid));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "SessionManager.h"
|
#include "SessionManager.h"
|
||||||
|
#include "drogon/utils/Utilities.h"
|
||||||
#include "impl_forwards.h"
|
#include "impl_forwards.h"
|
||||||
|
|
||||||
namespace trantor
|
namespace trantor
|
||||||
@ -250,7 +251,9 @@ class HttpAppFrameworkImpl final : public HttpAppFramework
|
|||||||
HttpAppFramework &setSessionIdGenerator(
|
HttpAppFramework &setSessionIdGenerator(
|
||||||
SessionManager::IdGeneratorCallback idGeneratorCallback = nullptr)
|
SessionManager::IdGeneratorCallback idGeneratorCallback = nullptr)
|
||||||
{
|
{
|
||||||
sessionIdGeneratorCallback_ = idGeneratorCallback;
|
sessionIdGeneratorCallback_ =
|
||||||
|
idGeneratorCallback ? idGeneratorCallback
|
||||||
|
: []() { return utils::getUuid(true); };
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -760,7 +760,7 @@ void HttpRequestImpl::appendToBody(const char *data, size_t length)
|
|||||||
void HttpRequestImpl::createTmpFile()
|
void HttpRequestImpl::createTmpFile()
|
||||||
{
|
{
|
||||||
auto tmpfile = HttpAppFrameworkImpl::instance().getUploadPath();
|
auto tmpfile = HttpAppFrameworkImpl::instance().getUploadPath();
|
||||||
auto fileName = utils::getUuid();
|
auto fileName = utils::getUuid(false);
|
||||||
tmpfile.append("/tmp/")
|
tmpfile.append("/tmp/")
|
||||||
.append(1, fileName[0])
|
.append(1, fileName[0])
|
||||||
.append(1, fileName[1])
|
.append(1, fileName[1])
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "SessionManager.h"
|
#include "SessionManager.h"
|
||||||
#include <drogon/utils/Utilities.h>
|
|
||||||
|
|
||||||
using namespace drogon;
|
using namespace drogon;
|
||||||
|
|
||||||
@ -27,8 +26,7 @@ SessionManager::SessionManager(
|
|||||||
timeout_(timeout),
|
timeout_(timeout),
|
||||||
sessionStartAdvices_(startAdvices),
|
sessionStartAdvices_(startAdvices),
|
||||||
sessionDestroyAdvices_(destroyAdvices),
|
sessionDestroyAdvices_(destroyAdvices),
|
||||||
idGeneratorCallback_(idGeneratorCallback ? idGeneratorCallback
|
idGeneratorCallback_(idGeneratorCallback)
|
||||||
: utils::getUuid)
|
|
||||||
{
|
{
|
||||||
if (timeout_ > 0)
|
if (timeout_ > 0)
|
||||||
{
|
{
|
||||||
|
@ -37,7 +37,7 @@ class SessionManager : public trantor::NonCopyable
|
|||||||
size_t timeout,
|
size_t timeout,
|
||||||
const std::vector<AdviceStartSessionCallback> &startAdvices,
|
const std::vector<AdviceStartSessionCallback> &startAdvices,
|
||||||
const std::vector<AdviceDestroySessionCallback> &destroyAdvices,
|
const std::vector<AdviceDestroySessionCallback> &destroyAdvices,
|
||||||
IdGeneratorCallback idGeneratorCallback = nullptr);
|
IdGeneratorCallback idGeneratorCallback);
|
||||||
|
|
||||||
~SessionManager()
|
~SessionManager()
|
||||||
{
|
{
|
||||||
|
@ -289,31 +289,55 @@ std::string hexToBinaryString(const char *ptr, size_t length)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string binaryStringToHex(const unsigned char *ptr, size_t length)
|
DROGON_EXPORT void binaryStringToHex(const char *ptr,
|
||||||
|
size_t length,
|
||||||
|
char *out,
|
||||||
|
bool lowerCase)
|
||||||
{
|
{
|
||||||
std::string idString;
|
|
||||||
for (size_t i = 0; i < length; ++i)
|
for (size_t i = 0; i < length; ++i)
|
||||||
{
|
{
|
||||||
int value = (ptr[i] & 0xf0) >> 4;
|
int value = (ptr[i] & 0xf0) >> 4;
|
||||||
if (value < 10)
|
if (value < 10)
|
||||||
{
|
{
|
||||||
idString.append(1, char(value + 48));
|
out[i * 2] = char(value + 48);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
idString.append(1, char(value + 55));
|
if (!lowerCase)
|
||||||
|
{
|
||||||
|
out[i * 2] = char(value + 55);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out[i * 2] = char(value + 87);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
value = (ptr[i] & 0x0f);
|
value = (ptr[i] & 0x0f);
|
||||||
if (value < 10)
|
if (value < 10)
|
||||||
{
|
{
|
||||||
idString.append(1, char(value + 48));
|
out[i * 2 + 1] = char(value + 48);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
idString.append(1, char(value + 55));
|
if (!lowerCase)
|
||||||
|
{
|
||||||
|
out[i * 2 + 1] = char(value + 55);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out[i * 2 + 1] = char(value + 87);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string binaryStringToHex(const unsigned char *ptr,
|
||||||
|
size_t length,
|
||||||
|
bool lowercase)
|
||||||
|
{
|
||||||
|
std::string idString(length * 2, '\0');
|
||||||
|
binaryStringToHex((const char *)ptr, length, &idString[0], lowercase);
|
||||||
return idString;
|
return idString;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,7 +366,23 @@ std::set<std::string> splitStringToSet(const std::string &str,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string getUuid()
|
inline std::string createUuidString(const char *str, size_t len, bool lowercase)
|
||||||
|
{
|
||||||
|
assert(len == 16);
|
||||||
|
std::string uuid(36, '\0');
|
||||||
|
binaryStringToHex(str, 4, &uuid[0], lowercase);
|
||||||
|
uuid[8] = '-';
|
||||||
|
binaryStringToHex(str + 4, 2, &uuid[9], lowercase);
|
||||||
|
uuid[13] = '-';
|
||||||
|
binaryStringToHex(str + 6, 2, &uuid[14], lowercase);
|
||||||
|
uuid[18] = '-';
|
||||||
|
binaryStringToHex(str + 8, 2, &uuid[19], lowercase);
|
||||||
|
uuid[23] = '-';
|
||||||
|
binaryStringToHex(str + 10, 6, &uuid[24], lowercase);
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getUuid(bool lowercase)
|
||||||
{
|
{
|
||||||
#if USE_OSSP_UUID
|
#if USE_OSSP_UUID
|
||||||
uuid_t *uuid;
|
uuid_t *uuid;
|
||||||
@ -352,7 +392,7 @@ std::string getUuid()
|
|||||||
size_t len{0};
|
size_t len{0};
|
||||||
uuid_export(uuid, UUID_FMT_BIN, &str, &len);
|
uuid_export(uuid, UUID_FMT_BIN, &str, &len);
|
||||||
uuid_destroy(uuid);
|
uuid_destroy(uuid);
|
||||||
std::string ret{binaryStringToHex((const unsigned char *)str, len)};
|
auto ret = createUuidString(str, len, lowercase);
|
||||||
free(str);
|
free(str);
|
||||||
return ret;
|
return ret;
|
||||||
#elif defined __FreeBSD__ || defined __OpenBSD__
|
#elif defined __FreeBSD__ || defined __OpenBSD__
|
||||||
@ -370,7 +410,7 @@ std::string getUuid()
|
|||||||
uuid_enc_be(binstr, uuid);
|
uuid_enc_be(binstr, uuid);
|
||||||
#endif /* _BYTE_ORDER == _LITTLE_ENDIAN */
|
#endif /* _BYTE_ORDER == _LITTLE_ENDIAN */
|
||||||
delete uuid;
|
delete uuid;
|
||||||
std::string ret{binaryStringToHex((const unsigned char *)binstr, 16)};
|
auto ret = createUuidString(binstr, 16, lowercase);
|
||||||
free(binstr);
|
free(binstr);
|
||||||
return ret;
|
return ret;
|
||||||
#elif defined _WIN32
|
#elif defined _WIN32
|
||||||
@ -379,7 +419,7 @@ std::string getUuid()
|
|||||||
char tempStr[100];
|
char tempStr[100];
|
||||||
auto len = snprintf(tempStr,
|
auto len = snprintf(tempStr,
|
||||||
sizeof(tempStr),
|
sizeof(tempStr),
|
||||||
"%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
|
"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||||
uu.Data1,
|
uu.Data1,
|
||||||
uu.Data2,
|
uu.Data2,
|
||||||
uu.Data3,
|
uu.Data3,
|
||||||
@ -395,7 +435,8 @@ std::string getUuid()
|
|||||||
#else
|
#else
|
||||||
uuid_t uu;
|
uuid_t uu;
|
||||||
uuid_generate(uu);
|
uuid_generate(uu);
|
||||||
return binaryStringToHex(uu, 16);
|
auto uuid = createUuidString((const char *)uu, 16, lowercase);
|
||||||
|
return uuid;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,9 @@ set(UNITTEST_SOURCES
|
|||||||
unittests/StringOpsTest.cc
|
unittests/StringOpsTest.cc
|
||||||
unittests/ControllerCreationTest.cc
|
unittests/ControllerCreationTest.cc
|
||||||
unittests/MultiPartParserTest.cc
|
unittests/MultiPartParserTest.cc
|
||||||
unittests/SlashRemoverTest.cc)
|
unittests/SlashRemoverTest.cc
|
||||||
|
unittests/UuidUnittest.cc
|
||||||
|
)
|
||||||
|
|
||||||
if(DROGON_CXX_STANDARD GREATER_EQUAL 20 AND HAS_COROUTINE)
|
if(DROGON_CXX_STANDARD GREATER_EQUAL 20 AND HAS_COROUTINE)
|
||||||
set(UNITTEST_SOURCES ${UNITTEST_SOURCES} unittests/CoroutineTest.cc)
|
set(UNITTEST_SOURCES ${UNITTEST_SOURCES} unittests/CoroutineTest.cc)
|
||||||
|
17
lib/tests/unittests/UuidUnittest.cc
Normal file
17
lib/tests/unittests/UuidUnittest.cc
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#include <string_view>
|
||||||
|
#include <drogon/utils/Utilities.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <drogon/drogon_test.h>
|
||||||
|
|
||||||
|
DROGON_TEST(UuidTest)
|
||||||
|
{
|
||||||
|
auto uuid = drogon::utils::getUuid();
|
||||||
|
|
||||||
|
std::cout << "uuid: " << uuid << std::endl;
|
||||||
|
|
||||||
|
CHECK(uuid[8] == '-');
|
||||||
|
CHECK(uuid[13] == '-');
|
||||||
|
CHECK(uuid[18] == '-');
|
||||||
|
CHECK(uuid[23] == '-');
|
||||||
|
CHECK(uuid.size() == 36);
|
||||||
|
}
|
@ -167,7 +167,6 @@ class BaseBuilder
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
#ifdef __cpp_if_constexpr
|
|
||||||
static ResultType convert_result(const Result &r)
|
static ResultType convert_result(const Result &r)
|
||||||
{
|
{
|
||||||
if constexpr (SelectAll)
|
if constexpr (SelectAll)
|
||||||
@ -198,48 +197,6 @@ class BaseBuilder
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
template <bool SA = SelectAll,
|
|
||||||
bool SI = Single,
|
|
||||||
std::enable_if_t<SA, std::nullptr_t> = nullptr,
|
|
||||||
std::enable_if_t<SI, std::nullptr_t> = nullptr>
|
|
||||||
static inline T convert_result(const Result &r)
|
|
||||||
{
|
|
||||||
return T(r[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <bool SA = SelectAll,
|
|
||||||
bool SI = Single,
|
|
||||||
std::enable_if_t<SA, std::nullptr_t> = nullptr,
|
|
||||||
std::enable_if_t<!SI, std::nullptr_t> = nullptr>
|
|
||||||
static inline std::vector<T> convert_result(const Result &r)
|
|
||||||
{
|
|
||||||
std::vector<T> ret;
|
|
||||||
for (const Row &row : r)
|
|
||||||
{
|
|
||||||
ret.template emplace_back(T(row));
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <bool SA = SelectAll,
|
|
||||||
bool SI = Single,
|
|
||||||
std::enable_if_t<!SA, std::nullptr_t> = nullptr,
|
|
||||||
std::enable_if_t<SI, std::nullptr_t> = nullptr>
|
|
||||||
static inline Row convert_result(const Result &r)
|
|
||||||
{
|
|
||||||
return r[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
template <bool SA = SelectAll,
|
|
||||||
bool SI = Single,
|
|
||||||
std::enable_if_t<!SA, std::nullptr_t> = nullptr,
|
|
||||||
std::enable_if_t<!SI, std::nullptr_t> = nullptr>
|
|
||||||
static inline Result convert_result(const Result &r)
|
|
||||||
{
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
inline ResultType execSync(const DbClientPtr &client)
|
inline ResultType execSync(const DbClientPtr &client)
|
||||||
{
|
{
|
||||||
|
@ -80,13 +80,12 @@ class CoroMapper : public Mapper<T>
|
|||||||
|
|
||||||
inline internal::MapperAwaiter<T> findByPrimaryKey(const TraitsPKType &key)
|
inline internal::MapperAwaiter<T> findByPrimaryKey(const TraitsPKType &key)
|
||||||
{
|
{
|
||||||
if constexpr (!std::is_same<typename T::PrimaryKeyType, void>::value)
|
if constexpr (!std::is_same_v<typename T::PrimaryKeyType, void>)
|
||||||
{
|
{
|
||||||
auto lb = [this, key](SingleRowCallback &&callback,
|
auto lb = [this, key](SingleRowCallback &&callback,
|
||||||
ExceptPtrCallback &&errCallback) mutable {
|
ExceptPtrCallback &&errCallback) mutable {
|
||||||
static_assert(
|
static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
|
||||||
!std::is_same<typename T::PrimaryKeyType, void>::value,
|
"No primary key in the table!");
|
||||||
"No primary key in the table!");
|
|
||||||
static_assert(
|
static_assert(
|
||||||
internal::has_sqlForFindingByPrimaryKey<T>::value,
|
internal::has_sqlForFindingByPrimaryKey<T>::value,
|
||||||
"No function member named sqlForFindingByPrimaryKey, "
|
"No function member named sqlForFindingByPrimaryKey, "
|
||||||
@ -417,9 +416,8 @@ class CoroMapper : public Mapper<T>
|
|||||||
auto lb = [this, obj](CountCallback &&callback,
|
auto lb = [this, obj](CountCallback &&callback,
|
||||||
ExceptPtrCallback &&errCallback) {
|
ExceptPtrCallback &&errCallback) {
|
||||||
this->clear();
|
this->clear();
|
||||||
static_assert(
|
static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
|
||||||
!std::is_same<typename T::PrimaryKeyType, void>::value,
|
"No primary key in the table!");
|
||||||
"No primary key in the table!");
|
|
||||||
std::string sql = "update ";
|
std::string sql = "update ";
|
||||||
sql += T::tableName;
|
sql += T::tableName;
|
||||||
sql += " set ";
|
sql += " set ";
|
||||||
@ -530,9 +528,8 @@ class CoroMapper : public Mapper<T>
|
|||||||
auto lb = [this, obj](CountCallback &&callback,
|
auto lb = [this, obj](CountCallback &&callback,
|
||||||
ExceptPtrCallback &&errCallback) {
|
ExceptPtrCallback &&errCallback) {
|
||||||
this->clear();
|
this->clear();
|
||||||
static_assert(
|
static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
|
||||||
!std::is_same<typename T::PrimaryKeyType, void>::value,
|
"No primary key in the table!");
|
||||||
"No primary key in the table!");
|
|
||||||
std::string sql = "delete from ";
|
std::string sql = "delete from ";
|
||||||
sql += T::tableName;
|
sql += T::tableName;
|
||||||
sql += " ";
|
sql += " ";
|
||||||
@ -555,9 +552,8 @@ class CoroMapper : public Mapper<T>
|
|||||||
auto lb = [this, criteria](CountCallback &&callback,
|
auto lb = [this, criteria](CountCallback &&callback,
|
||||||
ExceptPtrCallback &&errCallback) {
|
ExceptPtrCallback &&errCallback) {
|
||||||
this->clear();
|
this->clear();
|
||||||
static_assert(
|
static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
|
||||||
!std::is_same<typename T::PrimaryKeyType, void>::value,
|
"No primary key in the table!");
|
||||||
"No primary key in the table!");
|
|
||||||
std::string sql = "delete from ";
|
std::string sql = "delete from ";
|
||||||
sql += T::tableName;
|
sql += T::tableName;
|
||||||
|
|
||||||
@ -584,7 +580,7 @@ class CoroMapper : public Mapper<T>
|
|||||||
inline internal::MapperAwaiter<size_t> deleteByPrimaryKey(
|
inline internal::MapperAwaiter<size_t> deleteByPrimaryKey(
|
||||||
const TraitsPKType &key)
|
const TraitsPKType &key)
|
||||||
{
|
{
|
||||||
static_assert(!std::is_same<typename T::PrimaryKeyType, void>::value,
|
static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
|
||||||
"No primary key in the table!");
|
"No primary key in the table!");
|
||||||
static_assert(
|
static_assert(
|
||||||
internal::has_sqlForDeletingByPrimaryKey<T>::value,
|
internal::has_sqlForDeletingByPrimaryKey<T>::value,
|
||||||
|
@ -110,9 +110,10 @@ struct FunctionTraits<ReturnType (*)(Arguments...)>
|
|||||||
|
|
||||||
static const std::size_t arity = sizeof...(Arguments);
|
static const std::size_t arity = sizeof...(Arguments);
|
||||||
|
|
||||||
// static const bool isSqlCallback = false;
|
|
||||||
static const bool isSqlCallback = true;
|
static const bool isSqlCallback = true;
|
||||||
static const bool isStepResultCallback = true;
|
static const bool isStepResultCallback = true;
|
||||||
|
static const bool isExceptCallback = false;
|
||||||
|
static const bool isPtr = false;
|
||||||
};
|
};
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace orm
|
} // namespace orm
|
||||||
|
@ -62,8 +62,7 @@ struct has_sqlForFindingByPrimaryKey
|
|||||||
static no test(...);
|
static no test(...);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static constexpr bool value =
|
static constexpr bool value = std::is_same_v<decltype(test<T>(0)), yes>;
|
||||||
std::is_same<decltype(test<T>(0)), yes>::value;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -81,8 +80,7 @@ struct has_sqlForDeletingByPrimaryKey
|
|||||||
static no test(...);
|
static no test(...);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static constexpr bool value =
|
static constexpr bool value = std::is_same_v<decltype(test<T>(0)), yes>;
|
||||||
std::is_same<decltype(test<T>(0)), yes>::value;
|
|
||||||
};
|
};
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
@ -185,7 +183,7 @@ class Mapper
|
|||||||
using CountCallback = std::function<void(const size_t)>;
|
using CountCallback = std::function<void(const size_t)>;
|
||||||
|
|
||||||
using TraitsPKType = typename internal::
|
using TraitsPKType = typename internal::
|
||||||
Traits<T, !std::is_same<typename T::PrimaryKeyType, void>::value>::type;
|
Traits<T, !std::is_same_v<typename T::PrimaryKeyType, void>>::type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Find a record by the primary key.
|
* @brief Find a record by the primary key.
|
||||||
@ -196,53 +194,48 @@ class Mapper
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
template <typename U = T>
|
template <typename U = T>
|
||||||
inline typename std::enable_if<
|
inline T findByPrimaryKey(const TraitsPKType &key) noexcept(false)
|
||||||
!std::is_same<typename U::PrimaryKeyType, void>::value,
|
|
||||||
T>::type
|
|
||||||
findByPrimaryKey(const TraitsPKType &key) noexcept(false)
|
|
||||||
{
|
{
|
||||||
static_assert(!std::is_same<typename T::PrimaryKeyType, void>::value,
|
if constexpr (!std::is_same_v<typename U::PrimaryKeyType, void>)
|
||||||
"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 findOne(Criteria(T::primaryKeyName, key));
|
|
||||||
std::string sql = T::sqlForFindingByPrimaryKey();
|
|
||||||
if (forUpdate_)
|
|
||||||
{
|
{
|
||||||
sql += " for update";
|
static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
|
||||||
|
"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 findOne(Criteria(T::primaryKeyName, key));
|
||||||
|
std::string sql = T::sqlForFindingByPrimaryKey();
|
||||||
|
if (forUpdate_)
|
||||||
|
{
|
||||||
|
sql += " for update";
|
||||||
|
}
|
||||||
|
clear();
|
||||||
|
Result r(nullptr);
|
||||||
|
{
|
||||||
|
auto binder = *client_ << std::move(sql);
|
||||||
|
outputPrimeryKeyToBinder(key, binder);
|
||||||
|
binder << Mode::Blocking;
|
||||||
|
binder >> [&r](const Result &result) { r = result; };
|
||||||
|
binder.exec(); // exec may be throw exception;
|
||||||
|
}
|
||||||
|
if (r.size() == 0)
|
||||||
|
{
|
||||||
|
throw UnexpectedRows("0 rows found");
|
||||||
|
}
|
||||||
|
else if (r.size() > 1)
|
||||||
|
{
|
||||||
|
throw UnexpectedRows("Found more than one row");
|
||||||
|
}
|
||||||
|
auto row = r[0];
|
||||||
|
return T(row);
|
||||||
}
|
}
|
||||||
clear();
|
else
|
||||||
Result r(nullptr);
|
|
||||||
{
|
{
|
||||||
auto binder = *client_ << std::move(sql);
|
LOG_FATAL << "The table must have a primary key";
|
||||||
outputPrimeryKeyToBinder(key, binder);
|
abort();
|
||||||
binder << Mode::Blocking;
|
|
||||||
binder >> [&r](const Result &result) { r = result; };
|
|
||||||
binder.exec(); // exec may be throw exception;
|
|
||||||
}
|
}
|
||||||
if (r.size() == 0)
|
|
||||||
{
|
|
||||||
throw UnexpectedRows("0 rows found");
|
|
||||||
}
|
|
||||||
else if (r.size() > 1)
|
|
||||||
{
|
|
||||||
throw UnexpectedRows("Found more than one row");
|
|
||||||
}
|
|
||||||
auto row = r[0];
|
|
||||||
return T(row);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename U = T>
|
|
||||||
inline typename std::enable_if<
|
|
||||||
std::is_same<typename U::PrimaryKeyType, void>::value,
|
|
||||||
T>::type
|
|
||||||
findByPrimaryKey(const TraitsPKType &key) noexcept(false)
|
|
||||||
{
|
|
||||||
LOG_FATAL << "The table must have a primary key";
|
|
||||||
abort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -253,56 +246,49 @@ class Mapper
|
|||||||
* @param ecb Is called when an error occurs or a record cannot be found.
|
* @param ecb Is called when an error occurs or a record cannot be found.
|
||||||
*/
|
*/
|
||||||
template <typename U = T>
|
template <typename U = T>
|
||||||
inline typename std::enable_if<
|
inline void findByPrimaryKey(const TraitsPKType &key,
|
||||||
!std::is_same<typename U::PrimaryKeyType, void>::value,
|
const SingleRowCallback &rcb,
|
||||||
void>::type
|
const ExceptionCallback &ecb) noexcept
|
||||||
findByPrimaryKey(const TraitsPKType &key,
|
|
||||||
const SingleRowCallback &rcb,
|
|
||||||
const ExceptionCallback &ecb) noexcept
|
|
||||||
{
|
{
|
||||||
static_assert(!std::is_same<typename T::PrimaryKeyType, void>::value,
|
if constexpr (!std::is_same_v<typename U::PrimaryKeyType, void>)
|
||||||
"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");
|
|
||||||
// findOne(Criteria(T::primaryKeyName, key), rcb, ecb);
|
|
||||||
std::string sql = T::sqlForFindingByPrimaryKey();
|
|
||||||
if (forUpdate_)
|
|
||||||
{
|
{
|
||||||
sql += " for update";
|
static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
|
||||||
|
"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");
|
||||||
|
// findOne(Criteria(T::primaryKeyName, key), rcb, ecb);
|
||||||
|
std::string sql = T::sqlForFindingByPrimaryKey();
|
||||||
|
if (forUpdate_)
|
||||||
|
{
|
||||||
|
sql += " for update";
|
||||||
|
}
|
||||||
|
clear();
|
||||||
|
auto binder = *client_ << std::move(sql);
|
||||||
|
outputPrimeryKeyToBinder(key, binder);
|
||||||
|
binder >> [ecb, rcb](const Result &r) {
|
||||||
|
if (r.size() == 0)
|
||||||
|
{
|
||||||
|
ecb(UnexpectedRows("0 rows found"));
|
||||||
|
}
|
||||||
|
else if (r.size() > 1)
|
||||||
|
{
|
||||||
|
ecb(UnexpectedRows("Found more than one row"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rcb(T(r[0]));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
binder >> ecb;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_FATAL << "The table must have a primary key";
|
||||||
|
abort();
|
||||||
}
|
}
|
||||||
clear();
|
|
||||||
auto binder = *client_ << std::move(sql);
|
|
||||||
outputPrimeryKeyToBinder(key, binder);
|
|
||||||
binder >> [ecb, rcb](const Result &r) {
|
|
||||||
if (r.size() == 0)
|
|
||||||
{
|
|
||||||
ecb(UnexpectedRows("0 rows found"));
|
|
||||||
}
|
|
||||||
else if (r.size() > 1)
|
|
||||||
{
|
|
||||||
ecb(UnexpectedRows("Found more than one row"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
rcb(T(r[0]));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
binder >> ecb;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename U = T>
|
|
||||||
inline typename std::enable_if<
|
|
||||||
std::is_same<typename U::PrimaryKeyType, void>::value,
|
|
||||||
void>::type
|
|
||||||
findByPrimaryKey(const TraitsPKType &key,
|
|
||||||
const SingleRowCallback &rcb,
|
|
||||||
const ExceptionCallback &ecb) noexcept
|
|
||||||
{
|
|
||||||
LOG_FATAL << "The table must have a primary key";
|
|
||||||
abort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -315,60 +301,56 @@ class Mapper
|
|||||||
* user calls the get() method of the future object.
|
* user calls the get() method of the future object.
|
||||||
*/
|
*/
|
||||||
template <typename U = T>
|
template <typename U = T>
|
||||||
inline typename std::enable_if<
|
inline std::future<T> findFutureByPrimaryKey(
|
||||||
!std::is_same<typename U::PrimaryKeyType, void>::value,
|
const TraitsPKType &key) noexcept
|
||||||
std::future<T>>::type
|
|
||||||
findFutureByPrimaryKey(const TraitsPKType &key) noexcept
|
|
||||||
{
|
{
|
||||||
static_assert(!std::is_same<typename T::PrimaryKeyType, void>::value,
|
if constexpr (!std::is_same_v<typename U::PrimaryKeyType, void>)
|
||||||
"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 (forUpdate_)
|
|
||||||
{
|
{
|
||||||
sql += " for update";
|
static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
|
||||||
|
"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 (forUpdate_)
|
||||||
|
{
|
||||||
|
sql += " for update";
|
||||||
|
}
|
||||||
|
clear();
|
||||||
|
auto binder = *client_ << std::move(sql);
|
||||||
|
outputPrimeryKeyToBinder(key, binder);
|
||||||
|
|
||||||
|
std::shared_ptr<std::promise<T>> prom =
|
||||||
|
std::make_shared<std::promise<T>>();
|
||||||
|
binder >> [prom](const Result &r) {
|
||||||
|
if (r.size() == 0)
|
||||||
|
{
|
||||||
|
prom->set_exception(std::make_exception_ptr(
|
||||||
|
UnexpectedRows("0 rows found")));
|
||||||
|
}
|
||||||
|
else if (r.size() > 1)
|
||||||
|
{
|
||||||
|
prom->set_exception(std::make_exception_ptr(
|
||||||
|
UnexpectedRows("Found more than one row")));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
prom->set_value(T(r[0]));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
binder >>
|
||||||
|
[prom](const std::exception_ptr &e) { prom->set_exception(e); };
|
||||||
|
binder.exec();
|
||||||
|
return prom->get_future();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_FATAL << "The table must have a primary key";
|
||||||
|
abort();
|
||||||
}
|
}
|
||||||
clear();
|
|
||||||
auto binder = *client_ << std::move(sql);
|
|
||||||
outputPrimeryKeyToBinder(key, binder);
|
|
||||||
|
|
||||||
std::shared_ptr<std::promise<T>> prom =
|
|
||||||
std::make_shared<std::promise<T>>();
|
|
||||||
binder >> [prom](const Result &r) {
|
|
||||||
if (r.size() == 0)
|
|
||||||
{
|
|
||||||
prom->set_exception(
|
|
||||||
std::make_exception_ptr(UnexpectedRows("0 rows found")));
|
|
||||||
}
|
|
||||||
else if (r.size() > 1)
|
|
||||||
{
|
|
||||||
prom->set_exception(std::make_exception_ptr(
|
|
||||||
UnexpectedRows("Found more than one row")));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
prom->set_value(T(r[0]));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
binder >>
|
|
||||||
[prom](const std::exception_ptr &e) { prom->set_exception(e); };
|
|
||||||
binder.exec();
|
|
||||||
return prom->get_future();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename U = T>
|
|
||||||
inline typename std::enable_if<
|
|
||||||
std::is_same<typename U::PrimaryKeyType, void>::value,
|
|
||||||
std::future<U>>::type
|
|
||||||
findFutureByPrimaryKey(const TraitsPKType &key) noexcept
|
|
||||||
{
|
|
||||||
LOG_FATAL << "The table must have a primary key";
|
|
||||||
abort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -701,67 +683,57 @@ class Mapper
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename PKType = decltype(T::primaryKeyName)>
|
template <typename PKType = decltype(T::primaryKeyName)>
|
||||||
typename std::enable_if<std::is_same<const std::string, PKType>::value,
|
void makePrimaryKeyCriteria(std::string &sql)
|
||||||
void>::type
|
|
||||||
makePrimaryKeyCriteria(std::string &sql)
|
|
||||||
{
|
{
|
||||||
sql += " where ";
|
if constexpr (std::is_same_v<const std::string, PKType>)
|
||||||
sql += T::primaryKeyName;
|
|
||||||
sql += " = $?";
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename PKType = decltype(T::primaryKeyName)>
|
|
||||||
typename std::enable_if<
|
|
||||||
std::is_same<const std::vector<std::string>, PKType>::value,
|
|
||||||
void>::type
|
|
||||||
makePrimaryKeyCriteria(std::string &sql)
|
|
||||||
{
|
|
||||||
sql += " where ";
|
|
||||||
for (size_t i = 0; i < T::primaryKeyName.size(); ++i)
|
|
||||||
{
|
{
|
||||||
sql += T::primaryKeyName[i];
|
sql += " where ";
|
||||||
|
sql += T::primaryKeyName;
|
||||||
sql += " = $?";
|
sql += " = $?";
|
||||||
if (i < (T::primaryKeyName.size() - 1))
|
}
|
||||||
|
else if constexpr (std::is_same_v<const std::vector<std::string>,
|
||||||
|
PKType>)
|
||||||
|
{
|
||||||
|
sql += " where ";
|
||||||
|
for (size_t i = 0; i < T::primaryKeyName.size(); ++i)
|
||||||
{
|
{
|
||||||
sql += " and ";
|
sql += T::primaryKeyName[i];
|
||||||
|
sql += " = $?";
|
||||||
|
if (i < (T::primaryKeyName.size() - 1))
|
||||||
|
{
|
||||||
|
sql += " and ";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename PKType = decltype(T::primaryKeyName)>
|
template <typename PKType = decltype(T::primaryKeyName)>
|
||||||
typename std::enable_if<std::is_same<const std::string, PKType>::value,
|
void outputPrimeryKeyToBinder(const TraitsPKType &pk,
|
||||||
void>::type
|
internal::SqlBinder &binder)
|
||||||
outputPrimeryKeyToBinder(const TraitsPKType &pk,
|
|
||||||
internal::SqlBinder &binder)
|
|
||||||
{
|
{
|
||||||
binder << pk;
|
if constexpr (std::is_same_v<const std::string, PKType>)
|
||||||
}
|
{
|
||||||
|
binder << pk;
|
||||||
template <typename PKType = decltype(T::primaryKeyName)>
|
}
|
||||||
typename std::enable_if<
|
else if constexpr (std::is_same_v<const std::vector<std::string>,
|
||||||
std::is_same<const std::vector<std::string>, PKType>::value,
|
PKType>)
|
||||||
void>::type
|
{
|
||||||
outputPrimeryKeyToBinder(const TraitsPKType &pk,
|
tupleToBinder<typename T::PrimaryKeyType>(pk, binder);
|
||||||
internal::SqlBinder &binder)
|
}
|
||||||
{
|
|
||||||
tupleToBinder<typename T::PrimaryKeyType>(pk, binder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TP, ssize_t N = std::tuple_size<TP>::value>
|
template <typename TP, ssize_t N = std::tuple_size<TP>::value>
|
||||||
typename std::enable_if<(N > 1), void>::type tupleToBinder(
|
void tupleToBinder(const TP &t, internal::SqlBinder &binder)
|
||||||
const TP &t,
|
|
||||||
internal::SqlBinder &binder)
|
|
||||||
{
|
{
|
||||||
tupleToBinder<TP, N - 1>(t, binder);
|
if constexpr (N > 1)
|
||||||
binder << std::get<N - 1>(t);
|
{
|
||||||
}
|
tupleToBinder<TP, N - 1>(t, binder);
|
||||||
|
binder << std::get<N - 1>(t);
|
||||||
template <typename TP, ssize_t N = std::tuple_size<TP>::value>
|
}
|
||||||
typename std::enable_if<(N == 1), void>::type tupleToBinder(
|
else if constexpr (N == 1)
|
||||||
const TP &t,
|
{
|
||||||
internal::SqlBinder &binder)
|
binder << std::get<0>(t);
|
||||||
{
|
}
|
||||||
binder << std::get<0>(t);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string replaceSqlPlaceHolder(const std::string &sqlStr,
|
std::string replaceSqlPlaceHolder(const std::string &sqlStr,
|
||||||
@ -1321,7 +1293,7 @@ template <typename T>
|
|||||||
inline size_t Mapper<T>::update(const T &obj) noexcept(false)
|
inline size_t Mapper<T>::update(const T &obj) noexcept(false)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
static_assert(!std::is_same<typename T::PrimaryKeyType, void>::value,
|
static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
|
||||||
"No primary key in the table!");
|
"No primary key in the table!");
|
||||||
std::string sql = "update ";
|
std::string sql = "update ";
|
||||||
sql += T::tableName;
|
sql += T::tableName;
|
||||||
@ -1394,7 +1366,7 @@ inline void Mapper<T>::update(const T &obj,
|
|||||||
const ExceptionCallback &ecb) noexcept
|
const ExceptionCallback &ecb) noexcept
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
static_assert(!std::is_same<typename T::PrimaryKeyType, void>::value,
|
static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
|
||||||
"No primary key in the table!");
|
"No primary key in the table!");
|
||||||
std::string sql = "update ";
|
std::string sql = "update ";
|
||||||
sql += T::tableName;
|
sql += T::tableName;
|
||||||
@ -1457,7 +1429,7 @@ template <typename T>
|
|||||||
inline std::future<size_t> Mapper<T>::updateFuture(const T &obj) noexcept
|
inline std::future<size_t> Mapper<T>::updateFuture(const T &obj) noexcept
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
static_assert(!std::is_same<typename T::PrimaryKeyType, void>::value,
|
static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
|
||||||
"No primary key in the table!");
|
"No primary key in the table!");
|
||||||
std::string sql = "update ";
|
std::string sql = "update ";
|
||||||
sql += T::tableName;
|
sql += T::tableName;
|
||||||
@ -1529,7 +1501,7 @@ template <typename T>
|
|||||||
inline size_t Mapper<T>::deleteOne(const T &obj) noexcept(false)
|
inline size_t Mapper<T>::deleteOne(const T &obj) noexcept(false)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
static_assert(!std::is_same<typename T::PrimaryKeyType, void>::value,
|
static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
|
||||||
"No primary key in the table!");
|
"No primary key in the table!");
|
||||||
std::string sql = "delete from ";
|
std::string sql = "delete from ";
|
||||||
sql += T::tableName;
|
sql += T::tableName;
|
||||||
@ -1556,7 +1528,7 @@ inline void Mapper<T>::deleteOne(const T &obj,
|
|||||||
const ExceptionCallback &ecb) noexcept
|
const ExceptionCallback &ecb) noexcept
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
static_assert(!std::is_same<typename T::PrimaryKeyType, void>::value,
|
static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
|
||||||
"No primary key in the table!");
|
"No primary key in the table!");
|
||||||
std::string sql = "delete from ";
|
std::string sql = "delete from ";
|
||||||
sql += T::tableName;
|
sql += T::tableName;
|
||||||
@ -1575,7 +1547,7 @@ template <typename T>
|
|||||||
inline std::future<size_t> Mapper<T>::deleteFutureOne(const T &obj) noexcept
|
inline std::future<size_t> Mapper<T>::deleteFutureOne(const T &obj) noexcept
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
static_assert(!std::is_same<typename T::PrimaryKeyType, void>::value,
|
static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
|
||||||
"No primary key in the table!");
|
"No primary key in the table!");
|
||||||
std::string sql = "delete from ";
|
std::string sql = "delete from ";
|
||||||
sql += T::tableName;
|
sql += T::tableName;
|
||||||
@ -1599,7 +1571,7 @@ template <typename T>
|
|||||||
inline size_t Mapper<T>::deleteBy(const Criteria &criteria) noexcept(false)
|
inline size_t Mapper<T>::deleteBy(const Criteria &criteria) noexcept(false)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
static_assert(!std::is_same<typename T::PrimaryKeyType, void>::value,
|
static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
|
||||||
"No primary key in the table!");
|
"No primary key in the table!");
|
||||||
std::string sql = "delete from ";
|
std::string sql = "delete from ";
|
||||||
sql += T::tableName;
|
sql += T::tableName;
|
||||||
@ -1631,7 +1603,7 @@ inline void Mapper<T>::deleteBy(const Criteria &criteria,
|
|||||||
const ExceptionCallback &ecb) noexcept
|
const ExceptionCallback &ecb) noexcept
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
static_assert(!std::is_same<typename T::PrimaryKeyType, void>::value,
|
static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
|
||||||
"No primary key in the table!");
|
"No primary key in the table!");
|
||||||
std::string sql = "delete from ";
|
std::string sql = "delete from ";
|
||||||
sql += T::tableName;
|
sql += T::tableName;
|
||||||
@ -1657,7 +1629,7 @@ inline std::future<size_t> Mapper<T>::deleteFutureBy(
|
|||||||
const Criteria &criteria) noexcept
|
const Criteria &criteria) noexcept
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
static_assert(!std::is_same<typename T::PrimaryKeyType, void>::value,
|
static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
|
||||||
"No primary key in the table!");
|
"No primary key in the table!");
|
||||||
std::string sql = "delete from ";
|
std::string sql = "delete from ";
|
||||||
sql += T::tableName;
|
sql += T::tableName;
|
||||||
@ -1797,7 +1769,7 @@ template <typename T>
|
|||||||
inline size_t Mapper<T>::deleteByPrimaryKey(
|
inline size_t Mapper<T>::deleteByPrimaryKey(
|
||||||
const typename Mapper<T>::TraitsPKType &key) noexcept(false)
|
const typename Mapper<T>::TraitsPKType &key) noexcept(false)
|
||||||
{
|
{
|
||||||
static_assert(!std::is_same<typename T::PrimaryKeyType, void>::value,
|
static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
|
||||||
"No primary key in the table!");
|
"No primary key in the table!");
|
||||||
static_assert(internal::has_sqlForDeletingByPrimaryKey<T>::value,
|
static_assert(internal::has_sqlForDeletingByPrimaryKey<T>::value,
|
||||||
"No function member named sqlForDeletingByPrimaryKey, please "
|
"No function member named sqlForDeletingByPrimaryKey, please "
|
||||||
@ -1821,7 +1793,7 @@ inline void Mapper<T>::deleteByPrimaryKey(
|
|||||||
const CountCallback &rcb,
|
const CountCallback &rcb,
|
||||||
const ExceptionCallback &ecb) noexcept
|
const ExceptionCallback &ecb) noexcept
|
||||||
{
|
{
|
||||||
static_assert(!std::is_same<typename T::PrimaryKeyType, void>::value,
|
static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
|
||||||
"No primary key in the table!");
|
"No primary key in the table!");
|
||||||
static_assert(internal::has_sqlForDeletingByPrimaryKey<T>::value,
|
static_assert(internal::has_sqlForDeletingByPrimaryKey<T>::value,
|
||||||
"No function member named sqlForDeletingByPrimaryKey, please "
|
"No function member named sqlForDeletingByPrimaryKey, please "
|
||||||
@ -1839,7 +1811,7 @@ template <typename T>
|
|||||||
inline std::future<size_t> Mapper<T>::deleteFutureByPrimaryKey(
|
inline std::future<size_t> Mapper<T>::deleteFutureByPrimaryKey(
|
||||||
const typename Mapper<T>::TraitsPKType &key) noexcept
|
const typename Mapper<T>::TraitsPKType &key) noexcept
|
||||||
{
|
{
|
||||||
static_assert(!std::is_same<typename T::PrimaryKeyType, void>::value,
|
static_assert(!std::is_same_v<typename T::PrimaryKeyType, void>,
|
||||||
"No primary key in the table!");
|
"No primary key in the table!");
|
||||||
static_assert(internal::has_sqlForDeletingByPrimaryKey<T>::value,
|
static_assert(internal::has_sqlForDeletingByPrimaryKey<T>::value,
|
||||||
"No function member named sqlForDeletingByPrimaryKey, please "
|
"No function member named sqlForDeletingByPrimaryKey, please "
|
||||||
|
@ -203,83 +203,78 @@ class CallbackHolder : public CallbackHolderBase
|
|||||||
static const size_t argumentCount = traits::arity;
|
static const size_t argumentCount = traits::arity;
|
||||||
|
|
||||||
template <bool isStep = traits::isStepResultCallback>
|
template <bool isStep = traits::isStepResultCallback>
|
||||||
typename std::enable_if<isStep, void>::type run(const Result &result)
|
void run(const Result &result)
|
||||||
{
|
{
|
||||||
if (result.empty())
|
if constexpr (isStep)
|
||||||
{
|
{
|
||||||
|
if (result.empty())
|
||||||
|
{
|
||||||
|
run(nullptr, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (auto const &row : result)
|
||||||
|
{
|
||||||
|
run(&row, false);
|
||||||
|
}
|
||||||
run(nullptr, true);
|
run(nullptr, true);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
for (auto const &row : result)
|
else
|
||||||
{
|
{
|
||||||
run(&row, false);
|
static_assert(argumentCount == 0,
|
||||||
|
"Your sql callback function type is wrong!");
|
||||||
|
function_(result);
|
||||||
}
|
}
|
||||||
run(nullptr, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <bool isStep = traits::isStepResultCallback>
|
|
||||||
typename std::enable_if<!isStep, void>::type run(const Result &result)
|
|
||||||
{
|
|
||||||
static_assert(argumentCount == 0,
|
|
||||||
"Your sql callback function type is wrong!");
|
|
||||||
function_(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Values, std::size_t Boundary = argumentCount>
|
template <typename... Values, std::size_t Boundary = argumentCount>
|
||||||
typename std::enable_if<(sizeof...(Values) < Boundary), void>::type run(
|
void run(const Row *const row, bool isNull, Values &&...values)
|
||||||
const Row *const row,
|
|
||||||
bool isNull,
|
|
||||||
Values &&...values)
|
|
||||||
{
|
{
|
||||||
// call this function recursively until parameter's count equals to the
|
if constexpr (sizeof...(Values) < Boundary)
|
||||||
// count of target function parameters
|
|
||||||
static_assert(
|
|
||||||
CallbackArgTypeTraits<NthArgumentType<sizeof...(Values)>>::isValid,
|
|
||||||
"your sql callback function argument type must be value "
|
|
||||||
"type or "
|
|
||||||
"const "
|
|
||||||
"left-reference type");
|
|
||||||
using ValueType =
|
|
||||||
typename std::remove_cv<typename std::remove_reference<
|
|
||||||
NthArgumentType<sizeof...(Values)>>::type>::type;
|
|
||||||
ValueType value = ValueType();
|
|
||||||
if (row && row->size() > sizeof...(Values))
|
|
||||||
{
|
{
|
||||||
// if(!VectorTypeTraits<ValueType>::isVector)
|
// call this function recursively until parameter's count equals to
|
||||||
// value = (*row)[sizeof...(Values)].as<ValueType>();
|
// the count of target function parameters
|
||||||
// else
|
static_assert(
|
||||||
// ; // value =
|
CallbackArgTypeTraits<
|
||||||
// (*row)[sizeof...(Values)].asArray<VectorTypeTraits<ValueType>::ItemsType>();
|
NthArgumentType<sizeof...(Values)>>::isValid,
|
||||||
value =
|
"your sql callback function argument type must be value "
|
||||||
makeValue<ValueType>((*row)[(Row::SizeType)sizeof...(Values)]);
|
"type or "
|
||||||
|
"const "
|
||||||
|
"left-reference type");
|
||||||
|
using ValueType =
|
||||||
|
typename std::remove_cv<typename std::remove_reference<
|
||||||
|
NthArgumentType<sizeof...(Values)>>::type>::type;
|
||||||
|
ValueType value = ValueType();
|
||||||
|
if (row && row->size() > sizeof...(Values))
|
||||||
|
{
|
||||||
|
// if(!VectorTypeTraits<ValueType>::isVector)
|
||||||
|
// value = (*row)[sizeof...(Values)].as<ValueType>();
|
||||||
|
// else
|
||||||
|
// ; // value =
|
||||||
|
// (*row)[sizeof...(Values)].asArray<VectorTypeTraits<ValueType>::ItemsType>();
|
||||||
|
value = makeValue<ValueType>(
|
||||||
|
(*row)[(Row::SizeType)sizeof...(Values)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
run(row, isNull, std::forward<Values>(values)..., std::move(value));
|
||||||
|
}
|
||||||
|
else if constexpr (sizeof...(Values) == Boundary)
|
||||||
|
{
|
||||||
|
function_(isNull, std::move(values)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
run(row, isNull, std::forward<Values>(values)..., std::move(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename... Values, std::size_t Boundary = argumentCount>
|
|
||||||
typename std::enable_if<(sizeof...(Values) == Boundary), void>::type run(
|
|
||||||
const Row *const,
|
|
||||||
bool isNull,
|
|
||||||
Values &&...values)
|
|
||||||
{
|
|
||||||
function_(isNull, std::move(values)...);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ValueType>
|
template <typename ValueType>
|
||||||
typename std::enable_if<VectorTypeTraits<ValueType>::isVector,
|
ValueType makeValue(const Field &field)
|
||||||
ValueType>::type
|
|
||||||
makeValue(const Field &field)
|
|
||||||
{
|
{
|
||||||
return field.asArray<typename VectorTypeTraits<ValueType>::ItemsType>();
|
if constexpr (VectorTypeTraits<ValueType>::isVector)
|
||||||
}
|
{
|
||||||
|
return field
|
||||||
template <typename ValueType>
|
.asArray<typename VectorTypeTraits<ValueType>::ItemsType>();
|
||||||
typename std::enable_if<!VectorTypeTraits<ValueType>::isVector,
|
}
|
||||||
ValueType>::type
|
else
|
||||||
makeValue(const Field &field)
|
{
|
||||||
{
|
return field.as<ValueType>();
|
||||||
return field.as<ValueType>();
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -346,51 +341,38 @@ class DROGON_EXPORT SqlBinder : public trantor::NonCopyable
|
|||||||
template <typename CallbackType,
|
template <typename CallbackType,
|
||||||
typename traits =
|
typename traits =
|
||||||
FunctionTraits<typename std::decay<CallbackType>::type>>
|
FunctionTraits<typename std::decay<CallbackType>::type>>
|
||||||
typename std::enable_if<traits::isExceptCallback && traits::isPtr,
|
self &operator>>(CallbackType &&callback)
|
||||||
self>::type &
|
|
||||||
operator>>(CallbackType &&callback)
|
|
||||||
{
|
{
|
||||||
// LOG_DEBUG << "ptr callback";
|
if constexpr (traits::isExceptCallback)
|
||||||
isExceptionPtr_ = true;
|
{
|
||||||
exceptionPtrCallback_ = std::forward<CallbackType>(callback);
|
if constexpr (traits::isPtr)
|
||||||
return *this;
|
{
|
||||||
}
|
// LOG_DEBUG << "ptr callback";
|
||||||
|
isExceptionPtr_ = true;
|
||||||
template <typename CallbackType,
|
exceptionPtrCallback_ = std::forward<CallbackType>(callback);
|
||||||
typename traits =
|
return *this;
|
||||||
FunctionTraits<typename std::decay<CallbackType>::type>>
|
}
|
||||||
typename std::enable_if<traits::isExceptCallback && !traits::isPtr,
|
else
|
||||||
self>::type &
|
{
|
||||||
operator>>(CallbackType &&callback)
|
isExceptionPtr_ = false;
|
||||||
{
|
exceptionCallback_ = std::forward<CallbackType>(callback);
|
||||||
isExceptionPtr_ = false;
|
return *this;
|
||||||
exceptionCallback_ = std::forward<CallbackType>(callback);
|
}
|
||||||
return *this;
|
}
|
||||||
}
|
else if constexpr (traits::isSqlCallback)
|
||||||
|
{
|
||||||
template <typename CallbackType,
|
callbackHolder_ = std::shared_ptr<CallbackHolderBase>(
|
||||||
typename traits =
|
new CallbackHolder<typename std::decay<CallbackType>::type>(
|
||||||
FunctionTraits<typename std::decay<CallbackType>::type>>
|
std::forward<CallbackType>(callback)));
|
||||||
typename std::enable_if<traits::isSqlCallback, self>::type &operator>>(
|
return *this;
|
||||||
CallbackType &&callback)
|
}
|
||||||
{
|
|
||||||
callbackHolder_ = std::shared_ptr<CallbackHolderBase>(
|
|
||||||
new CallbackHolder<typename std::decay<CallbackType>::type>(
|
|
||||||
std::forward<CallbackType>(callback)));
|
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
typename std::enable_if<
|
self &operator<<(T &¶meter)
|
||||||
!std::is_same<typename std::remove_cv<
|
|
||||||
typename std::remove_reference<T>::type>::type,
|
|
||||||
trantor::Date>::value,
|
|
||||||
self &>::type
|
|
||||||
operator<<(T &¶meter)
|
|
||||||
{
|
{
|
||||||
|
using ParaType = std::remove_cv_t<std::remove_reference_t<T>>;
|
||||||
++parametersNumber_;
|
++parametersNumber_;
|
||||||
using ParaType = typename std::remove_cv<
|
|
||||||
typename std::remove_reference<T>::type>::type;
|
|
||||||
std::shared_ptr<void> obj = std::make_shared<ParaType>(parameter);
|
std::shared_ptr<void> obj = std::make_shared<ParaType>(parameter);
|
||||||
if (type_ == ClientType::PostgreSQL)
|
if (type_ == ClientType::PostgreSQL)
|
||||||
{
|
{
|
||||||
@ -482,12 +464,7 @@ class DROGON_EXPORT SqlBinder : public trantor::NonCopyable
|
|||||||
|
|
||||||
self &operator<<(std::string &&str);
|
self &operator<<(std::string &&str);
|
||||||
|
|
||||||
self &operator<<(trantor::Date &&date)
|
self &operator<<(trantor::Date date)
|
||||||
{
|
|
||||||
return operator<<(date.toDbStringLocal());
|
|
||||||
}
|
|
||||||
|
|
||||||
self &operator<<(const trantor::Date &date)
|
|
||||||
{
|
{
|
||||||
return operator<<(date.toDbStringLocal());
|
return operator<<(date.toDbStringLocal());
|
||||||
}
|
}
|
||||||
|
2
trantor
2
trantor
@ -1 +1 @@
|
|||||||
Subproject commit 624fc083076d7da88b1fb1dca1669ff48168a3ce
|
Subproject commit d596221dd13a27ae86a637dba82154d0c5f96331
|
Loading…
x
Reference in New Issue
Block a user