Browse Source

* Refactored create / update operation (not finished now)

* Refactored includes (removed ring dependencies)
refactoring
bergmann 4 years ago
parent
commit
25a468c379
82 changed files with 1783 additions and 2770 deletions
  1. +2
    -0
      include/cpphibernate.h
  2. +2
    -0
      include/cpphibernate/context.h
  3. +0
    -2
      include/cpphibernate/context/context.h
  4. +10
    -5
      include/cpphibernate/context/context.inl
  5. +6
    -1
      include/cpphibernate/driver/mariadb.h
  6. +2
    -0
      include/cpphibernate/driver/mariadb/classes/attributes.h
  7. +8
    -5
      include/cpphibernate/driver/mariadb/classes/attributes/attributes.h
  8. +1
    -12
      include/cpphibernate/driver/mariadb/classes/attributes/attributes.inl
  9. +13
    -0
      include/cpphibernate/driver/mariadb/classes/fields.h
  10. +56
    -6
      include/cpphibernate/driver/mariadb/classes/fields/field.h
  11. +3
    -7
      include/cpphibernate/driver/mariadb/classes/fields/field.inl
  12. +0
    -2
      include/cpphibernate/driver/mariadb/classes/fields/field_data.h
  13. +1
    -3
      include/cpphibernate/driver/mariadb/classes/fields/field_foreign_table.h
  14. +20
    -3
      include/cpphibernate/driver/mariadb/classes/fields/field_primary_key.h
  15. +28
    -0
      include/cpphibernate/driver/mariadb/classes/fields/field_primary_key.inl
  16. +5
    -3
      include/cpphibernate/driver/mariadb/classes/fields/field_simple.h
  17. +1
    -0
      include/cpphibernate/driver/mariadb/classes/fields/field_simple.inl
  18. +17
    -2
      include/cpphibernate/driver/mariadb/classes/fields/field_value.h
  19. +18
    -0
      include/cpphibernate/driver/mariadb/classes/fields/field_value.inl
  20. +2
    -5
      include/cpphibernate/driver/mariadb/classes/fields/fields.h
  21. +0
    -4
      include/cpphibernate/driver/mariadb/classes/fields/fields.inl
  22. +0
    -28
      include/cpphibernate/driver/mariadb/classes/forward.h
  23. +2
    -0
      include/cpphibernate/driver/mariadb/classes/schema.h
  24. +19
    -8
      include/cpphibernate/driver/mariadb/classes/schema/schema.h
  25. +3
    -2
      include/cpphibernate/driver/mariadb/classes/schema/schema.inl
  26. +0
    -3
      include/cpphibernate/driver/mariadb/classes/tables.h
  27. +84
    -16
      include/cpphibernate/driver/mariadb/classes/tables/table.h
  28. +5
    -5
      include/cpphibernate/driver/mariadb/classes/tables/table.inl
  29. +2
    -4
      include/cpphibernate/driver/mariadb/classes/tables/table_polymorphic.h
  30. +2
    -4
      include/cpphibernate/driver/mariadb/classes/tables/table_simple.h
  31. +0
    -6
      include/cpphibernate/driver/mariadb/classes/tables/tables.h
  32. +2
    -3
      include/cpphibernate/driver/mariadb/classes/tables/tables.inl
  33. +7
    -0
      include/cpphibernate/driver/mariadb/context.h
  34. +0
    -3
      include/cpphibernate/driver/mariadb/context/base_context.h
  35. +71
    -0
      include/cpphibernate/driver/mariadb/context/create_update_context.h
  36. +57
    -0
      include/cpphibernate/driver/mariadb/context/create_update_context.inl
  37. +67
    -0
      include/cpphibernate/driver/mariadb/context/data_context.h
  38. +99
    -0
      include/cpphibernate/driver/mariadb/context/data_context.inl
  39. +0
    -4
      include/cpphibernate/driver/mariadb/context/init_context.h
  40. +2
    -0
      include/cpphibernate/driver/mariadb/context/init_context.inl
  41. +11
    -5
      include/cpphibernate/driver/mariadb/driver.h
  42. +10
    -3
      include/cpphibernate/driver/mariadb/driver.inl
  43. +4
    -2
      include/cpphibernate/driver/mariadb/helper.h
  44. +1
    -3
      include/cpphibernate/driver/mariadb/helper/key_properties.h
  45. +2
    -2
      include/cpphibernate/driver/mariadb/helper/key_properties.inl
  46. +1
    -3
      include/cpphibernate/driver/mariadb/helper/nullable_helper.h
  47. +3
    -3
      include/cpphibernate/driver/mariadb/helper/nullable_helper.inl
  48. +1
    -9
      include/cpphibernate/driver/mariadb/helper/type_properties.h
  49. +0
    -4
      include/cpphibernate/driver/mariadb/helper/type_properties.inl
  50. +6
    -7
      include/cpphibernate/driver/mariadb/impl.h
  51. +70
    -64
      include/cpphibernate/driver/mariadb/impl/_context.h
  52. +62
    -20
      include/cpphibernate/driver/mariadb/impl/_context.inl
  53. +6
    -6
      include/cpphibernate/driver/mariadb/impl/_destroy.h
  54. +3
    -3
      include/cpphibernate/driver/mariadb/impl/_limit.h
  55. +2
    -2
      include/cpphibernate/driver/mariadb/impl/_modifier_tags.h
  56. +4
    -4
      include/cpphibernate/driver/mariadb/impl/_order_by.h
  57. +6
    -6
      include/cpphibernate/driver/mariadb/impl/_read.h
  58. +4
    -4
      include/cpphibernate/driver/mariadb/impl/_where.h
  59. +14
    -0
      include/cpphibernate/driver/mariadb/impl/create_update.h
  60. +31
    -23
      include/cpphibernate/driver/mariadb/impl/create_update.inl
  61. +10
    -3
      include/cpphibernate/driver/mariadb/impl/driver_impl.h
  62. +13
    -2
      include/cpphibernate/driver/mariadb/impl/driver_impl.inl
  63. +60
    -0
      include/cpphibernate/driver/mariadb/impl/filter.h
  64. +131
    -0
      include/cpphibernate/driver/mariadb/impl/filter.inl
  65. +13
    -0
      include/cpphibernate/driver/mariadb/types.h
  66. +3
    -0
      include/cpphibernate/misc.h
  67. +21
    -0
      include/cpphibernate/modifier.h
  68. +8
    -0
      include/cpphibernate/schema.h
  69. +1
    -0
      include/cpphibernate/schema/field.h
  70. +2
    -0
      include/cpphibernate/schema/table.h
  71. +10
    -0
      include/cpphibernate/types.h
  72. +0
    -282
      src/cpphibernate/driver/mariadb/classes/field.xcpp
  73. +15
    -8
      src/cpphibernate/driver/mariadb/classes/fields/misc.cpp
  74. +0
    -259
      src/cpphibernate/driver/mariadb/classes/schema.xcpp
  75. +2
    -1
      src/cpphibernate/driver/mariadb/classes/schema/init.cpp
  76. +35
    -10
      src/cpphibernate/driver/mariadb/classes/schema/misc.cpp
  77. +0
    -1827
      src/cpphibernate/driver/mariadb/classes/table.xcpp
  78. +483
    -0
      src/cpphibernate/driver/mariadb/classes/tables/create_update.cpp
  79. +58
    -47
      src/cpphibernate/driver/mariadb/classes/tables/init.cpp
  80. +56
    -9
      src/cpphibernate/driver/mariadb/classes/tables/misc.cpp
  81. +4
    -3
      test/cpphibernate/cpphibernate_create.cpp
  82. +0
    -0
      test/cpphibernate/cpphibernate_init.xcpp

+ 2
- 0
include/cpphibernate.h View File

@@ -5,3 +5,5 @@
#include "cpphibernate/modifier.h"
#include "cpphibernate/schema.h"
#include "cpphibernate/types.h"

#include "cpphibernate/types.inl"

+ 2
- 0
include/cpphibernate/context.h View File

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

#include "context/context.h"

#include "context/context.inl"

+ 0
- 2
include/cpphibernate/context/context.h View File

@@ -102,5 +102,3 @@ namespace cpphibernate
constexpr decltype(auto) make_context_ptr(T_schema&& schema, T_args&&... args);

}

#include "context.inl"

+ 10
- 5
include/cpphibernate/context/context.inl View File

@@ -21,7 +21,9 @@ namespace cpphibernate
template<typename T_impl, typename T_bool>
struct init_builder<
mp::list<T_impl, T_bool>,
mp::enable_if_t<mp::is_same_v<bool, mp::decay_t<T_bool>>>>
mp::enable_if_t<
mp::is_valid_v<decltype(std::declval<T_impl>().init(std::declval<bool>()))>
&& mp::is_same_v<bool, mp::decay_t<T_bool>>>>
{
static constexpr decltype(auto) apply(T_impl& impl, bool recreate)
{ return impl.init(recreate); }
@@ -39,15 +41,18 @@ namespace cpphibernate
{ static_assert(sizeof...(T_args) == -1, "Invalid parameters for context::create(...)!"); }
};

constexpr decltype(auto) create = mp::generic_predicate<create_builder> { };
#if 0
template<typename T_impl, typename T_dataset>
struct create_impl<mp::list<T_impl, T_dataset>, void>
struct create_builder<
mp::list<T_impl, T_dataset>,
mp::enable_if_t<
mp::is_valid_v<decltype(std::declval<T_impl>().create(std::declval<T_dataset&>()))>>>
{
static constexpr decltype(auto) apply(T_impl& impl, T_dataset& dataset)
{ return impl.create(dataset); }
};
#endif

constexpr decltype(auto) create = mp::generic_predicate<create_builder> { };

/* read_builder */

template<typename X, typename = void>


+ 6
- 1
include/cpphibernate/driver/mariadb.h View File

@@ -3,7 +3,12 @@
#include <cpphibernate/config.h>

#ifdef CPPHIBERNATE_HAS_CPPMARIADB
#include <cpphibernate/driver/mariadb/driver.h>
#include "mariadb/classes.h"
#include "mariadb/context.h"
#include "mariadb/driver.h"
#include "mariadb/driver.inl"
#include "mariadb/helper.h"
#include "mariadb/impl.h"

namespace cpphibernate
{


+ 2
- 0
include/cpphibernate/driver/mariadb/classes/attributes.h View File

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

#include "attributes/attributes.h"

#include "attributes/attributes.inl"

+ 8
- 5
include/cpphibernate/driver/mariadb/classes/attributes/attributes.h View File

@@ -1,8 +1,8 @@
#pragma once

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

#include "../forward.h"
#include <cpphibernate/config.h>

namespace cpphibernate {
namespace mariadb {
@@ -31,7 +31,12 @@ namespace mariadb {
/**
* @brief Set of attributes.
*/
struct attributes_t;
struct attributes_t :
public std::set<attribute_t>
{
using base_type = std::set<attribute_t>;
using base_type::base_type;
};

/**
* @brief Predicate to create attributes set from attributes schema.
@@ -39,5 +44,3 @@ namespace mariadb {
constexpr decltype(auto) make_attributes = mp::generic_predicate<__impl::attributes_builder> { };

} }

#include "attributes.inl"

+ 1
- 12
include/cpphibernate/driver/mariadb/classes/attributes/attributes.inl View File

@@ -1,12 +1,10 @@
#pragma once

#include <set>
#include "attributes.h"

#include <cpphibernate/schema/attribute.h>
#include <cpphibernate/schema/attributes.h>

#include "attributes.h"

namespace cpphibernate {
namespace mariadb {

@@ -62,13 +60,4 @@ namespace mariadb {

}

/* attributes_t */

struct attributes_t :
public std::set<attribute_t>
{
using base_type = std::set<attribute_t>;
using base_type::base_type;
};

} }

+ 13
- 0
include/cpphibernate/driver/mariadb/classes/fields.h View File

@@ -2,3 +2,16 @@

#include "fields/field.h"
#include "fields/fields.h"
#include "fields/field_data.h"
#include "fields/field_foreign_table.h"
#include "fields/field_primary_key.h"
#include "fields/field_simple.h"
#include "fields/field_value.h"

#include "fields/field.inl"
#include "fields/fields.inl"
#include "fields/field_data.inl"
#include "fields/field_foreign_table.inl"
#include "fields/field_primary_key.inl"
#include "fields/field_simple.inl"
#include "fields/field_value.inl"

+ 56
- 6
include/cpphibernate/driver/mariadb/classes/fields/field.h View File

@@ -1,14 +1,17 @@
#pragma once

#include <memory>
#include <cpphibernate/config.h>
#include <cppmariadb.h>

#include "../forward.h"
#include "../attributes.h"
#include "../../types.h"
#include "../attributes/attributes.h"

namespace cpphibernate {
namespace mariadb {

struct table_t;
struct data_context;
struct create_update_context;

/**
* @brief Abstract field class.
*/
@@ -78,6 +81,53 @@ namespace mariadb {
*/
std::ostream& print(std::ostream& os) const;

public:
/**
* @brief Get the value of this field from the current dataset.
*
* @param[in] context Data context to get the dataset from.
*
* @return Value of the field from the current dataset.
*/
virtual value_t get(const data_context& context) const;

/**
* @brief Set a new value of this field in the current dataset.
*
* @param[in] context Data context to get the dataset from.
* @param[in] value Value of the field to assign to the dataset.
*/
virtual void set(const data_context& context, const value_t& value) const;

/**
* @brief Check if the value that is represented by this field has the default value.
*
* @param[in] context Data context to receive the value of the assigned dataset.
*
* @retval true If the dataset in the context is the default value for this field.
* @retval false If the dataset in the context is not the default value for this field.
*/
virtual bool is_default(const data_context& context) const;

/**
* @brief Create a new value that is represented by this field.
*
* @param[in] connection Connection to use to create the value.
*
* @return New created value for this field.
*/
virtual std::string generate_value(::cppmariadb::connection& connection) const;

public:
/**
* @brief Execute a create/update operation on the foreign table this field represents (if it is a foreign field)
*
* @param[in] context Create/Update context with the needed data for the operation.
*
* @return Key of the created/updated foreign dataset.
*/
virtual value_t foreign_create_update(const create_update_context& context) const;

private:
/**
* @brief Initialize the field.
@@ -85,6 +135,8 @@ namespace mariadb {
void init();
};

using field_ptr_u = std::unique_ptr<const field_t>;

namespace __impl
{

@@ -102,5 +154,3 @@ namespace mariadb {
constexpr decltype(auto) make_field = mp::generic_predicate<__impl::field_builder> { };

} }

#include "field.inl"

+ 3
- 7
include/cpphibernate/driver/mariadb/classes/fields/field.inl View File

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

#include <cpphibernate/schema/field.h>
#include <cpphibernate/schema/table.h>
#include <cpphibernate/schema/schema.h>

#include "field.h"
#include "field_data.h"
#include "field_primary_key.h"
#include "field_foreign_table.h"

#include <cpphibernate/schema/schema.h>
#include <cpphibernate/misc/type_helper.h>

namespace cpphibernate {
namespace mariadb {


+ 0
- 2
include/cpphibernate/driver/mariadb/classes/fields/field_data.h View File

@@ -35,5 +35,3 @@ namespace mariadb {
};

} }

#include "field_data.inl"

+ 1
- 3
include/cpphibernate/driver/mariadb/classes/fields/field_foreign_table.h View File

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

#include "field_simple.h"

namespace cpphibernate {
namespace mariadb {
@@ -35,5 +35,3 @@ namespace mariadb {
};

} }

#include "field_foreign_table.inl"

+ 20
- 3
include/cpphibernate/driver/mariadb/classes/fields/field_primary_key.h View File

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

#include "field_value.h"
#include "../../helper/key_properties.h"

namespace cpphibernate {
@@ -37,8 +36,26 @@ namespace mariadb {
const T_schema& p_schema,
const T_table& p_table,
const T_field& p_field);

public:
/**
* @brief Check if the value that is represented by this field has the default value.
*
* @param[in] context Data context to receive the value of the assigned dataset.
*
* @retval true If the dataset in the context is the default value for this field.
* @retval false If the dataset in the context is not the default value for this field.
*/
bool is_default(const data_context& context) const override;

/**
* @brief Create a new value that is represented by this field.
*
* @param[in] connection Connection to use to create the value.
*
* @return New created value for this field.
*/
std::string generate_value(::cppmariadb::connection& connection) const override;
};

} }

#include "field_primary_key.inl"

+ 28
- 0
include/cpphibernate/driver/mariadb/classes/fields/field_primary_key.inl View File

@@ -2,6 +2,8 @@

#include "field_primary_key.h"

#include "../../context/data_context.inl"

namespace cpphibernate {
namespace mariadb {

@@ -30,4 +32,30 @@ namespace mariadb {
this->name = this->table.name + '_' + this->name;
}

template<
typename T_field>
bool field_primary_key_t<T_field>
::is_default(const data_context& context) const
{
using dataset_type = typename mp::decay_t<T_field>::dataset_type;
auto& dataset = context.get<dataset_type>();
return key_props.is_default(this->_field.getter(dataset));
}

template<
typename T_field>
std::string field_primary_key_t<T_field>
::generate_value(::cppmariadb::connection& connection) const
{
auto * query = key_props.create_key_query();
if (!query)
throw exception("unable to generate key value: no query defined for this key type!");

auto ret = connection.execute_used(query);
if (!ret || !ret->next())
throw exception("unable to generate key value: empty result!");

return ret->current()->at(0).template get<std::string>();
}

} }

+ 5
- 3
include/cpphibernate/driver/mariadb/classes/fields/field_simple.h View File

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

#include "field.h"

namespace cpphibernate {
namespace mariadb {
@@ -14,6 +14,10 @@ namespace mariadb {
{
private:
using base_type = field_t;
using field_type = T_field;

protected:
const field_type& _field;

public:
/**
@@ -35,5 +39,3 @@ namespace mariadb {
};

} }

#include "field_simple.inl"

+ 1
- 0
include/cpphibernate/driver/mariadb/classes/fields/field_simple.inl View File

@@ -22,6 +22,7 @@ namespace mariadb {
p_schema,
p_table,
p_field)
, _field(p_field)
{ }

} }

+ 17
- 2
include/cpphibernate/driver/mariadb/classes/fields/field_value.h View File

@@ -41,8 +41,23 @@ namespace mariadb {
const T_schema& p_schema,
const T_table& p_table,
const T_field& p_field);

/**
* @brief Get the value of this field from the current dataset.
*
* @param[in] context Data context to get the dataset from.
*
* @return Value of the field from the current dataset.
*/
virtual value_t get(const data_context& context) const;

/**
* @brief Set a new value of this field in the current dataset.
*
* @param[in] context Data context to get the dataset from.
* @param[in] value Value of the field to assign to the dataset.
*/
virtual void set(const data_context& context, const value_t& value) const;
};

} }

#include "field_value.inl"

+ 18
- 0
include/cpphibernate/driver/mariadb/classes/fields/field_value.inl View File

@@ -34,4 +34,22 @@ namespace mariadb {
this->convert_from_close = value_props.convert_from_close() + this->convert_from_close;
}

template<typename T_field>
value_t field_value_t<T_field>::
get(const data_context& context) const
{
using dataset_type = typename mp::decay_t<T_field>::dataset_type;
auto& dataset = context.get<dataset_type>();
return value_props.convert_from(this->_field.getter(dataset));
}

template<typename T_field>
void field_value_t<T_field>
::set(const data_context& context, const value_t& value) const
{
using dataset_type = typename mp::decay_t<T_field>::dataset_type;
auto& dataset = context.get<dataset_type>();
this->_field.setter(dataset, value_props.convert_to(value));
}

} }

+ 2
- 5
include/cpphibernate/driver/mariadb/classes/fields/fields.h View File

@@ -1,9 +1,8 @@
#pragma once

#include <vector>

#include "../forward.h"
#include "field.h"

namespace cpphibernate {
namespace mariadb {
@@ -35,5 +34,3 @@ namespace mariadb {
constexpr decltype(auto) make_fields = mp::generic_predicate<__impl::fields_builder> { };

} }

#include "fields.inl"

+ 0
- 4
include/cpphibernate/driver/mariadb/classes/fields/fields.inl View File

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

#include <cpphibernate/schema/table.h>
#include <cpphibernate/schema/schema.h>

#include "field.h"
#include "fields.h"

namespace cpphibernate {
namespace mariadb {


+ 0
- 28
include/cpphibernate/driver/mariadb/classes/forward.h View File

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

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

namespace cpphibernate {
namespace mariadb {

enum init_stage
{
unknown = 0,
stage1,
stage2,
};

enum class attribute_t;
struct attributes_t;
struct field_t;
struct fields_t;
struct table_t;
struct tables_t;
struct schema_t;

using field_ptr_u = std::unique_ptr<const field_t>;
using table_ptr_u = std::unique_ptr<const table_t>;
using schema_ptr_u = std::unique_ptr<schema_t>;

} }

+ 2
- 0
include/cpphibernate/driver/mariadb/classes/schema.h View File

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

#include "schema/schema.h"

#include "schema/schema.inl"

+ 19
- 8
include/cpphibernate/driver/mariadb/classes/schema/schema.h View File

@@ -1,10 +1,9 @@
#pragma once

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

#include "../forward.h"
#include "../tables/table.h"
#include "../tables/tables.h"
#include "../../context.h"

namespace cpphibernate {
namespace mariadb {
@@ -16,13 +15,15 @@ namespace mariadb {
{
public:
using table_map = std::map<size_t, const table_t *>;
using field_map = std::map<size_t, const field_t *>;

private:
table_map _lookup; //!< dataset id to table pointer map
table_map _table_lookup; //!< dataset id to table pointer map
field_map _field_lookup; //!< field id to field pointer map

public:
std::string name; //!< name of the schema
tables_t tables; //!< tables that are managed by this schema.
std::string name; //!< name of the schema
tables_t tables; //!< tables that are managed by this schema.

public:
/**
@@ -58,6 +59,16 @@ namespace mariadb {
*/
void init(const init_context& context) const;

/**
* @brief Find the table for the passed dataset id in the schema.
*/
const table_t& table(size_t dataset_id) const;

/**
* @brief Find the field for the passed field id in the schema.
*/
const field_t& field(size_t field_id) const;

private:
/**
* @brief Initialize the field.
@@ -65,6 +76,8 @@ namespace mariadb {
void init();
};

using schema_ptr_u = std::unique_ptr<const schema_t>;

namespace __impl
{

@@ -82,5 +95,3 @@ namespace mariadb {
constexpr decltype(auto) make_schema = mp::generic_predicate<__impl::schema_builder> { };

} }

#include "schema.inl"

+ 3
- 2
include/cpphibernate/driver/mariadb/classes/schema/schema.inl View File

@@ -1,9 +1,10 @@
#pragma once

#include <cpphibernate/schema/schema.h>

#include "schema.h"

#include <cpphibernate/types.inl>
#include "../tables/tables.inl"

namespace cpphibernate {
namespace mariadb {



+ 0
- 3
include/cpphibernate/driver/mariadb/classes/tables.h View File

@@ -1,4 +1 @@
#pragma once

#include "tables/table.h"
#include "tables/tables.h"

+ 84
- 16
include/cpphibernate/driver/mariadb/classes/tables/table.h View File

@@ -1,16 +1,27 @@
#pragma once

#include <string>
#include <vector>
#include <memory>
#include <cpphibernate/config.h>
#include <cppmariadb.h>

#include "../forward.h"
#include "../fields/field.h"
#include "../fields/fields.h"
#include "../../context.h"

namespace cpphibernate {
namespace mariadb {

struct filter_t;
struct schema_t;
struct init_context;
struct create_update_context;

enum init_stage
{
unknown = 0,
stage1,
stage2,
};

/**
* @brief Abstract table class.
*/
@@ -20,10 +31,6 @@ namespace mariadb {
using size_vector = std::vector<size_t>; //!< vector of size_t
using table_vector = std::vector<const table_t *>; //!< vector of constant field pointers
using field_vector = std::vector<const field_t *>; //!< vector of constant field pointers
using field_map = std::map<size_t, const field_t *>; //!< map of field id to field

private:
field_map _lookup; //!< field id to field pointer map

public:
size_t id { 0 }; //!< unique id of the table assigned by the user
@@ -88,6 +95,7 @@ namespace mariadb {
*/
std::ostream& print(std::ostream& os) const;

public:
/**
* @brief Initialize the table using the passed context.
*
@@ -95,21 +103,68 @@ namespace mariadb {
* table is created. In the second stage the table contraints are added.
* The first stage must be completed for all tables before stage two of
* any table is executed.
*
* @param[in] context Context that stores the needed data for the operation.
* @param[in] stage Stage to execute.
*/
void init(const init_context& context, init_stage stage) const;

private:
/**
* @brief Execute a create/update operation on the current table.
*
* For a polymorphic type this will check the derived tables before executing the actual opertion.
* If the dataset matches one of the dericed tables, the operation is executed on this table.
* This operation also updates the base table if the dataset has one.
*
* @param[in] context Context that stores the needed data for the operation.
*
* @return Returns the key of the created/updated dataset in it's string representation.
*/
virtual std::string create_update(const create_update_context& context) const;

public:
/**
* @brief Get the value of the primary key of this table.
*
* @param[in] context Data context to get the dataset from.
*
* @return Value of the primary key.
*/
std::string get_primary_key(const data_context& context) const;

/**
* @brief Get the value of the primary key of this table,
* by fetching it from the base table.
*
* @param[in] context Data context to get the dataset from.
*
* @return Value of the primary key.
*/
std::string get_key_from_base(const data_context& context) const;

/**
* @brief Initialize the field.
* @brief Execute the actual create/update operation.
*
* Other than create_update this will not check the derived tables. It will execute the query
* and forward the operation to the base table if the dataset has one.
*/
void init();
std::string create_update_exec(const create_update_context& context) const;

private:
using statement_ptr_u = std::unique_ptr<::cppmariadb::statement>;
using statement_ptr_u = std::unique_ptr<::cppmariadb::statement>;
using statement_key = std::tuple<size_t, const field_t*>;
using statement_map = std::map<statement_key, ::cppmariadb::statement>;

mutable statement_ptr_u _statement_key_from_base; //!< Statement to fetch the key of this table from the base table.
mutable statement_ptr_u _statement_init_stage1; //!< Statement for init stage 1 (create table).
mutable statement_ptr_u _statement_init_stage2; //!< Statement for init stage 2 (alter table).
mutable statement_ptr_u _statement_insert_into; //!< Statement for create operation (inser into)
mutable statement_map _statement_update; //!< Map of all update statements

mutable statement_ptr_u _statement_init_stage1; //!< Statement for init stage 1 (create table).
mutable statement_ptr_u _statement_init_stage2; //!< Statement for init stage 2 (alter table).
/**
* @brief Get the statement to fetch the key of this table from the base table.
*/
::cppmariadb::statement& get_statement_key_from_base() const;

/**
* @brief Get or create the mariadb statement for init stage 1.
@@ -120,8 +175,23 @@ namespace mariadb {
* @brief Get or create the mariadb statement for init stage 2.
*/
::cppmariadb::statement* get_statement_init_stage2() const;

/**
* Get the statement for the create operation. If the statement is empty nullptr is returned;
*/
::cppmariadb::statement* get_statement_insert_into() const;

/**
* Get the statement for the update operation. If the statement is empty nullptr is returned;
*
* @param[in] filter Filter to use for the update statement.
* @param[in] owner Field the current dataset is owned by (if this table is used in a foreign field).
*/
::cppmariadb::statement* get_statement_update(const filter_t& filter, const field_t * owner) const;
};

using table_ptr_u = std::unique_ptr<const table_t>;

namespace __impl
{

@@ -139,5 +209,3 @@ namespace mariadb {
constexpr decltype(auto) make_table = mp::generic_predicate<__impl::table_builder> { };

} }

#include "table.inl"

+ 5
- 5
include/cpphibernate/driver/mariadb/classes/tables/table.inl View File

@@ -1,11 +1,11 @@
#pragma once

#include <cpphibernate/schema/table.h>
#include <cpphibernate/schema/schema.h>
#include <cpphibernate/schema/schema.inl>

#include "table.h"
#include "table_simple.h"
#include "table_polymorphic.h"

#include "table_simple.inl"
#include "table_polymorphic.inl"

namespace cpphibernate {
namespace mariadb {
@@ -24,7 +24,7 @@ namespace mariadb {
, name (p_table.name)
, schema (p_owner)
, fields (make_fields(*this, p_schema, p_table))
{ init(); }
{ }

namespace __impl
{


+ 2
- 4
include/cpphibernate/driver/mariadb/classes/tables/table_polymorphic.h View File

@@ -1,8 +1,8 @@
#pragma once

#include <cpphibernate/config.h>

#include "table.h"



namespace cpphibernate {
namespace mariadb {
@@ -35,5 +35,3 @@ namespace mariadb {
};

} }

#include "table_polymorphic.inl"

+ 2
- 4
include/cpphibernate/driver/mariadb/classes/tables/table_simple.h View File

@@ -1,8 +1,8 @@
#pragma once

#include <cpphibernate/config.h>

#include "table.h"



namespace cpphibernate {
namespace mariadb {
@@ -35,5 +35,3 @@ namespace mariadb {
};

} }

#include "table_simple.inl"

+ 0
- 6
include/cpphibernate/driver/mariadb/classes/tables/tables.h View File

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

#include <vector>

#include "table.h"

namespace cpphibernate {
namespace mariadb {

@@ -34,5 +30,3 @@ namespace mariadb {
constexpr decltype(auto) make_tables = mp::generic_predicate<__impl::tables_builder> { };

} }

#include "tables.inl"

+ 2
- 3
include/cpphibernate/driver/mariadb/classes/tables/tables.inl View File

@@ -1,10 +1,9 @@
#pragma once

#include <cpphibernate/schema/tables.h>
#include <cpphibernate/schema/schema.h>

#include "tables.h"

#include "table.inl"

namespace cpphibernate {
namespace mariadb {



+ 7
- 0
include/cpphibernate/driver/mariadb/context.h View File

@@ -1,4 +1,11 @@
#pragma once

#include "context/base_context.h"
#include "context/create_update_context.h"
#include "context/data_context.h"
#include "context/init_context.h"

#include "context/base_context.inl"
#include "context/create_update_context.inl"
#include "context/data_context.inl"
#include "context/init_context.inl"

+ 0
- 3
include/cpphibernate/driver/mariadb/context/base_context.h View File

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

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

namespace cpphibernate {
namespace mariadb {
@@ -25,5 +24,3 @@ namespace mariadb {
};

} }

#include "base_context.inl"

+ 71
- 0
include/cpphibernate/driver/mariadb/context/create_update_context.h View File

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

#include "data_context.h"
#include "../impl/filter.h"

namespace cpphibernate {
namespace mariadb {

/**
* @brief Context that is used for create or update operations.
*/
struct create_update_context
: public data_context
{
const filter_t * filter; //!< Filter that is used for update operation.
//!< Also indicated if this is an update or create operation.
const table_t * derived_table; //!< Derived table if the current context is executed in a base table.
const field_t * owner_field; //!< Field the current dataset is owned by (for foreign fields)
std::string owner_key; //!< Key of the dataset the current dataset is owned by.
ssize_t index; //!< Index of the current dataset in the container.

/**
* @brief Constructor. Creates a create context (no filters are passed).
*
* @param[in] p_schema Mariadb driver schema to use for the operation.
* @param[in] p_connection Mariadb connection to execute queries with.
* @param[in] p_dataset Dataset to store in the context.
*/
template<typename T_dataset>
inline create_update_context(
const schema_t& p_schema,
::cppmariadb::connection& p_connection,
T_dataset& p_dataset);

/**
* @brief Constructor. Create an update context.
*
* @param[in] p_schema Mariadb driver schema to use for the operation.
* @param[in] p_connection Mariadb connection to execute queries with.
* @param[in] p_dataset Dataset to store in the context.
* @param[in] p_filter Filters to use for the update operation.
*/
template<typename T_dataset>
inline create_update_context(
const schema_t& p_schema,
::cppmariadb::connection& p_connection,
T_dataset& p_dataset,
const filter_t& p_filter);

/**
* @brief Create a create context from the current context.
*/
inline decltype(auto) make_create_context() const;

/**
* @brief Create an update context from the current context.
*/
inline decltype(auto) make_update_context(const filter_t& p_filter) const;

/**
* @brief Returns true if this is an create context, false otherwise.
*/
inline bool is_create() const;

/**
* @brief Returns true if this is an update context, false otherwise.
*/
inline bool is_update() const;
};

} }

+ 57
- 0
include/cpphibernate/driver/mariadb/context/create_update_context.inl View File

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

#include "create_update_context.h"

namespace cpphibernate {
namespace mariadb {

/* create_update_context */

template<typename T_dataset>
create_update_context::create_update_context(
const schema_t& p_schema,
::cppmariadb::connection& p_connection,
T_dataset& p_dataset)
: data_context (p_schema, p_connection, p_dataset)
, filter (nullptr)
, derived_table (nullptr)
, owner_field (nullptr)
, owner_key ()
, index (0)
{ }

template<typename T_dataset>
create_update_context::create_update_context(
const schema_t& p_schema,
::cppmariadb::connection& p_connection,
T_dataset& p_dataset,
const filter_t& p_filter)
: data_context (p_schema, p_connection, p_dataset)
, filter (&p_filter)
, derived_table (nullptr)
, owner_field (nullptr)
, owner_key ()
, index (0)
{ }

decltype(auto) create_update_context::make_create_context() const
{
auto ret = *this;
ret.filter = nullptr;
return ret;
}

decltype(auto) create_update_context::make_update_context(const filter_t& p_filter) const
{
auto ret = *this;
ret.filter = &p_filter;
return ret;
}

bool create_update_context::is_create() const
{ return !static_cast<bool>(filter); }

bool create_update_context::is_update() const
{ return static_cast<bool>(filter); }

} }

+ 67
- 0
include/cpphibernate/driver/mariadb/context/data_context.h View File

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

#include "base_context.h"

namespace cpphibernate {
namespace mariadb {

namespace __impl
{

/**
* @brief Helper class to create the change_context predicate.
*/
template<typename X, typename = void>
struct change_context_builder;

}

/**
* @brief Predicate to change the stored dataset of any data_context.
*/
constexpr decltype(auto) change_context = cppmp::generic_predicate<__impl::change_context_builder> { };

/**
* @brief Mariadb driver context that helds a specific dataset.
*/
struct data_context
: public base_context
{
private:
mutable size_t _dataset_id; //!< Unique type id of the dataset that is stored in this context.
mutable void * _dataset; //!< Pointer to the stored dataset.
mutable const table_t * _table; //!< Table this context/dataset belongs to

template<typename X, typename T_enable>
friend struct __impl::change_context_builder;

public:
/**
* @brief Constructor.
*
* @param[in] p_schema Mariadb driver schema to use for the operation.
* @param[in] p_connection Mariadb connection to execute queries with.
* @param[in] p_dataset Dataset to store in the context.
*/
template<typename T_dataset>
inline data_context(
const schema_t& p_schema,
::cppmariadb::connection& p_connection,
T_dataset& p_dataset);

/**
* @brief Get a reference to the stored dataset if the type matches.
* If an invalid type is requested an exception is thrown.
*/
template<typename T_dataset>
inline decltype(auto) get() const;

private:
/**
* @brief Set the dataset that is stored in this context.
*/
template<typename T_dataset>
inline void set(T_dataset& dataset);
};

} }

+ 99
- 0
include/cpphibernate/driver/mariadb/context/data_context.inl View File

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

#include "data_context.h"

#include "../classes/schema/schema.inl"

namespace cpphibernate {
namespace mariadb {

/* data_context */

template<typename T_dataset>
data_context::data_context(
const schema_t& p_schema,
::cppmariadb::connection& p_connection,
T_dataset& p_dataset)
: base_context (p_schema, p_connection)
, _dataset_id (0)
, _dataset (nullptr)
, _table (nullptr)
{ set(p_dataset); }

template<typename T_dataset>
decltype(auto) data_context::get() const
{
using dataset_type = mp::decay_t<T_dataset>;

/* check if tha context has a dataset assigned (should never fail) */
if (!_dataset)
throw exception("no data assigned!");

auto dataset_id = get_type_id(hana::type_c<dataset_type>);

/* if the dataset IDs does not match, search in the base tables for a matching ID */
if (dataset_id != _dataset_id)
{
/* get the table of the stored dataset */
if (!_table)
_table = &schema.table(_dataset_id);

/* check if the table matches the stored dataset (should never happen) */
else if (_table->dataset_id != _dataset_id)
throw exception("invalid table!");

/* walk through base tables until we have found a matching ID */
auto table = _table;
while(table && table->dataset_id != dataset_id)
table = table->base_table;

/* check if we have found a suitable table, if not throw an exception */
if (!table)
{
throw exception(cppcore::type_helper<dataset_type>::name() +
" is not a derived type of dataset with id " + std::to_string(_dataset_id));
}
}

/* return the dataset */
return *static_cast<dataset_type*>(_dataset);
}

template<typename T_dataset>
void data_context::set(T_dataset& dataset)
{
_dataset_id = get_type_id(hana::type_c<mp::decay_t<T_dataset>>);
_dataset = &dataset;
_table = nullptr;
}

namespace __impl
{

/* change_context_builder */

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

template<typename T_context, typename T_dataset>
struct change_context_builder<
mp::list<T_context, T_dataset>,
mp::enable_if_t<
mp::is_base_of_v<data_context, mp::decay_t<T_context>>>>
{
static constexpr decltype(auto) apply(const T_context& context, T_dataset& dataset)
{
auto new_context = context;
new_context.set(dataset);
return new_context;
}
};

}

} }

+ 0
- 4
include/cpphibernate/driver/mariadb/context/init_context.h View File

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

#include <cppmariadb.h>
#include <cpphibernate/config.h>
#include "base_context.h"

namespace cpphibernate {
@@ -22,5 +20,3 @@ namespace mariadb {
};

} }

#include "init_context.inl"

+ 2
- 0
include/cpphibernate/driver/mariadb/context/init_context.inl View File

@@ -2,6 +2,8 @@

#include "init_context.h"

#include "base_context.inl"

namespace cpphibernate {
namespace mariadb {



+ 11
- 5
include/cpphibernate/driver/mariadb/driver.h View File

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

#include <cppmariadb.h>

#include "classes.h"
#include "impl/driver_impl.h"

namespace cpphibernate {
@@ -23,10 +20,21 @@ namespace mariadb {
public:
/**
* @brief Constructor. Initializes the driver with the passed schema.
*
* @param[in] p_schema Schema to use with this driver.
*/
template<typename T_schema>
inline driver_t(T_schema&& p_schema);

/**
* @brief Constructor. Initializes the driver with the passed schema.
*
* @param[in] p_schema Schema to use with this driver.
* @param[in] p_connection Connection to the mariadb server to use for queries.
*/
template<typename T_schema>
inline driver_t(T_schema&& p_schema, ::cppmariadb::connection& p_connection);

/**
* @brief Print the schema of the driver to the passed stream.
*/
@@ -156,5 +164,3 @@ namespace mariadb {
};

} }

#include "driver.inl"

+ 10
- 3
include/cpphibernate/driver/mariadb/driver.inl View File

@@ -1,14 +1,21 @@
#pragma once

#include "driver.h"
#include "impl/driver_impl.inl"

namespace cpphibernate {
namespace mariadb {

template<typename T_schema>
driver_t::driver_t(T_schema&& p_schema)
: _impl(*this, std::forward<T_schema>(p_schema))
: _impl (*this, std::forward<T_schema>(p_schema))
, _connection (nullptr)
{ }

template<typename T_schema>
driver_t::driver_t(T_schema&& p_schema, ::cppmariadb::connection& p_connection)
: _impl (*this, std::forward<T_schema>(p_schema))
, _connection (&p_connection)
{ }

std::ostream& driver_t::print(std::ostream& os) const


+ 4
- 2
include/cpphibernate/driver/mariadb/helper.h View File

@@ -1,7 +1,9 @@
#pragma once

#include "helper/type_properties.h"
#include "helper/key_properties.h"
#include "helper/nullable_helper.h"
#include "helper/transaction_lock.h"
#include "helper/type_properties.h"

#include "helper/key_properties.inl"
#include "helper/nullable_helper.inl"
#include "helper/type_properties.inl"

+ 1
- 3
include/cpphibernate/driver/mariadb/helper/key_properties.h View File

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

#include <cpphibernate/config.h>

namespace cpphibernate {
namespace mariadb {
@@ -37,5 +37,3 @@ namespace mariadb {
};

} }

#include "key_properties.inl"

+ 2
- 2
include/cpphibernate/driver/mariadb/helper/key_properties.inl View File

@@ -1,8 +1,8 @@
#pragma once

#include "key_properties.h"

#include <cpphibernate/types.h>



namespace cpphibernate {
namespace mariadb {


+ 1
- 3
include/cpphibernate/driver/mariadb/helper/nullable_helper.h View File

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

#include <cpphibernate/config.h>

namespace cpphibernate {
namespace mariadb {
@@ -31,5 +31,3 @@ namespace mariadb {
};

} }

#include "nullable_helper.inl"

+ 3
- 3
include/cpphibernate/driver/mariadb/helper/nullable_helper.inl View File

@@ -1,8 +1,8 @@
#include "nullable_helper.h"

#include <memory>

#include <cppcore/misc/nullable.h>




namespace cpphibernate {
namespace mariadb {


+ 1
- 9
include/cpphibernate/driver/mariadb/helper/type_properties.h View File

@@ -1,16 +1,10 @@
#pragma once

#include <cpphibernate/config.h>
#include <cppcore/misc/nullable.h>
#include <memory>

namespace cpphibernate {
namespace mariadb {

/**
* @brief Value received from the database.
*/
using value_t = cppcore::nullable<std::string>;

/**
* @brief Type properties for the passed type.
*
@@ -56,5 +50,3 @@ namespace mariadb {
};

} }

#include "type_properties.inl"

+ 0
- 4
include/cpphibernate/driver/mariadb/helper/type_properties.inl View File

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

#include <cpphibernate/types.h>
#include <cppcore/conversion/string.h>

#include "type_properties.h"
#include "nullable_helper.h"

namespace cpphibernate {
namespace mariadb {


+ 6
- 7
include/cpphibernate/driver/mariadb/impl.h View File

@@ -1,10 +1,9 @@
#pragma once

#include <cpphibernate/driver/mariadb/impl/create_update.h>
#include <cpphibernate/driver/mariadb/impl/destroy.h>
#include <cpphibernate/driver/mariadb/impl/limit.h>
#include <cpphibernate/driver/mariadb/impl/order_by.h>
#include <cpphibernate/driver/mariadb/impl/read.h>
#include <cpphibernate/driver/mariadb/impl/where.h>
#include "impl/create_update.h"
#include "impl/driver_impl.h"
#include "impl/filter.h"

#include <cpphibernate/driver/mariadb/helper/context.inl>
#include "impl/create_update.inl"
#include "impl/driver_impl.inl"
#include "impl/filter.inl"

include/cpphibernate/driver/mariadb/impl/context.h → include/cpphibernate/driver/mariadb/impl/_context.h View File

@@ -1,8 +1,10 @@
#pragma once

#include <cppmariadb.h>
#include <cpphibernate/config.h>
#include "../classes.h"






namespace cpphibernate {
namespace mariadb {
@@ -17,6 +19,9 @@ namespace mariadb {

/**
* @brief Constructor.
*
* @param[in] p_schema Mariadb driver schema to use for the operation.
* @param[in] p_connection Mariadb connection to execute queries with.
*/
inline base_context(
const schema_t& p_schema,
@@ -29,87 +34,88 @@ namespace mariadb {
struct init_context
: public base_context
{
bool recreate;
bool recreate; //!< Drop existing tables before createing new once.

/**
* @brief Constructor.
*
* @param[in] p_schema Mariadb driver schema to use for the operation.
* @param[in] p_connection Mariadb connection to execute queries with.
* @param[in] p_recreate Drop existing tables before createing new once.
*/
inline init_context(
const schema_t& p_schema,
::cppmariadb::connection& p_connection,
bool p_recreate);
};

#if 0
/* init_context */
struct init_context
/**
* @brief Mariadb driver context that helds a specific dataset.
*/
struct data_context
: public base_context
{
bool recreate;
private:
mutable size_t _dataset_id; //!< Unique type id of the dataset that is stored in this context.
mutable void* _dataset; //!< Pointer to the stored dataset.
mutable const table_t* _table; //!< Table this context/dataset belongs to

inline init_context(
const schema_t& p_schema,
::cppmariadb::connection& p_connection,
bool p_recreate)
: base_context (p_schema, p_connection)
, recreate (p_recreate)
{ }
};
friend __impl::change_context_builder;

namespace __impl
{
struct change_context_impl
{
template<typename T_context, typename T_data>
constexpr decltype(auto) operator()(const T_context& context, T_data& data) const
{
auto new_context = context;
new_context.set(data);
return new_context;
}
};
}
public:
/**
* @brief Constructor.
*
* @param[in] p_schema Mariadb driver schema to use for the operation.
* @param[in] p_connection Mariadb connection to execute queries with.
* @param[in] p_dataset Dataset to store in the context.
*/
template<typename T_dataset>
inline data_context(
const schema_t& p_schema,
::cppmariadb::connection& p_connection,
T_dataset& p_dataset);

/**
* @brief Get a reference to the stored dataset if the type matches.
* If an invalid type is requested an exception is thrown.
*/
template<typename T_dataset>
inline decltype(auto) get() const;

constexpr decltype(auto) change_context = __impl::change_context_impl { };
private:
/**
* @brief Set the dataset that is stored in this context.
*/
template<typename T_dataset>
inline void set(T_dataset& dataset);
};

/* data_context */

struct data_context
: public base_context
namespace __impl
{
private:
friend __impl::change_context_impl;

mutable size_t _dataset_id;
mutable void* _dataset;
mutable const table_t* _table;
/**
* @brief Helper class to create the change_context predicate.
*/
template<typename X, typename = void>
struct change_context_builder;

protected:
template<typename T_dataset>
inline void* set(T_dataset& dataset, size_t dataset_id = 0) const;
}

public:
template<typename T_dataset>
inline decltype(auto) get() const;
/**
* @brief Change the stored dataset of any data_context.
*
* @param[in] context Any data_context.
* @param[in] dataset New dataset of the context.
*
* @return The new conext that stores the passed dataset.
*/
constexpr decltype(auto) change_context = cppmp::generic_predicate<__impl::change_context_builder> { };

inline data_context(
const schema_t& p_schema,
::cppmariadb::connection& p_connection)
: base_context (p_schema, p_connection)
, _dataset_id (0)
, _dataset (nullptr)
, _table (nullptr)
{ }

template<typename T_data>
inline data_context(
T_data& p_data,
const schema_t& p_schema,
::cppmariadb::connection& p_connection)
: base_context (p_schema, p_connection)
, _dataset_id (misc::get_type_id(hana::type_c<mp::decay_t<T_data>>))
, _dataset (&p_data)
, _table (nullptr)
{ }
};
#if 0

/* filter_context */


include/cpphibernate/driver/mariadb/impl/context.inl → include/cpphibernate/driver/mariadb/impl/_context.inl View File

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

#include "context.h"

namespace cpphibernate {
namespace mariadb {
@@ -14,57 +14,99 @@ namespace mariadb {
, connection(p_connection)
{ }



#if 0
/* data_context */

template<typename T_dataset>
inline void* data_context
::set(T_dataset& dataset, size_t dataset_id) const
{
using dataset_type = mp::decay_t<T_dataset>;

_table = nullptr;
_dataset = &dataset;
_dataset_id = (dataset_id == 0)
? misc::get_type_id(hana::type_c<dataset_type>)
: dataset_id;

return _dataset;
}
data_context::data_context(
const schema_t& p_schema,
::cppmariadb::connection& p_connection,
T_dataset& p_dataset)
: base_context (p_schema, p_connection)
, _dataset_id (0)
, _dataset (nullptr)
, _table (nullptr)
{ set(p_dataset); }

template<typename T_dataset>
inline decltype(auto) data_context
::get() const
decltype(auto) data_context::get() const
{
using dataset_type = mp::decay_t<T_dataset>;

/* check if tha context has a dataset assigned (should never fail) */
if (!_dataset)
throw misc::hibernate_exception("no data assigned!");

auto dataset_id = misc::get_type_id(hana::type_c<dataset_type>);

/* if the dataset IDs does not match, search in the base tables for a matching ID */
if (dataset_id != _dataset_id)
{
/* check table */
/* get the table of the stored dataset */
if (!_table)
_table = &schema.table(_dataset_id);

/* check if the table matches the stored dataset (should never happen) */
else if (_table->dataset_id != _dataset_id)
throw misc::hibernate_exception("invalid table!");

/* walk through base tables until we have found a matching ID */
auto table = _table;
while(table && table->dataset_id != dataset_id)
table = table->base_table;

/* check if we have found a suitable table, if not throw an exception */
if (!table)
{
throw misc::hibernate_exception(utl::type_helper<dataset_type>::name() +
" is not a derived type of dataset with id " + std::to_string(_dataset_id));
}
}

/* return the dataset */
return *static_cast<dataset_type*>(_dataset);
}

template<typename T_dataset>
void data_context::set(T_dataset& dataset)
{
_dataset_id = misc::get_type_id(hana::type_c<mp::decay_t<T_dataset>>);
_dataset = &dataset;
_table = nullptr;
}



namespace __impl
{

/* change_context_builder */

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

template<typename T_context, typename T_dataset>
struct change_context_builder<
mp::list<T_context, T_dataset>,
mp::enable_if_t<
mp::is_base_of_v<data_context, mp::decay_t<T_context>>>>
{
static constexpr decltype(auto) apply(const T_context& context, T_dataset& dataset)
{
auto new_context = context;
new_context.set(dataset);
return new_context;
}
};

}

#if 0

/* read_context */

template<typename T_dataset>

+ 6
- 6
include/cpphibernate/driver/mariadb/impl/_destroy.h View File

@@ -1,10 +1,10 @@
#pragma once

#include <cppmariadb.h>
#include <cpphibernate/misc.h>
#include <cpphibernate/config.h>
#include <cpphibernate/driver/mariadb/helper.h>
#include <cpphibernate/driver/mariadb/schema/schema.h>

beg_namespace_cpphibernate_driver_mariadb
{
@@ -93,4 +93,4 @@ beg_namespace_cpphibernate_driver_mariadb
};

}
end_namespace_cpphibernate_driver_mariadb
end_namespace_cpphibernate_driver_mariadb

+ 3
- 3
include/cpphibernate/driver/mariadb/impl/_limit.h View File

@@ -1,8 +1,8 @@
#pragma once

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

beg_namespace_cpphibernate_driver_mariadb
{


+ 2
- 2
include/cpphibernate/driver/mariadb/impl/_modifier_tags.h View File

@@ -1,7 +1,7 @@
#pragma once

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

beg_namespace_cpphibernate_driver_mariadb
{


+ 4
- 4
include/cpphibernate/driver/mariadb/impl/_order_by.h View File

@@ -1,9 +1,9 @@
#pragma once

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

beg_namespace_cpphibernate_driver_mariadb
{


+ 6
- 6
include/cpphibernate/driver/mariadb/impl/_read.h View File

@@ -1,10 +1,10 @@
#pragma once

#include <cppmariadb.h>
#include <cpphibernate/misc.h>
#include <cpphibernate/config.h>
#include <cpphibernate/driver/mariadb/helper.h>
#include <cpphibernate/driver/mariadb/schema/schema.h>

beg_namespace_cpphibernate_driver_mariadb
{
@@ -262,4 +262,4 @@ beg_namespace_cpphibernate_driver_mariadb
constexpr decltype(auto) make_fake_context = misc::make_generic_predicate<__impl::make_fake_context_impl> { };

}
end_namespace_cpphibernate_driver_mariadb
end_namespace_cpphibernate_driver_mariadb

+ 4
- 4
include/cpphibernate/driver/mariadb/impl/_where.h View File

@@ -1,9 +1,9 @@
#pragma once

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

beg_namespace_cpphibernate_driver_mariadb
{


+ 14
- 0
include/cpphibernate/driver/mariadb/impl/create_update.h View File

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

namespace cpphibernate {
namespace mariadb {

/**
* @brief Helper class to select the right implementation of the create/update operation for the passed datatype.
*
* @tparam T_dataset Dataset type to select implementation for.
*/
template<typename T_dataset, typename = void>
struct create_update_impl_t;

} }

include/cpphibernate/driver/mariadb/impl/_create_update.h → include/cpphibernate/driver/mariadb/impl/create_update.inl View File

@@ -1,47 +1,54 @@
#pragma once

#include <cppmariadb.h>
#include <cpphibernate/misc.h>
#include <cpphibernate/config.h>
#include <cpphibernate/driver/mariadb/helper.h>
#include <cpphibernate/driver/mariadb/schema/schema.h>

beg_namespace_cpphibernate_driver_mariadb
{

/* create_update_impl_t */

template<typename T_dataset, typename = void>
namespace cpphibernate {
namespace mariadb {

/* create_update_impl_t - default (normal dataset) */

template<typename T_dataset, typename>
struct create_update_impl_t
{
using dataset_type = T_dataset;

static inline value_t apply(const create_update_context& context, bool strict = true)
{
using namespace ::cppmariadb;

value_t ret;

auto dataset_id = misc::get_type_id(hana::type_c<dataset_type>);
auto dataset_id = get_type_id(hana::type_c<dataset_type>);
auto& connection = context.connection;
auto& schema = context.schema;
auto& table = schema.table(dataset_id);

assert(table.primary_key_field);
transaction_lock trans(connection);
if (table.primary_key_field->is_default(context) == context.is_update)

/* if the value of primary key field does not match the operation of the context */
if (table.primary_key_field->is_default(context) != context.is_create())
{
/* if we are not in strict mode, change the context to an update context */
if (!strict)
{
auto update_context = context;
update_context.is_update = !update_context.is_update;
ret = table.create_update(update_context);
static const filter_t dummy;
ret = table.create_update(context.make_update_context(dummy));
}
else if (context.is_update)

/* if we expect an update operation in strict mode throw an exception
* because an update operation needs an primary key assigned */
else if (context.is_update())
{
throw misc::hibernate_exception("can not update dataset with no primary key assigned!");
throw exception("can not update dataset with no primary key assigned!");
}

/* if we expect an create operation in strict mode throw an exception
because an create operation expects the primary key to not be assigned */
else
{
throw misc::hibernate_exception("can not create dataset with primary key assigned!");
throw exception("can not create dataset with primary key assigned!");
}
}
else
@@ -58,10 +65,10 @@ beg_namespace_cpphibernate_driver_mariadb
template<typename T_dataset>
struct create_update_impl_t<
T_dataset,
mp::enable_if<misc::is_nullable<T_dataset>>>
mp::enable_if_t<is_nullable_v<T_dataset>>>
{
using dataset_type = T_dataset;
using nullable_helper_type = misc::nullable_helper<dataset_type>;
using nullable_helper_type = nullable_helper<dataset_type>;

static inline value_t apply(const create_update_context& context, bool strict = true)
{
@@ -77,7 +84,7 @@ beg_namespace_cpphibernate_driver_mariadb
}
else if (strict)
{
throw misc::hibernate_exception("can not create nullable type with no value!");
throw exception("can not create nullable type with no value!");
}
return ret;
}
@@ -88,12 +95,14 @@ beg_namespace_cpphibernate_driver_mariadb
template<typename T_dataset>
struct create_update_impl_t<
T_dataset,
mp::enable_if<misc::is_container<T_dataset>>>
mp::enable_if_t<is_container_v<T_dataset>>>
{
using dataset_type = T_dataset;

static inline value_t apply(const create_update_context& context, bool strict = true)
{
using namespace ::cppmariadb;

value_t ret;
auto& connection = context.connection;
auto& dataset = context.get<dataset_type>();
@@ -113,5 +122,4 @@ beg_namespace_cpphibernate_driver_mariadb
}
};

}
end_namespace_cpphibernate_driver_mariadb
} }

+ 10
- 3
include/cpphibernate/driver/mariadb/impl/driver_impl.h View File

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

#include <cppmariadb.h>

#include "../classes.h"
#include "../classes/schema/schema.h"

namespace cpphibernate {
namespace mariadb {
@@ -36,6 +34,15 @@ namespace mariadb {
*/
inline void init(bool recreate) const;

/**
* @brief Create a new dataset in the database.
* This will update the primary key field of the passed dataset.
*
* @param[in] dataset Dataset to create in database.
*/
template<typename T_dataset>
inline void create(T_dataset& dataset) const;

/*
}



+ 13
- 2
include/cpphibernate/driver/mariadb/impl/driver_impl.inl View File

@@ -1,7 +1,8 @@
#pragma once

#include "driver_impl.h"
#include "../driver.h"




namespace cpphibernate {
namespace mariadb {
@@ -24,4 +25,14 @@ namespace mariadb {
trans.commit();
}

template<typename T_dataset>
void driver_impl_t::create(T_dataset& dataset) const
{
auto * connection = owner.connection();
if (!connection)
throw exception("Cpphibernate mariadb driver is not connected to any database!");
create_update_impl_t<T_dataset>::apply(
create_update_context(*schema, *connection, dataset));
}

} }

+ 60
- 0
include/cpphibernate/driver/mariadb/impl/filter.h View File

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

namespace cpphibernate {
namespace mariadb {

struct field_t;
struct table_t;
struct schema_t;

/**
* @brief Inclusive or exclusive field and table filter.
* Is used in update and read operations to select the fields that should be updated / fetched.
*/
struct filter_t
{
public:
using field_set_type = std::set<const field_t *>;
using table_set_type = std::set<const table_t *>;

ssize_t cache_id { 0 }; //!< Unique ID that indicates the current filtered tables and fields
bool exclusive { true }; //!< True: Use exclusive filter. False: Use inclusive filter.
field_set_type fields; //!< Set of fields assigned to the filter.
table_set_type tables; //!< Set of tables assigned to the filter.

public:
/**
* @brief Returns true if the passed table is excluded.
*/
inline bool is_excluded(const table_t& table) const;

/**
* @brief Returns true if the passed field is excluded.
*/
inline bool is_excluded(const field_t& field) const;

/**
* @brief Set included fields and tables.
*
* @param[in] schema Mariadb driver schame to use for looking up fields and tables.
* @param[in] args Fields and tables from the cpphibernate schema to include in this filter.
*/
template<typename... T_args>
inline void set_inclusive(const schema_t& schema, T_args&&... args);

/**
* @brief Set excluded fields and tables.
*
* @param[in] schema Mariadb driver schame to use for looking up fields and tables.
* @param[in] args Fields and tables from the cpphibernate schema to exclude in this filter.
*/
template<typename... T_args>
inline void set_exclusive(const schema_t& schema, T_args&&... args);

/**
* @brief Clear the filter.
*/
inline void clear();
};

} }

+ 131
- 0
include/cpphibernate/driver/mariadb/impl/filter.inl View File

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

#include <cpphibernate/config.h>

#include "filter.h"
#include "../classes/fields/field.h"
#include "../classes/tables/table.h"
#include "../classes/schema/schema.h"

#include <cpphibernate/schema/field.inl>
#include <cpphibernate/schema/table.inl>
#include <cpphibernate/schema/schema.inl>

namespace cpphibernate {
namespace mariadb {

namespace __impl
{

/* filter_add_element_impl */

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

template<typename T_table>
struct filter_add_element_impl<
mp::list<filter_t&, const schema_t&, T_table>,
mp::enable_if_t<
schema::is_table_v<mp::decay_t<T_table>>>>
{
static constexpr decltype(auto) apply(filter_t& filter, const schema_t& schema, const T_table& table)
{
auto dataset_id = get_type_id(table.wrapped_dataset);
auto& t = schema.table(dataset_id);
filter.tables.emplace(&t);
for (auto& ptr : t.fields)
{
filter.fields.emplace(ptr.get());
}
}
};

template<typename T_field>
struct filter_add_element_impl<
mp::list<filter_t&, const schema_t&, T_field>,
mp::enable_if_t<
schema::is_field_v<mp::decay_t<T_field>>>>
{
static constexpr decltype(auto) apply(filter_t& filter, const schema_t& schema, const T_field& field)
{
auto field_id = get_type_id(hana::type_c<mp::decay_t<T_field>>);
auto& f = schema.field(field_id);
filter.fields.emplace(&f);
filter.tables.emplace(f.table);
}
};

constexpr decltype(auto) filter_add_element = ::cppmp::generic_predicate<__impl::filter_add_element_impl> { };

}

/* filter_t */

bool filter_t::is_excluded(const table_t& table) const
{
auto ret = static_cast<bool>(tables.count(&table));
if (!exclusive)
ret = !ret;
return ret;
}

bool filter_t::is_excluded(const field_t& field) const
{
auto ret = static_cast<bool>(fields.count(&field));
if (!exclusive)
ret = !ret;
return ret;
}

template<typename... T_args>
void filter_t::set_inclusive(const schema_t& schema, T_args&&... args)
{
clear();
exclusive = false;
cache_id = static_cast<ssize_t>(cppcore::get_unique_id<filter_t, mp::decay_t<T_args>...>() + 1);
int dummy[] = { 0, (__impl::filter_add_element(*this, schema, std::forward<T_args>(args)), void(), 0)... };
(void)dummy;
}

template<typename... T_args>
void filter_t::set_exclusive(const schema_t& schema, T_args&&... args)
{
clear();
exclusive = true;
cache_id = -static_cast<ssize_t>(cppcore::get_unique_id<filter_t, mp::decay_t<T_args>...>() + 1);
int dummy[] = { 0, (__impl::filter_add_element(*this, schema, std::forward<T_args>(args)), void(), 0)... };
(void)dummy;

// remove excluded tables if not all fields are excluded
auto it = tables.begin();
while (it != tables.end())
{
bool removed = false;
for (auto& field : (*it)->fields)
{
if (fields.count(field.get()))
{
it = tables.erase(it);
removed = true;
break;
}
}
if (!removed)
++it;
}
}

void filter_t::clear()
{
cache_id = 0;
exclusive = true;
fields.clear();
tables.clear();
}

} }

+ 13
- 0
include/cpphibernate/driver/mariadb/types.h View File

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

#include <cppcore/misc/nullable.h>

namespace cpphibernate {
namespace mariadb {

/**
* @brief Value received from the database.
*/
using value_t = cppcore::nullable<std::string>;

} }

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

@@ -4,3 +4,6 @@
#include "misc/print_container.h"
#include "misc/printing.h"
#include "misc/type_helper.h"

#include "misc/print_container.inl"
#include "misc/type_helper.inl"

+ 21
- 0
include/cpphibernate/modifier.h View File

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



#include "modifier/modifier.h"
#include "modifier/modifiers.h"

@@ -16,3 +18,22 @@
#include "modifier/where/negation.h"
#include "modifier/where/conjunction.h"
#include "modifier/where/disjunction.h"



#include "modifier/modifier.inl"
#include "modifier/modifiers.inl"

#include "modifier/limit.inl"
#include "modifier/offset.inl"

#include "modifier/order_by.inl"
#include "modifier/order_by/ascending.inl"
#include "modifier/order_by/descending.inl"

#include "modifier/where.inl"
#include "modifier/where/where_clause.inl"
#include "modifier/where/equal.inl"
#include "modifier/where/negation.inl"
#include "modifier/where/conjunction.inl"
#include "modifier/where/disjunction.inl"

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

@@ -9,3 +9,11 @@
#include "schema/table.h"
#include "schema/tables.h"
#include "schema/schema.h"

#include "schema/attribute.inl"
#include "schema/attributes.inl"
#include "schema/field.inl"
#include "schema/fields.inl"
#include "schema/table.inl"
#include "schema/tables.inl"
#include "schema/schema.inl"

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

@@ -2,6 +2,7 @@

#include <cpphibernate/config.h>
#include <cpphibernate/misc/type_helper.h>
#include <cpphibernate/misc/equality_compare.h>

namespace cpphibernate {
namespace schema {


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

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

#include <cpphibernate/config.h>
#include <cpphibernate/misc/type_helper.h>
#include <cpphibernate/misc/equality_compare.h>

namespace cpphibernate {
namespace schema {


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

@@ -90,6 +90,16 @@ namespace cpphibernate
*/
inline uuid(const uuid&) = default;

/**
* @brief Move assignment constructor.
*/
inline uuid& operator = (uuid&&) = default;

/**
* @brief Copy assignment constructor.
*/
inline uuid& operator = (const uuid&) = default;

/**
* @brief Write the UUID to passed stream.
*


+ 0
- 282
src/cpphibernate/driver/mariadb/classes/field.xcpp View File

@@ -1,282 +0,0 @@
#include <string>
#include <iostream>

#include <cpputils/misc/enum.h>
#include <cpputils/misc/string.h>
#include <cpputils/misc/indent.h>

#include <cpphibernate/misc.h>
#include <cpphibernate/driver/mariadb/schema/field.h>
#include <cpphibernate/driver/mariadb/schema/table.h>

using namespace ::std;
using namespace ::utl;
using namespace ::cpphibernate::driver::mariadb_impl;

void field_t::print(std::ostream& os) const
{
os << indent << '{'
<< incindent

<< 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_pointer\": " << (value_is_pointer ? "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") << ","

<< indent << "\"schema_name\": \"" << schema_name << "\","
<< indent << "\"table_name\": \"" << table_name << "\","
<< indent << "\"field_name\": \"" << field_name << "\","
<< indent << "\"type\": \"" << type << "\","
<< indent << "\"create_arguments\": \"" << create_arguments << "\","

<< 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 << "\","

<< indent << "\"attributes\": " << misc::print_container(attributes, false)

<< decindent
<< indent << '}';
}

void field_t::update()
{
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 */
{
std::ostringstream ss;
for (auto it = this->attributes.begin(); it != this->attributes.end(); ++it)
{
switch(*it)
{
case attribute_t::hex:
ss << "HEX(";
break;
case attribute_t::compress:
ss << "COMPRESS(";
break;
default:
break;
}
}
convert_to_open = ss.str();
}

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

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

/* convert_from_close */
{
std::ostringstream ss;
for (auto it = this->attributes.rbegin(); it != this->attributes.rend(); ++it)
{
switch(*it)
{
case attribute_t::hex:
case attribute_t::compress:
ss << ')';
break;
default:
break;
}
}
convert_from_close = 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&)
throw_not_implemented(read_context_ptr, foreign_read, const read_context&, bool fake_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&)

/* statements */

throw_not_implemented(::cppmariadb::statement&, get_statement_foreign_one_delete, bool)
throw_not_implemented(::cppmariadb::statement&, get_statement_foreign_many_update)

::cppmariadb::statement& field_t::get_statement_foreign_one_delete_impl(bool key_known, statement_ptr& known, statement_ptr& unknown) const
{
assert(table);
assert(table->primary_key_field);
assert(referenced_table);
assert(referenced_table->primary_key_field);

if (key_known)
{
if (!known)
{
auto& ref_table = *referenced_table;
auto& key_info = *table->primary_key_field;
auto& ref_key_info = *ref_table.primary_key_field;

std::ostringstream os;
os << "WHERE `"
<< ref_key_info.field_name
<< "` IN (SELECT `"
<< ref_key_info.table_name
<< "_id_"
<< field_name
<< "` FROM `"
<< key_info.table_name
<< "` WHERE `"
<< key_info.field_name
<< "`="
<< key_info.convert_to_open
<< "?\?"
<< key_info.convert_to_close
<< " AND `"
<< ref_key_info.table_name
<< "_id_"
<< field_name
<< "`!="
<< ref_key_info.convert_to_open
<< "?\?"
<< ref_key_info.convert_to_close
<< ")";

auto where = os.str();
auto query = ref_table.build_delete_query(&where);
known.reset(new ::cppmariadb::statement(query));
}
return *known;
}
else
{
if (!unknown)
{
auto& ref_table = *referenced_table;
auto& key_info = *table->primary_key_field;
auto& ref_key_info = *ref_table.primary_key_field;

std::ostringstream os;
os << "WHERE `"
<< ref_key_info.field_name
<< "` IN (SELECT `"
<< ref_key_info.table_name
<< "_id_"
<< field_name
<< "` FROM `"
<< key_info.table_name
<< "` WHERE `"
<< key_info.field_name
<< "`="
<< key_info.convert_to_open
<< "?\?"
<< key_info.convert_to_close
<< ")";

auto where = os.str();
auto query = ref_table.build_delete_query(&where);
unknown.reset(new ::cppmariadb::statement(query));
}
return *unknown;
}
}

::cppmariadb::statement& field_t::get_statement_foreign_many_update_impl(statement_ptr& statement) const
{
assert(referenced_table);
assert(referenced_table->primary_key_field);
if (!statement)
{
auto& ref_key_info = *referenced_table->primary_key_field;

std::ostringstream os;
os << "UPDATE `"
<< ref_key_info.table_name
<< "` SET `"
<< table_name
<< "_id_"
<< field_name
<< "`=NULL";
if (value_is_container)
{
os << ", `"
<< table_name
<< "_index_"
<< field_name
<< "`=0";
}
os << " WHERE `"
<< table_name
<< "_id_"
<< field_name
<< "`="
<< ref_key_info.convert_to_open
<< "?\?"
<< ref_key_info.convert_to_close;
statement.reset(new ::cppmariadb::statement(os.str()));
}
return *statement;
}

+ 15
- 8
src/cpphibernate/driver/mariadb/classes/fields/misc.cpp View File

@@ -1,3 +1,4 @@
#include <cpphibernate/types.h>
#include <cpphibernate/misc/print_container.h>
#include <cpphibernate/driver/mariadb/classes/fields/field.h>
#include <cpphibernate/driver/mariadb/classes/tables/table.h>
@@ -20,9 +21,6 @@ std::ostream& field_t::print(std::ostream& os) const
<< incindent

<< indent << "\"id\": " << id << ","
// TODO
// << 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") << ","
@@ -33,11 +31,6 @@ std::ostream& field_t::print(std::ostream& os) const
<< indent << "\"referenced_table\": " << (referenced_table
? std::string("\"") + referenced_table->name + "\""
: "null") << ","

// TODO
// << indent << "\"schema_name\": \"" << schema_name << "\","
// << indent << "\"table_name\": \"" << table_name << "\","
// << indent << "\"field_name\": \"" << field_name << "\","
<< indent << "\"name\": \"" << name << "\","
<< indent << "\"type\": \"" << type << "\","
<< indent << "\"create_arguments\": \"" << create_arguments << "\","
@@ -133,3 +126,17 @@ void field_t::init()
convert_from_close = ss.str();
}
}

#define throw_not_implemented(p_ret, p_name, ...) \
p_ret field_t::p_name(__VA_ARGS__) const \
{ \
throw ::cpphibernate::exception( \
std::string("'") + table.name + "." + name + \
"' does not implement the " #p_name "() method!"); \
}

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

+ 0
- 259
src/cpphibernate/driver/mariadb/classes/schema.xcpp View File

@@ -1,259 +0,0 @@
#include <string>
#include <sstream>

#include <cpputils/misc/enum.h>
#include <cpputils/misc/string.h>
#include <cpputils/misc/indent.h>

#include <cpphibernate/misc.h>
#include <cpphibernate/driver/mariadb/schema/schema.h>

using namespace ::utl;
using namespace ::cpphibernate::driver::mariadb_impl;

void schema_t::update()
{
// clear everything
for (auto& kvp : tables)
{
assert(static_cast<bool>(kvp.second));
auto& table = *kvp.second;
table.primary_key_field = nullptr;
table.derived_tables.clear();
table.foreign_key_fields.clear();
table.foreign_table_fields.clear();
table.foreign_table_one_fields.clear();
table.foreign_table_many_fields.clear();
table.data_fields.clear();
table.is_used_in_container = false;

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

// update references
for (auto& kvp : tables)
{
assert(static_cast<bool>(kvp.second));
auto& table = *kvp.second;

// base table
auto it = tables.find(table.base_dataset_id);
table.base_table = (it != tables.end()
? it->second.get()
: nullptr);

// derived tables
for (auto& id : table.derived_dataset_ids)
{
it = tables.find(id);
if (it == tables.end())
throw misc::hibernate_exception(std::string("unable to find derived table for dataset id ") + std::to_string(id));
table.derived_tables.emplace_back(it->second.get());
}

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

// table
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.real_value_id);
auto referenced_table = (it != tables.end()
? it->second.get()
: nullptr);
field.referenced_table = referenced_table;

// is primary key field
if (field.attributes.count(attribute_t::primary_key))
{
if (static_cast<bool>(table.primary_key_field))
throw misc::hibernate_exception(std::string("Table '") + table.table_name + "' can not have more then one primary key!");
table.primary_key_field = &field;
}

// is foreign table field
else if (static_cast<bool>(referenced_table))
{
table.foreign_table_fields.emplace_back(&field);
if (field.value_is_container)
{
referenced_table->is_used_in_container = true;
}
}

// is data field
else
{
table.data_fields.emplace_back(&field);
}
}
if (!static_cast<bool>(table.primary_key_field))
throw misc::hibernate_exception(std::string("Table '") + table.table_name + "' does not have a primary key!");
}

// update foreign fields (one, many, key)
for (auto& kvp : tables)
{
assert(static_cast<bool>(kvp.second));
auto& table = *kvp.second;

for (auto& ptr : table.foreign_table_fields)
{
assert(ptr);
assert(ptr->referenced_table);
auto& field = *ptr;
auto& referenced_table = *field.referenced_table;

if (field.value_is_container)
{
table.foreign_table_many_fields.emplace_back(&field);
referenced_table.foreign_key_fields.push_back(&field);
}
else
{
table.foreign_table_one_fields.emplace_back(&field);
if (referenced_table.is_used_in_container)
{
referenced_table.foreign_key_fields.push_back(&field);
}
}
}
}
}

void schema_t::print(std::ostream& os) const
{
os << indent << '{'
<< incindent
<< indent << "\"schema_name\": \"" << schema_name << "\","
<< indent << "\"tables\": " << misc::print_container(tables, true, [](auto& s, auto& kvp) {
kvp.second->print(s);
})
<< decindent
<< indent << '}';
}

const table_t& schema_t::table(size_t dataset_id) const
{
auto it = tables.find(dataset_id);
if (it == tables.end())
throw misc::hibernate_exception(std::string("unable to find table for dataset with id ") + std::to_string(dataset_id));
assert(static_cast<bool>(it->second));
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()); \
connection.execute(ss.str()); \
ss.str(std::string()); \
ss.clear(); \
} while(0)

void schema_t::init(const init_context& context) const
{
std::ostringstream ss;
auto& connection = context.connection;

if (context.recreate)
{
ss << "DROP DATABASE IF EXISTS `"
<< schema_name
<< "`";
exec_query();
}

/* create schema */
ss << "CREATE SCHEMA IF NOT EXISTS `"
<< schema_name
<< "` DEFAULT CHARACTER SET utf8";
exec_query();

/* use schema */
ss << "USE `"
<< schema_name
<< "`";
exec_query();

/* UuidToBin */
ss << "CREATE FUNCTION IF NOT EXISTS UuidToBin(_uuid CHAR(36))\n"
" RETURNS BINARY(16)\n"
" LANGUAGE SQL\n"
" DETERMINISTIC\n"
" CONTAINS SQL\n"
" SQL SECURITY INVOKER\n"
"RETURN\n"
" UNHEX(CONCAT(\n"
" SUBSTR(_uuid, 25, 12),\n" // node id
" SUBSTR(_uuid, 20, 4),\n" // clock sequence
" SUBSTR(_uuid, 15, 4),\n" // time high and version
" SUBSTR(_uuid, 10, 4),\n" // time mid
" SUBSTR(_uuid, 1, 8)\n" // time low
" )\n"
")";
exec_query();

/* BinToUuid */
ss << "CREATE FUNCTION IF NOT EXISTS BinToUuid(_bin BINARY(16))\n"
" RETURNS CHAR(36)\n"
" LANGUAGE SQL\n"
" DETERMINISTIC\n"
" CONTAINS SQL\n"
" SQL SECURITY INVOKER\n"
"RETURN\n"
" IF(\n"
" _bin IS NULL,\n"
" NULL,\n"
" LCASE(CONCAT_WS('-',\n"
" HEX(SUBSTR(_bin, 13, 4)),\n" // time low
" HEX(SUBSTR(_bin, 11, 2)),\n" // time mid
" HEX(SUBSTR(_bin, 9, 2)),\n" // time high and version
" HEX(SUBSTR(_bin, 7, 2)),\n" // clock sequence
" HEX(SUBSTR(_bin, 1, 6))\n" // node id
" )\n"
" )\n"
")";
exec_query();

/* initialize tables */
for (auto& kvp : tables)
{
assert(kvp.second);
kvp.second->init_stage1(context);
}
for (auto& kvp : tables)
{
assert(kvp.second);
kvp.second->init_stage2(context);
}
}

#undef exec_query

+ 2
- 1
src/cpphibernate/driver/mariadb/classes/schema/init.cpp View File

@@ -1,4 +1,5 @@
#include <cpphibernate/driver/mariadb/classes/schema/schema.h>
#include <cpphibernate/driver/mariadb/context/init_context.inl>
#include <cpphibernate/driver/mariadb/classes/schema/schema.inl>

using namespace ::cpphibernate;
using namespace ::cpphibernate::mariadb;


+ 35
- 10
src/cpphibernate/driver/mariadb/classes/schema/misc.cpp View File

@@ -1,8 +1,9 @@
#include <cppcore/misc/indent.h>

#include <cpphibernate/types.h>
#include <cpphibernate/misc/print_container.h>
#include <cpphibernate/driver/mariadb/classes/schema/schema.h>

#include <cppcore/misc/indent.h>

using namespace ::cpphibernate;
using namespace ::cpphibernate::mariadb;

@@ -26,11 +27,17 @@ std::ostream& schema_t::print(std::ostream& os) const

void schema_t::init()
{
/* build lookup */
/* build lookup tables */
for (auto& t : tables)
{
assert(static_cast<bool>(t));
_lookup.emplace(t->dataset_id, t.get());
_table_lookup.emplace(t->dataset_id, t.get());

for (auto& f : t->fields)
{
assert(static_cast<bool>(f));
_field_lookup.emplace(f->id, f.get());
}
}

/* update table referencs */
@@ -40,16 +47,16 @@ void schema_t::init()
auto& table = const_cast<table_t&>(*t);

/* get base table */
auto it = _lookup.find(table.base_dataset_id);
table.base_table = (it != _lookup.end()
auto it = _table_lookup.find(table.base_dataset_id);
table.base_table = (it != _table_lookup.end()
? it->second
: nullptr);

/* dereived tables */
for (auto& id : table.derived_dataset_ids)
{
it = _lookup.find(id);
if (it == _lookup.end())
it = _table_lookup.find(id);
if (it == _table_lookup.end())
throw exception(std::string("unable to find derived table for dataset id ") + std::to_string(id));
table.derived_tables.emplace_back(it->second);
}
@@ -61,8 +68,8 @@ void schema_t::init()
auto& field = const_cast<field_t&>(*f);

/* referenced_table */
it = _lookup.find(field.real_value_id);
auto * referenced_table = (it != _lookup.end()
it = _table_lookup.find(field.real_value_id);
auto * referenced_table = (it != _table_lookup.end()
? const_cast<table_t*>(it->second)
: nullptr);
field.referenced_table = referenced_table;
@@ -125,3 +132,21 @@ void schema_t::init()
}
}
}

const table_t& schema_t::table(size_t dataset_id) const
{
auto it = _table_lookup.find(dataset_id);
if (it == _table_lookup.end())
throw exception(std::string("unable to find table for dataset with id ") + std::to_string(dataset_id));
assert(static_cast<bool>(it->second));
return *it->second;
}

const field_t& schema_t::field(size_t field_id) const
{
auto it = _field_lookup.find(field_id);
if (it == _field_lookup.end())
throw exception(std::string("unable to find field for dataset with id ") + std::to_string(field_id));
assert(static_cast<bool>(it->second));
return *it->second;
}

+ 0
- 1827
src/cpphibernate/driver/mariadb/classes/table.xcpp
File diff suppressed because it is too large
View File


+ 483
- 0
src/cpphibernate/driver/mariadb/classes/tables/create_update.cpp View File

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

#include <cpphibernate/types.inl>
#include <cpphibernate/driver/mariadb/impl/filter.inl>
#include <cpphibernate/driver/mariadb/classes/tables/table.inl>
#include <cpphibernate/driver/mariadb/context/create_update_context.inl>

using namespace ::cpphibernate;
using namespace ::cpphibernate::mariadb;

static std::string build_create_update_query(
const table_t& table,
const filter_t * filter,
const field_t * owner);

static std::string execute_create_update(
const table_t& table,
const create_update_context& context,
::cppmariadb::statement * statement);

/* table_t */

std::string table_t::create_update(const create_update_context& context) const
{ return create_update_exec(context); }

std::string table_t::create_update_exec(const create_update_context& context) const
{
auto * statement = context.is_update()
? get_statement_update(*context.filter, context.owner_field)
: get_statement_insert_into();
return execute_create_update(*this, context, statement);
}

::cppmariadb::statement* table_t::get_statement_insert_into() const
{
if (!_statement_insert_into)
{
auto query = build_create_update_query(*this, nullptr, nullptr);
_statement_insert_into.reset(new ::cppmariadb::statement(query));
}
return _statement_insert_into->empty()
? nullptr
: _statement_insert_into.get();
}

::cppmariadb::statement* table_t::get_statement_update(const filter_t& filter, const field_t * owner) const
{
auto key = std::make_tuple(filter.cache_id, owner);
auto it = _statement_update.find(key);
if (it == _statement_update.end())
{
auto query = build_create_update_query(*this, &filter, owner);
it = _statement_update.emplace(key, ::cppmariadb::statement(query)).first;
}
return it->second.empty()
? nullptr
: &it->second;
}

std::string build_create_update_query(const table_t& table, const filter_t* filter, const field_t* owner)
{
std::ostringstream os;

size_t index = 0;
bool is_update = static_cast<bool>(filter);
bool is_create = !is_update;

/* INSER INTO / UPDATE */
os << (is_update
? "UPDATE"
: "INSERT INTO")
<< " `"
<< table.name
<< "`";

/* primary key */
if (is_create)
{
assert(table.primary_key_field);
auto& key_info = *table.primary_key_field;
if (!key_info.value_is_auto_incremented)
{
if (index++)
os << ", ";
else
os << " SET ";
os << "`"
<< key_info.name
<< "`="
<< key_info.convert_to_open
<< "?"
<< key_info.name
<< "?"
<< key_info.convert_to_close;
}
}

/* base table key fields */
if ( static_cast<bool>(table.base_table)
&& ( is_create
|| !filter->is_excluded(*table.base_table)))
{
if (index++)
os << ", ";
else
os << " SET ";
auto& base_table_info = *table.base_table;
assert(base_table_info.primary_key_field);
auto& key_info = *base_table_info.primary_key_field;
os << "`"
<< key_info.name
<< "`="
<< key_info.convert_to_open
<< "?"
<< key_info.name
<< "?"
<< key_info.convert_to_close;
}

/* foreign table one fields */
for (auto& ptr : table.foreign_table_one_fields)
{
assert(static_cast<bool>(ptr));
auto& field_info = *ptr;
if (is_update && filter->is_excluded(field_info))
continue;
assert(field_info.referenced_table);
assert(field_info.referenced_table->primary_key_field);
if (field_info.referenced_table->is_used_in_container)
continue;
if (index++)
os << ", ";
else
os << " SET ";
auto& key_info = *field_info.referenced_table->primary_key_field;
os << "`"
<< key_info.table.name
<< "_id_"
<< field_info.name
<< "`="
<< key_info.convert_to_open
<< "?"
<< key_info.table.name
<< "_id_"
<< field_info.name
<< "?"
<< key_info.convert_to_close;
}

/* foreign fields */
for (auto& ptr : table.foreign_key_fields)
{
assert(static_cast<bool>(ptr));
if (is_update && ptr != owner)
continue;
if (index++)
os << ", ";
else
os << " SET ";
auto& field_info = *ptr;
assert(field_info.table.primary_key_field);
auto& key_info = *field_info.table.primary_key_field;
os << "`"
<< field_info.table.name
<< "_id_"
<< field_info.name
<< "`="
<< key_info.convert_to_open
<< "?"
<< field_info.table.name
<< "_id_"
<< field_info.name
<< "?"
<< key_info.convert_to_close;
if (field_info.value_is_ordered)
{
if (index++)
os << ", ";
else
os << " SET ";
os << "`"
<< field_info.table.name
<< "_index_"
<< field_info.name
<< "`=?\?";
}
}

/* data fields */
for (auto& ptr : table.data_fields)
{
assert(ptr);
auto& field_info = *ptr;
if (is_update && filter->is_excluded(field_info))
continue;
if (index++)
os << ", ";
else
os << " SET ";
os << "`"
<< field_info.name
<< "`="
<< field_info.convert_to_open
<< "?"
<< field_info.name
<< "?"
<< field_info.convert_to_close;
}

/* type field for derived tables */
if ( !table.derived_tables.empty()
&& !table.base_table
&& is_create)
{
if (index++)
os << ", ";
else
os << " SET ";
os << "`__type`=?__type?";
}

/* where primary key (for update) */
if (is_update)
{
assert(table.primary_key_field);
auto& key_info = *table.primary_key_field;
os << " WHERE `"
<< key_info.name
<< "`="
<< key_info.convert_to_open
<< "?"
<< key_info.name
<< "?"
<< key_info.convert_to_close;
}

return index == 0 && !(table.primary_key_field->value_is_auto_incremented && is_create)
? std::string()
: os.str();
}

std::string execute_create_update(
const table_t& table,
const create_update_context& context,
::cppmariadb::statement * statement)
{
auto& connection = context.connection;
auto* filter = context.filter;

size_t index = 0;
bool is_update = context.is_update();
bool is_create = context.is_create();

std::string primary_key;
if (statement) statement->clear();

/* primary key */
assert(table.primary_key_field);
if (is_update)
{
primary_key = table.get_primary_key(context);
}
else if (!table.primary_key_field->value_is_auto_incremented)
{
primary_key = table.primary_key_field->generate_value(context.connection);
if (statement) statement->set(index, primary_key);
++index;
}

/* base_key */
if ( table.base_table
&& ( is_create
|| !filter->is_excluded(*table.base_table)))
{
auto new_context = context;
if (!new_context.derived_table)
new_context.derived_table = &table;
// TODO std::string key = create_update_base(new_context);
std::string key = table.base_table->create_update_exec(new_context);
if (statement) statement->set(index, std::move(key));
++index;
}

if (is_update && filter->is_excluded(table))
return primary_key;

/* foreign table one fields */
for (auto& ptr : table.foreign_table_one_fields)
{
assert(ptr);
assert(ptr->referenced_table);

auto& field = *ptr;
if (is_update && filter->is_excluded(field))
continue;
if (field.referenced_table->is_used_in_container)
continue;

/* insert/update dataset */
value_t key = field.foreign_create_update(context);
if (key.has_value())
{
if (statement) statement->set(index, *key);
}
else if (field.value_is_nullable)
{
if (statement) statement->set_null(index);
}
else
{
throw exception("Received null key for non nullable foreign dataset!");
}
++index;

/* cleanup old dataset (if new one was created) */
if (context.is_update())
{
/* TODO
auto& delete_statement = field.get_statement_foreign_one_delete(key.has_value());
delete_statement.set(0, primary_key);
if (key.has_value())
delete_statement.set(1, *key);
cpphibernate_log_debug("execute DELETE old foreign one query: " << std::endl << delete_statement.query(connection) << std::endl);
connection.execute(delete_statement);

table_set processed;
field.referenced_table->destroy_cleanup(context, processed, true, true);
*/
}
}

/* foreign key fields */
for (auto& ptr : table.foreign_key_fields)
{
assert(ptr);
if (is_update && ptr != context.owner_field)
continue;

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

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

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

/* data fields */
for (auto& ptr : table.data_fields)
{
assert(ptr);
if (is_update && filter->is_excluded(*ptr))
continue;

auto& field_info = *ptr;
auto value = field_info.get(context);

if (value.has_value())
{
if (statement) statement->set(index, *value);
}
else
{
if (statement) statement->set_null(index);
}
++index;
}

/* type field for derived tables */
if ( !table.derived_tables.empty()
&& !table.base_table
&& is_create)
{
if (statement) statement->set(index, context.derived_table
? context.derived_table->id
: table.id);
++index;
}

/* where primary key (for update) */
if (is_update)
{
assert(table.primary_key_field);
if (statement) statement->set(index, *table.primary_key_field->get(context));
++index;
}

/* execute */
if (statement)
{
if (is_create)
{
cpphibernate_log_debug("execute INSERT query: " << std::endl << statement->query(connection) << std::endl);
}
else
{
cpphibernate_log_debug("execute UPDATE query: " << std::endl << statement->query(connection) << std::endl);
}

if ( table.primary_key_field->value_is_auto_incremented
&& is_create)
{
auto id = connection.execute_id(*statement);
primary_key = cppcore::to_string(id);
}
else
{
auto count = connection.execute_rows(*statement);
if (count > 1)
throw exception("Expected one/ row to be inserted/updated!");
cpphibernate_log_debug(count << " rows inserted/updated" << std::endl);
}
table.primary_key_field->set(context, primary_key);
}

/* foreign table many fields */
for (auto& ptr : table.foreign_table_fields)
{
assert(ptr);
assert(ptr->referenced_table);

auto& field = *ptr;
auto& ref_table = *field.referenced_table;

if (!ref_table.is_used_in_container)
continue;

if ( is_update
&& ( filter->is_excluded(field)
|| filter->is_excluded(ref_table)))
continue;

/* set foreign keys of existing elements to null */
if (context.is_update())
{
/* TODO
auto& update_statement = field.get_statement_foreign_many_update();
update_statement.set(0, primary_key);
cpphibernate_debug_log("execute UPDATE old foreign many query: " << update_statement.query(connection));
connection.execute(update_statement);
*/
}

/* update elements */
auto next_context = context;
next_context.owner_field = ptr;
next_context.owner_key = primary_key;
next_context.derived_table = nullptr;
field.foreign_create_update(next_context);

/* delete non referenced elements */
if (context.is_update())
{
/* TODO
table_set processed;
ref_table.destroy_cleanup(context, processed, true, true);
*/
}
}

return primary_key;
}

+ 58
- 47
src/cpphibernate/driver/mariadb/classes/tables/init.cpp View File

@@ -1,10 +1,16 @@
#include <cppcore/misc/indent.h>
#include <cpphibernate/driver/mariadb/classes/tables/table.h>
#include <cpphibernate/driver/mariadb/classes/schema/schema.h>

#include <cpphibernate/types.inl>
#include <cpphibernate/driver/mariadb/classes/tables/table.inl>
#include <cpphibernate/driver/mariadb/classes/schema/schema.inl>
#include <cpphibernate/driver/mariadb/context/init_context.inl>

using namespace ::cpphibernate;
using namespace ::cpphibernate::mariadb;

static std::string build_init_stage1_query(const table_t& table);
static std::string build_init_stage2_query(const table_t& table);

void table_t::init(const init_context& context, init_stage stage) const
{
switch (stage)
@@ -13,7 +19,7 @@ void table_t::init(const init_context& context, init_stage stage) const
{
auto& statement = get_statement_init_stage1();
auto& connection = context.connection;
cpphibernate_log_debug("execute CREATE TABLE query: " << statement.query(connection));
cpphibernate_log_debug("execute CREATE TABLE query: " << std::endl << statement.query(connection) << std::endl);
connection.execute(statement);
}
break;
@@ -24,7 +30,7 @@ void table_t::init(const init_context& context, init_stage stage) const
auto& connection = context.connection;
if (!statement)
return;
cpphibernate_log_debug("execute ALTER TABLE query: " << statement->query(connection));
cpphibernate_log_debug("execute ALTER TABLE query: " << std::endl << statement->query(connection) << std::endl);
connection.execute(*statement);
}
break;
@@ -37,16 +43,30 @@ void table_t::init(const init_context& context, init_stage stage) const

::cppmariadb::statement& table_t::get_statement_init_stage1() const
{
using namespace ::cppcore;
if (!_statement_init_stage1)
_statement_init_stage1.reset(new ::cppmariadb::statement(build_init_stage1_query(*this)));
return *_statement_init_stage1;
}

if (_statement_init_stage1)
return *_statement_init_stage1;
::cppmariadb::statement* table_t::get_statement_init_stage2() const
{
if (!_statement_init_stage2)
_statement_init_stage2.reset(new ::cppmariadb::statement(build_init_stage2_query(*this)));

return _statement_init_stage2->empty()
? nullptr
: _statement_init_stage2.get();
}

std::string build_init_stage1_query(const table_t& table)
{
using namespace ::cppcore;

std::ostringstream os;

/* CREATE TABLE */
os << "CREATE TABLE IF NOT EXISTS `"
<< name
<< table.name
<< "`"
<< indent
<< "("
@@ -54,8 +74,8 @@ void table_t::init(const init_context& context, init_stage stage) const

/* primary key */
{
assert(primary_key_field);
auto& key_info = *primary_key_field;
assert(table.primary_key_field);
auto& key_info = *table.primary_key_field;
auto args = key_info.create_arguments;

os << indent
@@ -70,9 +90,9 @@ void table_t::init(const init_context& context, init_stage stage) const
}

/* base table key fields */
if (static_cast<bool>(base_table))
if (static_cast<bool>(table.base_table))
{
auto& base_table_info = *base_table;
auto& base_table_info = *table.base_table;

assert(base_table_info.primary_key_field);
auto& key_info = *base_table_info.primary_key_field;
@@ -86,7 +106,7 @@ void table_t::init(const init_context& context, init_stage stage) const
}

/* foreign table one fields */
for (auto& ptr : foreign_table_one_fields)
for (auto& ptr : table.foreign_table_one_fields)
{
assert(static_cast<bool>(ptr));
auto& field_info = *ptr;
@@ -112,7 +132,7 @@ void table_t::init(const init_context& context, init_stage stage) const
}

/* foreign fields */
for (auto& ptr : foreign_key_fields)
for (auto& ptr : table.foreign_key_fields)
{
assert(static_cast<bool>(ptr));
auto& field_info = *ptr;
@@ -140,7 +160,7 @@ void table_t::init(const init_context& context, init_stage stage) const
}

/* data fields */
for (auto& ptr : data_fields)
for (auto& ptr : table.data_fields)
{
assert(static_cast<bool>(ptr));
auto& field_info = *ptr;
@@ -156,8 +176,8 @@ void table_t::init(const init_context& context, init_stage stage) const
}

/* type field for derived tables */
if (!derived_tables.empty() &&
!base_table)
if (!table.derived_tables.empty() &&
!table.base_table)
{
os << indent
<< "`__type` INT UNSIGNED NOT NULL,";
@@ -165,8 +185,8 @@ void table_t::init(const init_context& context, init_stage stage) const

/* PRIMARY KEY */
{
assert(primary_key_field);
auto& key_info = *primary_key_field;
assert(table.primary_key_field);
auto& key_info = *table.primary_key_field;

os << indent
<< "PRIMARY KEY ( `"
@@ -176,8 +196,8 @@ void table_t::init(const init_context& context, init_stage stage) const

/* UNIQUE INDEX primary key */
{
assert(primary_key_field);
auto& key_info = *primary_key_field;
assert(table.primary_key_field);
auto& key_info = *table.primary_key_field;

os << ','
<< indent
@@ -189,9 +209,9 @@ void table_t::init(const init_context& context, init_stage stage) const
}

/* UNIQUE INDEX base table keys */
if (base_table)
if (table.base_table)
{
auto& table_info = *base_table;
auto& table_info = *table.base_table;

assert(table_info.primary_key_field);
auto& key_info = *table_info.primary_key_field;
@@ -206,7 +226,7 @@ void table_t::init(const init_context& context, init_stage stage) const
}

/* INDEX foreign table one fields */
for (auto& ptr : foreign_table_one_fields)
for (auto& ptr : table.foreign_table_one_fields)
{
assert(static_cast<bool>(ptr));
auto& field_info = *ptr;
@@ -233,7 +253,7 @@ void table_t::init(const init_context& context, init_stage stage) const
}

/* INDEX foreign fields */
for (auto& ptr : foreign_key_fields)
for (auto& ptr : table.foreign_key_fields)
{
assert(static_cast<bool>(ptr));
auto& field_info = *ptr;
@@ -260,39 +280,33 @@ void table_t::init(const init_context& context, init_stage stage) const
<< indent
<< "DEFAULT CHARACTER SET = utf8";

_statement_init_stage1.reset(new ::cppmariadb::statement(os.str()));
return *_statement_init_stage1;
return os.str();
}

::cppmariadb::statement* table_t::get_statement_init_stage2() const
std::string build_init_stage2_query(const table_t& table)
{
using namespace ::cppcore;

if (_statement_init_stage2)
return _statement_init_stage2->empty()
? nullptr
: _statement_init_stage2.get();

std::ostringstream os;

/* ALTER TABLE */
os << "ALTER TABLE `"
<< name
<< table.name
<< "`"
<< incindent;

size_t index = 0;

/* CONSTRAINT base table */
if (base_table)
if (table.base_table)
{
assert(base_table->primary_key_field);
auto& ref_key_info = *base_table->primary_key_field;
assert(table.base_table->primary_key_field);
auto& ref_key_info = *table.base_table->primary_key_field;

if (index++) os << ",";
os << indent
<< "ADD CONSTRAINT `fk_"
<< name
<< table.name
<< "_"
<< ref_key_info.name
<< "`"
@@ -317,7 +331,7 @@ void table_t::init(const init_context& context, init_stage stage) const
}

/* CONSTRAINT foreign table one fields */
for (auto& ptr : foreign_table_one_fields)
for (auto& ptr : table.foreign_table_one_fields)
{
assert(static_cast<bool>(ptr));
auto& field_info = *ptr;
@@ -333,7 +347,7 @@ void table_t::init(const init_context& context, init_stage stage) const
if (index++) os << ",";
os << indent
<< "ADD CONSTRAINT `fk_"
<< name
<< table.name
<< "_"
<< ref_key_info.table.name
<< "_"
@@ -365,7 +379,7 @@ void table_t::init(const init_context& context, init_stage stage) const
}

/* CONSTRAINT foreign fields */
for (auto& ptr : foreign_key_fields)
for (auto& ptr : table.foreign_key_fields)
{
assert(static_cast<bool>(ptr));
auto& field_info = *ptr;
@@ -376,7 +390,7 @@ void table_t::init(const init_context& context, init_stage stage) const
if (index++) os << ",";
os << indent
<< "ADD CONSTRAINT `fk_"
<< name
<< table.name
<< "_"
<< field_info.table.name
<< "_"
@@ -404,10 +418,7 @@ void table_t::init(const init_context& context, init_stage stage) const
<< decindent;
}

_statement_init_stage2.reset(new ::cppmariadb::statement(index == 0
return index == 0
? std::string { }
: os.str()));
return _statement_init_stage2->empty()
? nullptr
: _statement_init_stage2.get();
: os.str();
}

+ 56
- 9
src/cpphibernate/driver/mariadb/classes/tables/misc.cpp View File

@@ -3,6 +3,9 @@

#include <cppcore/misc/indent.h>

#include <cpphibernate/types.inl>
#include <cpphibernate/driver/mariadb/context/data_context.inl>

using namespace ::cpphibernate;
using namespace ::cpphibernate::mariadb;

@@ -18,13 +21,9 @@ std::ostream& table_t::print(std::ostream& os) const
os << indent << '{'
<< incindent
<< indent << "\"id\": " << id << ","
// TODO
<< indent << "\"dataset_id\": " << dataset_id << ","
<< indent << "\"base_dataset_id\": " << base_dataset_id << ","
<< indent << "\"derived_dataset_ids\": " << make_print_container(derived_dataset_ids, false) << ","
// TODO
// << indent << "\"schema_name\": \"" << schema_name << "\","
// << indent << "\"table_name\": \"" << table_name << "\","
<< indent << "\"name\": \"" << name << "\","
<< indent << "\"base_table\": " << (base_table ? std::string("\"") + base_table->name + "\"" : "null") << ","
<< indent << "\"derived_tables\":" << make_print_container(derived_tables, true, [](auto& s, auto& ptr){
@@ -55,12 +54,60 @@ std::ostream& table_t::print(std::ostream& os) const
return os;
}

void table_t::init()
std::string table_t::get_primary_key(const data_context& context) const
{
assert(primary_key_field);
if ( primary_key_field->is_default(context)
&& base_table)
{
auto key = get_key_from_base(context);
primary_key_field->set(context, key);
return key;
}
else
{
return *primary_key_field->get(context);
}
}

std::string table_t::get_key_from_base(const data_context& context) const
{
if (!base_table)
{
throw exception(std::string("table has no base table: ") + name);
}
auto& statement = get_statement_key_from_base();
auto base_key = base_table->get_primary_key(context);
statement.set(0, base_key);
auto result = context.connection.execute_stored(statement);
if (!result)
throw exception("unable to fetch key from database: unable to execute query!");
auto row = result->next();
if (!row)
throw exception("unable to fetch key from database: result set is empty!");
return row->at(0).get<std::string>();
}

::cppmariadb::statement& table_t::get_statement_key_from_base() const
{
/* build field lookup */
for (auto& f : fields)
if (!_statement_key_from_base)
{
assert(static_cast<bool>(f));
_lookup.emplace(f->id, f.get());
if (!base_table)
throw exception(std::string("table has no base table: ") + name);
assert(primary_key_field);
assert(base_table);
assert(base_table->primary_key_field);
auto& key_info = *primary_key_field;
auto& base_key = *base_table->primary_key_field;
std::ostringstream os;
os << "SELECT `"
<< key_info.name
<< "` FROM `"
<< key_info.table.name
<< "` WHERE `"
<< base_key.table.name
<< "_id`=?\?";
_statement_key_from_base.reset(new ::cppmariadb::statement(os.str()));
}
return *_statement_key_from_base;
}

test/cpphibernate/cpphibernate_create.xcpp → test/cpphibernate/cpphibernate_create.cpp View File

@@ -45,10 +45,10 @@ TEST(CppHibernateTests, create_test1)
t1.u32_ptr_s = std::make_shared<uint32_t>(789);

::cppmariadb::connection connection(reinterpret_cast<MYSQL*>(0x1111));
auto context = make_context<driver::mariadb>(test_schema, connection);
auto context = make_context<mariadb_driver>(test_schema, connection);
context.create(t1);
}
#if 0
TEST(CppHibernateTests, create_test2)
{
StrictMock<mariadb_mock> mock;
@@ -576,4 +576,5 @@ TEST(CppHibernateTests, create_double_usage)
EXPECT_EQ(d.single_item->id, 1001);
EXPECT_EQ(d.multiple_items[0].id, 1002);
EXPECT_EQ(d.multiple_items[1].id, 1003);
}
}
#endif

test/cpphibernate/cpphibernate_init.cpp → test/cpphibernate/cpphibernate_init.xcpp View File


Loading…
Cancel
Save