Skip to content

Instantly share code, notes, and snippets.

@pfultz2
Created July 16, 2014 15:53
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pfultz2/abbea635bdc8a4971424 to your computer and use it in GitHub Desktop.
Save pfultz2/abbea635bdc8a4971424 to your computer and use it in GitHub Desktop.
A simple example of how to use Boost.Fusion for ORM
#include <iostream>
#include <sstream>
#include <type_traits>
#include <boost/mpl/range_c.hpp>
#include <boost/fusion/adapted/struct/define_assoc_struct.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/fusion/algorithm/transformation/zip.hpp>
#include <boost/fusion/sequence/intrinsic/at_c.hpp>
#include <boost/fusion/sequence/intrinsic/at.hpp>
#include <boost/fusion/sequence/intrinsic/size.hpp>
#include <boost/fusion/algorithm/transformation/transform.hpp>
using boost::mpl::range_c;
using namespace boost::fusion;
using boost::fusion::extension::struct_member_name;
using boost::fusion::extension::struct_assoc_key;
// Primary key attribute
struct primary_key {};
// Attribute to specify max length
struct max_length_base {};
template<int N>
struct max_length : max_length_base
{
static const int max_length_value = N;
};
namespace fields
{
struct name : primary_key, max_length<250>
{};
struct age
{};
}
BOOST_FUSION_DEFINE_ASSOC_STRUCT((), person,
(std::string, name, fields::name)
(int, age, fields::age)
);
template<class Attribute, class Key>
constexpr bool has_attribute(const Key&)
{
return std::is_base_of<Attribute, Key>();
}
#define REQUIRES(...) std::enable_if_t<(__VA_ARGS__), int> = 0
template<class Key, REQUIRES(has_attribute<max_length_base>(Key()))>
int get_max_length(const Key&)
{
return Key::max_length_value;
}
template<class Key, REQUIRES(!has_attribute<max_length_base>(Key()))>
int get_max_length(const Key&)
{
return -1;
}
template<class Struct>
auto with_names_and_keys(const Struct& s)
{
typedef range_c<int, 0, result_of::size<Struct>::type::value> range;
static auto names = transform(range(), [](auto i) -> std::string
{
return struct_member_name<Struct, i>::call();
});
static auto keys = transform(range(), [](auto i)
{
return typename struct_assoc_key<Struct, i>::type();
});
return zip(s, names, keys);
}
template<class T>
auto get_value(const T& x)
{
return at_c<0>(x);
}
template<class T>
std::string get_name(const T& x)
{
return at_c<1>(x);
}
template<class T>
auto get_key(const T& x)
{
return at_c<2>(x);
}
template<class T>
using value_type = typename result_of::at_c<T, 0>::type;
template<class T>
using key_type = typename result_of::at_c<T, 2>::type;
template<class T>
std::string create_column(const T& x)
{
std::stringstream ss;
ss << std::endl << " " << get_name(x);
if (std::is_convertible<decltype(get_value(x)), std::string>())
{
int max = get_max_length(get_key(x));
if (max < 0) ss << " text ";
else ss << " char(" << max << ")";
}
else ss << " " << typeid(get_value(x)).name();
if (has_attribute<primary_key>(get_key(x))) ss << " primary key";
return ss.str();
}
template<class T>
std::string create_table(const T& x, const std::string& table_name)
{
std::stringstream ss;
ss << "create table " << table_name;
char delim = '(';
for_each(with_names_and_keys(x), [&](const auto& field)
{
ss << delim << create_column(field);
delim = ',';
});
ss << ')';
return ss.str();
}
int main()
{
person p = { "Tom", 52 };
std::cout << std::endl;
std::cout << create_table(p, "person");
std::cout << std::endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment