Browse Source

* implemented schema classes

master
bergmann 5 years ago
parent
commit
35fe18d77a
23 changed files with 1543 additions and 0 deletions
  1. +6
    -0
      include/cpphibernate.h
  2. +0
    -0
     
  3. +56
    -0
      include/cpphibernate/config.h
  4. +5
    -0
      include/cpphibernate/misc.h
  5. +19
    -0
      include/cpphibernate/misc/general.h
  6. +130
    -0
      include/cpphibernate/misc/meta.h
  7. +44
    -0
      include/cpphibernate/misc/wrap.h
  8. +13
    -0
      include/cpphibernate/schema.h
  9. +60
    -0
      include/cpphibernate/schema/attribute.h
  10. +63
    -0
      include/cpphibernate/schema/attributes.h
  11. +115
    -0
      include/cpphibernate/schema/field.h
  12. +62
    -0
      include/cpphibernate/schema/fields.h
  13. +206
    -0
      include/cpphibernate/schema/getter.h
  14. +43
    -0
      include/cpphibernate/schema/macros.h
  15. +18
    -0
      include/cpphibernate/schema/print.h
  16. +85
    -0
      include/cpphibernate/schema/schema.h
  17. +206
    -0
      include/cpphibernate/schema/setter.h
  18. +109
    -0
      include/cpphibernate/schema/table.h
  19. +62
    -0
      include/cpphibernate/schema/tables.h
  20. +51
    -0
      include/cpphibernate/types.h
  21. +8
    -0
      src/CMakeLists.txt
  22. +54
    -0
      src/types.cpp
  23. +128
    -0
      test/cpphibernate.cpp

+ 6
- 0
include/cpphibernate.h View File

@@ -0,0 +1,6 @@
#pragma once

#include <cpphibernate/config.h>
#include <cpphibernate/misc.h>
#include <cpphibernate/schema.h>
#include <cpphibernate/types.h>

+ 0
- 0
View File


+ 56
- 0
include/cpphibernate/config.h View File

@@ -0,0 +1,56 @@
#pragma once

#include <boost/hana.hpp>
#include <cpputils/mp/core.h>

#define cpphibernate_equality_comparable() \
template<typename T_other> \
constexpr decltype(auto) operator==(T_other&&) const \
{ \
return ::boost::hana::type<::utl::mp::decay_t<decltype(*this)>> { } == \
::boost::hana::type<::utl::mp::decay_t<T_other>> { }; \
} \
\
template<typename T_other> \
constexpr decltype(auto) operator!=(T_other&&) const \
{ \
return ::boost::hana::type<::utl::mp::decay_t<decltype(*this)>> { } != \
::boost::hana::type<::utl::mp::decay_t<T_other>> { }; \
}

#define cpphibernate_constructable(name, value) \
name() = value

#define cpphibernate_copyable(name, value) \
name(const name&) = value; \
name& operator=(const name&) = value

#define cpphibernate_moveable(name, value) \
name(name&&) = value; \
name& operator=(name&&) = value

#define cpphibernate_define_namespace_beg(parent, name) \
parent { \
namespace name

#define cpphibernate_define_namespace_end(parent) \
} \
parent

#define beg_namespace_cpphibernate namespace cpphibernate
#define end_namespace_cpphibernate

#define beg_namespace_cpphibernate_schema cpphibernate_define_namespace_beg(beg_namespace_cpphibernate, schema)
#define end_namespace_cpphibernate_schema cpphibernate_define_namespace_end(end_namespace_cpphibernate)

#define beg_namespace_cpphibernate_misc cpphibernate_define_namespace_beg(beg_namespace_cpphibernate, misc)
#define end_namespace_cpphibernate_misc cpphibernate_define_namespace_end(end_namespace_cpphibernate)

beg_namespace_cpphibernate
{

namespace mp = ::utl::mp;
namespace hana = ::boost::hana;

}
end_namespace_cpphibernate

+ 5
- 0
include/cpphibernate/misc.h View File

@@ -0,0 +1,5 @@
#pragma once

#include <cpphibernate/misc/general.h>
#include <cpphibernate/misc/meta.h>
#include <cpphibernate/misc/wrap.h>

+ 19
- 0
include/cpphibernate/misc/general.h View File

@@ -0,0 +1,19 @@
#pragma once

#include <cpphibernate/config.h>

beg_namespace_cpphibernate_misc
{

/* make_generic_predicate */

template<template<typename...> class T_builder>
struct make_generic_predicate
{
template<typename... T_args>
constexpr decltype(auto) operator()(T_args&&... args) const
{ return T_builder<mp::list<T_args...>>::apply(std::forward<T_args>(args)...); }
};

}
end_namespace_cpphibernate_misc

+ 130
- 0
include/cpphibernate/misc/meta.h View File

@@ -0,0 +1,130 @@
#pragma once

#include <list>
#include <vector>
#include <memory>

#include <cpphibernate/config.h>

#include <cpputils/container/nullable.h>

beg_namespace_cpphibernate_misc
{

namespace __impl
{

/* is_container_impl */

template<typename T>
struct is_container_impl
: public mp::c_false_t
{ };

template<typename T>
struct is_container_impl<std::list<T>>
: public mp::c_true_t
{ };

template<typename T>
struct is_container_impl<std::vector<T>>
: public mp::c_true_t
{ };

/* is_nullable_impl */

template<typename T>
struct is_nullable_impl
: public mp::c_false_t
{ };

template<typename T>
struct is_nullable_impl<utl::nullable<T>>
: public mp::c_true_t
{ };

template<typename T>
struct is_nullable_impl<std::unique_ptr<T>>
: public mp::c_true_t
{ };

template<typename T>
struct is_nullable_impl<std::shared_ptr<T>>
: public mp::c_true_t
{ };

/* is_pointer_impl */

template<typename T>
struct is_pointer_impl
: public mp::c_false_t
{ };

template<typename T>
struct is_pointer_impl<std::unique_ptr<T>>
: public mp::c_true_t
{ };

template<typename T>
struct is_pointer_impl<std::shared_ptr<T>>
: public mp::c_true_t
{ };

/* real_dataset_impl */

template<typename T, typename = void>
struct real_dataset_impl
{ using type = T; };

template<typename T>
struct real_dataset_impl<utl::nullable<T>, void>
{ using type = typename real_dataset_impl<T>::type; };

template<typename T>
struct real_dataset_impl<std::unique_ptr<T>, void>
{ using type = typename real_dataset_impl<T>::type; };

template<typename T>
struct real_dataset_impl<std::shared_ptr<T>, void>
{ using type = typename real_dataset_impl<T>::type; };

template<typename T>
struct real_dataset_impl<std::vector<T>, void>
{ using type = typename real_dataset_impl<T>::type; };

template<typename T>
struct real_dataset_impl<std::list<T>, void>
{ using type = typename real_dataset_impl<T>::type; };

template<typename T_from, typename T_to, typename = void>
struct change_dataset_type_impl
{ using type = T_to; };

template<template<typename...> class X, typename T_from, typename T_to>
struct change_dataset_type_impl<X<T_from>, T_to, void>
{ using type = X<T_to>; };

}

/* meta */

template<typename T>
struct is_container
: public __impl::is_container_impl<T>
{ };

template<typename T>
struct is_nullable
: public __impl::is_nullable_impl<T>
{ };

template<typename T>
struct is_pointer
: public __impl::is_pointer_impl<T>
{ };

template<typename T>
using real_dataset_t = typename __impl::real_dataset_impl<T>::type;

}
end_namespace_cpphibernate_misc

+ 44
- 0
include/cpphibernate/misc/wrap.h View File

@@ -0,0 +1,44 @@
#pragma once

#include <list>
#include <vector>
#include <memory>

#include <cpphibernate/config.h>

#include <cpputils/container/nullable.h>

beg_namespace_cpphibernate_misc
{

template<typename T>
using unwrap_t = typename T::type;

template<typename T>
using decay_unwrap_t = typename mp::decay_t<T>::type;

namespace __impl
{

struct wrap_t
{
template<typename T>
constexpr decltype(auto) operator()(T) const noexcept
{ return hana::type_c<T>; }
};

struct unwrapped_t
{
template<typename T>
constexpr decltype(auto) operator()(T) const noexcept
{ return unwrap_t<T> { }; }
};

}

constexpr decltype(auto) wrap = __impl::wrap_t { };

constexpr decltype(auto) unwrap = __impl::unwrapped_t { };

}
end_namespace_cpphibernate_misc

+ 13
- 0
include/cpphibernate/schema.h View File

@@ -0,0 +1,13 @@
#pragma once

#include <cpphibernate/schema/attribute.h>
#include <cpphibernate/schema/attributes.h>
#include <cpphibernate/schema/field.h>
#include <cpphibernate/schema/fields.h>
#include <cpphibernate/schema/getter.h>
#include <cpphibernate/schema/macros.h>
#include <cpphibernate/schema/print.h>
#include <cpphibernate/schema/schema.h>
#include <cpphibernate/schema/setter.h>
#include <cpphibernate/schema/table.h>
#include <cpphibernate/schema/tables.h>

+ 60
- 0
include/cpphibernate/schema/attribute.h View File

@@ -0,0 +1,60 @@
#pragma once

#include <cpphibernate/config.h>

beg_namespace_cpphibernate_schema
{

namespace __impl
{

/* attribute_t */

template<typename T_inner>
struct attribute_t
: public T_inner
{
using inner_type = T_inner;
using this_type = attribute_t<inner_type>;

cpphibernate_equality_comparable();
};

struct hex_t { static constexpr decltype(auto) name = "hex"; };
struct compress_t { static constexpr decltype(auto) name = "compress"; };
struct primary_key_t { static constexpr decltype(auto) name = "primary_key"; };

}

namespace attribute
{

using hex_type = __impl::attribute_t<__impl::hex_t>;
using compress_type = __impl::attribute_t<__impl::compress_t>;
using primary_key_type = __impl::attribute_t<__impl::primary_key_t>;

/** value is stored as hexadecimal string, and will be converted to its binary form on read */
constexpr hex_type hex { };

/** value is stored as compressed binary, and will be uncompressed on read */
constexpr compress_type compress { };

/** this value represents a primary key (it must be stored in the dataset to be able to do the operations on the database) */
constexpr primary_key_type primary_key { };

}

/* meta */

template<typename T>
struct is_attribute
: public mp::is_specialization_of<T, __impl::attribute_t>
{ };

template<typename... T>
struct all_are_attribures
: public mp::all_true<is_attribute<T>::value...>
{ };

}
end_namespace_cpphibernate_schema

+ 63
- 0
include/cpphibernate/schema/attributes.h View File

@@ -0,0 +1,63 @@
#pragma once

#include <cpphibernate/config.h>
#include <cpphibernate/misc.h>
#include <cpphibernate/schema/attribute.h>

beg_namespace_cpphibernate_schema
{

namespace __impl
{

/* attributes_t */

template<typename... T_attributes>
using attributes_t = hana::basic_tuple<T_attributes...>;

/* is_attributes_impl */

template<typename T, typename = void>
struct is_attributes_impl
: mp::c_false_t
{ };

template<typename... T>
struct is_attributes_impl<attributes_t<T...>, mp::enable_if<all_are_attribures<T...>>>
: mp::c_true_t
{ };

/* attributes_builder */

template<typename T, typename = void>
struct attributes_builder
{
template<typename... T_args>
static constexpr decltype(auto) apply(T_args&&...)
{ static_assert(sizeof...(T_args) == -1, "Invalid parameters for hibernate::schema::make_attributes(...)!"); }
};

template<typename... T>
struct attributes_builder<mp::list<T...>, mp::enable_if_c<
all_are_attribures<mp::decay_t<T>...>::value>>
{
template<typename... T_args>
static constexpr decltype(auto) apply(T_args&&...)
{ return attributes_t<mp::decay_t<T_args>...> { }; }
};

}

/* meta */

template<typename T>
struct is_attributes
: public __impl::is_attributes_impl<T>
{ };

/* make */

constexpr decltype(auto) make_attributes = misc::make_generic_predicate<__impl::attributes_builder> { };

}
end_namespace_cpphibernate_schema

+ 115
- 0
include/cpphibernate/schema/field.h View File

@@ -0,0 +1,115 @@
#pragma once

#include <cpphibernate/misc.h>
#include <cpphibernate/config.h>
#include <cpphibernate/schema/getter.h>
#include <cpphibernate/schema/setter.h>

#include <cpputils/misc/indent.h>
#include <cpputils/misc/type_helper.h>

beg_namespace_cpphibernate_schema
{

namespace __impl
{

/* field_t */

template<typename T_name, typename T_getter, typename T_setter, typename T_attributes>
struct field_t
{
using name_type = T_name;
using getter_type = T_getter;
using setter_type = T_setter;
using attributes_type = T_attributes;
using this_type = field_t<name_type, getter_type, setter_type, attributes_type>;

name_type name;
getter_type getter;
setter_type setter;
attributes_type attributes;

constexpr field_t(
T_name&& p_name,
T_getter&& p_getter,
T_setter&& p_setter,
T_attributes&& p_attributes)
: name (std::forward<T_name> (p_name))
, getter (std::forward<T_getter> (p_getter))
, setter (std::forward<T_setter> (p_setter))
, attributes (std::forward<T_attributes>(p_attributes))
{ }

cpphibernate_copyable(field_t, delete);
cpphibernate_moveable(field_t, default);

cpphibernate_equality_comparable();

inline void print(std::ostream& os) const
{
using namespace ::utl;
using value_type = typename mp::decay_t<getter_type>::value_type;
using dataset_type = misc::real_dataset_t<value_type>;
size_t index = 0;
os << indent << '{'
<< incindent
<< indent << "\"name\": \"" << name << "\","
<< indent << "\"value_type\": \"" << utl::type_helper<value_type>::name() << "\""
<< indent << "\"dataset_type\": \"" << utl::type_helper<dataset_type>::name() << "\""
<< indent << "\"attributes\": "
<< indent << '['
<< incindent;
hana::for_each(attributes, [&](auto& attrib){
if (index++ > 0) os << ",";
os << indent << attrib.name;
});
os << decindent
<< indent << ']'
<< decindent
<< indent << '}';
}
};

/* field_builder */

template<typename X, typename = void>
struct field_builder
{
template <typename ...T_args>
static constexpr decltype(auto) apply(T_args&&... args)
{ static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::make_field(...)!"); }
};

template<typename T_name, typename T_getter, typename T_setter, typename T_attributes>
struct field_builder<mp::list<T_name, T_getter, T_setter, T_attributes>, mp::enable_if_c<
is_getter<mp::decay_t<T_getter>>::value
&& is_setter<mp::decay_t<T_setter>>::value
&& is_attributes<mp::decay_t<T_attributes>>::value>>
{
using field_type = field_t<T_name, T_getter, T_setter, T_attributes>;

static constexpr decltype(auto) apply(T_name&& name, T_getter&& getter, T_setter&& setter, T_attributes&& attributes)
{ return field_type(std::forward<T_name>(name), std::forward<T_getter>(getter), std::forward<T_setter>(setter), std::forward<T_attributes>(attributes)); }
};

}

/* meta */

template<typename T>
struct is_field
: public mp::is_specialization_of<T, __impl::field_t>
{ };

template<typename... T>
struct all_are_fields
: public mp::all_true<is_field<T>::value...>
{ };

/* make */

constexpr decltype(auto) make_field = misc::make_generic_predicate<__impl::field_builder> { };

}
end_namespace_cpphibernate_schema

+ 62
- 0
include/cpphibernate/schema/fields.h View File

@@ -0,0 +1,62 @@
#pragma once

#include <cpphibernate/config.h>
#include <cpphibernate/misc/general.h>
#include <cpphibernate/schema/field.h>

beg_namespace_cpphibernate_schema
{

namespace __impl
{

/* fields_t */

template<typename... T_fields>
using fields_t = hana::basic_tuple<T_fields...>;

/* is_fields_impl */

template<typename T, typename = void>
struct is_fields_impl
: public mp::c_false_t
{ };

template<typename... T>
struct is_fields_impl<fields_t<T...>, mp::enable_if<all_are_fields<T...>>>
: public mp::c_true_t
{ };

/* fields_builder */

template <typename T, typename = void>
struct fields_builder
{
template <typename ...T_args>
static constexpr decltype(auto) apply(T_args&&... args)
{ static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::make_fields(...)!"); }
};

template<typename... T>
struct fields_builder<mp::list<T...>, mp::enable_if<all_are_fields<T...>>>
{
template <typename ...T_args>
static constexpr decltype(auto) apply(T_args&&... args)
{ return fields_t<T_args...>(std::forward<T_args>(args)...); }
};

}

/* meta */

template<typename T>
struct is_fields :
public __impl::is_fields_impl<T>
{ };

/* constructors */

constexpr decltype(auto) make_fields = misc::make_generic_predicate<__impl::fields_builder> { };

}
end_namespace_cpphibernate_schema

+ 206
- 0
include/cpphibernate/schema/getter.h View File

@@ -0,0 +1,206 @@
#pragma once

#include <cpphibernate/config.h>
#include <cpphibernate/misc/general.h>

beg_namespace_cpphibernate_schema
{

namespace __impl
{

/* getter_t */

template<typename T_value>
struct getter_t
{
using value_type = T_value;
};


/* getter_none_t */

struct getter_none_t
: public getter_t<void>
{
using base_type = getter_t<void>;
using value_type = typename base_type::value_type;

cpphibernate_constructable(getter_none_t, default);
cpphibernate_copyable (getter_none_t, delete);
cpphibernate_moveable (getter_none_t, default);
};

/* getter_member_var_t */

template<typename T_dataset, typename T_value, typename T_member>
struct getter_member_var_t
: public getter_t<T_value>
{
using base_type = getter_t<T_value>;
using value_type = typename base_type::value_type;
using dataset_type = T_dataset;
using member_type = T_member;

member_type member;

template<typename X_member>
constexpr getter_member_var_t(X_member&& p_member)
: member(std::forward<X_member>(p_member))
{ }

cpphibernate_copyable(getter_member_var_t, delete);
cpphibernate_moveable(getter_member_var_t, default);

template<typename X_dataset>
constexpr decltype(auto) operator()(X_dataset&& data) const
{ return std::forward<X_dataset>(data).*member; }
};

/* getter_member_func_t */

template<typename T_dataset, typename T_value, typename T_member>
struct getter_member_func_t
: public getter_t<T_value>
{
using base_type = getter_t<T_value>;
using value_type = typename base_type::value_type;
using dataset_type = T_dataset;
using member_type = T_member;

member_type member;

template<typename X_member>
constexpr getter_member_func_t(X_member&& p_member)
: member(std::forward<X_member>(p_member))
{ };

cpphibernate_copyable(getter_member_func_t, delete);
cpphibernate_moveable(getter_member_func_t, default);

template<typename X_dataset>
constexpr decltype(auto) operator()(X_dataset&& data) const
{ return (std::forward<X_dataset>(data).*member)(); }
};

/* getter_lambda_t */

template<typename T_dataset, typename T_lambda>
struct getter_lambda_t
: public getter_t<decltype(std::declval<T_lambda>()(std::declval<T_dataset>()))>
{
using base_type = getter_t<decltype(std::declval<T_lambda>()(std::declval<T_dataset>()))>;
using value_type = typename base_type::value_type;
using dataset_type = T_dataset;
using lambda_type = T_lambda;

lambda_type lambda;

template<typename X_lambda>
constexpr getter_lambda_t(X_lambda&& p_lambda)
: lambda(std::forward<X_lambda>(p_lambda))
{ }

cpphibernate_copyable(getter_lambda_t, delete);
cpphibernate_moveable(getter_lambda_t, default);

template<typename X_dataset>
constexpr decltype(auto) operator()(X_dataset&& data) const
{ return lambda(std::forward<X_dataset>(data)); }
};

/* is_getter_impl */

template<typename T, typename = void>
struct is_getter_impl
: public mp::c_false_t
{ };

template<typename T>
struct is_getter_impl<T, mp::enable_if_c<
mp::is_base_of<getter_t<typename T::value_type>, T>::value>>
: public mp::c_true_t
{ };

}

/* meta */

template<typename T>
struct is_getter :
public __impl::is_getter_impl<T>
{ };

/* make */

constexpr decltype(auto) make_getter_none()
{ return __impl::getter_none_t(); }

template<typename T_dataset, typename T_value>
constexpr decltype(auto) make_getter_member_var(T_value T_dataset::* member)
{ return __impl::getter_member_var_t<T_dataset, T_value, T_value T_dataset::*>(member); }

template<typename T_dataset, typename T_value>
constexpr decltype(auto) make_getter_member_func(T_value (T_dataset::*member)())
{ return __impl::getter_member_func_t<T_dataset, T_value, T_value (T_dataset::*)()>(member); }

template<typename T_dataset, typename T_value>
constexpr decltype(auto) make_getter_member_func(T_value (T_dataset::*member)() const)
{ return __impl::getter_member_func_t<const T_dataset, T_value, T_value (T_dataset::*)() const>(member); }

template<typename T_dataset, typename T_lambda>
constexpr decltype(auto) make_getter_lambda(T_lambda&& lambda, boost::hana::basic_type<T_dataset>)
{ return __impl::getter_lambda_t<T_dataset, T_lambda>(std::forward<T_lambda>(lambda)); }


namespace __impl
{

/* getter_buildser */

template<typename X, typename = void>
struct getter_builder
{
template<typename... Args>
static constexpr decltype(auto) apply(Args&&...)
{ return make_getter_none(); }
};

template<typename T_dataset, typename T_value>
struct getter_builder<mp::list<T_value T_dataset::*>, void>
{
static constexpr decltype(auto) apply(T_value T_dataset::*member)
{ return make_getter_member_var(member); }
};

template<typename T_dataset, typename T_value>
struct getter_builder<mp::list<T_value (T_dataset::*)(void)>, void>
{
static constexpr decltype(auto) apply(T_value (T_dataset::*member)(void))
{ return make_getter_member_func(member); }
};

template<typename T_dataset, typename T_value>
struct getter_builder<mp::list<T_value (T_dataset::*)(void) const>, void>
{
static constexpr decltype(auto) apply(T_value (T_dataset::*member)(void) const)
{ return make_getter_member_func(member); }
};

template<typename T_func, typename T_dataset_type, typename T_value_type>
struct getter_builder<mp::list<T_func, T_dataset_type, T_value_type>, mp::enable_if_c<
hana::is_a<hana::type_tag, mp::decay_t<T_dataset_type>>
&& hana::is_a<hana::type_tag, mp::decay_t<T_value_type>>>>
{
static constexpr decltype(auto) apply(T_func&& func, T_dataset_type&& dataset_type, T_value_type&& value_type)
{ return make_getter_lambda(std::forward<T_func>(func), std::forward<T_dataset_type>(dataset_type), std::forward<T_value_type>(value_type)); }
};

}

/* make */

constexpr decltype(auto) make_getter = misc::make_generic_predicate<__impl::getter_builder> { };

}
end_namespace_cpphibernate_schema

+ 43
- 0
include/cpphibernate/schema/macros.h View File

@@ -0,0 +1,43 @@
#pragma once

#include <cpphibernate/config.h>
#include <cpphibernate/types.h>

#define cpphibernate_make_string(str) \
#str

#define cpphibernate_make_schema(name, ...) \
cpphibernate::schema::make_schema( \
cpphibernate_make_string(name), \
cpphibernate::schema::make_tables(__VA_ARGS__))

#define cpphibernate_make_table_name(name, type, id, ...) \
cpphibernate::schema::make_table( \
cpphibernate_make_string(name), \
boost::hana::type_c<type>, \
boost::hana::size_c<id>, \
cpphibernate::schema::make_fields(__VA_ARGS__))

#define cpphibernate_make_table(name, id, ...) \
cpphibernate_make_table_name(name, name, id, __VA_ARGS__)

#define cpphibernate_make_field_custom(name, getter, setter, ...) \
cpphibernate::schema::make_field( \
cpphibernate_make_string(name), \
cpphibernate::schema::make_getter(getter), \
cpphibernate::schema::make_setter(setter), \
cpphibernate::schema::make_attributes(__VA_ARGS__))

#define cpphibernate_make_field_name(name, member_ptr, ...) \
cpphibernate_make_field_custom( \
name, member_ptr, member_ptr, __VA_ARGS__)

#define cpphibernate_make_field(type, member, ...) \
cpphibernate_make_field_name( \
member, &type::member, __VA_ARGS__)

#define cpphibernate_make_id(member_ptr) \
cpphibernate_make_field_name( \
null, \
member_ptr, \
cpphibernate::schema::attribute::primary_key)

+ 18
- 0
include/cpphibernate/schema/print.h View File

@@ -0,0 +1,18 @@
#pragma once

#include <cpphibernate/config.h>

namespace std
{

template<typename T_char, typename T_traits, typename X>
inline auto operator <<(basic_ostream<T_char, T_traits>& os, X&& x)
-> ::utl::mp::enable_if<
utl::mp::is_valid<decltype(std::forward<X>(x).print(os))>,
basic_ostream<T_char, T_traits>&>
{
std::forward<X>(x).print(os);
return os;
}

}

+ 85
- 0
include/cpphibernate/schema/schema.h View File

@@ -0,0 +1,85 @@
#pragma once

#include <cpphibernate/config.h>
#include <cpphibernate/misc/general.h>
#include <cpphibernate/schema/tables.h>

beg_namespace_cpphibernate_schema
{

namespace __impl
{

/* schema_t */

template<typename T_name, typename T_tables>
struct schema_t
{
using name_type = T_name;
using tables_type = T_tables;

name_type name;
tables_type tables;

constexpr schema_t(
T_name&& p_name,
T_tables&& p_tables)
: name (std::forward<T_name> (p_name))
, tables(std::forward<T_tables>(p_tables))
{ }

cpphibernate_copyable(schema_t, delete);
cpphibernate_moveable(schema_t, default);

inline void print(std::ostream& os) const
{
using namespace ::utl;
size_t index = 0;
os << indent << '{'
<< incindent
<< indent << "\"name\": \"" << name << "\","
<< indent << "\"tables\": "
<< indent << '['
<< incindent;
hana::for_each(tables, [&](auto& table){
if (index++ > 0) os << ",";
table.print(os);
});
os << decindent
<< indent << ']'
<< decindent
<< indent << '}';
}
};

/* schema_builder */

template <typename X, typename = void>
struct schema_builder
{
template <typename... T_args>
static constexpr decltype(auto) apply(T_args&&... args)
{ static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::make_schema(...)!"); }
};

template<typename T_name, typename T_tables>
struct schema_builder<mp::list<T_name, T_tables>, mp::enable_if_c<
is_tables<mp::clean_type<T_tables>>::value>>
{
static constexpr decltype(auto) apply(T_name&& name, T_tables&& tables)
{ return schema_t<T_name, T_tables>(std::forward<T_name>(name), std::forward<T_tables>(tables)); }
};

}

/* meta */

template<typename T>
struct is_schema : mp::is_specialization_of<T, __impl::schema_t> { };

/* make */

constexpr decltype(auto) make_schema = misc::make_generic_predicate<__impl::schema_builder> { };

}
end_namespace_cpphibernate_schema

+ 206
- 0
include/cpphibernate/schema/setter.h View File

@@ -0,0 +1,206 @@
#pragma once

#include <cpphibernate/config.h>
#include <cpphibernate/misc/general.h>

beg_namespace_cpphibernate_schema
{

namespace __impl
{

/* setter_t */

template<typename T_value>
struct setter_t
{
using value_type = T_value;
};


/* setter_none_t */

struct setter_none_t
: public setter_t<void>
{
using base_type = setter_t<void>;
using value_type = typename base_type::value_type;

cpphibernate_constructable(setter_none_t, default);
cpphibernate_copyable (setter_none_t, delete);
cpphibernate_moveable (setter_none_t, default);
};

/* setter_member_var_t */

template<typename T_dataset, typename T_value, typename T_member>
struct setter_member_var_t
: public setter_t<T_value>
{
using base_type = setter_t<T_value>;
using value_type = typename base_type::value_type;
using dataset_type = T_dataset;
using member_type = T_member;

member_type member;

template<typename X_member>
constexpr setter_member_var_t(X_member&& p_member)
: member(std::forward<X_member>(p_member))
{ }

cpphibernate_copyable(setter_member_var_t, delete);
cpphibernate_moveable(setter_member_var_t, default);

template<typename X_dataset, typename X_value>
constexpr decltype(auto) operator()(X_dataset&& data, X_value&& value) const
{ return std::forward<X_dataset>(data).*member = std::forward<X_value>(value); }
};

/* setter_member_func_t */

template<typename T_dataset, typename T_value, typename T_member>
struct setter_member_func_t
: public setter_t<T_value>
{
using base_type = setter_t<T_value>;
using value_type = typename base_type::value_type;
using dataset_type = T_dataset;
using member_type = T_member;

member_type member;

template<typename X_member>
constexpr setter_member_func_t(X_member&& p_member)
: member(std::forward<X_member>(p_member))
{ };

cpphibernate_copyable(setter_member_func_t, delete);
cpphibernate_moveable(setter_member_func_t, default);

template<typename X_dataset, typename X_value>
constexpr decltype(auto) operator()(X_dataset&& data, X_value&& value) const
{ return (std::forward<X_dataset>(data).*member)(std::forward<X_value>(value)); }
};

/* setter_lambda_t */

template<typename T_dataset, typename T_value, typename T_lambda>
struct setter_lambda_t
: public setter_t<T_value>
{
using base_type = setter_t<T_value>;
using value_type = typename base_type::value_type;
using dataset_type = T_dataset;
using lambda_type = T_lambda;

lambda_type lambda;

template<typename X_lambda>
constexpr setter_lambda_t(X_lambda&& p_lambda)
: lambda(std::forward<X_lambda>(p_lambda))
{ }

cpphibernate_copyable(setter_lambda_t, delete);
cpphibernate_moveable(setter_lambda_t, default);

template<typename X_dataset, typename X_value>
constexpr decltype(auto) operator()(X_dataset&& data, X_value&& value) const
{ return lambda(std::forward<X_dataset>(data), std::forward<X_value>(value)); }
};

/* is_setter_impl */

template<typename T, typename = void>
struct is_setter_impl
: public mp::c_false_t
{ };

template<typename T>
struct is_setter_impl<T, mp::enable_if_c<
mp::is_base_of<setter_t<typename T::value_type>, T>::value>>
: public mp::c_true_t
{ };

}

/* meta */

template<typename T>
struct is_setter :
public __impl::is_setter_impl<T>
{ };

/* make */

constexpr decltype(auto) make_setter_none()
{ return __impl::setter_none_t(); }

template<typename T_dataset, typename T_value>
constexpr decltype(auto) make_setter_member_var(T_value T_dataset::* member)
{ return __impl::setter_member_var_t<T_dataset, T_value, T_value T_dataset::*>(member); }

template<typename T_dataset, typename T_value, typename T_return>
constexpr decltype(auto) make_setter_member_func(T_return (T_dataset::*member)(T_value))
{ return __impl::setter_member_func_t<T_dataset, T_value, T_return (T_dataset::*)(T_value)>(member); }

template<typename T_dataset, typename T_value, typename T_return>
constexpr decltype(auto) make_setter_member_func(T_return (T_dataset::*member)(T_value) const)
{ return __impl::setter_member_func_t<const T_dataset, T_value, T_return (T_dataset::*)(T_value) const>(member); }

template<typename T_dataset, typename T_value, typename T_lambda>
constexpr decltype(auto) make_setter_lambda(T_lambda&& lambda, boost::hana::basic_type<T_dataset>, boost::hana::basic_type<T_value>)
{ return __impl::setter_lambda_t<T_dataset, T_value, T_lambda>(std::forward<T_lambda>(lambda)); }


namespace __impl
{

/* setter_buildser */

template<typename X, typename = void>
struct setter_builder
{
template<typename... Args>
static constexpr decltype(auto) apply(Args&&...)
{ return make_setter_none(); }
};

template<typename T_dataset, typename T_value>
struct setter_builder<mp::list<T_value T_dataset::*>, void>
{
static constexpr decltype(auto) apply(T_value T_dataset::*member)
{ return make_setter_member_var(member); }
};

template<typename T_dataset, typename T_value>
struct setter_builder<mp::list<T_value (T_dataset::*)(void)>, void>
{
static constexpr decltype(auto) apply(T_value (T_dataset::*member)(void))
{ return make_setter_member_func(member); }
};

template<typename T_dataset, typename T_value>
struct setter_builder<mp::list<T_value (T_dataset::*)(void) const>, void>
{
static constexpr decltype(auto) apply(T_value (T_dataset::*member)(void) const)
{ return make_setter_member_func(member); }
};

template<typename T_func, typename T_dataset_type, typename T_value_type>
struct setter_builder<mp::list<T_func, T_dataset_type, T_value_type>, mp::enable_if_c<
hana::is_a<hana::type_tag, mp::clean_type<T_dataset_type>>
&& hana::is_a<hana::type_tag, mp::clean_type<T_value_type>>>>
{
static constexpr decltype(auto) apply(T_func&& func, T_dataset_type&& dataset_type, T_value_type&& value_type)
{ return make_setter_lambda(std::forward<T_func>(func), std::forward<T_dataset_type>(dataset_type), std::forward<T_value_type>(value_type)); }
};

}

/* make */

constexpr decltype(auto) make_setter = misc::make_generic_predicate<__impl::setter_builder> { };

}
end_namespace_cpphibernate_schema

+ 109
- 0
include/cpphibernate/schema/table.h View File

@@ -0,0 +1,109 @@
#pragma once

#include <cpphibernate/config.h>
#include <cpphibernate/misc/wrap.h>
#include <cpphibernate/misc/general.h>
#include <cpphibernate/schema/fields.h>

beg_namespace_cpphibernate_schema
{

namespace __impl
{

/* table_t */

template<typename T_name, typename T_dataset_wrapped, typename T_table_id, typename T_fields>
struct table_t
{
using name_type = T_name;
using dataset_wrapped_type = mp::decay_t<T_dataset_wrapped>;
using table_id_type = T_table_id;
using fields_type = T_fields;
using this_type = table_t<name_type, dataset_wrapped_type, table_id_type, fields_type>;

name_type name;
dataset_wrapped_type dataset_wrapped;
table_id_type table_id;
fields_type fields;

constexpr table_t(
T_name p_name,
T_dataset_wrapped p_dataset_wrapped,
T_table_id p_table_id,
T_fields p_fields)
: name (std::forward<T_name> (p_name))
, dataset_wrapped (std::forward<T_dataset_wrapped>(p_dataset_wrapped))
, table_id (std::forward<T_table_id> (p_table_id))
, fields (std::forward<T_fields> (p_fields))
{ }

cpphibernate_copyable(table_t, delete);
cpphibernate_moveable(table_t, default);

cpphibernate_equality_comparable();

inline void print(std::ostream& os) const
{
using namespace ::utl;
size_t index = 0;
os << indent << '{'
<< incindent
<< indent << "\"name\": \"" << name << "\","
<< indent << "\"dataset_wrapped\": \"" << utl::type_helper<misc::decay_unwrap_t<dataset_wrapped_type>>::name() << "\""
<< indent << "\"table_id\": \"" << hana::value(table_id) << "\""
<< indent << "\"fields\": "
<< indent << '['
<< incindent;
hana::for_each(fields, [&](auto& field){
if (index++ > 0) os << ",";
field.print(os);
});
os << decindent
<< indent << ']'
<< decindent
<< indent << '}';
}
};

/* table_builder */

template <typename X, typename = void>
struct table_builder
{
template <typename... T_args>
static constexpr decltype(auto) apply(T_args&&... args)
{ static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::make_table(...)!"); }
};

template<typename T_name, typename T_dataset_wrapped, typename T_id, typename T_fields>
struct table_builder<mp::list<T_name, T_dataset_wrapped, T_id, T_fields>, mp::enable_if_c<
hana::is_a<hana::type_tag, T_dataset_wrapped>
&& is_fields<mp::decay_t<T_fields>>::value>>
{
static constexpr decltype(auto) apply(T_name&& name, T_dataset_wrapped&& dataset_wrapped, T_id&& id, T_fields&& fields)
{
return table_t<T_name, T_dataset_wrapped, T_id, T_fields>(
std::forward<T_name> (name),
std::forward<T_dataset_wrapped> (dataset_wrapped),
std::forward<T_id> (id),
std::forward<T_fields> (fields));
}
};

}

/* meta */

template<typename T>
struct is_table : mp::is_specialization_of<T, __impl::table_t> { };

template<typename... T>
struct all_are_tables : mp::all_true<is_table<T>::value...> { };

/* make */

constexpr decltype(auto) make_table = misc::make_generic_predicate<__impl::table_builder> { };

}
end_namespace_cpphibernate_schema

+ 62
- 0
include/cpphibernate/schema/tables.h View File

@@ -0,0 +1,62 @@
#pragma once

#include <cpphibernate/config.h>
#include <cpphibernate/misc/general.h>
#include <cpphibernate/schema/table.h>

beg_namespace_cpphibernate_schema
{

namespace __impl
{

/* tables_t */

template<typename... T_table>
using tables_t = hana::tuple<T_table...>;

/* is_tables_impl */

template<typename T, typename = void>
struct is_tables_impl
: mp::c_false_t
{ };

template<typename... T>
struct is_tables_impl<tables_t<T...>, mp::enable_if<all_are_tables<T...>>>
: mp::c_true_t
{ };

/* tables_builder */

template <typename X, typename = void>
struct tables_builder
{
template <typename... T_args>
static constexpr decltype(auto) apply(T_args&&... args)
{ static_assert(sizeof...(args) == -1, "Invalid parameters for hibernate::schema::make_tables(...)!"); }
};

template<typename... T>
struct tables_builder<mp::list<T...>, mp::enable_if<all_are_tables<T...>>>
{
template <typename ...T_tables>
static constexpr decltype(auto) apply(T_tables&&... tables)
{ return tables_t<T_tables...>(std::forward<T_tables>(tables)...); }
};

}

/* meta */

template<typename T>
struct is_tables
: public __impl::is_tables_impl<T>
{ };

/* make */

constexpr decltype(auto) make_tables = misc::make_generic_predicate<__impl::tables_builder> { };

}
end_namespace_cpphibernate_schema

+ 51
- 0
include/cpphibernate/types.h View File

@@ -0,0 +1,51 @@
#pragma once

#include <string>
#include <iostream>

#include <cpphibernate/config.h>

#include <cpputils/misc/exception.h>

beg_namespace_cpphibernate
{

/* string */

template<size_t N>
struct string
: public std::string
{
static constexpr decltype(auto) max_size = N;
using std::string::string;
using std::string::operator=;
};

/* uuid */

struct uuid
: public std::array<uint8_t, 16>
{
public:
inline uuid()
: std::array<uint8_t, 16>::array({ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } })
{ }

inline uuid(const std::string& str)
: std::array<uint8_t, 16>::array({ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } })
{
if (!from_string(str, *this))
throw utl::argument_exception("str", "invalid uuid");
}

cpphibernate_copyable(uuid, default);
cpphibernate_moveable(uuid, default);

void to_string(std::ostream& os) const;

public:
static bool from_string(const std::string& str, uuid& val);
};

}
end_namespace_cpphibernate

+ 8
- 0
src/CMakeLists.txt View File

@@ -11,6 +11,10 @@ Set ( CMAKE_CXX_STANDARD 17 )
Set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${PEDANTIC_C_FLAGS}" )
Set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PEDANTIC_CXX_FLAGS}" )

# Dependencies ####################################################################################

Find_Package ( cpputils REQUIRED )

# Project: cpphibernate ###############################################################################

Project ( cpphibernate VERSION 1.0.0.0 LANGUAGES CXX )
@@ -20,6 +24,10 @@ Target_Include_Directories (
cpphibernate
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../include
)
Target_Link_Libraries (
cpphibernate
cpputils
)
If ( __COTIRE_INCLUDED )
Cotire ( cpphibernate )
EndIf ( )


+ 54
- 0
src/types.cpp View File

@@ -0,0 +1,54 @@
#include <iomanip>

#include <cpphibernate/types.h>

using namespace ::cpphibernate;;

void uuid::to_string(std::ostream& os) const
{
os << std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[ 0]
<< std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[ 1]
<< std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[ 2]
<< std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[ 3]
<< '-'
<< std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[ 4]
<< std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[ 5]
<< '-'
<< std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[ 6]
<< std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[ 7]
<< '-'
<< std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[ 8]
<< std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[ 9]
<< '-'
<< std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[10]
<< std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[11]
<< std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[12]
<< std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[13]
<< std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[14]
<< std::setw(2) << std::setfill('0') << std::hex << (int)(*this)[15];
}

bool uuid::from_string(const std::string& str, uuid& val)
{
const char* c = str.data();
const char* e = c + str.size();
size_t i = 0;
val.fill(0);
while(i < 32 && c < e)
{
if (*c >= '0' && *c <= '9')
val[i >> 1] |= ((*c - '0') << (4 * (1 - (i & 1))));
else if (*c >= 'a' && *c <= 'f')
val[i >> 1] |= ((*c - 'a' + 10) << (4 * (1 - (i & 1))));
else if (*c >= 'A' && *c <= 'F')
val[i >> 1] |= ((*c - 'A' + 10) << (4 * (1 - (i & 1))));
else if (*c != '-')
return false;
if (*c != '-')
++i;
++c;
}
if (i != 32 || c != e)
return false;
return true;
}

+ 128
- 0
test/cpphibernate.cpp View File

@@ -0,0 +1,128 @@
#include <gtest/gtest.h>
#include <cpphibernate.h>

using namespace ::cpphibernate;

struct test1
{
uuid id;
std::string str_data;
string<64> str64_data;
};

struct test2
{
uuid id;
uint8_t u8_data;
int8_t i8_data;
uint16_t u16_data;
int16_t i16_data;
};

struct test3
{
uuid id;
uint32_t u32_data;
int32_t i32_data;
uint64_t u64_data;
int64_t i64_data;
};

struct base
{
uuid id;
std::string name;
};

struct derived1
: public base
{
uuid derived1_id;
test1 test1_data;
};

struct derived2
: public base
{
uuid derived2_id;
utl::nullable<test2> test2_nullable;
std::unique_ptr<test2> test2_ptr_u;
std::shared_ptr<test2> test2_ptr_s;
};

struct derived3
: public derived1
{
uuid derived3_id;
std::list<test3> test3_list;
std::vector<test3> test3_vector;
};

constexpr decltype(auto) test_schema = cpphibernate_make_schema(
test,
cpphibernate_make_table_name(
tbl_test1,
test1,
1,
cpphibernate_make_id (&test1::id),
cpphibernate_make_field (test1, str_data),
cpphibernate_make_field (test1, str64_data)
),
cpphibernate_make_table_name(
tbl_test2,
test2,
2,
cpphibernate_make_id (&test2::id),
cpphibernate_make_field (test2, u8_data),
cpphibernate_make_field (test2, i8_data),
cpphibernate_make_field (test2, u16_data),
cpphibernate_make_field (test2, i16_data)
),
cpphibernate_make_table_name(
tbl_test3,
test3,
3,
cpphibernate_make_id (&test3::id),
cpphibernate_make_field (test3, u32_data),
cpphibernate_make_field (test3, i32_data),
cpphibernate_make_field (test3, u64_data),
cpphibernate_make_field (test3, i64_data)
),

cpphibernate_make_table_name(
tbl_base,
base,
10,
cpphibernate_make_id (&base::id),
cpphibernate_make_field (base, name)
),
cpphibernate_make_table_name(
tbl_derived1,
derived1,
11,
cpphibernate_make_id (&derived1::derived1_id),
cpphibernate_make_field (derived1, test1_data)
),
cpphibernate_make_table_name(
tbl_derived2,
derived2,
12,
cpphibernate_make_id (&derived2::derived2_id),
cpphibernate_make_field (derived2, test2_nullable),
cpphibernate_make_field (derived2, test2_ptr_u),
cpphibernate_make_field (derived2, test2_ptr_s)
),
cpphibernate_make_table_name(
tbl_derived3,
derived3,
13,
cpphibernate_make_id (&derived3::derived3_id),
cpphibernate_make_field (derived3, test3_list),
cpphibernate_make_field (derived3, test3_vector)
)
);

TEST(CppHibernateTests, fuuu)
{
std::cout << test_schema << std::endl;
}

Loading…
Cancel
Save