Skip to content

Instantly share code, notes, and snippets.

@wichert
Last active December 17, 2015 16:09
Show Gist options
  • Save wichert/5636906 to your computer and use it in GitHub Desktop.
Save wichert/5636906 to your computer and use it in GitHub Desktop.
Minimal uuid and HSTORE support for pqxx
#include <boost/algorithm/string/join.hpp>
#include <boost/format.hpp>
#include <boost/regex.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <stylist/private/pqxx.hh>
using namespace std;
namespace {
boost::uuids::nil_generator nil_gen;
boost::uuids::string_generator parse_uuid;
const boost::regex regexp_kv(
// A quoted key
"\"(.*?)(?!\\\\)\""
// assignment, possibly with extra whitespace
"\\s*=>\\s*"
// NULL or quoted value
"(NULL|\"(.*?)(?!\\\\)\")");
}
namespace stylist {
namespace pg {
string escape(const string &value) {
string result;
result.reserve(value.length()+5);
for (auto chr : value) {
if (chr=='\\' || chr=='"')
result+='\\';
result+=chr;
}
return result;
}
string unescape(const string &value) {
string result;
result.reserve(value.length());
for (string::const_iterator it=value.begin(); it!=value.end(); it++) {
if (*it=='\\') {
it++;
if (it==value.end())
break;
}
result.push_back(*it);
}
return result;
}
}
}
namespace pqxx {
boost::uuids::uuid string_traits<boost::uuids::uuid>::null() {
return nil_gen();
}
void string_traits<boost::uuids::uuid>::from_string(const char str[], value_type &uuid) {
uuid=parse_uuid(str);
}
std::string string_traits<boost::uuids::uuid>::to_string(const value_type &uuid) {
return boost::uuids::to_string(uuid);
}
void string_traits<map<string, string>>::from_string(const char str[], value_type &output) {
string input(str);
boost::sregex_iterator begin(input.begin(), input.end(), regexp_kv);
boost::sregex_iterator end;
output.clear();
for (auto match=begin; match!=end; match++) {
string key(stylist::pg::unescape(match->str(1)));
int hits = match->size();
string v(match->str(2));
string value(stylist::pg::unescape(match->str(3)));
output[key]=value;
}
}
string string_traits<map<string, string>>::to_string(const value_type &obj) {
list<string> parts;
for (auto i : obj) {
string key(stylist::pg::escape(i.first));
string value(stylist::pg::escape(i.second));
parts.push_back((boost::format("\"%s\"=>\"%s\"") % key % value).str());
}
return boost::algorithm::join(parts, ", ");
}
}
#ifndef _STYLIST_PRIVATE_PQXX_INCLUDED_
#define _STYLIST_PRIVATE_PQXX_INCLUDED_
#include <map>
#include <string>
#include <boost/uuid/uuid.hpp>
#include <pqxx/pqxx>
namespace stylist {
namespace pg {
std::string escape(const std::string &value);
std::string unescape(const std::string &value);
}
}
namespace pqxx {
template<>
struct string_traits<boost::uuids::uuid> {
typedef boost::uuids::uuid value_type;
static const char *name() {
return "UUID";
}
static bool has_null() {
return true;
}
static bool is_null(const value_type &uuid) {
return uuid.is_nil();
}
static boost::uuids::uuid null();
static void from_string(const char str[], value_type &uuid);
static std::string to_string(const value_type &uuid);
};
template<>
struct string_traits<std::map<std::string, std::string>> {
typedef std::map<std::string, std::string> value_type;
static const char *name() {
return "map<string, string>";
}
static bool has_null() {
return true;
}
static bool is_null(const value_type& value) {
return value.empty();
}
static value_type null() {
return value_type();
}
static void from_string(const char str[], value_type &output);
static std::string to_string(const value_type &obj);
};
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment