所以我对sqlite3cpp wiki抱怨。而且它有一个很好的API:
sqlite3pp::command cmd(db, "INSERT INTO contacts (name, phone) VALUES (:user, :phone)");
cmd.bind(":user", "Mike");
cmd.bind(":phone", "555-1234");
cmd.execute();
我想知道如何使用boost来创建类似于std :: string的API?意思是
std::string str = "INSERT INTO contacts (name, phone) VALUES (:user, :phone)";
bind(str, ":user", "Mike");
bind(str, ":phone", "555-1234");
是否有可能通过提升来创造这样的事情以及如何做到这一点?
答案 0 :(得分:2)
可能:boost::algorithm::replace_all
?如果您不想修改原始字符串,也可以boost::algorithm::replace_all_copy
。
答案 1 :(得分:1)
替换字符串很简单,但是要执行类型安全并且很好地转换SQL的东西,会略有不同。我们需要一个可以通过传递类型绑定的绑定器类,并进行任何必要的转换。
首先,我们需要结束std::type_info
,以便可以在哈希映射中使用它:
class typeInfoWrapper
{
friend bool operator == (const typeInfoWrapper& l, const typeInfoWrapper& r);
private:
const std::type_info& typeInfo_;
public:
typeInfoWrapper(const std::type_info& info) : typeInfo_(info) { };
// hasher
class hash
{
public:
size_t operator()(const typeInfoWrapper& typeInfo) const
{
return typeInfo.typeInfo_.hash_code();
};
}; // eo class hash
}; // eo class typeInfoWrapper
bool operator == (const typeInfoWrapper& l, const typeInfoWrapper& r)
{
return l.typeInfo_.hash_code() == r.typeInfo_.hash_code();
} // eo operator ==
接下来,我们需要课程本身。我在这里使用C ++ 11,所以我将使用lambdas。对于我们注册的每种类型,我们将注册一个函数,该函数接受一个字符串并以适合SQL的格式返回它。在这个例子中,我为一个字符串注册一个,为int注册一个。字符串1只用'
替换''
并将其返回引号本身。 int只返回自己,没有为SQL做解析。
class binder
{
private:
typedef std::function<std::string(std::string&)> ReplaceFunc;
typedef std::tr1::unordered_map<typeInfoWrapper, ReplaceFunc, typeInfoWrapper::hash> ReplaceMap;
typedef std::pair<typeInfoWrapper, ReplaceFunc> ReplacePair;
ReplaceMap typeMap_;
public:
binder()
{
// add string and int for test purposes
typeMap_.insert(ReplacePair(typeid(const char*), [](std::string& data) -> std::string
{
// escape the "'" to prevent SQL injection
boost::replace_all(data, "'", "''");
return "'" + data + "'";
}));
typeMap_.insert(ReplacePair(typeid(int), [](std::string& data) -> std::string
{
// for sql, this is easy, just return the value as is
return data;
}));
};
// func
template<class T>
void bind(std::string& input, const std::string& expr, T data)
{
ReplaceMap::const_iterator cit(typeMap_.find(typeid(T)));
if(cit != typeMap_.end())
boost::replace_all(input, expr, cit->second(boost::lexical_cast<std::string>(data)));
}; // eo bind
}; // eo class bind
正如您所看到的,我们有绑定功能。
现在我们可以以类型安全的方式绑定了!
binder b;
std::string data = "SELECT * FROM table WHERE _user = :user AND _id = :id";
b.bind(data, ":user", "Moo-Juice");
b.bind(data, ":id", 32);
编辑:修正了一些错误。