mirror of
https://github.com/drogonframework/drogon.git
synced 2025-08-29 00:02:44 -04:00
Add default value interface to sqlbinder for mysql and postgresql (#704)
This commit is contained in:
parent
4c577e6fa9
commit
6542236b20
@ -420,6 +420,7 @@ set(ORM_HEADERS
|
||||
orm_lib/inc/drogon/orm/ArrayParser.h
|
||||
orm_lib/inc/drogon/orm/Criteria.h
|
||||
orm_lib/inc/drogon/orm/DbClient.h
|
||||
orm_lib/inc/drogon/orm/DbTypes.h
|
||||
orm_lib/inc/drogon/orm/Exception.h
|
||||
orm_lib/inc/drogon/orm/Field.h
|
||||
orm_lib/inc/drogon/orm/FunctionTraits.h
|
||||
|
@ -147,5 +147,12 @@ std::string formattedString(const char *format, ...);
|
||||
*/
|
||||
int createPath(const std::string &path);
|
||||
|
||||
/// Replace all occurances of from to to inplace
|
||||
/**
|
||||
* @param from string to replace
|
||||
* @param to string to replace with
|
||||
*/
|
||||
void replaceAll(std::string &s, const std::string &from, const std::string &to);
|
||||
|
||||
} // namespace utils
|
||||
} // namespace drogon
|
||||
|
@ -1163,5 +1163,15 @@ std::string getMd5(const char *data, const size_t dataLen)
|
||||
#endif
|
||||
}
|
||||
|
||||
void replaceAll(std::string &s, const std::string &from, const std::string &to)
|
||||
{
|
||||
size_t pos = 0;
|
||||
while ((pos = s.find(from, pos)) != std::string::npos)
|
||||
{
|
||||
s.replace(pos, from.size(), to);
|
||||
pos += to.size();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace utils
|
||||
} // namespace drogon
|
||||
|
40
orm_lib/inc/drogon/orm/DbTypes.h
Normal file
40
orm_lib/inc/drogon/orm/DbTypes.h
Normal file
@ -0,0 +1,40 @@
|
||||
/**
|
||||
*
|
||||
* @file DbTypes.h
|
||||
* @author interfector18
|
||||
*
|
||||
* Copyright 2020, An Tao. All rights reserved.
|
||||
* https://github.com/an-tao/drogon
|
||||
* Use of this source code is governed by a MIT license
|
||||
* that can be found in the License file.
|
||||
*
|
||||
* Drogon
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace drogon
|
||||
{
|
||||
namespace orm
|
||||
{
|
||||
class DefaultValue
|
||||
{
|
||||
};
|
||||
|
||||
namespace internal
|
||||
{
|
||||
enum FieldType
|
||||
{
|
||||
MySqlTiny,
|
||||
MySqlShort,
|
||||
MySqlLong,
|
||||
MySqlLongLong,
|
||||
MySqlNull,
|
||||
MySqlString,
|
||||
DrogonDefaultValue,
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace orm
|
||||
} // namespace drogon
|
@ -13,6 +13,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <drogon/orm/DbTypes.h>
|
||||
#include <drogon/orm/Exception.h>
|
||||
#include <drogon/orm/Field.h>
|
||||
#include <drogon/orm/FunctionTraits.h>
|
||||
@ -432,6 +433,7 @@ class SqlBinder
|
||||
}
|
||||
self &operator<<(double f);
|
||||
self &operator<<(std::nullptr_t nullp);
|
||||
self &operator<<(DefaultValue dv);
|
||||
self &operator<<(const Mode &mode)
|
||||
{
|
||||
mode_ = mode;
|
||||
@ -466,7 +468,7 @@ class SqlBinder
|
||||
int getMysqlTypeBySize(size_t size);
|
||||
std::shared_ptr<std::string> sqlPtr_;
|
||||
const char *sqlViewPtr_;
|
||||
const size_t sqlViewLength_;
|
||||
size_t sqlViewLength_;
|
||||
DbClient &client_;
|
||||
size_t parametersNumber_{0};
|
||||
std::vector<const char *> parameters_;
|
||||
|
@ -15,8 +15,10 @@
|
||||
#include <drogon/config.h>
|
||||
#include <drogon/orm/DbClient.h>
|
||||
#include <drogon/orm/SqlBinder.h>
|
||||
#include <drogon/utils/Utilities.h>
|
||||
#include <future>
|
||||
#include <iostream>
|
||||
#include <regex>
|
||||
#include <stdio.h>
|
||||
#if USE_MYSQL
|
||||
#include <mysql.h>
|
||||
@ -144,9 +146,7 @@ SqlBinder &SqlBinder::operator<<(const std::string &str)
|
||||
}
|
||||
else if (type_ == ClientType::Mysql)
|
||||
{
|
||||
#if USE_MYSQL
|
||||
formats_.push_back(MYSQL_TYPE_STRING);
|
||||
#endif
|
||||
formats_.push_back(MySqlString);
|
||||
}
|
||||
else if (type_ == ClientType::Sqlite3)
|
||||
{
|
||||
@ -169,9 +169,7 @@ SqlBinder &SqlBinder::operator<<(std::string &&str)
|
||||
}
|
||||
else if (type_ == ClientType::Mysql)
|
||||
{
|
||||
#if USE_MYSQL
|
||||
formats_.push_back(MYSQL_TYPE_STRING);
|
||||
#endif
|
||||
formats_.push_back(MySqlString);
|
||||
}
|
||||
else if (type_ == ClientType::Sqlite3)
|
||||
{
|
||||
@ -194,9 +192,7 @@ SqlBinder &SqlBinder::operator<<(const std::vector<char> &v)
|
||||
}
|
||||
else if (type_ == ClientType::Mysql)
|
||||
{
|
||||
#if USE_MYSQL
|
||||
formats_.push_back(MYSQL_TYPE_STRING);
|
||||
#endif
|
||||
formats_.push_back(MySqlString);
|
||||
}
|
||||
else if (type_ == ClientType::Sqlite3)
|
||||
{
|
||||
@ -204,6 +200,7 @@ SqlBinder &SqlBinder::operator<<(const std::vector<char> &v)
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
SqlBinder &SqlBinder::operator<<(std::vector<char> &&v)
|
||||
{
|
||||
std::shared_ptr<std::vector<char>> obj =
|
||||
@ -218,9 +215,7 @@ SqlBinder &SqlBinder::operator<<(std::vector<char> &&v)
|
||||
}
|
||||
else if (type_ == ClientType::Mysql)
|
||||
{
|
||||
#if USE_MYSQL
|
||||
formats_.push_back(MYSQL_TYPE_STRING);
|
||||
#endif
|
||||
formats_.push_back(MySqlString);
|
||||
}
|
||||
else if (type_ == ClientType::Sqlite3)
|
||||
{
|
||||
@ -243,6 +238,7 @@ SqlBinder &SqlBinder::operator<<(double f)
|
||||
}
|
||||
return operator<<(std::to_string(f));
|
||||
}
|
||||
|
||||
SqlBinder &SqlBinder::operator<<(std::nullptr_t nullp)
|
||||
{
|
||||
(void)nullp;
|
||||
@ -255,9 +251,7 @@ SqlBinder &SqlBinder::operator<<(std::nullptr_t nullp)
|
||||
}
|
||||
else if (type_ == ClientType::Mysql)
|
||||
{
|
||||
#if USE_MYSQL
|
||||
formats_.push_back(MYSQL_TYPE_NULL);
|
||||
#endif
|
||||
formats_.push_back(MySqlNull);
|
||||
}
|
||||
else if (type_ == ClientType::Sqlite3)
|
||||
{
|
||||
@ -266,22 +260,65 @@ SqlBinder &SqlBinder::operator<<(std::nullptr_t nullp)
|
||||
return *this;
|
||||
}
|
||||
|
||||
SqlBinder &SqlBinder::operator<<(DefaultValue dv)
|
||||
{
|
||||
(void)dv;
|
||||
if (type_ == ClientType::PostgreSQL)
|
||||
{
|
||||
std::regex r("\\$" + std::to_string(parametersNumber_ + 1) + "\\b");
|
||||
// initialize with empty, as the next line will make a copy anyway
|
||||
if (!sqlPtr_)
|
||||
sqlPtr_ = std::make_shared<std::string>();
|
||||
|
||||
*sqlPtr_ = std::regex_replace(sqlViewPtr_, r, "default");
|
||||
|
||||
// decrement all other $n parameters by 1
|
||||
size_t i = parametersNumber_ + 2;
|
||||
while ((sqlPtr_->find("$" + std::to_string(i))) != std::string::npos)
|
||||
{
|
||||
r = "\\$" + std::to_string(i) + "\\b";
|
||||
// use sed format to avoid $n regex group substitution,
|
||||
// and use ->data() to compile in C++14 mode
|
||||
*sqlPtr_ = std::regex_replace(sqlPtr_->data(),
|
||||
r,
|
||||
"$" + std::to_string(i - 1),
|
||||
std::regex_constants::format_sed);
|
||||
++i;
|
||||
}
|
||||
sqlViewPtr_ = sqlPtr_->data();
|
||||
sqlViewLength_ = sqlPtr_->length();
|
||||
}
|
||||
else if (type_ == ClientType::Mysql)
|
||||
{
|
||||
++parametersNumber_;
|
||||
parameters_.push_back(NULL);
|
||||
lengths_.push_back(0);
|
||||
formats_.push_back(DrogonDefaultValue);
|
||||
}
|
||||
else if (type_ == ClientType::Sqlite3)
|
||||
{
|
||||
LOG_FATAL << "default not supported in sqlite3";
|
||||
exit(1);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
int SqlBinder::getMysqlTypeBySize(size_t size)
|
||||
{
|
||||
#if USE_MYSQL
|
||||
switch (size)
|
||||
{
|
||||
case 1:
|
||||
return MYSQL_TYPE_TINY;
|
||||
return MySqlTiny;
|
||||
break;
|
||||
case 2:
|
||||
return MYSQL_TYPE_SHORT;
|
||||
return MySqlShort;
|
||||
break;
|
||||
case 4:
|
||||
return MYSQL_TYPE_LONG;
|
||||
return MySqlLong;
|
||||
break;
|
||||
case 8:
|
||||
return MYSQL_TYPE_LONGLONG;
|
||||
return MySqlLongLong;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "MysqlConnection.h"
|
||||
#include "MysqlResultImpl.h"
|
||||
#include <algorithm>
|
||||
#include <drogon/orm/DbTypes.h>
|
||||
#include <drogon/utils/Utilities.h>
|
||||
#include <drogon/utils/string_view.h>
|
||||
#include <errmsg.h>
|
||||
@ -428,24 +429,24 @@ void MysqlConnection::execSqlInLoop(
|
||||
pos = seekPos + 1;
|
||||
switch (format[i])
|
||||
{
|
||||
case MYSQL_TYPE_TINY:
|
||||
case internal::MySqlTiny:
|
||||
sql_.append(std::to_string(*((char *)parameters[i])));
|
||||
break;
|
||||
case MYSQL_TYPE_SHORT:
|
||||
case internal::MySqlShort:
|
||||
sql_.append(std::to_string(*((short *)parameters[i])));
|
||||
break;
|
||||
case MYSQL_TYPE_LONG:
|
||||
case internal::MySqlLong:
|
||||
sql_.append(
|
||||
std::to_string(*((int32_t *)parameters[i])));
|
||||
break;
|
||||
case MYSQL_TYPE_LONGLONG:
|
||||
case internal::MySqlLongLong:
|
||||
sql_.append(
|
||||
std::to_string(*((int64_t *)parameters[i])));
|
||||
break;
|
||||
case MYSQL_TYPE_NULL:
|
||||
case internal::MySqlNull:
|
||||
sql_.append("NULL");
|
||||
break;
|
||||
case MYSQL_TYPE_STRING:
|
||||
case internal::MySqlString:
|
||||
{
|
||||
sql_.append("'");
|
||||
std::string to(length[i] * 2, '\0');
|
||||
@ -458,6 +459,9 @@ void MysqlConnection::execSqlInLoop(
|
||||
sql_.append("'");
|
||||
}
|
||||
break;
|
||||
case internal::DrogonDefaultValue:
|
||||
sql_.append("default");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
*/
|
||||
#include <drogon/config.h>
|
||||
#include <drogon/orm/DbClient.h>
|
||||
#include <drogon/orm/DbTypes.h>
|
||||
#include <trantor/utils/Logger.h>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
@ -125,12 +126,12 @@ void doPostgreTest(const drogon::orm::DbClientPtr &clientPtr)
|
||||
"postgresql - DbClient streaming-type interface(0)");
|
||||
};
|
||||
/// 1.2 insert,blocking
|
||||
*clientPtr << "insert into users (user_id,user_name,password,org_name) "
|
||||
"values($1,$2,$3,$4) returning *"
|
||||
<< "pg1"
|
||||
<< "postgresql1"
|
||||
<< "123"
|
||||
<< "default" << Mode::Blocking >>
|
||||
*clientPtr
|
||||
<< "insert into users (user_id,user_name,admin,password,org_name) "
|
||||
"values($1,$2,$3,$4,$5) returning *"
|
||||
<< "pg1"
|
||||
<< "postgresql1" << drogon::orm::DefaultValue{} << "123"
|
||||
<< "default" << Mode::Blocking >>
|
||||
[](const Result &r) {
|
||||
// std::cout << "id=" << r[0]["id"].as<int64_t>() << std::endl;
|
||||
testOutput(r[0]["id"].as<int64_t>() == 2,
|
||||
@ -811,12 +812,13 @@ void doMysqlTest(const drogon::orm::DbClientPtr &clientPtr)
|
||||
};
|
||||
/// Test1:DbClient streaming-type interface
|
||||
/// 1.1 insert,non-blocking
|
||||
*clientPtr << "insert into users (user_id,user_name,password,org_name) "
|
||||
"values(?,?,?,?)"
|
||||
<< "pg"
|
||||
<< "postgresql"
|
||||
<< "123"
|
||||
<< "default" >>
|
||||
*clientPtr
|
||||
<< "insert into users (user_id,user_name,password,org_name,admin) "
|
||||
"values(?,?,?,?,?)"
|
||||
<< "pg"
|
||||
<< "postgresql"
|
||||
<< "123"
|
||||
<< "default" << drogon::orm::DefaultValue{} >>
|
||||
[](const Result &r) {
|
||||
testOutput(r.insertId() == 1,
|
||||
"mysql - DbClient streaming-type interface(0)");
|
||||
|
Loading…
x
Reference in New Issue
Block a user