Procházet zdrojové kódy

* refactored field members (make virtual calls to members if possible)

* added index database field for sorted containers (like vector or list)
* started to implement mariadb read methods
master
bergmann před 7 roky
rodič
revize
33e34725ad
26 změnil soubory, kde provedl 878 přidání a 281 odebrání
  1. +6
    -5
      include/cpphibernate/context.h
  2. +2
    -0
      include/cpphibernate/driver/mariadb/helper/context.h
  3. +1
    -1
      include/cpphibernate/driver/mariadb/helper/type_properties.h
  4. +3
    -1
      include/cpphibernate/driver/mariadb/impl.h
  5. +4
    -1
      include/cpphibernate/driver/mariadb/impl/create_update.h
  6. +65
    -0
      include/cpphibernate/driver/mariadb/impl/limit.h
  7. +69
    -0
      include/cpphibernate/driver/mariadb/impl/modifier_tags.h
  8. +183
    -0
      include/cpphibernate/driver/mariadb/impl/where.h
  9. +9
    -0
      include/cpphibernate/driver/mariadb/mariadb.h
  10. +92
    -74
      include/cpphibernate/driver/mariadb/schema/field.h
  11. +48
    -54
      include/cpphibernate/driver/mariadb/schema/field.inl
  12. +1
    -0
      include/cpphibernate/driver/mariadb/schema/schema.h
  13. +3
    -0
      include/cpphibernate/driver/mariadb/schema/table.inl
  14. +22
    -0
      include/cpphibernate/misc/container_helper.h
  15. +32
    -11
      include/cpphibernate/misc/meta.h
  16. +1
    -0
      include/cpphibernate/modifier.h
  17. +1
    -1
      include/cpphibernate/modifier/modifier.h
  18. +65
    -0
      include/cpphibernate/modifier/modifiers.h
  19. +2
    -1
      include/cpphibernate/modifier/where/clauses.h
  20. +114
    -82
      src/driver/mariadb/schema/field.cpp
  21. +27
    -3
      src/driver/mariadb/schema/schema.cpp
  22. +55
    -23
      src/driver/mariadb/schema/table.cpp
  23. +1
    -0
      test/CMakeLists.txt
  24. +36
    -24
      test/cpphibernate_create.cpp
  25. +2
    -0
      test/cpphibernate_init.cpp
  26. +34
    -0
      test/cpphibernate_read.cpp

+ 6
- 5
include/cpphibernate/context.h Zobrazit soubor

@@ -53,13 +53,14 @@ beg_namespace_cpphibernate
template<typename T_dataset, typename... T_modifiers>
constexpr auto read(T_dataset& dataset, T_modifiers&&... modifiers)
-> mp::enable_if<
modifier::all_are_modifier<mp::decay_t<T_modifiers>...>>
modifier::all_are_modifiers<mp::decay_t<T_modifiers>...>>
{
using namespace modifier;
using real_dataset_type = misc::real_dataset_t<mp::decay_t<T_dataset>>;
schema::tables::find(_schema.tables, hana::type_c<real_dataset_type>);
this->read_impl(dataset, hana::make_tuple(std::forward<T_modifiers>(modifiers)...));
this->read_impl(dataset, modifier::make_list(std::forward<T_modifiers>(modifiers)...));
}
template<typename T_dataset>
constexpr auto read(T_dataset& dataset)
-> mp::enable_if_c<
@@ -70,7 +71,7 @@ beg_namespace_cpphibernate
using real_dataset_type = misc::real_dataset_t<mp::decay_t<T_dataset>>;
auto& table = schema::tables::find(_schema.tables, hana::type_c<real_dataset_type>);
auto& primary_key = schema::table::get_primary_key_field(table);
this->read_impl(dataset, hana::make_tuple(where(equal(primary_key, primary_key.getter(dataset)))));
this->read_impl(dataset, modifier::make_list(where(equal(primary_key, primary_key.getter(dataset)))));
}

template<typename T_dataset>
@@ -82,7 +83,7 @@ beg_namespace_cpphibernate
using namespace modifier;
using real_dataset_type = misc::real_dataset_t<mp::decay_t<T_dataset>>;
schema::tables::find(_schema.tables, hana::type_c<real_dataset_type>);
this->read_impl(dataset, hana::make_tuple());
this->read_impl(dataset, modifier::make_list());
}

/* update */


+ 2
- 0
include/cpphibernate/driver/mariadb/helper/context.h Zobrazit soubor

@@ -124,6 +124,7 @@ beg_namespace_cpphibernate_driver_mariadb
const table_t* derived_table;
const field_t* owner_field;
std::string owner_key;
ssize_t index;

template<typename T_data>
inline create_update_context(
@@ -136,6 +137,7 @@ beg_namespace_cpphibernate_driver_mariadb
, is_update (p_is_update)
, derived_table (nullptr)
, owner_field (nullptr)
, index (-1)
{ }
};



+ 1
- 1
include/cpphibernate/driver/mariadb/helper/type_properties.h Zobrazit soubor

@@ -211,7 +211,7 @@ beg_namespace_cpphibernate_driver_mariadb
};

template<typename T>
struct type_properties<T, mp::enable_if<misc::is_nullable<mp::clean_type<T>>>>
struct type_properties<T, mp::enable_if<misc::is_nullable<mp::decay_t<T>>>>
{
using nullable_type = T;
using nullable_helper_type = misc::nullable_helper<nullable_type>;


+ 3
- 1
include/cpphibernate/driver/mariadb/impl.h Zobrazit soubor

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

#include <cpphibernate/driver/mariadb/impl/create_update.h>
#include <cpphibernate/driver/mariadb/impl/create_update.h>
#include <cpphibernate/driver/mariadb/impl/limit.h>
#include <cpphibernate/driver/mariadb/impl/where.h>

+ 4
- 1
include/cpphibernate/driver/mariadb/impl/create_update.h Zobrazit soubor

@@ -99,11 +99,14 @@ beg_namespace_cpphibernate_driver_mariadb
auto& dataset = context.get<dataset_type>();

transaction_lock trans(connection);
ssize_t index = 0;
for (auto& x : dataset)
{
using new_dataset_type = mp::decay_t<decltype(x)>;
using new_create_update_impl_type = create_update_impl_t<new_dataset_type>;
new_create_update_impl_type::apply(change_context(context, x), strict);
auto new_context = change_context(context, x);
new_context.index = index++;
new_create_update_impl_type::apply(new_context, strict);
}
trans.commit();
return ret;


+ 65
- 0
include/cpphibernate/driver/mariadb/impl/limit.h Zobrazit soubor

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

#include <cpphibernate/config.h>
#include <cpphibernate/modifier.h>
#include <cpphibernate/driver/mariadb/impl/modifier_tags.h>

beg_namespace_cpphibernate_driver_mariadb
{

/* limit_builder */

template<typename T_modifiers>
struct limit_builder
{
::cppmariadb::statement statement;

limit_builder(const T_modifiers& modifier)
{
ssize_t limit = -1;
ssize_t offset = -1;

hana::for_each(modifier, [&limit, &offset](auto& modifier){
using modifier_type = mp::decay_t<decltype(modifier)>;
using is_limit_type = modifier::is_limit_modifier<modifier_type>;
using is_offset_type = modifier::is_offset_modifier<modifier_type>;
hana::eval_if(
is_limit_type { },
[&limit, &modifier](auto _){
limit = hana::value(_(modifier).value);
},
[&offset, &modifier](){
hana::eval_if(
is_offset_type { },
[&offset, &modifier](auto _){
offset = hana::value(_(modifier).value);
},
[]{
/* no-op */
});
});
});

if (offset >= 0 && limit < 0)
limit = 1000000;

if (limit >= 0)
{
std::ostringstream ss;
ss << "LIMIT " << limit;
if (offset >= 0)
ss << " OFFSET" << offset;
statement.assign(ss.str());
}
}
};

template<typename T_modifiers>
inline ::cppmariadb::statement& build_limit(const T_modifiers& modifiers)
{
static limit_builder<T_modifiers> builder(modifiers);
return builder.statement;
}

}
end_namespace_cpphibernate_driver_mariadb

+ 69
- 0
include/cpphibernate/driver/mariadb/impl/modifier_tags.h Zobrazit soubor

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

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

beg_namespace_cpphibernate_driver_mariadb
{

namespace __impl
{

/* make_modifier_tags_impl */

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

template<typename T_modifier>
struct make_modifier_tag_impl<
mp::list<T_modifier>,
mp::enable_if_c<
modifier::is_limit_modifier<mp::decay_t<T_modifier>>::value
|| modifier::is_offset_modifier<mp::decay_t<T_modifier>>::value>>
{
static constexpr decltype(auto) apply(T_modifier&&)
{ return T_modifier { }; }
};

}

constexpr decltype(auto) make_modifier_tag = misc::make_generic_predicate<__impl::make_modifier_tag_impl> { };

namespace __impl
{

/* make_modifier_tags_impl */

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

template<typename T_modifiers>
struct make_modifier_tags_impl<
mp::list<T_modifiers>,
mp::enable_if_c<
modifier::is_modifiers<mp::decay_t<T_modifiers>>::value>>
{
static constexpr decltype(auto) apply(T_modifiers&& modifiers)
{
return hana::transform(
modifiers,
make_modifier_tag);
}
};

}

constexpr decltype(auto) make_modifier_tags = misc::make_generic_predicate<__impl::make_modifier_tags_impl> { };

}
end_namespace_cpphibernate_driver_mariadb

+ 183
- 0
include/cpphibernate/driver/mariadb/impl/where.h Zobrazit soubor

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

#include <sstream>
#include <cpphibernate/config.h>
#include <cpphibernate/modifier.h>
#include <cpphibernate/driver/mariadb/schema/schema.h>

beg_namespace_cpphibernate_driver_mariadb
{

/* where_builder */

template<typename T_modifiers>
struct where_builder
{
private:
struct build_t
{
const schema_t& schema;
const T_modifiers& modifiers;
std::ostringstream os;

inline build_t(const schema_t& p_schema, const T_modifiers& p_modifiers)
: schema (p_schema)
, modifiers (p_modifiers)
{ }

template<typename T_clause>
inline auto build_clause(T_clause&& clause)
-> mp::enable_if<modifier::is_where_clause_and<mp::decay_t<T_clause>>>
{
os << "(";
build_clause(os, clause.clauses[hana::size_c<0>]);
os << ")";
hana::for_each(
hana::remove_at(clause.clauses, hana::size_c<0>),
[&](auto& clause) {
os << " AND (";
build_clause(os, clause);
os << ")";
});
}

template<typename T_clause>
inline auto build_clause(T_clause&& clause)
-> mp::enable_if<modifier::is_where_clause_or<mp::decay_t<T_clause>>>
{
os << "(";
build_clause(os, clause.clauses[hana::size_c<0>]);
os << ")";
hana::for_each(
hana::remove_at(clause.clauses, hana::size_c<0>),
[&](auto& clause) {
os << " OR (";
build_clause(os, clause);
os << ")";
});
}

template<typename T_clause>
inline auto build_clause(T_clause&& clause)
-> mp::enable_if<modifier::is_where_clause_not<mp::decay_t<T_clause>>>
{
os << "NOT (";
build_clause(os, clause.clause);
os << ")";
}

template<typename T_clause>
inline auto build_clause(T_clause&& clause)
-> mp::enable_if<modifier::is_where_clause_equal<mp::decay_t<T_clause>>>
{
auto field_id = misc::get_type_id(hana::type_c<mp::decay_t<decltype(clause.field)>>);
auto& field = schema.field(field_id);
os << "`"
<< field.table_name
<< "`.`"
<< field.field_name
<< "`="
<< field.convert_to_open
<< "?\?"
<< field.convert_to_close;
}

inline void build(::cppmariadb::statement& statement)
{
size_t index = 0;
hana::for_each(modifiers, [&](auto& modifier){
using modifier_type = mp::decay_t<decltype(modifier)>;
using is_where_type = modifier::is_where_modifier<modifier_type>;
hana::eval_if(
is_where_type { },
[&](auto _){
if (index++ == 0) os << "WHERE (";
else os << " AND (";
build_clause(_(modifier).clause);
os << ")";
},
[]{ });
});
os << ")";
statement.assign(os.str());
}
};

struct assign_t
{
::cppmariadb::statement& statement;
const T_modifiers& modifiers;
size_t index { 0 };

inline assign_t(::cppmariadb::statement& p_statement, const T_modifiers& p_modifiers)
: statement(p_statement)
, modifiers(p_modifiers)
{ }

template<typename T_clause>
inline auto assign_clause(T_clause&& clause)
-> mp::enable_if_c<
modifier::is_where_clause_and<mp::decay_t<T_clause>>::value
|| modifier::is_where_clause_or <mp::decay_t<T_clause>>::value>
{
hana::for_each([&](auto& clause) {
assign_clause(clause);
});
}

template<typename T_clause>
inline auto assign_clause(T_clause&& clause)
-> mp::enable_if<modifier::is_where_clause_not<mp::decay_t<T_clause>>>
{
assign_clause(clause.clause);
}

template<typename T_clause>
inline auto assign_clause(T_clause&& clause)
-> mp::enable_if<modifier::is_where_clause_equal<mp::decay_t<T_clause>>>
{
statement.set(index, clause.value);
++index;
}

inline void assign()
{
hana::for_each(modifiers, [&](auto& modifier){
using modifier_type = mp::decay_t<decltype(modifier)>;
using is_where_type = modifier::is_where_modifier<modifier_type>;
hana::eval_if(
is_where_type { },
[&](auto _){
assign_clause(_(modifier).clause);
},
[]{ });
});
}
};

private:
const schema_t* _schema { nullptr };
::cppmariadb::statement _statement;

public:
inline ::cppmariadb::statement& assign(const schema_t& schema, const T_modifiers& modifiers)
{
if (_schema != &schema)
{
build_t(schema, modifiers).build(_statement);
_schema = &schema;
}
assign_t(_statement, modifiers).assign();
return _statement;
}
};

template<typename T_modifiers>
inline decltype(auto) build_where(const schema_t& schema, const T_modifiers& modifiers)
{
static where_builder<T_modifiers> builder;
return builder.assign(schema, modifiers);
}

}
end_namespace_cpphibernate_driver_mariadb

+ 9
- 0
include/cpphibernate/driver/mariadb/mariadb.h Zobrazit soubor

@@ -40,6 +40,15 @@ beg_namespace_cpphibernate_driver_mariadb
create_update_impl_t<T_dataset>::apply(
create_update_context(dataset, _schema, _connection, _filter, false));
}

template<typename T_dataset, typename T_modifiers>
inline void read_impl(T_dataset& dataset, T_modifiers&& modifiers) const
{
auto& where = build_where(_schema, modifiers);
auto& limit = build_limit(modifiers);
std::cout << "WHERE = " << where.query(_connection) << std::endl;
std::cout << "LIMIT = " << limit.query(_connection) << std::endl;
}
};

}

+ 92
- 74
include/cpphibernate/driver/mariadb/schema/field.h Zobrazit soubor

@@ -17,104 +17,128 @@ beg_namespace_cpphibernate_driver_mariadb

struct field_t
{
size_t table_dataset_id { 0 };
size_t value_dataset_id { 0 };
bool value_is_nullable { false };
bool value_is_container { false };
std::string schema_name;
std::string table_name;
std::string field_name;
attributes_t attributes;

const table_t* table { nullptr };
const table_t* referenced_table { nullptr };
size_t id { 0 }; // unique id of the field
size_t dataset_id { 0 }; // unique id of the dataset type
size_t real_dataset_id { 0 }; // unique id of the real/unwrapped dataset type
size_t value_id { 0 }; // unique id of the value type
size_t real_value_id { 0 }; // unique id of the real/unwrapped value type

bool value_is_nullable { false }; // value is stored in a nullable container
bool value_is_container { false }; // value is stored in a container
bool value_is_ordered { false }; // value is stored in a ordered container (vector, list, ...)
bool value_is_auto_incremented { false }; // value is a auto incremented field

const table_t* table { nullptr }; // table this field belongs to
const table_t* referenced_table { nullptr }; // table that belongs to the value (if exists)

std::string schema_name; // name of the SQL schema
std::string table_name; // name of the SQL table
std::string field_name; // name of the SQL field
std::string type; // SQL type name
std::string create_arguments; // additional arguments for CREATE TABLE command

std::string convert_to_open; // SQL code to open the "convert to" operation
std::string convert_to_close; // SQL code to close the "convert to" operation
std::string convert_from_open; // SQL code to open the "convert from" operation
std::string convert_from_close; // SQL code to close the "convert from" operation

attributes_t attributes; // attributes for the field

inline field_t() = default;
inline field_t(const field_t&) = delete;
inline field_t(field_t&& other)
: table_dataset_id (std::move(other).table_dataset_id)
, value_dataset_id (std::move(other).value_dataset_id)
, value_is_nullable (std::move(other).value_is_nullable)
, value_is_container(std::move(other).value_is_container)
, schema_name (std::move(other).schema_name)
, table_name (std::move(other).table_name)
, field_name (std::move(other).field_name)
, attributes (std::move(other).attributes)
, table (nullptr)
, referenced_table (nullptr)
: id (std::move(other).id)
, dataset_id (std::move(other).dataset_id)
, real_dataset_id (std::move(other).real_dataset_id)
, value_id (std::move(other).value_id)
, real_value_id (std::move(other).real_value_id)
, value_is_nullable (std::move(other).value_is_nullable)
, value_is_container (std::move(other).value_is_container)
, value_is_auto_incremented (std::move(other).value_is_auto_incremented)
, table (nullptr)
, referenced_table (nullptr)
, schema_name (std::move(other).schema_name)
, table_name (std::move(other).table_name)
, field_name (std::move(other).field_name)
, type (std::move(other).type)
, create_arguments (std::move(other).create_arguments)
, convert_to_open (std::move(other).convert_to_open)
, convert_to_close (std::move(other).convert_to_close)
, convert_from_open (std::move(other).convert_from_open)
, convert_from_close (std::move(other).convert_from_close)
, attributes (std::move(other).attributes)
{ }
virtual ~field_t() { };

void print(std::ostream& os) const;
void print (std::ostream& os) const;
virtual void update ();

/* CRUD */
virtual value_t foreign_create_update(const create_update_context& context) const;
virtual value_t foreign_create_update (const create_update_context& context) const;

/* properties */
virtual std::string type () const;
virtual std::string create_table_arguments () const;
virtual std::string generate_value (::cppmariadb::connection& connection) const;
virtual bool is_auto_generated () const;
virtual bool is_default (const data_context& context) const;
virtual std::string convert_to_open () const;
virtual std::string convert_to_close () const;
virtual std::string convert_from_open () const;
virtual std::string convert_from_close () const;
virtual value_t get (const data_context& context) const;
virtual void set (const data_context& context, const value_t&) const;
virtual bool is_default (const data_context& context) const;
virtual std::string generate_value (::cppmariadb::connection& connection) const;
};

/* simple_field_t */

template<typename T_schema, typename T_field>
template<typename T_field>
struct simple_field_t
: public field_t
{
using schema_type = T_schema;
using field_type = T_field;
using getter_type = typename mp::decay_t<field_type>::getter_type;
using dataset_type = typename getter_type::dataset_type;
using value_type = typename getter_type::value_type;

const schema_type& schema;
const field_type& field;

inline simple_field_t(const schema_type& p_schema, const field_type& p_field)
using base_type = field_t;
using field_type = T_field;
using getter_type = typename mp::decay_t<field_type>::getter_type;
using dataset_type = typename getter_type::dataset_type;
using real_dataset_type = misc::real_dataset_t<dataset_type>;
using value_type = typename getter_type::value_type;
using real_value_type = misc::real_dataset_t<value_type>;
using type_props = type_properties<value_type>;

const field_type& field;

inline simple_field_t(const field_type& p_field)
: field_t ()
, schema (p_schema)
, field (p_field)
{ }

virtual void update() override;
};

/* value_field_t */

template<typename T_schema, typename T_field>
template<typename T_field>
struct value_field_t
: public simple_field_t<T_schema, T_field>
: public simple_field_t<T_field>
{
using base_type = simple_field_t<T_schema, T_field>;
using schema_type = T_schema;
using field_type = T_field;
using getter_type = typename base_type::getter_type;
using dataset_type = typename base_type::dataset_type;
using value_type = typename base_type::value_type;
using type_props = type_properties<value_type>;
using base_type = simple_field_t<T_field>;
using field_type = typename base_type::field_type;
using getter_type = typename base_type::getter_type;
using dataset_type = typename base_type::dataset_type;
using real_dataset_type = typename base_type::dataset_type;
using value_type = typename base_type::value_type;
using real_value_type = typename base_type::real_value_type;
using type_props = typename base_type::type_props;

using base_type::base_type;

virtual std::string type() const override;
virtual value_t get (const data_context& context) const override;
virtual void set (const data_context& context, const value_t&) const override;
static_assert(mp::is_same<dataset_type, real_dataset_type>::value, "internal error: dataset type mismatch!");

virtual void update () override;
virtual value_t get (const data_context& context) const override;
virtual void set (const data_context& context, const value_t&) const override;
};

/* primary_key_field_t */

template<typename T_schema, typename T_field>
template<typename T_field>
struct primary_key_field_t
: public value_field_t<T_schema, T_field>
: public value_field_t<T_field>
{
using base_type = value_field_t<T_schema, T_field>;
using schema_type = typename base_type::schema_type;
using base_type = value_field_t<T_field>;
using field_type = typename base_type::field_type;
using dataset_type = typename base_type::dataset_type;
using value_type = typename base_type::value_type;
@@ -122,35 +146,29 @@ beg_namespace_cpphibernate_driver_mariadb

using base_type::base_type;

virtual std::string create_table_arguments () const override;
virtual std::string generate_value (::cppmariadb::connection& connection) const override;
virtual bool is_auto_generated () const override;
virtual bool is_default (const data_context& context) const override;
virtual std::string convert_to_open () const override;
virtual std::string convert_to_close () const override;
virtual std::string convert_from_open () const override;
virtual std::string convert_from_close () const override;
virtual bool is_default (const data_context& context) const override;
virtual std::string generate_value(::cppmariadb::connection& connection) const override;
};

/* data_field_t */

template<typename T_schema, typename T_field>
template<typename T_field>
struct data_field_t
: public value_field_t<T_schema, T_field>
: public value_field_t<T_field>
{
using base_type = value_field_t<T_schema, T_field>;
using base_type = value_field_t<T_field>;

using base_type::base_type;
};

/* foreign_table_field_t */

template<typename T_schema, typename T_field>
template<typename T_field>
struct foreign_table_field_t
: public simple_field_t<T_schema, T_field>
: public simple_field_t<T_field>
{
public:
using base_type = simple_field_t<T_schema, T_field>;
using base_type = simple_field_t<T_field>;
using dataset_type = typename base_type::dataset_type;

using base_type::base_type;


+ 48
- 54
include/cpphibernate/driver/mariadb/schema/field.inl Zobrazit soubor

@@ -6,21 +6,46 @@
beg_namespace_cpphibernate_driver_mariadb
{

/* simple_field_t */

template<typename T_field>
void simple_field_t<T_field>
::update()
{
base_type::update();

id = misc::get_type_id(hana::type_c<field_type>);
dataset_id = misc::get_type_id(hana::type_c<dataset_type>);
real_dataset_id = misc::get_type_id(hana::type_c<real_dataset_type>);
value_id = misc::get_type_id(hana::type_c<value_type>);
real_value_id = misc::get_type_id(hana::type_c<real_value_type>);

value_is_nullable = misc::is_nullable<value_type>::value;
value_is_container = misc::is_container<value_type>::value;
value_is_ordered = misc::is_ordered<value_type>::value;
}

/* value_field_t */

template<typename T_schema, typename T_field>
std::string value_field_t<T_schema, T_field>::type() const
{ return type_props::type(); }
template<typename T_field>
void value_field_t<T_field>
::update()
{
base_type::update();
this->type = type_props::type();
}

template<typename T_schema, typename T_field>
value_t value_field_t<T_schema, T_field>::get(const data_context& context) const
template<typename T_field>
value_t value_field_t<T_field>
::get(const data_context& context) const
{
auto& dataset = context.get<dataset_type>();
return type_props::convert_from(this->field.getter(dataset));
}

template<typename T_schema, typename T_field>
void value_field_t<T_schema, T_field>::set(const data_context& context, const value_t& value) const
template<typename T_field>
void value_field_t<T_field>
::set(const data_context& context, const value_t& value) const
{
auto& dataset = context.get<dataset_type>();
this->field.setter(dataset, type_props::convert_to(value));
@@ -28,12 +53,16 @@ beg_namespace_cpphibernate_driver_mariadb

/* primary_key_field_t */

template<typename T_schema, typename T_field>
std::string primary_key_field_t<T_schema, T_field>::create_table_arguments() const
{ return key_props::create_table_argument; }
template<typename T_field>
bool primary_key_field_t<T_field>
::is_default(const data_context& context) const
{
auto& dataset = context.get<dataset_type>();
return key_props::is_default(this->field.getter(dataset));
}

template<typename T_schema, typename T_field>
std::string primary_key_field_t<T_schema, T_field>
template<typename T_field>
std::string primary_key_field_t<T_field>
::generate_value(::cppmariadb::connection& connection) const
{
auto ret = connection.execute_used(key_props::create_key_query);
@@ -42,37 +71,10 @@ beg_namespace_cpphibernate_driver_mariadb
return ret->current()->at(0).template get<std::string>();
}

template<typename T_schema, typename T_field>
bool primary_key_field_t<T_schema, T_field>::is_auto_generated() const
{ return key_props::auto_generated::value; }

template<typename T_schema, typename T_field>
bool primary_key_field_t<T_schema, T_field>::is_default(const data_context& context) const
{
auto& dataset = context.get<dataset_type>();
return key_props::is_default(this->field.getter(dataset));
}

template<typename T_schema, typename T_field>
std::string primary_key_field_t<T_schema, T_field>::convert_to_open() const
{ return key_props::convert_to_open; }

template<typename T_schema, typename T_field>
std::string primary_key_field_t<T_schema, T_field>::convert_to_close() const
{ return key_props::convert_to_close; }

template<typename T_schema, typename T_field>
std::string primary_key_field_t<T_schema, T_field>::convert_from_open() const
{ return key_props::convert_from_open; }

template<typename T_schema, typename T_field>
std::string primary_key_field_t<T_schema, T_field>::convert_from_close() const
{ return key_props::convert_from_close; }

/* foreign_table_field_t */

template<typename T_schema, typename T_field>
value_t foreign_table_field_t<T_schema, T_field>
template<typename T_field>
value_t foreign_table_field_t<T_field>
::foreign_create_update(const create_update_context& context) const
{
auto& dataset = context.get<dataset_type>();
@@ -114,15 +116,15 @@ beg_namespace_cpphibernate_driver_mariadb

template<typename T_schema, typename T_field, typename = void>
struct field_type
{ using type = data_field_t<T_schema, T_field>; };
{ using type = data_field_t<T_field>; };

template<typename T_schema, typename T_field>
struct field_type<T_schema, T_field, mp::enable_if<is_primary_key_field<T_field>>>
{ using type = primary_key_field_t<T_schema, T_field>; };
{ using type = primary_key_field_t<T_field>; };

template<typename T_schema, typename T_field>
struct field_type<T_schema, T_field, mp::enable_if<is_foreign_table_field<T_schema, T_field>>>
{ using type = foreign_table_field_t<T_schema, T_field>; };
{ using type = foreign_table_field_t<T_field>; };

template<typename T_schema, typename T_field>
using field_type_t = typename field_type<T_schema, T_field>::type;
@@ -149,17 +151,9 @@ beg_namespace_cpphibernate_driver_mariadb
{
using schema_type = mp::decay_t<T_schema>;
using field_type = mp::decay_t<T_field>;
using getter_type = mp::decay_t<typename field_type::getter_type>;
using value_type = mp::decay_t<typename getter_type::value_type>;
using dataset_type = mp::decay_t<typename getter_type::dataset_type>;
using value_dataset_type = misc::real_dataset_t<value_type>;
using return_type = field_type_t<schema_type, field_type>;
using primary_key_type = primary_key_field_t<schema_type, field_type>;
return_type ret(schema, field);
ret.table_dataset_id = misc::get_type_id(hana::type_c<dataset_type>);
ret.value_dataset_id = misc::get_type_id(hana::type_c<value_dataset_type>);
ret.value_is_nullable = misc::is_nullable<value_type>::value;
ret.value_is_container = misc::is_container<value_type>::value;
using primary_key_type = primary_key_field_t<field_type>;
return_type ret(field);
ret.schema_name = schema.name;
ret.table_name = table.name;
ret.field_name = field.name;


+ 1
- 0
include/cpphibernate/driver/mariadb/schema/schema.h Zobrazit soubor

@@ -27,6 +27,7 @@ beg_namespace_cpphibernate_driver_mariadb
void print (std::ostream& os) const;

const table_t& table(size_t dataset_id) const;
const field_t& field(size_t field_id) const;

/* CRUD */
void init(const init_context& context) const;


+ 3
- 0
include/cpphibernate/driver/mariadb/schema/table.inl Zobrazit soubor

@@ -150,8 +150,11 @@ beg_namespace_cpphibernate_driver_mariadb
std::declval<T_table>().wrapped_dataset))>;
using wrapped_dataset_type = typename mp::decay_t<T_table>::wrapped_dataset_type;
using dataset_type = misc::unwrap_t<wrapped_dataset_type>;
using real_dataset_type = misc::real_dataset_t<dataset_type>;
using table_type = table_type_t<dataset_type, base_type>;

static_assert(mp::is_same<dataset_type, real_dataset_type>::value, "table cn only be created for simple dataset types (not for containers)!");

table_type ret(schema, table);
ret.dataset_id = misc::get_type_id(table.wrapped_dataset);
ret.base_dataset_id = misc::get_type_id(wrapped_base_type { });


+ 22
- 0
include/cpphibernate/misc/container_helper.h Zobrazit soubor

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

#include <set>
#include <list>
#include <vector>

#include <cpphibernate/config.h>

beg_namespace_cpphibernate_misc
{

/* container_helper */

template<typename T_container, typename = void>
struct container_helper
{
using container_type = T_container;
using value_type = real_dataset_t<container_type>;
};

}
end_namespace_cpphibernate_misc

+ 32
- 11
include/cpphibernate/misc/meta.h Zobrazit soubor

@@ -22,13 +22,13 @@ beg_namespace_cpphibernate_misc
: public mp::c_false_t
{ };

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

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

@@ -71,6 +71,23 @@ beg_namespace_cpphibernate_misc
: public mp::c_true_t
{ };

/* is_ordered_impl */

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

template<typename T, typename... T_args>
struct is_ordered_impl<std::list<T, T_args...>>
: public mp::c_true_t
{ };

template<typename T, typename... T_args>
struct is_ordered_impl<std::vector<T, T_args...>>
: public mp::c_true_t
{ };

/* real_dataset_impl */

template<typename T, typename = void>
@@ -81,22 +98,21 @@ beg_namespace_cpphibernate_misc
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>
template<typename T, typename... T_args>
struct real_dataset_impl<std::unique_ptr<T, T_args...>, 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>
template<typename T, typename... T_args>
struct real_dataset_impl<std::list<T, T_args...>, void>
{ using type = typename real_dataset_impl<T>::type; };

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

}

/* meta */
@@ -111,6 +127,11 @@ beg_namespace_cpphibernate_misc
: public __impl::is_nullable_impl<T>
{ };

template<typename T>
struct is_ordered
: public __impl::is_ordered_impl<T>
{ };

template<typename T>
struct is_pointer
: public __impl::is_pointer_impl<T>


+ 1
- 0
include/cpphibernate/modifier.h Zobrazit soubor

@@ -2,5 +2,6 @@

#include <cpphibernate/modifier/limit.h>
#include <cpphibernate/modifier/modifier.h>
#include <cpphibernate/modifier/modifiers.h>
#include <cpphibernate/modifier/offset.h>
#include <cpphibernate/modifier/where.h>

+ 1
- 1
include/cpphibernate/modifier/modifier.h Zobrazit soubor

@@ -23,7 +23,7 @@ beg_namespace_cpphibernate_modifier
{ };

template<typename... T>
struct all_are_modifier
struct all_are_modifiers
: public mp::all_true<is_modifier<T>::value...>
{ };



+ 65
- 0
include/cpphibernate/modifier/modifiers.h Zobrazit soubor

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

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

beg_namespace_cpphibernate_modifier
{

namespace __impl
{

/* is_modifiers_impl */

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

template<typename... T>
struct is_modifiers_impl<hana::basic_tuple<T...>, mp::enable_if<all_are_modifiers<T...>>>
: mp::c_true_t
{ };

}

/* meta */

template<typename T>
struct is_modifiers
: public __impl::is_modifiers_impl<T>
{ };

/* operations */

namespace __impl
{

/* make_modifiers_impl */

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

template<typename... T>
struct make_modifiers_impl<
mp::list<T...>,
mp::enable_if_c<
all_are_modifiers<mp::decay_t<T>...>::value>>
{
template<typename... T_args>
static constexpr decltype(auto) apply(T_args&&... args)
{ return hana::make_basic_tuple(std::forward<T_args>(args)...); }
};

}

constexpr decltype(auto) make_list = misc::make_generic_predicate<__impl::make_modifiers_impl> { };

}
end_namespace_cpphibernate_modifier

+ 2
- 1
include/cpphibernate/modifier/where/clauses.h Zobrazit soubor

@@ -3,4 +3,5 @@
#include <cpphibernate/modifier/where/clauses/and.h>
#include <cpphibernate/modifier/where/clauses/clause.h>
#include <cpphibernate/modifier/where/clauses/equal.h>
#include <cpphibernate/modifier/where/clauses/not.h>
#include <cpphibernate/modifier/where/clauses/not.h>
#include <cpphibernate/modifier/where/clauses/or.h>

+ 114
- 82
src/driver/mariadb/schema/field.cpp Zobrazit soubor

@@ -17,111 +17,143 @@ void field_t::print(std::ostream& os) const
{
os << indent << '{'
<< incindent
<< indent << "\"table_dataset_id\": " << table_dataset_id << ","
<< indent << "\"value_dataset_id\": " << value_dataset_id << ","
<< indent << "\"value_is_nullable\": " << (value_is_nullable ? "true" : "false") << ","
<< indent << "\"value_is_container\": " << (value_is_container ? "true" : "false") << ","
<< indent << "\"schema_name\": \"" << schema_name << "\","
<< indent << "\"table_name\": \"" << table_name << "\","
<< indent << "\"field_name\": \"" << field_name << "\","
<< indent << "\"attributes\": " << misc::print_container(attributes, false) << ","
<< indent << "\"table\": " << (table ? std::string("\"") + table->table_name + "\"" : "null") << ","
<< indent << "\"referenced_table\": " << (referenced_table ? std::string("\"") + referenced_table->table_name + "\"" : "null")
<< decindent
<< indent << '}';
}

#define throw_not_implemented(p_ret, p_name, ...) \
p_ret field_t::p_name(__VA_ARGS__) const \
{ \
throw misc::hibernate_exception( \
std::string("'") + table_name + "." + field_name + \
"' does not implement the " #p_name "() method!"); \
}

/* CRUD */
<< indent << "\"id\": " << id << ","
<< indent << "\"dataset_id\": " << dataset_id << ","
<< indent << "\"real_dataset_id\": " << real_dataset_id << ","
<< indent << "\"value_id\": " << value_id << ","
<< indent << "\"real_value_id\": " << real_value_id << ","
<< indent << "\"value_is_nullable\": " << (value_is_nullable ? "true" : "false") << ","
<< indent << "\"value_is_container\": " << (value_is_container ? "true" : "false") << ","
<< indent << "\"value_is_auto_incremented\": " << (value_is_auto_incremented ? "true" : "false") << ","
<< indent << "\"table\": " << (table ? std::string("\"") + table->table_name + "\"" : "null") << ","
<< indent << "\"referenced_table\": " << (referenced_table ? std::string("\"") + referenced_table->table_name + "\"" : "null") << ","

throw_not_implemented(value_t, foreign_create_update, const create_update_context&)
<< indent << "\"schema_name\": \"" << schema_name << "\","
<< indent << "\"table_name\": \"" << table_name << "\","
<< indent << "\"field_name\": \"" << field_name << "\","
<< indent << "\"type\": \"" << type << "\","
<< indent << "\"create_arguments\": \"" << create_arguments << "\","

/* properties */
<< indent << "\"convert_to_open\": \"" << convert_to_open << "\","
<< indent << "\"convert_to_close\": \"" << convert_to_close << "\","
<< indent << "\"convert_from_open\": \"" << convert_from_open << "\","
<< indent << "\"convert_from_close\": \"" << convert_from_close << "\","

throw_not_implemented(bool, is_default, const data_context& context)
throw_not_implemented(string, type)
throw_not_implemented(string, create_table_arguments)
throw_not_implemented(string, generate_value, ::cppmariadb::connection&)
throw_not_implemented(value_t, get, const data_context& context)
throw_not_implemented(void, set, const data_context& context, const value_t&)
<< indent << "\"attributes\": " << misc::print_container(attributes, false)

bool field_t::is_auto_generated() const
{ return false; }
<< decindent
<< indent << '}';
}

std::string field_t::convert_to_open() const
void field_t::update()
{
std::ostringstream ss;
for (auto it = this->attributes.begin(); it != this->attributes.end(); ++it)
id = 0;
dataset_id = 0;
real_dataset_id = 0;
value_id = 0;
real_value_id = 0;
value_is_nullable = false;
value_is_container = false;
value_is_auto_incremented = false;
table = nullptr;
referenced_table = nullptr;

type.clear();
create_arguments.clear();

/* conver_to_open */
{
switch(*it)
std::ostringstream ss;
for (auto it = this->attributes.begin(); it != this->attributes.end(); ++it)
{
case attribute_t::hex: ss << "HEX("; break;
case attribute_t::compress: ss << "COMPRESS("; break;
case attribute_t::primary_key: break;
switch(*it)
{
case attribute_t::hex:
ss << "HEX(";
break;
case attribute_t::compress:
ss << "COMPRESS(";
break;
case attribute_t::primary_key:
ss << "UuidToBin(";
break;
}
}
convert_to_open = ss.str();
}
return ss.str();
}

std::string field_t::convert_to_close() const
{
std::ostringstream ss;
for (auto it = this->attributes.begin(); it != this->attributes.end(); ++it)
/* convert_to_close */
{
switch(*it)
std::ostringstream ss;
for (auto it = this->attributes.begin(); it != this->attributes.end(); ++it)
{
case attribute_t::hex:
case attribute_t::compress:
ss << ')';
break;
case attribute_t::primary_key:
break;
switch(*it)
{
case attribute_t::hex:
case attribute_t::compress:
case attribute_t::primary_key:
ss << ')';
break;
}
}
convert_to_close = ss.str();
}
return ss.str();
}

std::string field_t::convert_from_open() const
{
std::ostringstream ss;
for (auto it = this->attributes.rbegin(); it != this->attributes.rend(); ++it)
/* convert_from_open */
{
switch(*it)
std::ostringstream ss;
for (auto it = this->attributes.rbegin(); it != this->attributes.rend(); ++it)
{
case attribute_t::hex:
ss << "UNHEX(";
break;
case attribute_t::compress:
ss << "UNCOMPRESS(";
break;
case attribute_t::primary_key:
break;
switch(*it)
{
case attribute_t::hex:
ss << "UNHEX(";
break;
case attribute_t::compress:
ss << "UNCOMPRESS(";
break;
case attribute_t::primary_key:
ss << "BinToUuid(";
break;
}
}
convert_from_open = ss.str();
}
return ss.str();
}

std::string field_t::convert_from_close() const
{
std::ostringstream ss;
for (auto it = this->attributes.rbegin(); it != this->attributes.rend(); ++it)
/* convert_from_close */
{
switch(*it)
std::ostringstream ss;
for (auto it = this->attributes.rbegin(); it != this->attributes.rend(); ++it)
{
case attribute_t::hex:
case attribute_t::compress:
ss << ')';
break;
case attribute_t::primary_key:
break;
switch(*it)
{
case attribute_t::hex:
case attribute_t::compress:
case attribute_t::primary_key:
ss << ')';
break;
}
}
convert_from_close = ss.str();
}
return ss.str();
}
}

#define throw_not_implemented(p_ret, p_name, ...) \
p_ret field_t::p_name(__VA_ARGS__) const \
{ \
throw misc::hibernate_exception( \
std::string("'") + table_name + "." + field_name + \
"' does not implement the " #p_name "() method!"); \
}

/* CRUD */

throw_not_implemented(value_t, foreign_create_update, const create_update_context&)

/* properties */

throw_not_implemented(bool, is_default, const data_context& context)
throw_not_implemented(string, generate_value, ::cppmariadb::connection&)
throw_not_implemented(value_t, get, const data_context& context)
throw_not_implemented(void, set, const data_context& context, const value_t&)

+ 27
- 3
src/driver/mariadb/schema/schema.cpp Zobrazit soubor

@@ -13,7 +13,7 @@ using namespace ::cpphibernate::driver::mariadb_impl;

void schema_t::update()
{
// clear everything
// clear everything
for (auto& kvp : tables)
{
assert(static_cast<bool>(kvp.second));
@@ -25,6 +25,13 @@ void schema_t::update()
table.foreign_table_one_fields.clear();
table.foreign_table_many_fields.clear();
table.data_fields.clear();

for (auto& ptr : table.fields)
{
assert(ptr);
auto& field = *ptr;
field.update();
}
}

// update references
@@ -54,12 +61,12 @@ void schema_t::update()
auto& field = *ptr;

// table
if (table.dataset_id != field.table_dataset_id)
if (table.dataset_id != field.dataset_id)
throw misc::hibernate_exception(std::string("dataset id of field '") + field.table_name + '.' + field.field_name + "' does not match!");
field.table = &table;

// referenced table
it = tables.find(field.value_dataset_id);
it = tables.find(field.real_value_id);
auto referenced_table = (it != tables.end()
? it->second.get()
: nullptr);
@@ -120,6 +127,23 @@ const table_t& schema_t::table(size_t dataset_id) const
return *it->second;
}

const field_t& schema_t::field(size_t field_id) const
{
for (auto& kvp : tables)
{
assert(kvp.second);
auto& table = *kvp.second;
for (auto& ptr : table.fields)
{
assert(ptr);
auto& field = *ptr;
if (field.id == field_id)
return field;
}
}
throw misc::hibernate_exception(std::string("unable to find field with id ") + std::to_string(field_id));
}

#define exec_query() \
do { \
cpphibernate_debug_log("execute init query: " << ss.str()); \


+ 55
- 23
src/driver/mariadb/schema/table.cpp Zobrazit soubor

@@ -30,12 +30,12 @@ std::string build_init_stage1_query(const table_t& table)
{
assert(table.primary_key_field);
auto& key_info = *table.primary_key_field;
auto args = key_info.create_table_arguments();
auto args = key_info.create_arguments;
os << indent
<< "`"
<< key_info.field_name
<< "` "
<< key_info.type()
<< key_info.type
<< " NOT NULL"
<< (args.empty() ? "" : " ")
<< args
@@ -52,7 +52,7 @@ std::string build_init_stage1_query(const table_t& table)
<< "`"
<< key_info.field_name
<< "` "
<< key_info.type()
<< key_info.type
<< " NOT NULL,";
}

@@ -70,7 +70,7 @@ std::string build_init_stage1_query(const table_t& table)
<< "_id_"
<< field_info.field_name
<< "` "
<< ref_key_info.type()
<< ref_key_info.type
<< (field_info.value_is_nullable
? " NULL DEFAULT NULL,"
: " NOT NULL,");
@@ -90,8 +90,17 @@ std::string build_init_stage1_query(const table_t& table)
<< "_id_"
<< field_info.field_name
<< "` "
<< ref_key_info.type()
<< ref_key_info.type
<< " NULL DEFAULT NULL,";
if (field_info.value_is_ordered)
{
os << indent
<< "`"
<< field_info.table_name
<< "_index_"
<< field_info.field_name
<< "` UNSIGNED INT NOT NULL,";
}
}

/* data fields */
@@ -103,7 +112,7 @@ std::string build_init_stage1_query(const table_t& table)
<< "`"
<< field_info.field_name
<< "` "
<< field_info.type()
<< field_info.type
<< (field_info.value_is_nullable
? " NULL DEFAULT NULL,"
: " NOT NULL,");
@@ -353,18 +362,18 @@ std::string build_create_update_query(const table_t& table, const filter_t* filt
{
assert(table.primary_key_field);
auto& key_info = *table.primary_key_field;
if (!key_info.is_auto_generated())
if (!key_info.value_is_auto_incremented)
{
if (index++)
os << ", ";
os << "`"
<< key_info.field_name
<< "`="
<< key_info.convert_to_open()
<< key_info.convert_to_open
<< "?"
<< key_info.field_name
<< "?"
<< key_info.convert_to_close();
<< key_info.convert_to_close;
}
}

@@ -381,11 +390,11 @@ std::string build_create_update_query(const table_t& table, const filter_t* filt
os << "`"
<< key_info.field_name
<< "`="
<< key_info.convert_to_open()
<< key_info.convert_to_open
<< "?"
<< key_info.field_name
<< "?"
<< key_info.convert_to_close();
<< key_info.convert_to_close;
}

/* foreign table one fields */
@@ -405,13 +414,13 @@ std::string build_create_update_query(const table_t& table, const filter_t* filt
<< "_id_"
<< field_info.field_name
<< "`="
<< key_info.convert_to_open()
<< key_info.convert_to_open
<< "?"
<< key_info.table_name
<< "_id_"
<< field_info.field_name
<< "?"
<< key_info.convert_to_close();
<< key_info.convert_to_close;
}

/* foreign fields */
@@ -431,13 +440,23 @@ std::string build_create_update_query(const table_t& table, const filter_t* filt
<< "_id_"
<< field_info.field_name
<< "`="
<< key_info.convert_to_open()
<< key_info.convert_to_open
<< "?"
<< field_info.table_name
<< "_id_"
<< field_info.field_name
<< "?"
<< key_info.convert_to_close();
<< key_info.convert_to_close;
if (field_info.value_is_ordered)
{
if (index++)
os << ", ";
os << "`"
<< field_info.table_name
<< "_index_"
<< field_info.field_name
<< "`=?\?";
}
}

/* data fields */
@@ -452,11 +471,11 @@ std::string build_create_update_query(const table_t& table, const filter_t* filt
os << "`"
<< field_info.field_name
<< "`="
<< field_info.convert_to_open()
<< field_info.convert_to_open
<< "?"
<< field_info.field_name
<< "?"
<< field_info.convert_to_close();
<< field_info.convert_to_close;
}

/* type field for derived tables */
@@ -476,11 +495,11 @@ std::string build_create_update_query(const table_t& table, const filter_t* filt
os << " WHERE `"
<< key_info.field_name
<< "`="
<< key_info.convert_to_open()
<< key_info.convert_to_open
<< "?"
<< key_info.field_name
<< "?"
<< key_info.convert_to_close();
<< key_info.convert_to_close;
}

return os.str();
@@ -503,7 +522,7 @@ std::string table_t::execute_create_update(

/* primary key */
assert(primary_key_field);
if ( !primary_key_field->is_auto_generated()
if ( !primary_key_field->value_is_auto_incremented
&& !is_update)
{
primary_key = primary_key_field->generate_value(context.connection);
@@ -550,15 +569,28 @@ std::string table_t::execute_create_update(
if (is_update && ptr != context.owner_field)
continue;

if ( context.owner_field
&& ptr == context.owner_field)
auto& field_info = *ptr;
bool set_value =
context.owner_field
&& ptr == context.owner_field;

if (set_value)
{
assert(!context.owner_key.empty());
statement.set(index, context.owner_key);
}
else
{
statement.set_null(index);
}
++index;

if (field_info.value_is_ordered)
{
if (set_value) statement.set(index, context.index);
else statement.set(index, 0);
++index;
}
}

/* data fields */
@@ -604,7 +636,7 @@ std::string table_t::execute_create_update(
cpphibernate_debug_log("execute UPDATE query: " << statement.query(connection));
}

if ( primary_key_field->is_auto_generated()
if ( primary_key_field->value_is_auto_incremented
&& !is_update)
{
auto id = connection.execute_id(statement);


+ 1
- 0
test/CMakeLists.txt Zobrazit soubor

@@ -12,6 +12,7 @@ Set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PEDANTIC_CXX

Project ( test_cpphibernate )
File ( GLOB_RECURSE SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp )
List ( FILTER SOURCE_FILES EXCLUDE REGEX "/_[A-Za-z0-9_-]*\.cpp$" )
Add_Executable ( test_cpphibernate EXCLUDE_FROM_ALL ${SOURCE_FILES} )
Target_Link_Libraries (
test_cpphibernate


+ 36
- 24
test/cpphibernate_create.cpp Zobrazit soubor

@@ -103,7 +103,9 @@ TEST(CppHibernateTests, create_test3)
"SET "
"`tbl_test3_id`=UuidToBin('X3d12737a-abb9-11e8-98d0-529269fb1459X'), "
"`tbl_derived3_id_test3_list`=UuidToBin(null), "
"`tbl_derived3_index_test3_list`='X0X', "
"`tbl_derived3_id_test3_vector`=UuidToBin(null), "
"`tbl_derived3_index_test3_vector`='X0X', "
"`u32_data`='X5X', "
"`i32_data`='X6X', "
"`u64_data`='X7X', "
@@ -325,7 +327,9 @@ TEST(CppHibernateTests, create_derived3)
"SET "
"`tbl_test3_id`=UuidToBin('X3d1289f0-abb9-11e8-98d0-529269fb1459X'), "
"`tbl_derived3_id_test3_list`=UuidToBin('X3d12866c-abb9-11e8-98d0-529269fb1459X'), "
"`tbl_derived3_index_test3_list`='X0X', "
"`tbl_derived3_id_test3_vector`=UuidToBin(null), "
"`tbl_derived3_index_test3_vector`='X0X', "
"`u32_data`='X100X', "
"`i32_data`='X101X', "
"`u64_data`='X102X', "
@@ -340,7 +344,9 @@ TEST(CppHibernateTests, create_derived3)
"SET "
"`tbl_test3_id`=UuidToBin('X3d128b26-abb9-11e8-98d0-529269fb1459X'), "
"`tbl_derived3_id_test3_list`=UuidToBin('X3d12866c-abb9-11e8-98d0-529269fb1459X'), "
"`tbl_derived3_index_test3_list`='X1X', "
"`tbl_derived3_id_test3_vector`=UuidToBin(null), "
"`tbl_derived3_index_test3_vector`='X0X', "
"`u32_data`='X110X', "
"`i32_data`='X111X', "
"`u64_data`='X112X', "
@@ -355,11 +361,13 @@ TEST(CppHibernateTests, create_derived3)
"SET "
"`tbl_test3_id`=UuidToBin('X3d128eb4-abb9-11e8-98d0-529269fb1459X'), "
"`tbl_derived3_id_test3_list`=UuidToBin(null), "
"`tbl_derived3_index_test3_list`='X0X', "
"`tbl_derived3_id_test3_vector`=UuidToBin('X3d12866c-abb9-11e8-98d0-529269fb1459X'), "
"`u32_data`='X120X', "
"`i32_data`='X121X', "
"`u64_data`='X122X', "
"`i64_data`='X123X'",
"`tbl_derived3_index_test3_vector`='X0X', "
"`u32_data`='X200X', "
"`i32_data`='X201X', "
"`u64_data`='X202X', "
"`i64_data`='X203X'",
result_affected_rows(1));

expect_query(mock, "SELECT Uuid()", result_used({
@@ -370,11 +378,13 @@ TEST(CppHibernateTests, create_derived3)
"SET "
"`tbl_test3_id`=UuidToBin('X3d128ffe-abb9-11e8-98d0-529269fb1459X'), "
"`tbl_derived3_id_test3_list`=UuidToBin(null), "
"`tbl_derived3_index_test3_list`='X0X', "
"`tbl_derived3_id_test3_vector`=UuidToBin('X3d12866c-abb9-11e8-98d0-529269fb1459X'), "
"`u32_data`='X130X', "
"`i32_data`='X131X', "
"`u64_data`='X132X', "
"`i64_data`='X133X'",
"`tbl_derived3_index_test3_vector`='X1X', "
"`u32_data`='X210X', "
"`i32_data`='X211X', "
"`u64_data`='X212X', "
"`i64_data`='X213X'",
result_affected_rows(1));

expect_query(mock, "SELECT Uuid()", result_used({
@@ -385,11 +395,13 @@ TEST(CppHibernateTests, create_derived3)
"SET "
"`tbl_test3_id`=UuidToBin('X3d129134-abb9-11e8-98d0-529269fb1459X'), "
"`tbl_derived3_id_test3_list`=UuidToBin(null), "
"`tbl_derived3_index_test3_list`='X0X', "
"`tbl_derived3_id_test3_vector`=UuidToBin('X3d12866c-abb9-11e8-98d0-529269fb1459X'), "
"`u32_data`='X140X', "
"`i32_data`='X141X', "
"`u64_data`='X142X', "
"`i64_data`='X143X'",
"`tbl_derived3_index_test3_vector`='X2X', "
"`u32_data`='X220X', "
"`i32_data`='X221X', "
"`u64_data`='X222X', "
"`i64_data`='X223X'",
result_affected_rows(1));

expect_query(mock, "COMMIT");
@@ -418,20 +430,20 @@ TEST(CppHibernateTests, create_derived3)
d3.test3_list.back().u64_data = 112;
d3.test3_list.back().i64_data = 113;
d3.test3_vector.emplace_back();
d3.test3_vector.back().u32_data = 120;
d3.test3_vector.back().i32_data = 121;
d3.test3_vector.back().u64_data = 122;
d3.test3_vector.back().i64_data = 123;
d3.test3_vector.back().u32_data = 200;
d3.test3_vector.back().i32_data = 201;
d3.test3_vector.back().u64_data = 202;
d3.test3_vector.back().i64_data = 203;
d3.test3_vector.emplace_back();
d3.test3_vector.back().u32_data = 130;
d3.test3_vector.back().i32_data = 131;
d3.test3_vector.back().u64_data = 132;
d3.test3_vector.back().i64_data = 133;
d3.test3_vector.back().u32_data = 210;
d3.test3_vector.back().i32_data = 211;
d3.test3_vector.back().u64_data = 212;
d3.test3_vector.back().i64_data = 213;
d3.test3_vector.emplace_back();
d3.test3_vector.back().u32_data = 140;
d3.test3_vector.back().i32_data = 141;
d3.test3_vector.back().u64_data = 142;
d3.test3_vector.back().i64_data = 143;
d3.test3_vector.back().u32_data = 220;
d3.test3_vector.back().i32_data = 221;
d3.test3_vector.back().u64_data = 222;
d3.test3_vector.back().i64_data = 223;

::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111));
auto context = make_context<driver::mariadb>(test_schema, connection);


+ 2
- 0
test/cpphibernate_init.cpp Zobrazit soubor

@@ -79,7 +79,9 @@ TEST(CppHibernateTests, init)
"(\n"
" `tbl_test3_id` BINARY(16) NOT NULL,\n"
" `tbl_derived3_id_test3_list` BINARY(16) NULL DEFAULT NULL,\n"
" `tbl_derived3_index_test3_list` UNSIGNED INT NOT NULL,\n"
" `tbl_derived3_id_test3_vector` BINARY(16) NULL DEFAULT NULL,\n"
" `tbl_derived3_index_test3_vector` UNSIGNED INT NOT NULL,\n"
" `u32_data` INT UNSIGNED NOT NULL,\n"
" `i32_data` INT NOT NULL,\n"
" `u64_data` BIGINT UNSIGNED NOT NULL,\n"


+ 34
- 0
test/cpphibernate_read.cpp Zobrazit soubor

@@ -0,0 +1,34 @@
#include <cpphibernate/driver/mariadb.h>

#include "test_helper.h"
#include "test_schema.h"
#include "mariadb_mock.h"

using namespace ::testing;
using namespace ::cpphibernate;

TEST(CppHibernateTests, read_test1)
{
StrictMock<mariadb_mock> mock;

// expect_query(mock, "START TRANSACTION");
// expect_query(mock, "COMMIT");

EXPECT_CALL(
mock,
mysql_close(
reinterpret_cast<MYSQL*>(0x1111)));

EXPECT_CALL(
mock,
mysql_real_escape_string(reinterpret_cast<MYSQL*>(0x1111), _, _, _))
.Times(AnyNumber())
.WillRepeatedly(WithArgs<1, 2, 3>(EscapeString()));

test1 t1;
t1.id = uuid("1e133ad8-ad2e-11e8-98d0-529269fb1459");

::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111));
auto context = make_context<driver::mariadb>(test_schema, connection);
context.read(t1);
}

Načítá se…
Zrušit
Uložit