Created
July 16, 2014 15:53
-
-
Save pfultz2/abbea635bdc8a4971424 to your computer and use it in GitHub Desktop.
A simple example of how to use Boost.Fusion for ORM
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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