Преглед на файлове

Merge branch 'refactoring'

master
bergmann преди 6 години
родител
ревизия
7ba4e383c6
променени са 100 файла, в които са добавени 5048 реда и са изтрити 2768 реда
  1. +55
    -13
      CMakeLists.txt
  2. +3
    -3
      README.md
  3. +0
    -46
      cmake/Findcppmariadb.cmake
  4. +0
    -46
      cmake/Findcpputils.cmake
  5. +0
    -34
      cmake/Findmariadb.cmake
  6. +34
    -0
      cmake/config.h.in
  7. +10
    -0
      cmake/cpphibernate-config.cmake
  8. +21
    -0
      cmake/cpphibernate-options.cmake
  9. +31
    -0
      cmake/cpphibernate-var.cmake
  10. +1
    -1
      cmake/modules
  11. +0
    -9
      cmake/options.cmake
  12. +0
    -1
      cmake/options.h.in
  13. +7
    -6
      include/cpphibernate.h
  14. +0
    -73
      include/cpphibernate/config.h
  15. +2
    -120
      include/cpphibernate/context.h
  16. +104
    -0
      include/cpphibernate/context/context.h
  17. +235
    -0
      include/cpphibernate/context/context.inl
  18. +14
    -7
      include/cpphibernate/driver/mariadb.h
  19. +6
    -0
      include/cpphibernate/driver/mariadb/classes.h
  20. +5
    -0
      include/cpphibernate/driver/mariadb/classes/attributes.h
  21. +46
    -0
      include/cpphibernate/driver/mariadb/classes/attributes/attributes.h
  22. +11
    -10
      include/cpphibernate/driver/mariadb/classes/attributes/attributes.inl
  23. +17
    -0
      include/cpphibernate/driver/mariadb/classes/fields.h
  24. +214
    -0
      include/cpphibernate/driver/mariadb/classes/fields/field.h
  25. +122
    -0
      include/cpphibernate/driver/mariadb/classes/fields/field.inl
  26. +37
    -0
      include/cpphibernate/driver/mariadb/classes/fields/field_data.h
  27. +27
    -0
      include/cpphibernate/driver/mariadb/classes/fields/field_data.inl
  28. +57
    -0
      include/cpphibernate/driver/mariadb/classes/fields/field_foreign_table.h
  29. +73
    -0
      include/cpphibernate/driver/mariadb/classes/fields/field_foreign_table.inl
  30. +61
    -0
      include/cpphibernate/driver/mariadb/classes/fields/field_primary_key.h
  31. +61
    -0
      include/cpphibernate/driver/mariadb/classes/fields/field_primary_key.inl
  32. +41
    -0
      include/cpphibernate/driver/mariadb/classes/fields/field_simple.h
  33. +28
    -0
      include/cpphibernate/driver/mariadb/classes/fields/field_simple.inl
  34. +63
    -0
      include/cpphibernate/driver/mariadb/classes/fields/field_value.h
  35. +55
    -0
      include/cpphibernate/driver/mariadb/classes/fields/field_value.inl
  36. +36
    -0
      include/cpphibernate/driver/mariadb/classes/fields/fields.h
  37. +63
    -0
      include/cpphibernate/driver/mariadb/classes/fields/fields.inl
  38. +5
    -0
      include/cpphibernate/driver/mariadb/classes/schema.h
  39. +97
    -0
      include/cpphibernate/driver/mariadb/classes/schema/schema.h
  40. +44
    -0
      include/cpphibernate/driver/mariadb/classes/schema/schema.inl
  41. +1
    -0
      include/cpphibernate/driver/mariadb/classes/tables.h
  42. +319
    -0
      include/cpphibernate/driver/mariadb/classes/tables/table.h
  43. +128
    -0
      include/cpphibernate/driver/mariadb/classes/tables/table.inl
  44. +81
    -0
      include/cpphibernate/driver/mariadb/classes/tables/table_polymorphic.h
  45. +185
    -0
      include/cpphibernate/driver/mariadb/classes/tables/table_polymorphic.inl
  46. +35
    -0
      include/cpphibernate/driver/mariadb/classes/tables/table_simple.h
  47. +27
    -0
      include/cpphibernate/driver/mariadb/classes/tables/table_simple.inl
  48. +32
    -0
      include/cpphibernate/driver/mariadb/classes/tables/tables.h
  49. +66
    -0
      include/cpphibernate/driver/mariadb/classes/tables/tables.inl
  50. +11
    -0
      include/cpphibernate/driver/mariadb/context.h
  51. +26
    -0
      include/cpphibernate/driver/mariadb/context/base_context.h
  52. +17
    -0
      include/cpphibernate/driver/mariadb/context/base_context.inl
  53. +71
    -0
      include/cpphibernate/driver/mariadb/context/create_update_context.h
  54. +57
    -0
      include/cpphibernate/driver/mariadb/context/create_update_context.inl
  55. +92
    -0
      include/cpphibernate/driver/mariadb/context/data_context.h
  56. +119
    -0
      include/cpphibernate/driver/mariadb/context/data_context.inl
  57. +23
    -0
      include/cpphibernate/driver/mariadb/context/destroy_context.h
  58. +20
    -0
      include/cpphibernate/driver/mariadb/context/destroy_context.inl
  59. +22
    -0
      include/cpphibernate/driver/mariadb/context/init_context.h
  60. +20
    -0
      include/cpphibernate/driver/mariadb/context/init_context.inl
  61. +104
    -0
      include/cpphibernate/driver/mariadb/context/read_context.h
  62. +364
    -0
      include/cpphibernate/driver/mariadb/context/read_context.inl
  63. +86
    -0
      include/cpphibernate/driver/mariadb/driver.h
  64. +44
    -0
      include/cpphibernate/driver/mariadb/driver.inl
  65. +7
    -4
      include/cpphibernate/driver/mariadb/helper.h
  66. +27
    -0
      include/cpphibernate/driver/mariadb/helper/container_helper.h
  67. +43
    -0
      include/cpphibernate/driver/mariadb/helper/container_helper.inl
  68. +0
    -218
      include/cpphibernate/driver/mariadb/helper/context.h
  69. +0
    -91
      include/cpphibernate/driver/mariadb/helper/context.inl
  70. +30
    -33
      include/cpphibernate/driver/mariadb/helper/key_properties.h
  71. +48
    -0
      include/cpphibernate/driver/mariadb/helper/key_properties.inl
  72. +31
    -0
      include/cpphibernate/driver/mariadb/helper/nullable_helper.h
  73. +73
    -0
      include/cpphibernate/driver/mariadb/helper/nullable_helper.inl
  74. +0
    -93
      include/cpphibernate/driver/mariadb/helper/transaction_lock.h
  75. +37
    -568
      include/cpphibernate/driver/mariadb/helper/type_properties.h
  76. +559
    -0
      include/cpphibernate/driver/mariadb/helper/type_properties.inl
  77. +8
    -7
      include/cpphibernate/driver/mariadb/impl.h
  78. +10
    -113
      include/cpphibernate/driver/mariadb/impl/create_update.h
  79. +130
    -0
      include/cpphibernate/driver/mariadb/impl/create_update.inl
  80. +10
    -92
      include/cpphibernate/driver/mariadb/impl/destroy.h
  81. +112
    -0
      include/cpphibernate/driver/mariadb/impl/destroy.inl
  82. +72
    -0
      include/cpphibernate/driver/mariadb/impl/driver_impl.h
  83. +86
    -0
      include/cpphibernate/driver/mariadb/impl/driver_impl.inl
  84. +9
    -11
      include/cpphibernate/driver/mariadb/impl/driver_impl/limit.inl
  85. +13
    -15
      include/cpphibernate/driver/mariadb/impl/driver_impl/order_by.inl
  86. +22
    -22
      include/cpphibernate/driver/mariadb/impl/driver_impl/where.inl
  87. +60
    -0
      include/cpphibernate/driver/mariadb/impl/filter.h
  88. +25
    -16
      include/cpphibernate/driver/mariadb/impl/filter.inl
  89. +0
    -69
      include/cpphibernate/driver/mariadb/impl/modifier_tags.h
  90. +0
    -265
      include/cpphibernate/driver/mariadb/impl/read.h
  91. +0
    -120
      include/cpphibernate/driver/mariadb/mariadb.h
  92. +0
    -24
      include/cpphibernate/driver/mariadb/schema.h
  93. +0
    -34
      include/cpphibernate/driver/mariadb/schema/attributes.fwd.h
  94. +0
    -23
      include/cpphibernate/driver/mariadb/schema/attributes.h
  95. +0
    -31
      include/cpphibernate/driver/mariadb/schema/field.fwd.h
  96. +0
    -213
      include/cpphibernate/driver/mariadb/schema/field.h
  97. +0
    -228
      include/cpphibernate/driver/mariadb/schema/field.inl
  98. +0
    -29
      include/cpphibernate/driver/mariadb/schema/fields.fwd.h
  99. +0
    -25
      include/cpphibernate/driver/mariadb/schema/fields.h
  100. +0
    -55
      include/cpphibernate/driver/mariadb/schema/fields.inl

+ 55
- 13
CMakeLists.txt Целия файл

@@ -1,15 +1,57 @@
# Initialize CMake ################################################################################

CMake_Minimum_Required ( VERSION 3.5.1 FATAL_ERROR )
Include ( CTest )
If ( NOT CMAKE_BUILD_TYPE )
Set ( CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build!" FORCE )
EndIf ( NOT CMAKE_BUILD_TYPE )
Set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/"
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/" )

# Projects ########################################################################################

Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/src )
Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/test )
CMake_Minimum_Required ( VERSION 3.12.0 FATAL_ERROR )

# Set CMAKE_BUILD_TYPE
If ( NOT CMAKE_BUILD_TYPE )
Set ( CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build!" FORCE )
EndIf ( NOT CMAKE_BUILD_TYPE )
Set_Property ( CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS Debug Release RelWithDebInfo MinSizeRel )

# Set CMAKE_MODULE_PATH
If ( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" )
Set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/" )
EndIf ( )
If ( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" )
Set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" )
EndIf ( )

# Project #########################################################################################

Include ( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cpphibernate-var.cmake )
Include ( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cpphibernate-options.cmake )
Project ( cpphibernate
DESCRIPTION "A simple library"
VERSION "${CPPHIBERNATE_VERSION}" )
Include ( CTest )
Include ( GNUInstallDirs )

# Subdirectories
Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/src )
Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/test )

# Install
Include ( CMakePackageConfigHelpers )
Write_Basic_Package_Version_File ( "${CMAKE_CURRENT_BINARY_DIR}/cmake/cpphibernate-config-version.cmake"
VERSION ${CPPHIBERNATE_VERSION}
COMPATIBILITY AnyNewerVersion )
Configure_File ( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cpphibernate-config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/cmake/cpphibernate-config.cmake"
@ONLY )

Set ( ConfigPackageLocation "${CPPHIBERNATE_INSTALL_DIR_SHARE}/cmake" )
Install ( EXPORT
cpphibernate
NAMESPACE
cpphibernate::
DESTINATION
${ConfigPackageLocation} )
Install ( FILES
"${CMAKE_CURRENT_BINARY_DIR}/cmake/cpphibernate-config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/cmake/cpphibernate-config-version.cmake"
DESTINATION
${ConfigPackageLocation}
COMPONENT
Devel )

+ 3
- 3
README.md Целия файл

@@ -60,7 +60,7 @@ int main(int argc, char** argv)
connection c = database::connect("localhost", 3306, "testuser", "password", "", client_flags::empty());

/* create a hibernation context */
auto context = make_context_ptr<driver::mariadb>(test_schema, c);
auto context = make_context_ptr<mariadb_driver>(test_schema, c);

/* initialize the database schema */
context.init(); /* CREATE SCHEMA IF NOT EXISTS `test_schema` DEFAULT CHARACTER SET utf8;
@@ -327,7 +327,7 @@ int main(int argc, char** argv)
connection c = database::connect("localhost", 3306, "testuser", "password", "", client_flags::empty());

/* create a hibernation context */
auto context = make_context_ptr<driver::mariadb>(test_schema, c);
auto context = make_context_ptr<mariadb_driver>(test_schema, c);

/* initialize the database schema */
context.init();
@@ -405,4 +405,4 @@ int main(int argc, char** argv)

## License

This project is licensed under the MIT License - see the [LICENSE.txt](LICENSE.txt) file for details
This project is licensed under the MIT License - see the [LICENSE.txt](LICENSE.txt) file for details

+ 0
- 46
cmake/Findcppmariadb.cmake Целия файл

@@ -1,46 +0,0 @@
Include ( ExternalProject )
Include ( FindPackageHandleStandardArgs )

Set ( CPPMARIADB_PATH ${CMAKE_BINARY_DIR}/extern/cppmariadb )

If ( NOT TARGET cppmariadb_extern )
ExternalProject_Add ( cppmariadb_extern
PREFIX ${CPPMARIADB_PATH}
TMP_DIR ${CPPMARIADB_PATH}/tmp
STAMP_DIR ${CPPMARIADB_PATH}/stamp
SOURCE_DIR ${CPPMARIADB_PATH}/src
BINARY_DIR ${CPPMARIADB_PATH}/build
INSTALL_DIR ${CPPMARIADB_PATH}/install
GIT_REPOSITORY "https://git.bergmann89.de/cpp/cppmariadb.git"
GIT_TAG "master"
TEST_COMMAND make test
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}
-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DCMAKE_MODULE_PATH=${CMAKE_MODULE_PATH})
EndIf ( )

Set ( CPPMARIADB_LIBRARY ${CPPMARIADB_PATH}/install/lib/libcppmariadb.so )
Set ( CPPMARIADB_INCLUDE_DIR ${CPPMARIADB_PATH}/install/include )
Set ( CPPMARIADB_LIBRARIES ${CPPMARIADB_LIBRARY} )
Set ( CPPMARIADB_INCLUDE_DIRS ${CPPMARIADB_INCLUDE_DIR} )

File ( MAKE_DIRECTORY ${CPPMARIADB_INCLUDE_DIR} )

Find_Package_Handle_Standard_Args ( cppmariadb DEFAULT_MSG
CPPMARIADB_LIBRARY
CPPMARIADB_INCLUDE_DIR )

If ( NOT TARGET cppmariadb )
Add_Library ( cppmariadb SHARED IMPORTED )
Add_Dependencies ( cppmariadb cppmariadb_extern )
Set_Property ( TARGET cppmariadb
PROPERTY IMPORTED_LOCATION ${CPPMARIADB_LIBRARY} )
Set_Property ( TARGET cppmariadb
PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CPPMARIADB_INCLUDE_DIRS} )
Install ( FILES ${CPPMARIADB_LIBRARY} DESTINATION lib )
If ( CPPHIBERNATE_INSTALL_DEV_FILES )
Install ( DIRECTORY ${CPPMARIADB_INCLUDE_DIR}/ DESTINATION include )
EndIf ( )
EndIf ( )

+ 0
- 46
cmake/Findcpputils.cmake Целия файл

@@ -1,46 +0,0 @@
Include ( ExternalProject )
Include ( FindPackageHandleStandardArgs )

Set ( CPPUTILS_PATH ${CMAKE_BINARY_DIR}/extern/cpputils )

If ( NOT TARGET cpputils_extern )
ExternalProject_Add ( cpputils_extern
PREFIX ${CPPUTILS_PATH}
TMP_DIR ${CPPUTILS_PATH}/tmp
STAMP_DIR ${CPPUTILS_PATH}/stamp
SOURCE_DIR ${CPPUTILS_PATH}/src
BINARY_DIR ${CPPUTILS_PATH}/build
INSTALL_DIR ${CPPUTILS_PATH}/install
GIT_REPOSITORY "https://git.bergmann89.de/cpp/cpputils.git"
GIT_TAG "master"
TEST_COMMAND make test
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}
-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DCMAKE_MODULE_PATH=${CMAKE_MODULE_PATH})
EndIf ( )

Set ( CPPUTILS_LIBRARY ${CPPUTILS_PATH}/install/lib/libcpputils.so )
Set ( CPPUTILS_INCLUDE_DIR ${CPPUTILS_PATH}/install/include )
Set ( CPPUTILS_LIBRARIES ${CPPUTILS_LIBRARY} )
Set ( CPPUTILS_INCLUDE_DIRS ${CPPUTILS_INCLUDE_DIR} )

File ( MAKE_DIRECTORY ${CPPUTILS_INCLUDE_DIR} )

Find_Package_Handle_Standard_Args ( cpputils DEFAULT_MSG
CPPUTILS_LIBRARY
CPPUTILS_INCLUDE_DIR )

If ( NOT TARGET cpputils )
Add_Library ( cpputils SHARED IMPORTED )
Add_Dependencies ( cpputils cpputils_extern )
Set_Property ( TARGET cpputils
PROPERTY IMPORTED_LOCATION ${CPPUTILS_LIBRARY} )
Set_Property ( TARGET cpputils
PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${CPPUTILS_INCLUDE_DIRS} )
Install ( FILES ${CPPUTILS_LIBRARY} DESTINATION lib )
If ( CPPHIBERNATE_INSTALL_DEV_FILES )
Install ( DIRECTORY ${CPPUTILS_INCLUDE_DIR}/ DESTINATION include )
EndIf ( )
EndIf ( )

+ 0
- 34
cmake/Findmariadb.cmake Целия файл

@@ -1,34 +0,0 @@
Find_Library ( MARIADB_LIBRARY
NAMES mariadb mysql
PATH_SUFFIXES mariadb )

Find_File ( MARIADB_INCLUDE_DIR
NAMES mysql.h
PATH_SUFFIXES mariadb )

Get_Filename_Component ( MARIADB_INCLUDE_DIR
${MARIADB_INCLUDE_DIR}
DIRECTORY )

Include ( FindPackageHandleStandardArgs )

Find_Package_Handle_Standard_Args ( mariadb DEFAULT_MSG
MARIADB_LIBRARY
MARIADB_INCLUDE_DIR )

Mark_As_Advanced ( MARIADB_LIBRARY
MARIADB_LIBRARIES )

If ( MARIADB_FOUND )
Set ( MARIADB_LIBRARIES ${MARIADB_LIBRARY} )
Set ( MARIADB_INCLUDE_DIRS ${MARIADB_INCLUDE_DIR} )

If ( NOT TARGET mariadb )
Add_Library ( mariadb UNKNOWN IMPORTED )
Set_Property ( TARGET mariadb
PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${MARIADB_INCLUDE_DIRS}" )
Set_Property ( TARGET mariadb
APPEND
PROPERTY IMPORTED_LOCATION "${MARIADB_LIBRARY}")
EndIf ( )
EndIf ( )

+ 34
- 0
cmake/config.h.in Целия файл

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

#include <cppmp.h>
#include <boost/hana.hpp>

namespace cpphibernate
{

namespace mp = ::cppmp;
namespace hana = ::boost::hana;

}

#cmakedefine CPPHIBERNATE_DEBUG
#cmakedefine CPPHIBERNATE_HAS_CPPLOGGING
#cmakedefine CPPHIBERNATE_HAS_CPPMARIADB

#ifdef CPPHIBERNATE_HAS_CPPLOGGING
#include <cpplogging/interface.h>
#define cpphibernate_log(p_level) \
cpplogging_global_log(p_level)
#else
#include <iostream>
#define cpphibernate_log(p_level) \
::std::cout << #p_level << ' ' << __FILE__ << ':' << __LINE__ << " - "
#endif

#ifdef CPPHIBERNATE_DEBUG
#define cpphibernate_log_debug(...) \
cpphibernate_log(debug) << __VA_ARGS__
#else
#define cpphibernate_log_debug(...) \
do { } while (0)
#endif

+ 10
- 0
cmake/cpphibernate-config.cmake Целия файл

@@ -0,0 +1,10 @@
# cpphibernate-config.cmake - package configuration file

Message ( WARNING "Please configure the dependencies of this package!" )
# Include ( CMakeFindDependencyMacro )
# Find_Dependency ( <dependency> )

Include ( FindPackageHandleStandardArgs )
Set ( ${CMAKE_FIND_PACKAGE_NAME}_CONFIG ${CMAKE_CURRENT_LIST_FILE} )
Find_Package_Handle_Standard_Args ( cpphibernate CONFIG_MODE )
Include ( "${CMAKE_CURRENT_LIST_DIR}/cpphibernate.cmake")

+ 21
- 0
cmake/cpphibernate-options.cmake Целия файл

@@ -0,0 +1,21 @@
Option ( CPPHIBERNATE_USE_CPPLOGGING
"Try to find the cpplogging library and use it as logger instead of logging to std::cout."
OFF )
Option ( CPPHIBERNATE_INSTALL_HEADER
"Install headers of cpphibernate."
ON )
Option ( CPPHIBERNATE_INSTALL_STATIC
"Install static library of cpphibernate."
ON )
Option ( CPPHIBERNATE_INSTALL_SHARED
"Install shared library of cpphibernate."
ON )
Option ( CPPHIBERNATE_INSTALL_DEBUG
"Install the stripped debug informations of cpphibernate."
OFF )
Option ( CPPHIBERNATE_NO_STRIP
"Do not strip debug symbols from binary."
OFF )
Option ( CPPHIBERNATE_DEBUG
"Write extra debug output to the console/logger."
OFF )

+ 31
- 0
cmake/cpphibernate-var.cmake Целия файл

@@ -0,0 +1,31 @@
# Version
Set ( CPPHIBERNATE_VERSION_MAJOR 1 )
Set ( CPPHIBERNATE_VERSION_MINOR 0 )
Set ( CPPHIBERNATE_VERSION_PATCH 0 )
Set ( CPPHIBERNATE_VERSION_BUILD 0 )
Set ( CPPHIBERNATE_VERSION_SHORT "${CPPHIBERNATE_VERSION_MAJOR}.${CPPHIBERNATE_VERSION_MINOR}" )
Set ( CPPHIBERNATE_VERSION "${CPPHIBERNATE_VERSION_SHORT}.${CPPHIBERNATE_VERSION_PATCH}.${CPPHIBERNATE_VERSION_BUILD}" )
Set ( CPPHIBERNATE_NAME "cpphibernate-${CPPHIBERNATE_VERSION_SHORT}" )
Set ( CPPHIBERNATE_OUTPUTNAME "cpphibernate" )

# Install directories
Set ( CPPHIBERNATE_INSTALL_DIR_INCLUDE "include/${CPPHIBERNATE_NAME}" )
Set ( CPPHIBERNATE_INSTALL_DIR_LIB "lib" )
Set ( CPPHIBERNATE_INSTALL_DIR_SHARE "share/${CPPHIBERNATE_NAME}" )

# C Standard
Set ( CMAKE_C_STANDARD 11 )
Set ( CMAKE_CXX_STANDARD 17 )
Set ( CMAKE_C_STANDARD_REQUIRED ON )
Set ( CMAKE_CXX_STANDARD_REQUIRED ON )

# Git Version
Include ( git_helper OPTIONAL RESULT_VARIABLE HAS_GIT_HELPER )
If ( HAS_GIT_HELPER )
GitGetVersion ( ${CMAKE_CURRENT_LIST_DIR}/..
CPPHIBERNATE_VERSION_MAJOR
CPPHIBERNATE_VERSION_MINOR
CPPHIBERNATE_VERSION_PATCH
CPPHIBERNATE_VERSION_BUILD
CPPHIBERNATE_VERSION_HASH )
EndIf ( )

+ 1
- 1
cmake/modules

@@ -1 +1 @@
Subproject commit b125a1a176ae0aada1cd2ec90919061d202dcea9
Subproject commit 1a32531aef2deeebd5637b1873bc4e976628801c

+ 0
- 9
cmake/options.cmake Целия файл

@@ -1,9 +0,0 @@
Option ( CPPHIBERNATE_BUILD_SHARED
"Build cpphibernate shared library"
ON )
Option ( CPPHIBERNATE_INSTALL_DEV_FILES
"Install development files of cpphibernate"
ON )
Option ( CPPHIBERNATE_DEBUG
"Enable debug output"
OFF )

+ 0
- 1
cmake/options.h.in Целия файл

@@ -1 +0,0 @@
#cmakedefine CPPHIBERNATE_DEBUG

+ 7
- 6
include/cpphibernate.h Целия файл

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

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

#include "cpphibernate/types.inl"

+ 0
- 73
include/cpphibernate/config.h Целия файл

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

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

#ifdef CPPHIBERNATE_DEBUG
# include <cpputils/logging/global.h>
# define cpphibernate_debug_log(...) log_global_message(debug) << __VA_ARGS__
#else
# define cpphibernate_debug_log(...) do { } while(0)
#endif

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

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

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

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

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

#define cpphibernate_define_namespace_end(parent) \
} \
parent

#define beg_namespace_cpphibernate namespace cpphibernate
#define end_namespace_cpphibernate

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

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

#define beg_namespace_cpphibernate_modifier cpphibernate_define_namespace_beg(beg_namespace_cpphibernate, modifier)
#define end_namespace_cpphibernate_modifier cpphibernate_define_namespace_end(end_namespace_cpphibernate)

#define beg_namespace_cpphibernate_driver cpphibernate_define_namespace_beg(beg_namespace_cpphibernate, driver)
#define end_namespace_cpphibernate_driver cpphibernate_define_namespace_end(end_namespace_cpphibernate)

#define beg_namespace_cpphibernate_driver_mariadb cpphibernate_define_namespace_beg(beg_namespace_cpphibernate_driver, mariadb_impl)
#define end_namespace_cpphibernate_driver_mariadb cpphibernate_define_namespace_end(end_namespace_cpphibernate_driver)

beg_namespace_cpphibernate
{

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

}
end_namespace_cpphibernate

+ 2
- 120
include/cpphibernate/context.h Целия файл

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

#include <memory>
#include "context/context.h"

#include <cpphibernate/misc.h>
#include <cpphibernate/config.h>
#include <cpphibernate/schema/table.h>
#include <cpphibernate/schema/tables.h>
#include <cpphibernate/modifier/where.h>
#include <cpphibernate/modifier/modifiers.h>

beg_namespace_cpphibernate
{

namespace __impl
{

template<typename T_driver, typename T_schema>
struct context_t
: public T_driver
{
public:
using base_type = T_driver;
using driver_type = T_driver;
using schema_type = T_schema;

private:
const schema_type& _schema;

public:
template<typename... T_args>
constexpr context_t(const schema_type& p_schema, T_args&&... args)
: base_type (p_schema, std::forward<T_args>(args)...)
, _schema (p_schema)
{ }

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

/* init */

inline void init(bool recreate)
{ this->init_impl(recreate); }

/* create */

template<typename T_dataset>
constexpr void create(T_dataset& dataset)
{ this->create_impl(dataset); }

/* read */

template<typename T_dataset, typename... T_modifiers>
constexpr auto read(T_dataset& dataset, T_modifiers&&... modifiers)
-> mp::enable_if<
modifier::all_are_modifiers<mp::decay_t<T_modifiers>...>>
{
using namespace modifier;
using real_dataset_type = misc::real_dataset_t<mp::decay_t<T_dataset>>;
schema::tables::find(_schema.tables, hana::type_c<real_dataset_type>);
this->read_impl(dataset, modifier::make_list(std::forward<T_modifiers>(modifiers)...));
}

template<typename T_dataset>
constexpr auto read(T_dataset& dataset)
-> mp::enable_if_c<
!misc::is_container<mp::decay_t<T_dataset>>::value
&& !misc::is_nullable<mp::decay_t<T_dataset>>::value>
{
using namespace modifier;
using real_dataset_type = misc::real_dataset_t<mp::decay_t<T_dataset>>;
auto& table = schema::tables::find(_schema.tables, hana::type_c<real_dataset_type>);
auto& primary_key = schema::table::get_primary_key_field(table);
this->read_impl(dataset, modifier::make_list(where(equal(primary_key, primary_key.getter(dataset)))));
}

template<typename T_dataset>
constexpr auto read(T_dataset& dataset)
-> mp::enable_if_c<
misc::is_container<mp::decay_t<T_dataset>>::value
|| misc::is_nullable<mp::decay_t<T_dataset>>::value>
{
using namespace modifier;
using real_dataset_type = misc::real_dataset_t<mp::decay_t<T_dataset>>;
schema::tables::find(_schema.tables, hana::type_c<real_dataset_type>);
this->read_impl(dataset, modifier::make_list());
}

/* update */

template<typename T_dataset>
constexpr void update(T_dataset& dataset)
{ this->update_impl(dataset); }

/* destroy */

template<typename T_dataset>
constexpr void destroy(T_dataset& dataset)
{ this->destroy_impl(dataset); }
};

}

/* make */

template<typename T_driver, typename T_schema, typename... T_args>
constexpr decltype(auto) make_context(T_schema&& schema, T_args&&... args)
{
using context_type = __impl::context_t<T_driver, T_schema>;
return context_type(std::forward<T_schema>(schema), std::forward<T_args>(args)...);
}

template<typename T_driver, typename T_schema, typename... T_args>
constexpr decltype(auto) make_context_ptr(T_schema&& schema, T_args&&... args)
{
using context_type = __impl::context_t<T_driver, T_schema>;
using pointer_type = std::unique_ptr<context_type>;
return pointer_type(new context_type(std::forward<T_schema>(schema), std::forward<T_args>(args)...));
}


}
end_namespace_cpphibernate
#include "context/context.inl"

+ 104
- 0
include/cpphibernate/context/context.h Целия файл

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

#include <cpphibernate/config.h>

namespace cpphibernate
{

/**
* @brief Context class for cpphibernate.
*/
template<typename T_driver, typename T_schema>
struct context
: public T_driver
{
public:
using base_type = T_driver;
using driver_type = T_driver;
using schema_type = T_schema;

private:
const schema_type& _schema;

public:
/**
* @brief Value constructor. Create a new context object.
*
* @param p_schema Database schema to use.
* @param p_args Arguments to pass to underlying driver.
*/
template<typename... T_args>
constexpr context(const schema_type& p_schema, T_args&&... p_args);

/**
* @brief Nove constructor.
*/
constexpr context(context&&) = default;

/**
* @brief Copy constrcutor.
*/
constexpr context(const context&) = default;

/**
* @brief Initialize the database. This will create all non exsitsing tables.
*/
template<typename... T_args>
constexpr decltype(auto) init(T_args&&... args);

/**
* @brief Create the passed object in the database.
*/
template<typename... T_args>
constexpr decltype(auto) create(T_args&&... args);

/**
* @brief Read an object from the database.
*/
template<typename... T_args>
constexpr decltype(auto) read(T_args&&... args);

/**
* @brief Update the passed object in the database.
*/
template<typename... T_args>
constexpr decltype(auto) update(T_args&&... args);

/**
* @brief Destroy the passed object in the database.
*/
template<typename... T_args>
constexpr decltype(auto) destroy(T_args&&... args);
};

/**
* @brief Create a new cpphibernate context.
*
* @tparam T_driver Hibernate driver to use.
* @tparam T_schema Database schema to use.
* @tparam T_args Arguments to pass to underlying driver implementation.
*
* @param schema Database schema to use.
* @param args Arguments to pass to underlying driver implementation.
*
* @return Created hibernate context.
*/
template<typename T_driver, typename T_schema, typename... T_args>
constexpr decltype(auto) make_context(T_schema&& schema, T_args&&... args);

/**
* @brief Create a new cpphibernate context as a unique pointer.
*
* @tparam T_driver Hibernate driver to use.
* @tparam T_schema Database schema to use.
* @tparam T_args Arguments to pass to underlying driver implementation.
*
* @param schema Database schema to use.
* @param args Arguments to pass to underlying driver implementation.
*
* @return Unique pointer of the created hibernate context.
*/
template<typename T_driver, typename T_schema, typename... T_args>
constexpr decltype(auto) make_context_ptr(T_schema&& schema, T_args&&... args);

}

+ 235
- 0
include/cpphibernate/context/context.inl Целия файл

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

#include <cpphibernate/modifier.h>

#include "context.h"

namespace cpphibernate
{

namespace __impl
{

/* init_builder */

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

constexpr decltype(auto) init = mp::generic_predicate<init_builder> { };

template<typename T_impl, typename T_bool>
struct init_builder<
mp::list<T_impl, 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); }
};

/* create_builder */

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

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

template<typename T_impl, typename T_dataset>
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); }
};

/* read_builder */

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

constexpr decltype(auto) read = mp::generic_predicate<read_builder> { };

template<typename T_schema, typename T_impl, typename T_dataset, typename T_modifiers>
struct read_builder<
mp::list<T_schema, T_impl, T_dataset, T_modifiers>,
mp::enable_if_t<
schema::is_schema_v<mp::decay_t<T_schema>>
&& is_modifiers_v<mp::decay_t<T_modifiers>>
&& mp::is_valid_v<decltype(std::declval<T_impl>().read(
std::declval<T_dataset&>(),
std::declval<T_modifiers>()))>
>>
{
static constexpr decltype(auto) apply(const T_schema& schema, T_impl& impl, T_dataset& dataset, T_modifiers&& modifiers)
{ return impl.read(dataset, std::forward<T_modifiers>(modifiers)); }
};

template<typename T_schema, typename T_impl, typename T_dataset>
struct read_builder<
mp::list<T_schema, T_impl, T_dataset>,
mp::enable_if_t<
schema::is_schema_v<mp::decay_t<T_schema>>
&& !is_container_v<mp::decay_t<T_dataset>>
&& !is_nullable_v<mp::decay_t<T_dataset>>
>>
{
static constexpr decltype(auto) apply(const T_schema& schema, T_impl& impl, T_dataset& dataset)
{
using real_dataset_type = real_dataset_t<mp::decay_t<T_dataset>>;

auto& table = schema::find_table(schema.tables, hana::type_c<real_dataset_type>);
auto& primary_key = schema::get_primary_key_field(table);

return impl.read(dataset, make_modifiers(where(equal(primary_key, primary_key.getter(dataset)))));
}
};

template<typename T_schema, typename T_impl, typename T_dataset, typename... T_modifier>
struct read_builder<
mp::list<T_schema, T_impl, T_dataset, T_modifier...>,
mp::enable_if_t<
schema::is_schema_v<mp::decay_t<T_schema>>
&& mp::is_true_v<is_modifier_v<T_modifier>...>
&& ( is_container_v<mp::decay_t<T_dataset>>
|| is_nullable_v<mp::decay_t<T_dataset>>)
>>
{
static constexpr decltype(auto) apply(const T_schema& schema, T_impl& impl, T_dataset& dataset, T_modifier&&... modifier)
{ return impl.read(dataset, make_modifiers(std::forward<T_modifier>(modifier)...)); }
};

template<typename T_schema, typename T_impl, typename T_dataset, typename... T_modifier>
struct read_builder<
mp::list<T_schema, T_impl, T_dataset, T_modifier...>,
mp::enable_if_t<
schema::is_schema_v<mp::decay_t<T_schema>>
&& mp::is_true_v<is_modifier_v<T_modifier>...>
&& !is_container_v<mp::decay_t<T_dataset>>
&& !is_nullable_v<mp::decay_t<T_dataset>>
&& sizeof...(T_modifier)
>>
{
static constexpr decltype(auto) apply(const T_schema& schema, T_impl& impl, T_dataset& dataset, T_modifier&&... modifier)
{ return impl.read(dataset, make_modifiers(std::forward<T_modifier>(modifier)...)); }
};

/* update_builder */

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

constexpr decltype(auto) update = mp::generic_predicate<update_builder> { };

template<typename T_impl, typename T_dataset>
struct update_builder<
mp::list<T_impl, T_dataset>,
mp::enable_if_t<
mp::is_valid_v<decltype(std::declval<T_impl>().update(std::declval<T_dataset&>()))>>>
{
static constexpr decltype(auto) apply(T_impl& impl, T_dataset& dataset)
{ return impl.update(dataset); }
};

/* destroy_builder */

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

constexpr decltype(auto) destroy = mp::generic_predicate<destroy_builder> { };

template<typename T_impl, typename T_dataset>
struct destroy_builder<
mp::list<T_impl, T_dataset>,
mp::enable_if_t<
mp::is_valid_v<decltype(std::declval<T_impl>().destroy(std::declval<T_dataset&>()))>>>
{
static constexpr decltype(auto) apply(T_impl& impl, T_dataset& dataset)
{ return impl.destroy(dataset); }
};

}

/* context */

template<typename T_driver, typename T_schema>
template<typename... T_args>
constexpr context<T_driver, T_schema>::context(const schema_type& p_schema, T_args&&... p_args)
: base_type (p_schema, std::forward<T_args>(p_args)...)
, _schema (p_schema)
{ }

template<typename T_driver, typename T_schema>
template<typename... T_args>
constexpr decltype(auto) context<T_driver, T_schema>::init(T_args&&... args)
{ return __impl::init(this->impl(), std::forward<T_args>(args)...); }

template<typename T_driver, typename T_schema>
template<typename... T_args>
constexpr decltype(auto) context<T_driver, T_schema>::create(T_args&&... args)
{ return __impl::create(this->impl(), std::forward<T_args>(args)...); }

template<typename T_driver, typename T_schema>
template<typename... T_args>
constexpr decltype(auto) context<T_driver, T_schema>::read(T_args&&... args)
{ return __impl::read(_schema, this->impl(), std::forward<T_args>(args)...); }

template<typename T_driver, typename T_schema>
template<typename... T_args>
constexpr decltype(auto) context<T_driver, T_schema>::update(T_args&&... args)
{ return __impl::update(this->impl(), std::forward<T_args>(args)...); }

template<typename T_driver, typename T_schema>
template<typename... T_args>
constexpr decltype(auto) context<T_driver, T_schema>::destroy(T_args&&... args)
{ return __impl::destroy(this->impl(), std::forward<T_args>(args)...); }

/* make_context */

template<typename T_driver, typename T_schema, typename... T_args>
constexpr decltype(auto) make_context(T_schema&& schema, T_args&&... args)
{
using context_type = context<T_driver, T_schema>;
return context_type(std::forward<T_schema>(schema), std::forward<T_args>(args)...);
}

/* make_context_ptr */

template<typename T_driver, typename T_schema, typename... T_args>
constexpr decltype(auto) make_context_ptr(T_schema&& schema, T_args&&... args)
{
using context_type = context<T_driver, T_schema>;
using pointer_type = std::unique_ptr<context_type>;
return pointer_type(new context_type(std::forward<T_schema>(schema), std::forward<T_args>(args)...));
}

}

+ 14
- 7
include/cpphibernate/driver/mariadb.h Целия файл

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

#include <cpphibernate/config.h>
#include <cpphibernate/driver/mariadb/mariadb.h>

beg_namespace_cpphibernate_driver
{
using mariadb = mariadb_impl::mariadb_driver_t;
#ifdef CPPHIBERNATE_HAS_CPPMARIADB
#include "mariadb/classes.h"
#include "mariadb/context.h"
#include "mariadb/driver.h"
#include "mariadb/driver.inl"
#include "mariadb/helper.h"
#include "mariadb/impl.h"

}
end_namespace_cpphibernate_driver
namespace cpphibernate
{
using mariadb_driver = ::cpphibernate::mariadb::driver_t;
}
#else
#error "cppmariadb library was not found!"
#endif

+ 6
- 0
include/cpphibernate/driver/mariadb/classes.h Целия файл

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

#include "classes/attributes.h"
#include "classes/fields.h"
#include "classes/tables.h"
#include "classes/schema.h"

+ 5
- 0
include/cpphibernate/driver/mariadb/classes/attributes.h Целия файл

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

#include "attributes/attributes.h"

#include "attributes/attributes.inl"

+ 46
- 0
include/cpphibernate/driver/mariadb/classes/attributes/attributes.h Целия файл

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

#include <set>

#include <cpphibernate/config.h>

namespace cpphibernate {
namespace mariadb {

namespace __impl
{

/**
* @brief Helper class to create attributes type.
*/
template<typename X, typename = void>
struct attributes_builder;

}

/**
* @brief Attributes enumeration
*/
enum class attribute_t
{
hex, //!< The field is stored hex encoded.
compress, //!< The field is stored compressed.
primary_key, //!< The field is the primary key.
};

/**
* @brief Set of attributes.
*/
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.
*/
constexpr decltype(auto) make_attributes = mp::generic_predicate<__impl::attributes_builder> { };

} }

include/cpphibernate/driver/mariadb/schema/attributes.inl → include/cpphibernate/driver/mariadb/classes/attributes/attributes.inl Целия файл

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

#include <cpphibernate/driver/mariadb/schema/attributes.h>
#include "attributes.h"

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

namespace cpphibernate {
namespace mariadb {

namespace __impl
{
@@ -25,10 +28,10 @@ beg_namespace_cpphibernate_driver_mariadb
struct attribute_converter<schema::attribute::primary_key_type>
{ static constexpr decltype(auto) value = attribute_t::primary_key; };

/* make_attributes_impl */
/* attributes_builder */

template<typename T, typename>
struct make_attributes_impl
struct attributes_builder
{
template<typename... T_args>
static constexpr decltype(auto) apply(T_args&&... args)
@@ -36,10 +39,9 @@ beg_namespace_cpphibernate_driver_mariadb
};

template<typename T_attributes>
struct make_attributes_impl<
struct attributes_builder<
mp::list<T_attributes>,
mp::enable_if_c<
schema::is_attributes<mp::decay_t<T_attributes>>::value>>
mp::enable_if_t<schema::is_attributes_v<mp::decay_t<T_attributes>>>>
{
template<size_t... I>
static constexpr decltype(auto) helper(T_attributes&&, const std::index_sequence<I...>&)
@@ -58,5 +60,4 @@ beg_namespace_cpphibernate_driver_mariadb

}

}
end_namespace_cpphibernate_driver_mariadb
} }

+ 17
- 0
include/cpphibernate/driver/mariadb/classes/fields.h Целия файл

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

#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"

+ 214
- 0
include/cpphibernate/driver/mariadb/classes/fields/field.h Целия файл

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

#include <cppmariadb.h>

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

namespace cpphibernate {
namespace mariadb {

struct table_t;
struct data_context;
struct create_update_context;
struct read_context;

using read_context_ptr_u = std::unique_ptr<read_context>;

/**
* @brief Abstract field class.
*/
struct field_t
{
public:
size_t id { 0 }; //!< unique id of the field
size_t value_id { 0 }; //!< unique id of the value type
size_t real_value_id { 0 }; //!< unique id of the real/unwrapped value type

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

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

std::string name; //!< name of the SQL field
std::string type; //!< SQL type name
std::string create_arguments; //!< additional arguments for CREATE TABLE command

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

attributes_t attributes; //!< attributes for the field

public:
/**
* @brief Value constructor. Creates a mariadb field from the cpphibernate field.
*
* @param[in] p_owner Owner of the field.
* @param[in] p_schema Cpphibernate schema the mariadb field belongs to.
* @param[in] p_table Cpphibernate table the mariadb field belongs to.
* @param[in] p_field Cpphibernate field to create mariadb field for.
*/
template<
typename T_schema,
typename T_table,
typename T_field>
inline field_t(
const table_t& p_owner,
const T_schema& p_schema,
const T_table& p_table,
const T_field& p_field);

/**
* @brief Move constructor.
*/
inline field_t(field_t&& other) = delete;

/**
* @brief Copy constructor.
*/
inline field_t(const field_t&) = delete;

/**
* @brief Destructor.
*/
virtual ~field_t() = 0;

/**
* @brief Print the field values to the passed stream.
*/
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;

/**
* @brief Create a read context for the foreign key field.
*
* @param[in] context Read context to inherit new context from.
* @param[in] create_fake Create a fake context (not data will be written).
*
* @return The created read context.
*/
virtual read_context_ptr_u foreign_read(const read_context& context, bool create_fake) const;

/**
* @brief Delete all old datasets from the foreign table.
*
* If we update an exsisting foreign field with a new foreign dataset, the key of this dataset
* changes. So we need to delete the old/exsisting foreign dataset from the database.
*
* @param[in] context Create/Update context with the needed data for the operation.
* @param[in] primary_key Primary key of the current database.
* @param[in] foreign_key Primary kes of the new foreign dataset.
*/
void foreign_one_delete(
const create_update_context& context,
const std::string& primary_key,
const value_t& foreign_key) const;

/**
* @brief Update the foreign dataset. Set the foreign key field to NULL if it matches the passed
* primary key of the owner dataset.
*/
void foreign_many_update(
const create_update_context& context,
const std::string& primary_key) const;

private:
/**
* @brief Initialize the field.
*/
void init();

private:
using statement_ptr_u = std::unique_ptr<::cppmariadb::statement>;

mutable statement_ptr_u _statement_foreign_one_delete_key_known; //!< Statement to delete foreign datasets within an update operation (for known foreign keys)
mutable statement_ptr_u _statement_foreign_one_delete_key_unknown; //!< Statement to delete foreign datasets within an update operation (for unknown foreign keys)
mutable statement_ptr_u _statement_foreign_many_update; //!< Statement to update foreign many dataset (set foreign key to NULL if primary key of the owner matches)

/**
* @brief Get the statement to delete foreign datasets within an update operation (for known foreign keys).
*/
::cppmariadb::statement& get_statement_foreign_one_delete_key_known() const;

/**
* @brief Get the statement to delete foreign datasets within an update operation (for unknown foreign keys).
*/
::cppmariadb::statement& get_statement_foreign_one_delete_key_unknown() const;

/**
* @brief Get the statement to update foreign many dataset (set foreign key to NULL if primary key of the owner matches).
*/
::cppmariadb::statement& get_statement_foreign_many_update() const;
};

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

namespace __impl
{

/**
* @brief Helper type to build table.
*/
template<typename X, typename = void>
struct field_builder;

}

/**
* @brief Predicate to create mariadb table class.
*/
constexpr decltype(auto) make_field = mp::generic_predicate<__impl::field_builder> { };

} }

+ 122
- 0
include/cpphibernate/driver/mariadb/classes/fields/field.inl Целия файл

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

#include "field.h"

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

namespace cpphibernate {
namespace mariadb {

template<
typename T_schema,
typename T_table,
typename T_field>
field_t::field_t(
const table_t& p_owner,
const T_schema& p_schema,
const T_table& p_table,
const T_field& p_field)
: id (get_type_id(hana::type_c<mp::decay_t<T_field>>))
, value_id (get_type_id(hana::type_c<typename T_field::value_type>))
, real_value_id (get_type_id(hana::type_c<real_dataset_t<typename T_field::value_type>>))
, value_is_nullable (is_nullable_v <typename T_field::value_type>)
, value_is_pointer (is_pointer_v <typename T_field::value_type>)
, value_is_container (is_container_v<typename T_field::value_type>)
, value_is_ordered (is_ordered_v <typename T_field::value_type>)
, value_is_auto_incremented (false)
, table (p_owner)
, referenced_table (nullptr)
, name (p_field.name)
, type ()
, create_arguments ()
, convert_to_open ()
, convert_to_close ()
, convert_from_open ()
, convert_from_close ()
, attributes (make_attributes(p_field.attributes))
{ }

namespace __impl
{

/* field_builder */

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

template<typename T_owner, typename T_schema, typename T_table, typename T_field>
struct field_builder<
mp::list<T_owner, T_schema, T_table, T_field>,
mp::enable_if_t<
mp::is_base_of_v<table_t, mp::decay_t<T_owner>>
&& schema::is_schema_v<mp::decay_t<T_schema>>
&& schema::is_table_v<mp::decay_t<T_table>>
&& schema::is_field_v<mp::decay_t<T_field>>>>
{

/* is_primary_key_field */

template<typename X_field>
struct is_primary_key_field
: public decltype(
hana::contains(
std::declval<mp::decay_t<X_field>>().attributes,
schema::attribute::primary_key))
{ };

/* is_foreign_table_field */

template<typename X_schema, typename X_field>
struct is_foreign_table_field
: public decltype(
hana::contains(
hana::transform(
std::declval<X_schema>().tables,
schema::get_wrapped_dataset),
std::declval<X_field>().wrapped_real_value_type))
{ };

/* field_type */

template<typename X_schema, typename X_field, typename = void>
struct field_type
{ using type = field_data_t<T_field>; };

template<typename X_schema, typename X_field>
struct field_type<
X_schema,
X_field,
mp::enable_if_t<is_primary_key_field<X_field>::value>>
{ using type = field_primary_key_t<X_field>; };

template<typename X_schema, typename X_field>
struct field_type<
X_schema,
X_field,
mp::enable_if_t<is_foreign_table_field<X_schema, X_field>::value>>
{ using type = field_foreign_table_t<X_field>; };

template<typename X_schema, typename X_field>
using field_type_t = typename field_type<X_schema, X_field>::type;

/* apply */

static constexpr decltype(auto) apply(const table_t& owner, const T_schema& schema, const T_table& table, const T_field& field)
{
using schema_type = mp::decay_t<T_schema>;
using field_type = mp::decay_t<T_field>;
using return_type = field_type_t<schema_type, field_type>;

return std::make_unique<return_type>(owner, schema, table, field);
}
};

}

} }

+ 37
- 0
include/cpphibernate/driver/mariadb/classes/fields/field_data.h Целия файл

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

#include "field_value.h"

namespace cpphibernate {
namespace mariadb {

/**
* @brief Field that represents a data field.
*/
template<typename T_field>
struct field_data_t
: public field_value_t<T_field>
{
private:
using base_type = field_value_t<T_field>;

public:
/**
* @brief Value constructor. Creates a mariadb field from the cpphibernate field.
*
* @param[in] p_owner Owner of the field.
* @param[in] p_schema Cpphibernate schema the mariadb field belongs to.
* @param[in] p_table Cpphibernate table the mariadb field belongs to.
* @param[in] p_field Cpphibernate field to create mariadb field for.
*/
template<
typename T_schema,
typename T_table>
inline field_data_t(
const table_t& p_owner,
const T_schema& p_schema,
const T_table& p_table,
const T_field& p_field);
};

} }

+ 27
- 0
include/cpphibernate/driver/mariadb/classes/fields/field_data.inl Целия файл

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

#include "field_data.h"

namespace cpphibernate {
namespace mariadb {

/* field_data_t */

template<
typename T_field>
template<
typename T_schema,
typename T_table>
field_data_t<T_field>::field_data_t(
const table_t& p_owner,
const T_schema& p_schema,
const T_table& p_table,
const T_field& p_field)
: field_value_t<T_field>::field_value_t(
p_owner,
p_schema,
p_table,
p_field)
{ }

} }

+ 57
- 0
include/cpphibernate/driver/mariadb/classes/fields/field_foreign_table.h Целия файл

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



namespace cpphibernate {
namespace mariadb {

/**
* @brief Field that represents a foreign table.
*/
template<typename T_field>
struct field_foreign_table_t
: public field_simple_t<T_field>
{
private:
using base_type = field_simple_t<T_field>;

public:
/**
* @brief Value constructor. Creates a mariadb field from the cpphibernate field.
*
* @param[in] p_owner Owner of the field.
* @param[in] p_schema Cpphibernate schema the mariadb field belongs to.
* @param[in] p_table Cpphibernate table the mariadb field belongs to.
* @param[in] p_field Cpphibernate field to create mariadb field for.
*/
template<
typename T_schema,
typename T_table>
inline field_foreign_table_t(
const table_t& p_owner,
const T_schema& p_schema,
const T_table& p_table,
const T_field& p_field);

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.
*/
inline value_t foreign_create_update(const create_update_context& context) const override;

/**
* @brief Create a read context for the foreign key field.
*
* @param[in] context Read context to inherit new context from.
* @param[in] create_fake Create a fake context (not data will be written).
*
* @return The created read context.
*/
inline read_context_ptr_u foreign_read(const read_context& context, bool create_fake) const override;
};

} }

+ 73
- 0
include/cpphibernate/driver/mariadb/classes/fields/field_foreign_table.inl Целия файл

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

#include "field_foreign_table.h"

#include "../../impl/create_update.inl"
#include "../../context/read_context.inl"
#include "../../context/create_update_context.inl"

namespace cpphibernate {
namespace mariadb {

/* field_foreign_table_t */

template<
typename T_field>
template<
typename T_schema,
typename T_table>
field_foreign_table_t<T_field>::field_foreign_table_t(
const table_t& p_owner,
const T_schema& p_schema,
const T_table& p_table,
const T_field& p_field)
: field_simple_t<T_field>::field_simple_t(
p_owner,
p_schema,
p_table,
p_field)
{ }

template<
typename T_field>
value_t field_foreign_table_t<T_field>
::foreign_create_update(const create_update_context& context) const
{
using dataset_type = typename decltype(+this->_field.wrapped_dataset_type)::type;

auto& dataset = context.get<dataset_type>();
auto& foreign = this->_field.getter(dataset);
auto next_context = change_context(context, foreign);

using foreign_dataset_type = mp::decay_t<decltype(foreign)>;
return create_update_impl_t<foreign_dataset_type>::apply(
next_context,
false);
}

template<
typename T_field>
read_context_ptr_u field_foreign_table_t<T_field>
::foreign_read(const read_context& context, bool create_fake) const
{
using dataset_type = typename decltype(+this->_field.wrapped_dataset_type)::type;
using value_type = typename decltype(+this->_field.wrapped_value_type)::type;

if (create_fake)
{
auto new_context = make_read_context(context.schema, context.connection, hana::type_c<value_type>, context.filter);
using context_type = mp::decay_t<decltype(new_context)>;
return std::make_unique<context_type>(std::move(new_context));
}
else
{
auto& dataset = context.get<dataset_type>();
auto& member = this->_field.getter(dataset);
auto new_context = make_read_context(context.schema, context.connection, member, context.filter);

using context_type = mp::decay_t<decltype(new_context)>;
return std::make_unique<context_type>(std::move(new_context));
}
}

} }

+ 61
- 0
include/cpphibernate/driver/mariadb/classes/fields/field_primary_key.h Целия файл

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

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

namespace cpphibernate {
namespace mariadb {

/**
* @brief Field that represents a primary key field.
*/
template<typename T_field>
struct field_primary_key_t
: public field_value_t<T_field>
{
private:
using base_type = field_value_t<T_field>;

public:
static constexpr decltype(auto) key_props =
key_properties<typename decltype(+base_type::value_type)::type> { };

public:
/**
* @brief Value constructor. Creates a mariadb field from the cpphibernate field.
*
* @param[in] p_owner Owner of the field.
* @param[in] p_schema Cpphibernate schema the mariadb field belongs to.
* @param[in] p_table Cpphibernate table the mariadb field belongs to.
* @param[in] p_field Cpphibernate field to create mariadb field for.
*/
template<
typename T_schema,
typename T_table>
inline field_primary_key_t(
const table_t& p_owner,
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;
};

} }

+ 61
- 0
include/cpphibernate/driver/mariadb/classes/fields/field_primary_key.inl Целия файл

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

#include "field_primary_key.h"

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

namespace cpphibernate {
namespace mariadb {

/* field_primary_key_t */

template<
typename T_field>
template<
typename T_schema,
typename T_table>
field_primary_key_t<T_field>::field_primary_key_t(
const table_t& p_owner,
const T_schema& p_schema,
const T_table& p_table,
const T_field& p_field)
: field_value_t<T_field>::field_value_t(
p_owner,
p_schema,
p_table,
p_field)
{
this->value_is_auto_incremented = key_props.is_auto_generated();
auto args = key_props.create_table_argument();
if (args)
this->create_arguments = args;
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>();
}

} }

+ 41
- 0
include/cpphibernate/driver/mariadb/classes/fields/field_simple.h Целия файл

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



namespace cpphibernate {
namespace mariadb {

/**
* @brief Field that completely implementes the abstract field_t
*/
template<typename T_field>
struct field_simple_t
: public field_t
{
private:
using base_type = field_t;
using field_type = T_field;

protected:
const field_type& _field;

public:
/**
* @brief Value constructor. Creates a mariadb field from the cpphibernate field.
*
* @param[in] p_owner Owner of the field.
* @param[in] p_schema Cpphibernate schema the mariadb field belongs to.
* @param[in] p_table Cpphibernate table the mariadb field belongs to.
* @param[in] p_field Cpphibernate field to create mariadb field for.
*/
template<
typename T_schema,
typename T_table>
inline field_simple_t(
const table_t& p_owner,
const T_schema& p_schema,
const T_table& p_table,
const T_field& p_field);
};

} }

+ 28
- 0
include/cpphibernate/driver/mariadb/classes/fields/field_simple.inl Целия файл

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

#include "field_simple.h"

namespace cpphibernate {
namespace mariadb {

/* field_simple_t */

template<
typename T_field>
template<
typename T_schema,
typename T_table>
field_simple_t<T_field>::field_simple_t(
const table_t& p_owner,
const T_schema& p_schema,
const T_table& p_table,
const T_field& p_field)
: field_t::field_t(
p_owner,
p_schema,
p_table,
p_field)
, _field(p_field)
{ }

} }

+ 63
- 0
include/cpphibernate/driver/mariadb/classes/fields/field_value.h Целия файл

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

#include "field_simple.h"
#include "../../helper/type_properties.h"

namespace cpphibernate {
namespace mariadb {

/**
* @brief Field that represents a simple value.
*/
template<typename T_field>
struct field_value_t
: public field_simple_t<T_field>
{
private:
using base_type = field_simple_t<T_field>;

public:
static constexpr decltype(auto) field_type =
hana::type_c<mp::decay_t<T_field>>;
static constexpr decltype(auto) value_type =
hana::type_c<typename decltype(+field_type)::type::value_type>;
static constexpr decltype(auto) value_props =
type_properties<typename decltype(+value_type)::type> { };

public:
/**
* @brief Value constructor. Creates a mariadb field from the cpphibernate field.
*
* @param[in] p_owner Owner of the field.
* @param[in] p_schema Cpphibernate schema the mariadb field belongs to.
* @param[in] p_table Cpphibernate table the mariadb field belongs to.
* @param[in] p_field Cpphibernate field to create mariadb field for.
*/
template<
typename T_schema,
typename T_table>
inline field_value_t(
const table_t& p_owner,
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;
};

} }

+ 55
- 0
include/cpphibernate/driver/mariadb/classes/fields/field_value.inl Целия файл

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

#include "field_value.h"

namespace cpphibernate {
namespace mariadb {

/* field_value_t */

template<
typename T_field>
template<
typename T_schema,
typename T_table>
field_value_t<T_field>::field_value_t(
const table_t& p_owner,
const T_schema& p_schema,
const T_table& p_table,
const T_field& p_field)
: field_simple_t<T_field>::field_simple_t(
p_owner,
p_schema,
p_table,
p_field)
{
this->type = value_props.type();
if (value_props.convert_to_open())
this->convert_to_open = this->convert_to_open + value_props.convert_to_open();
if (value_props.convert_to_close())
this->convert_to_close = value_props.convert_to_close() + this->convert_to_close;
if (value_props.convert_from_open())
this->convert_from_open = this->convert_from_open + value_props.convert_from_open();
if (value_props.convert_from_close())
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));
}

} }

+ 36
- 0
include/cpphibernate/driver/mariadb/classes/fields/fields.h Целия файл

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





namespace cpphibernate {
namespace mariadb {

/**
* @brief Vector of fields.
*/
struct fields_t
: public std::vector<field_ptr_u>
{
using base_type = std::vector<field_ptr_u>;
using base_type::base_type;
};

namespace __impl
{

/**
* @brief Helper class to create table vector.
*/
template<typename X, typename = void>
struct fields_builder;

}

/**
* @brief Predicate to create table vector.
*/
constexpr decltype(auto) make_fields = mp::generic_predicate<__impl::fields_builder> { };

} }

+ 63
- 0
include/cpphibernate/driver/mariadb/classes/fields/fields.inl Целия файл

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

#include "field.h"

namespace cpphibernate {
namespace mariadb {

namespace __impl
{

/* fields_builder */

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

template<typename T_owner, typename T_schema, typename T_table>
struct fields_builder<
mp::list<T_owner, T_schema, T_table>,
mp::enable_if_t<
mp::is_same_v<table_t, mp::decay_t<T_owner>>
&& schema::is_schema_v<mp::decay_t<T_schema>>
&& schema::is_table_v<mp::decay_t<T_table>>>>
{
template<typename T_index>
static constexpr void emplace(
fields_t& result,
const table_t& owner,
const T_schema& schema,
const T_table& table,
T_index&& index)
{
result.emplace_back(make_field(owner, schema, table, table.fields[index]));
}

template<size_t... I>
static auto helper(
const table_t& owner,
const T_schema& schema,
const T_table& table,
std::index_sequence<I...>&&)
{
fields_t ret;
int dummy[] = { 0, (emplace(ret, owner, schema, table, hana::size_c<I>), void(), 0)... };
(void) dummy;
return ret;
}

static constexpr decltype(auto) apply(
const table_t& owner, const T_schema& schema, const T_table& table)
{
using size = decltype(hana::size(table.fields));
return helper(owner, schema, table, std::make_index_sequence<size::value> { });
}
};

}

} }

+ 5
- 0
include/cpphibernate/driver/mariadb/classes/schema.h Целия файл

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

#include "schema/schema.h"

#include "schema/schema.inl"

+ 97
- 0
include/cpphibernate/driver/mariadb/classes/schema/schema.h Целия файл

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

#include <map>

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

namespace cpphibernate {
namespace mariadb {

/**
* @brief Class to wrapp all values needed by the maraidb schema.
*/
struct schema_t
{
public:
using table_map = std::map<size_t, const table_t *>;
using field_map = std::map<size_t, const field_t *>;

private:
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.

public:
/**
* @brief Default constructor.
*/
inline schema_t() = default;

/**
* @brief Value constructor.
*
* @param[in] p_schema Cpphibernate schema to create mariadb schema from.
*/
template<typename T_schema>
inline schema_t(const T_schema& p_schema);

/**
* @brief Move constructor.
*/
inline schema_t(schema_t&&) = delete;

/**
* @brief Copy constructor.
*/
inline schema_t(const schema_t&) = delete;

/**
* @brief Print the schema to the passed stream.
*/
std::ostream& print(std::ostream& os) const;

/**
* @brief Initialize the whole schema using the passed context.
*/
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.
*/
void init();
};

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

namespace __impl
{

/**
* @brief Helper type to build schema.
*/
template<typename X, typename = void>
struct schema_builder;

}

/**
* @brief Predicate to create mariadb schema class.
*/
constexpr decltype(auto) make_schema = mp::generic_predicate<__impl::schema_builder> { };

} }

+ 44
- 0
include/cpphibernate/driver/mariadb/classes/schema/schema.inl Целия файл

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

#include "schema.h"

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

namespace cpphibernate {
namespace mariadb {

/* schema_t */

template<typename T_schema>
schema_t::schema_t(const T_schema& p_schema)
: name (p_schema.name)
, tables(make_tables(*this, p_schema))
{ init(); }

namespace __impl
{

/* schema_builder */

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

template<typename T_schema>
struct schema_builder<
mp::list<T_schema>,
mp::enable_if_t<
schema::is_schema_v<mp::decay_t<T_schema>>>>
{
static decltype(auto) apply(const T_schema& p_schema)
{ return std::make_unique<schema_t>(p_schema); }
};

}

} }

+ 1
- 0
include/cpphibernate/driver/mariadb/classes/tables.h Целия файл

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

+ 319
- 0
include/cpphibernate/driver/mariadb/classes/tables/table.h Целия файл

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

#include <set>
#include <string>
#include <vector>
#include <cppmariadb.h>

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

namespace cpphibernate {
namespace mariadb {

struct filter_t;
struct schema_t;
struct base_context;
struct init_context;
struct read_context;
struct create_update_context;
struct destroy_context;

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

/**
* @brief Abstract table class.
*/
struct table_t
{
public:
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 table_set = std::set<const table_t *>; //!< set of tables

public:
size_t id { 0 }; //!< unique id of the table assigned by the user
size_t dataset_id { 0 }; //!< unique id of the dataset type
size_t base_dataset_id { 0 }; //!< unique id of the dataset type
size_vector derived_dataset_ids; //!< vector of ids of all derived dataset

bool is_used_in_container { false }; //!< indicates if this table is used inside a container

std::string name; //!< name of the table
const schema_t& schema; //!< schema this table is owned by
fields_t fields; //!< vector of fields managed by this table

const table_t * base_table { nullptr }; //!< base table (if has one)
table_vector derived_tables; //!< vector of pointers of all derived tables

const field_t * primary_key_field { nullptr }; //!< primary key field
field_vector foreign_key_fields; //!< vector of pointers of all foreign key fields
field_vector foreign_table_fields; //!< vector of pointers of all foreign table fields
field_vector foreign_table_one_fields; //!< vector of pointers of all foreign table one fields
field_vector foreign_table_many_fields; //!< vector of pointers of all foreign table many fields
field_vector data_fields; //!< vector of pointers of all normal data fields

public:
/**
* @brief Default constructor.
*/
inline table_t() = default;

/**
* @brief Value constructor. Creates a mariadb table from the cpphibernate table.
*
* @param[in] p_owner Owner of the table.
* @param[in] p_schema Cpphibernate schema the table belongs to.
* @param[in] p_table Cpphibernate table to create mariadb table for.
*/
template<
typename T_schema,
typename T_table>
inline table_t(
const schema_t& p_owner,
const T_schema& p_schema,
const T_table& p_table);

/**
* @brief Move constructor.
*/
inline table_t(table_t&& other) = delete;

/**
* @brief Copy constructor.
*/
inline table_t(const table_t&) = delete;

/**
* @brief Destructor.
*/
virtual ~table_t() = 0;

/**
* @brief Print the table to the passed stream.
*/
std::ostream& print(std::ostream& os) const;

public:
/**
* @brief Initialize the table using the passed context.
*
* The initialization is splitted into two stages. In the first stage the
* 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;

/**
* @brief Execute a read operation on the current table.
*
* @param[in] context Context that stores the needed data for the operation.
*/
void read(const read_context& context) const;

/**
* @brief Execute a create/update operation on the current table.
*
* For a polymorphic type this will check the derived tables before executing the actual operation.
* 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;

/**
* @brief Execute a destroy operation on the current table.
*
* For a polymorphic type this will check the derived tables before executing the actual operation.
* 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.
*/
virtual void destroy(const destroy_context& context) const;

/**
* @brief Cleanup orphaned datasets beginning from this table.
*
* This operation will iterate through the different base, derived and foreign tables of this table
* and delete all datasets that are not referenced at least by one other dataset.
*
* @param[in] context Context that stores the needed data for the operation.
* @param[in] processed Contains all tables that are already cleared (to handle ring dependencies).
* @param[in] check_derived Check the derived tables.
* @param[in] check_base Check the base table.
*/
void cleanup(const base_context& context, table_set& processed, bool check_derived, bool check_base) 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 Execute the actual create/update operation.
*
* Other than the normal create_update method 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.
*/
std::string create_update_exec(const create_update_context& context) const;

/**
* @brief Execute the actual destroy operation.
*
* Other than the normal destroy method 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 destroy_exec(const destroy_context& context) const;

/**
* @brief Delete all datasets from the table that foreign keys are all set to NULL.
*
* @param[in] context Context that stores the needed data for this operation.
*/
void foreign_many_delete_exec(const base_context& context) const;

/**
* @brief Build the delete query for this table.
*
* @param[in] where Where expression to add to the delete query.
*
* @return The requested delete query.
*/
std::string build_delete_query(const std::string* where) const;

public:
/**
* @brief Emplace new dataset of the type the table represents.
*
* @param[in] context Context to emplace new dataset in.
*/
virtual void emplace(const read_context& context) const;

/**
* @brief Get the derived table by it's dataset id
*
* @param[in] p_id Dataset id to get derived table for.
*
* @return Derived table or nullptr if table was not found.
*/
inline const table_t* get_derived_by_dataset_id(size_t p_id) const;

/**
* @brief Get the derived table by it's table id
*
* @param[in] p_id Table id to get derived table for.
*
* @return Derived table or nullptr if table was not found.
*/
inline const table_t* get_derived_by_table_id(size_t p_id) const;

private:
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_select_static; //!< Statement to select simple datasets from the database
mutable statement_map _statement_select_dynamic; //!< Statement to select dynamic/polymorphic datasets from the database
mutable statement_map _statement_update; //!< Map of all update statements
mutable statement_ptr_u _statement_foreign_many_delete; //!< Statement to delete all datasets from the table that foreign keys are all set to NULL.
mutable statement_ptr_u _statement_delete; //!< Statement to delete datasets from the database

/**
* @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.
*/
::cppmariadb::statement& get_statement_init_stage1() const;

/**
* @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 select operations.
*
* @param[in] filter Filter to apply to the statement.
* @param[in] dynamic Get select statement for dynamic/polymorphic datasets, for simple datasets otherwise.
*/
::cppmariadb::statement& get_statement_select(const filter_t& filter, bool dynamic) 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;

/**
* @brief Get the statement to delete all datasets from the table that foreign keys are all set to NULL.
*/
::cppmariadb::statement& get_statement_foreign_many_delete() const;

/**
* @brief Get statement to delete datasets from the database.
*/
::cppmariadb::statement& get_statement_delete() const;
};

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

namespace __impl
{

/**
* @brief Helper type to build table.
*/
template<typename X, typename = void>
struct table_builder;

}

/**
* @brief Predicate to create mariadb table class.
*/
constexpr decltype(auto) make_table = mp::generic_predicate<__impl::table_builder> { };

} }

+ 128
- 0
include/cpphibernate/driver/mariadb/classes/tables/table.inl Целия файл

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

#include <cpphibernate/schema/schema.inl>

#include "table.h"

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

namespace cpphibernate {
namespace mariadb {

/* table_t */

template<
typename T_schema,
typename T_table>
table_t::table_t(
const schema_t& p_owner,
const T_schema& p_schema,
const T_table& p_table)
: id (hana::value(p_table.table_id))
, dataset_id(get_type_id(p_table.wrapped_dataset))
, name (p_table.name)
, schema (p_owner)
, fields (make_fields(*this, p_schema, p_table))
{ }

const table_t* table_t
::get_derived_by_dataset_id(size_t p_id) const
{
if (dataset_id == p_id)
return this;
for (auto& ptr : derived_tables)
{
assert(ptr);
auto ret = ptr->get_derived_by_dataset_id(p_id);
if (ret)
return ret;
}
return nullptr;
}

const table_t* table_t
::get_derived_by_table_id(size_t p_id) const
{
if (id == p_id)
return this;
for (auto& ptr : derived_tables)
{
assert(ptr);
auto ret = ptr->get_derived_by_table_id(p_id);
if (ret)
return ret;
}
return nullptr;
}

namespace __impl
{

/* table_builder */

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

template<typename T_owner, typename T_schema, typename T_table>
struct table_builder<
mp::list<T_owner, T_schema, T_table>,
mp::enable_if_t<
mp::is_same_v<schema_t, mp::decay_t<T_owner>>
&& schema::is_schema_v<mp::decay_t<T_schema>>
&& schema::is_table_v<mp::decay_t<T_table>>>>
{

/* table_type */

template<
typename T_dataset,
typename T_base_dataset,
typename T_derived_datasets,
typename = void>
struct table_type
{ using type = table_simple_t /* table_simple_t<mp::decay_t<T_schema>, mp::decay_t<T_table>, T_base_dataset> */; };

template<
typename T_dataset,
typename T_base_dataset,
typename T_derived_datasets>
struct table_type<
T_dataset,
T_base_dataset,
T_derived_datasets,
mp::enable_if_t<
decltype(hana::size(std::declval<T_derived_datasets>()) != hana::size_c<0>)::value
|| decltype(hana::not_equal(std::declval<T_base_dataset>(), hana::type_c<void>))::value>>
{ using type = table_polymorphic_t<mp::decay_t<T_schema>, mp::decay_t<T_table>>; };

template<
typename T_dataset,
typename T_base_dataset,
typename T_derived_datasets>
using table_type_t = typename table_type<T_dataset, T_base_dataset, T_derived_datasets>::type;

/* apply */

static decltype(auto) apply(const schema_t& owner, const T_schema& schema, const T_table& table)
{
using dataset_type = decltype(+table.wrapped_dataset);
using base_dataset_type = mp::decay_t<decltype(schema::get_base_type(schema, table.wrapped_dataset))>;
using derived_datasets_type = mp::decay_t<decltype(schema::get_derived_types(schema, table.wrapped_dataset))>;
using table_type = table_type_t<dataset_type, base_dataset_type, derived_datasets_type>;

return std::make_unique<table_type>(
owner, schema, table,
base_dataset_type { }, derived_datasets_type { });
}

};

}

} }

+ 81
- 0
include/cpphibernate/driver/mariadb/classes/tables/table_polymorphic.h Целия файл

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

#include "table.h"

namespace cpphibernate {
namespace mariadb {

/**
* @brief Table for polymorphic data types.
*/
template<typename T_schema, typename T_table>
struct table_polymorphic_t
: public table_t
{
public:
using dataset_type = typename T_table::dataset_type;

public:
/**
* @brief Value constructor. Creates a mariadb table from the cpphibernate table.
*
* @param[in] p_owner Owner of the table.
* @param[in] p_schema Cpphibernate schema the table belongs to.
* @param[in] p_table Cpphibernate table to create mariadb table for.
*/
template<
typename T_base_dataset,
typename T_derived_datasets>
inline table_polymorphic_t(
const schema_t& p_owner,
const T_schema& p_schema,
const T_table& p_table,
const T_base_dataset&&,
const T_derived_datasets&&);

public:
/**
* @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.
*/
std::string create_update(const create_update_context& context) const override;

/**
* @brief Execute a destroy operation on the current table.
*
* For a polymorphic type this will check the derived tables before executing the actual operation.
* 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.
*/
void destroy(const destroy_context& context) const override;

public:
/**
* @brief Emplace new dataset of the type the table represents.
*
* @param[in] context Context to emplace new dataset in.
*/
void emplace(const read_context& context) const override;

private:
/**
* @brief Execute the predicate for each derived type.
*
* @param[in] dataset Dataset to try to cast to derived type.
* @param[in] include_self True: Also check the dataset type. False: Only check derived types.
* @param[in] pred Predicate to execute if dataset could be cast to a derived type.
*/
template<typename T_dataset, typename T_pred, typename T_include_self>
constexpr void for_each_derived(T_dataset& dataset, const T_include_self& include_self, const T_pred& pred) const;
};

} }

+ 185
- 0
include/cpphibernate/driver/mariadb/classes/tables/table_polymorphic.inl Целия файл

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

#include "table_polymorphic.h"

#include "../../context/create_update_context.inl"
#include "../../context/destroy_context.inl"

namespace cpphibernate {
namespace mariadb {

namespace __impl
{

/* make_dataset_id_vector */

struct make_dataset_id_vector_impl
{
template<typename T_datasets, size_t... I>
static constexpr decltype(auto) helper(const T_datasets& datasets, std::index_sequence<I...>)
{
return std::vector<size_t>({
get_type_id(datasets[hana::size_c<I>])...
});
}

template<typename T_datasets>
constexpr decltype(auto) operator()(const T_datasets& datasets) const
{
using size = mp::decay_t<decltype(hana::size(datasets))>;
return helper(datasets, std::make_index_sequence<size::value> { });
}
};

static constexpr decltype(auto) make_dataset_id_vector = make_dataset_id_vector_impl { };

/* filter_own_type_impl */

template<typename T_dataset, typename T_include_self>
struct filter_self_type_impl
{
template<typename T_type>
inline decltype(auto) operator() (T_type&&) const
{
return hana::and_(
hana::not_(hana::trait<std::is_abstract>(T_type{ })),
hana::or_(
T_type{ } != hana::type_c<T_dataset>,
T_include_self { }));
}
};

template<typename T_dataset, typename T_include_self>
static constexpr decltype(auto) filter_self_type = filter_self_type_impl<T_dataset, T_include_self> { };

}

/* table_polymorphic_t */

template<
typename T_schema,
typename T_table>
template<
typename T_base_dataset,
typename T_derived_datasets>
table_polymorphic_t<T_schema, T_table>
::table_polymorphic_t(
const schema_t& p_owner,
const T_schema& p_schema,
const T_table& p_table,
const T_base_dataset&&,
const T_derived_datasets&&)
: table_t(
p_owner,
p_schema,
p_table)
{
this->base_dataset_id = hana::if_(
hana::equal(T_base_dataset { }, hana::type_c<void>),
static_cast<size_t>(0),
get_type_id(T_base_dataset { }));
this->derived_dataset_ids = __impl::make_dataset_id_vector(T_derived_datasets { });
}

template<
typename T_schema,
typename T_table>
std::string table_polymorphic_t<T_schema, T_table>
::create_update(const create_update_context& context) const
{
bool done = false;
auto& dataset = context.get<dataset_type>();
for_each_derived(dataset, hana::false_c, [&](auto& derived_dataset){
if (!done)
{
using derived_dataset_type = mp::decay_t<decltype(derived_dataset)>;
auto derived_dataset_id = get_type_id(hana::type_c<derived_dataset_type>);
auto derived_table = this->get_derived_by_dataset_id(derived_dataset_id);
if (!derived_table)
{
throw exception(static_cast<std::ostringstream&>(std::ostringstream { }
<< "unable to find derived table info for dataset '"
<< cppcore::type_helper<derived_dataset_type>::name() << "'!").str());
}
derived_table->create_update(change_context(context, derived_dataset));
done = true;
}
});

return done
? *this->primary_key_field->get(context)
: this->create_update_exec(context);
}

template<
typename T_schema,
typename T_table>
void table_polymorphic_t<T_schema, T_table>
::destroy(const destroy_context& context) const
{
bool done = false;
auto& dataset = context.get<dataset_type>();
for_each_derived(dataset, hana::false_c, [&](auto& derived_dataset){
if (!done)
{
using derived_dataset_type = mp::decay_t<decltype(derived_dataset)>;
auto derived_dataset_id = get_type_id(hana::type_c<derived_dataset_type>);
auto derived_table = this->get_derived_by_dataset_id(derived_dataset_id);
if (!derived_table)
{
throw exception(static_cast<std::ostringstream&>(std::ostringstream { }
<< "unable to find derived table info for dataset '"
<< cppcore::type_helper<derived_dataset_type>::name() << "'!").str());
}
auto new_context = change_context(context, derived_dataset);
derived_table->destroy(new_context);
done = true;
}
});

if (!done)
{
this->destroy_exec(context);
}
}

template<
typename T_schema,
typename T_table>
void table_polymorphic_t<T_schema, T_table>
::emplace(const read_context& context) const
{
hana::eval_if(
std::is_abstract_v<dataset_type>,
[](){
throw exception(std::string("can not create dataset of abstract type: ")
+ cppcore::type_helper<dataset_type>::name());
},
[&context, this](auto _){
_(context).template emplace<dataset_type>(this);
});
}

template<
typename T_schema,
typename T_table>
template<
typename T_dataset,
typename T_pred,
typename T_include_self>
constexpr void table_polymorphic_t<T_schema, T_table>
::for_each_derived(T_dataset& dataset, const T_include_self& include_self, const T_pred& pred) const
{
auto derived_types = decltype(hana::filter(
schema::get_all_derived_types(std::declval<T_schema>(), hana::type_c<dataset_type>),
__impl::filter_self_type<mp::decay_t<T_dataset>, mp::decay_t<T_include_self>>)) { };

hana::for_each(derived_types, [&](auto& type){
using derived_type = decay_unwrap_t<decltype(type)>;
auto* derived = dynamic_cast<derived_type*>(&dataset);
if (derived)
pred(*derived);
});
}

} }

+ 35
- 0
include/cpphibernate/driver/mariadb/classes/tables/table_simple.h Целия файл

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

#include "table.h"

namespace cpphibernate {
namespace mariadb {

/**
* @brief Table for non polymorphic datatypes.
*/
struct table_simple_t
: public table_t
{
public:
/**
* @brief Value constructor. Creates a mariadb table from the cpphibernate table.
*
* @param[in] p_owner Owner of the table.
* @param[in] p_schema Cpphibernate schema the table belongs to.
* @param[in] p_table Cpphibernate table to create mariadb table for.
*/
template<
typename T_schema,
typename T_table,
typename T_base_dataset,
typename T_derived_datasets>
inline table_simple_t(
const schema_t& p_owner,
const T_schema& p_schema,
const T_table& p_table,
const T_base_dataset&&,
const T_derived_datasets&&);
};

} }

+ 27
- 0
include/cpphibernate/driver/mariadb/classes/tables/table_simple.inl Целия файл

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

#include "table_simple.h"

namespace cpphibernate {
namespace mariadb {

/* table_simple_t */

template<
typename T_schema,
typename T_table,
typename T_base_dataset,
typename T_derived_datasets>
table_simple_t::table_simple_t(
const schema_t& p_owner,
const T_schema& p_schema,
const T_table& p_table,
const T_base_dataset&&,
const T_derived_datasets&&)
: table_t(
p_owner,
p_schema,
p_table)
{ }

} }

+ 32
- 0
include/cpphibernate/driver/mariadb/classes/tables/tables.h Целия файл

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

namespace cpphibernate {
namespace mariadb {

/**
* @brief Vector of tables.
*/
struct tables_t
: public std::vector<table_ptr_u>
{
using base_type = std::vector<table_ptr_u>;
using base_type::base_type;
};

namespace __impl
{

/**
* @brief Helper class to create table vector.
*/
template<typename X, typename = void>
struct tables_builder;

}

/**
* @brief Predicate to create table vector.
*/
constexpr decltype(auto) make_tables = mp::generic_predicate<__impl::tables_builder> { };

} }

+ 66
- 0
include/cpphibernate/driver/mariadb/classes/tables/tables.inl Целия файл

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

#include "tables.h"

#include "table.inl"

namespace cpphibernate {
namespace mariadb {

namespace __impl
{

/* tables_builder */

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

template<
typename T_owner,
typename T_schema>
struct tables_builder<
mp::list<T_owner, T_schema>,
mp::enable_if_t<
mp::is_same_v<schema_t, mp::decay_t<T_owner>>
&& schema::is_schema_v<mp::decay_t<T_schema>>>>
{
template<typename T_index>
static constexpr void emplace(
tables_t& result,
const schema_t& owner,
const T_schema& schema,
T_index&& index)
{
result.emplace_back(make_table(owner, schema, schema.tables[index]));
}

template<size_t... I>
static decltype(auto) helper(
const schema_t& owner,
const T_schema& schema,
std::index_sequence<I...> seq)
{
tables_t ret;
ret.reserve(sizeof...(I));
int dummy[] = { 0, (emplace(ret, owner, schema, hana::size_c<I>), void(), 0)... };
(void) dummy;
return ret;
}

static constexpr decltype(auto) apply(
const schema_t& owner,
const T_schema& schema)
{
using size = decltype(hana::size(schema.tables));
return helper(owner, schema, std::make_index_sequence<size::value> { });
}
};

}

} }

+ 11
- 0
include/cpphibernate/driver/mariadb/context.h Целия файл

@@ -0,0 +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"

+ 26
- 0
include/cpphibernate/driver/mariadb/context/base_context.h Целия файл

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

#include <cppmariadb.h>

namespace cpphibernate {
namespace mariadb {

struct schema_t;

/**
* @brief Base class for all mariadb driver context classes.
*/
struct base_context
{
const schema_t& schema; //!< schema to use for the operation
::cppmariadb::connection& connection; //!< mariadb connection to use for executing queries

/**
* @brief Constructor.
*/
inline base_context(
const schema_t& p_schema,
::cppmariadb::connection& p_connection);
};

} }

+ 17
- 0
include/cpphibernate/driver/mariadb/context/base_context.inl Целия файл

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

#include "base_context.h"

namespace cpphibernate {
namespace mariadb {

/* base_context */

base_context::base_context(
const schema_t& p_schema,
::cppmariadb::connection& p_connection)
: schema (p_schema)
, connection(p_connection)
{ }

} }

+ 71
- 0
include/cpphibernate/driver/mariadb/context/create_update_context.h Целия файл

@@ -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 Целия файл

@@ -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); }

} }

+ 92
- 0
include/cpphibernate/driver/mariadb/context/data_context.h Целия файл

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

#include <cpphibernate/config.h>

#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;

}

struct table_t;

/**
* @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;

protected:
/**
* @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 data_context(
const schema_t& p_schema,
::cppmariadb::connection& p_connection);

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;

protected:
/**
* @brief Set the dataset that is stored in this context.
*
* @param[in] dataset Dataset to store in the context.
* @param[in] dataset_id Unique id of the dataset stored in the context.
*
* @return Pointer to the stored dataset.
*/
template<typename T_dataset>
inline void * set(T_dataset& dataset, size_t dataset_id = 0) const;

/**
* @brief Clear the context (set the stored dataset to nullptr).
*/
inline void clear() const;
};

} }

+ 119
- 0
include/cpphibernate/driver/mariadb/context/data_context.inl Целия файл

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

#include "data_context.h"

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

namespace cpphibernate {
namespace mariadb {

/* data_context */

data_context::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_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, size_t dataset_id) const
{
_dataset_id = dataset_id
? dataset_id
: get_type_id(hana::type_c<mp::decay_t<T_dataset>>);
_dataset = &dataset;
_table = nullptr;
return _dataset;
}

void data_context::clear() const
{
_dataset_id = 0;
_dataset = nullptr;
_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;
}
};

}

} }

+ 23
- 0
include/cpphibernate/driver/mariadb/context/destroy_context.h Целия файл

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

#include "data_context.h"

namespace cpphibernate {
namespace mariadb {

/**
* @brief Mariadb driver context for deleting datasets from the database.
*/
struct destroy_context
: public data_context
{
std::string where; //!< Where clause for deleting datasets.

template<typename T_dataset>
inline destroy_context(
const schema_t& p_schema,
::cppmariadb::connection& p_connection,
T_dataset& p_dataset);
};

} }

+ 20
- 0
include/cpphibernate/driver/mariadb/context/destroy_context.inl Целия файл

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

#include "destroy_context.h"

#include "data_context.inl"

namespace cpphibernate {
namespace mariadb {

/* destroy_context */

template<typename T_dataset>
destroy_context::destroy_context(
const schema_t& p_schema,
::cppmariadb::connection& p_connection,
T_dataset& p_dataset)
: data_context (p_schema, p_connection, p_dataset)
{ }

} }

+ 22
- 0
include/cpphibernate/driver/mariadb/context/init_context.h Целия файл

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

#include "base_context.h"

namespace cpphibernate {
namespace mariadb {

/**
* @brief Mariadb driver context for initializing the database.
*/
struct init_context
: public base_context
{
bool recreate;

inline init_context(
const schema_t& p_schema,
::cppmariadb::connection& p_connection,
bool p_recreate);
};

} }

+ 20
- 0
include/cpphibernate/driver/mariadb/context/init_context.inl Целия файл

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

#include "init_context.h"

#include "base_context.inl"

namespace cpphibernate {
namespace mariadb {

/* init_context */

init_context::init_context(
const schema_t& p_schema,
::cppmariadb::connection& p_connection,
bool p_recreate)
: base_context (p_schema, p_connection)
, recreate (p_recreate)
{ }

} }

+ 104
- 0
include/cpphibernate/driver/mariadb/context/read_context.h Целия файл

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

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

namespace cpphibernate {
namespace mariadb {

/**
* @brief Context that is used for read operations.
*/
struct read_context
: public data_context
{
protected:
const size_t real_dataset_id; //!< Unique id of thre real dataset the context was created with.

public:
const filter_t& filter; //!< Filter that is used for read operation.
bool is_dynamic; //!< The dataset managed by this context is dynamic/polymorhp
std::string where; //!< Where statement to use for selection
std::string limit; //!< Limit statement to use for selection
std::string order_by; //!< Order statement to use for selection

public:
/**
* @brief Destructor.
*/
virtual ~read_context() = default;

/**
* @brief Emplace a new value in the dataset of the read context.
*
* @tparam T_dataset Type of the dataset to emplace.
*
* @param[in] table Table of the dataset to emplace.
* If the table is unknown, the table is searched within the schema.
*
* @return Reference to the emplaced dataset.
*/
template<typename T_dataset>
inline T_dataset& emplace(const table_t * table = nullptr) const;

/**
* @brief Emplace a new value in the dataset of the read context.
*/
inline void emplace() const;

/**
* @brief Finish the emplacement of values in the dataset.
*/
inline void finish() const;

private:
/**
* @brief Actual emplace method. This method should create a new value entry in the dataset of the read context.
*
* @param[in] data Actual data to emplace. If nullptr is passed a default value is created.
* @param[in] dataset_id Unique id of the dataset to emplace (must match the object pointed to by data).
*
* @return Pointer to the dataset that was emplaced.
*/
virtual void * emplace_intern(void * data, size_t dataset_id) const = 0;

/**
* @brief Actual finish method. Should check how many element has been emplaced in the dataset.
*/
virtual void finish_intern () const = 0;

protected:
/**
* @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_filter Filter to use for the read operation.
* @param[in] p_real_dataset_id Unique id the dataset that is stored in the context.
*/
inline read_context(
const schema_t& p_schema,
::cppmariadb::connection& p_connection,
const filter_t& p_filter,
size_t p_real_dataset_id);
};

using read_context_ptr_u = std::unique_ptr<read_context>;

namespace __impl
{

/**
* @brief Helper class to create read contexts.
*/
template<typename X, typename = void>
struct read_context_builder;

}

/**
* @brief Predicate to create read contexts.
*/
constexpr decltype(auto) make_read_context = mp::generic_predicate<__impl::read_context_builder> { };

} }

+ 364
- 0
include/cpphibernate/driver/mariadb/context/read_context.inl Целия файл

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

#include "read_context.h"

#include "data_context.inl"
#include "../helper/nullable_helper.inl"
#include "../helper/container_helper.inl"

namespace cpphibernate {
namespace mariadb {

read_context::read_context(
const schema_t& p_schema,
::cppmariadb::connection& p_connection,
const filter_t& p_filter,
size_t p_real_dataset_id)
: data_context (p_schema, p_connection)
, filter (p_filter)
, real_dataset_id (p_real_dataset_id)
, is_dynamic (false)
{ }

template<typename T_dataset>
T_dataset& read_context::emplace(const table_t * table) const
{
using dataset_type = mp::decay_t<T_dataset>;

/* check table */
auto dataset_id = get_type_id(hana::type_c<dataset_type>);
if (!table)
table = &schema.table(dataset_id);
else if (table->dataset_id != dataset_id)
throw exception("wrong table passed!");

/* check base */
auto tbl = table;
while (tbl && tbl->dataset_id != real_dataset_id)
tbl = tbl->base_table;
if (!tbl)
{
throw exception(cppcore::type_helper<dataset_type>::name() +
" is not a derived type of dataset with id " + std::to_string(real_dataset_id));
}

/* create dataset */
auto ptr = std::make_unique<dataset_type>();
auto data = emplace_intern(ptr.get(), dataset_id);
if (!data)
throw exception("unable to store created dataset in context!");
ptr.release();
return *static_cast<dataset_type*>(data);
}

void read_context::emplace() const
{ emplace_intern(nullptr, 0); }

void read_context::finish() const
{ finish_intern(); }

namespace __impl
{

/* read_context_builder */

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

/* read_context_builder - fake */

template<
typename T_schema,
typename T_connection,
typename T_dataset,
typename T_filter>
struct read_context_builder<
mp::list<T_schema, T_connection, T_dataset, T_filter>,
mp::enable_if_t<
mp::is_same_v<hana::type_tag, hana::tag_of_t<mp::decay_t<T_dataset>>>
>>
{
using dataset_type = typename mp::decay_t<T_dataset>::type;

struct context_impl
: public read_context
{
public:
inline context_impl(
const schema_t& p_schema,
::cppmariadb::connection& p_connection,
T_dataset& p_dataset,
const filter_t& p_filter)
: read_context (p_schema, p_connection, p_filter,
get_type_id(hana::type_c<real_dataset_t<mp::decay_t<dataset_type>>>))
{ }

private:
void * emplace_intern(void* data, size_t dataset_id) const override
{ return nullptr; }

void finish_intern() const override
{ clear(); }
};

template<typename... X_args>
static constexpr decltype(auto) apply(X_args&&... args)
{ return context_impl(std::forward<X_args>(args)...); }
};

/* read_context_builder - normal types */

template<
typename T_schema,
typename T_connection,
typename T_dataset,
typename T_filter>
struct read_context_builder<
mp::list<T_schema, T_connection, T_dataset, T_filter>,
mp::enable_if_t<
!is_container_v<mp::decay_t<T_dataset>>
&& !is_nullable_v<mp::decay_t<T_dataset>>
&& !mp::is_same_v<hana::type_tag, hana::tag_of_t<mp::decay_t<T_dataset>>>
>>
{
using dataset_type = mp::decay_t<T_dataset>;

struct context_impl
: public read_context
{
private:
mutable size_t _count;
dataset_type& _dataset;

public:
inline context_impl(
const schema_t& p_schema,
::cppmariadb::connection& p_connection,
T_dataset& p_dataset,
const filter_t& p_filter)
: read_context (p_schema, p_connection, p_filter,
get_type_id(hana::type_c<real_dataset_t<mp::decay_t<T_dataset>>>))
, _count (0)
, _dataset (p_dataset)
{ }

private:
void * emplace_intern(void* data, size_t dataset_id) const override
{
if (data || dataset_id != 0)
throw exception("Static datasets can not be assigned!");
++_count;
if (_count > 1)
throw exception("Expected exactly one dataset, but received more!");
return set(_dataset);
}

void finish_intern() const override
{
if (_count < 1)
throw exception("Expected exactly one dataset, but received none!");
clear();
}
};

template<typename... X_args>
static constexpr decltype(auto) apply(X_args&&... args)
{ return context_impl(std::forward<X_args>(args)...); }
};

/* read_context_builder - nullable */

template<
typename T_schema,
typename T_connection,
typename T_dataset,
typename T_filter>
struct read_context_builder<
mp::list<T_schema, T_connection, T_dataset, T_filter>,
mp::enable_if_t<
!is_container_v<mp::decay_t<T_dataset>>
&& is_nullable_v<mp::decay_t<T_dataset>>
>>
{
using dataset_type = mp::decay_t<T_dataset>;
using nullable_helper_type = nullable_helper<dataset_type>;
using value_type = typename nullable_helper_type::value_type;

struct context_impl
: public read_context
{
private:
dataset_type& _dataset;
mutable size_t _count;

public:
inline context_impl(
const schema_t& p_schema,
::cppmariadb::connection& p_connection,
T_dataset& p_dataset,
const filter_t& p_filter)
: read_context (p_schema, p_connection, p_filter,
get_type_id(hana::type_c<real_dataset_t<mp::decay_t<T_dataset>>>))
, _count (0)
, _dataset (p_dataset)
{
is_dynamic = is_pointer_v<dataset_type>;
nullable_helper_type::clear(_dataset);
}

private:
void * emplace_intern(void * data, size_t dataset_id) const override
{
if (data && !is_pointer_v<dataset_type>)
throw exception("None pointer type can not be assigned!");
++_count;
if (_count > 1)
throw exception("Expected exactly one dataset, but received more!");

if (data)
{
auto* cast = static_cast<value_type*>(data);
auto& value = nullable_helper_type::set(_dataset, cast);
if (cast != &value)
throw exception("Nullable pointer value has changed!");
return set(value, dataset_id);
}
else
{
auto& value = nullable_helper_type::set(_dataset, value_type { });
return set(value);
}
}

void finish_intern() const override
{ clear(); }
};

template<typename... X_args>
static constexpr decltype(auto) apply(X_args&&... args)
{ return context_impl(std::forward<X_args>(args)...); }
};

/* container_emplace_helper */

template<typename T_dataset, typename = void>
struct container_emplace_helper;

template<typename T_dataset>
struct container_emplace_helper<
T_dataset,
mp::enable_if_t<
mp::is_valid_v<typename container_helper<T_dataset>::value_type>
&& !is_pointer_v<typename container_helper<T_dataset>::value_type>
>>
{
static inline decltype(auto) emplace(T_dataset& dataset, void * data, size_t& data_id)
{
using container_helper_type = container_helper<T_dataset>;
using value_type = typename container_helper_type::value_type;

if (data || data_id != 0)
throw exception("Static datasets can not be assigned!");
auto& value = container_helper_type::emplace(dataset);
data_id = get_type_id(hana::type_c<value_type>);

return value;
}
};

template<typename T_dataset>
struct container_emplace_helper<
T_dataset,
mp::enable_if_t<
mp::is_valid_v<typename container_helper<T_dataset>::value_type>
&& is_pointer_v<typename container_helper<T_dataset>::value_type>
>>
{
static inline decltype(auto) emplace(T_dataset& dataset, void * data, size_t& data_id)
{
using container_helper_type = container_helper<T_dataset>;
using nullable_type = typename container_helper_type::value_type;
using nullable_helper_type = nullable_helper<nullable_type>;
using inner_value_type = typename nullable_helper_type::value_type;

if (!data)
throw exception("Expected dynamic data for pointer type!");
if (data_id == 0)
throw exception("Expected dataset id for pointer type!");
if (!is_pointer_v<nullable_type>)
throw exception("None pointer type can not be assigned!");

auto& nullable = container_helper_type::emplace(dataset);
auto* cast = static_cast<inner_value_type*>(data);
auto& value = nullable_helper_type::set(nullable, cast);
if (cast != &value)
throw exception("Nullable pointer value has changed!");

return value;
}
};

/* read_context_builder - container */

template<
typename T_schema,
typename T_connection,
typename T_dataset,
typename T_filter>
struct read_context_builder<
mp::list<T_schema, T_connection, T_dataset, T_filter>,
mp::enable_if_t<
is_container_v<mp::decay_t<T_dataset>>
&& !is_nullable_v<mp::decay_t<T_dataset>>
>>
{
using dataset_type = mp::decay_t<T_dataset>;
using real_dataset_type = real_dataset_t<dataset_type>;
using container_helper_type = container_helper<dataset_type>;
using value_type = typename container_helper_type::value_type;
using emplace_helper_type = container_emplace_helper<dataset_type>;

struct context_impl
: public read_context
{
private:
dataset_type& _dataset;

public:
inline context_impl(
const schema_t& p_schema,
::cppmariadb::connection& p_connection,
T_dataset& p_dataset,
const filter_t& p_filter)
: read_context (p_schema, p_connection, p_filter,
get_type_id(hana::type_c<real_dataset_t<mp::decay_t<T_dataset>>>))
, _dataset (p_dataset)
{
is_dynamic = is_pointer_v<value_type>;
container_helper_type::clear(_dataset);
}

private:
void * emplace_intern(void * data, size_t dataset_id) const override
{
auto& value = emplace_helper_type::emplace(_dataset, data, dataset_id);
return set(value, dataset_id);
}

void finish_intern() const override
{ clear(); }
};

template<typename... X_args>
static constexpr decltype(auto) apply(X_args&&... args)
{ return context_impl(std::forward<X_args>(args)...); }
};

}

} }

+ 86
- 0
include/cpphibernate/driver/mariadb/driver.h Целия файл

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

#include "impl/driver_impl.h"

namespace cpphibernate {
namespace mariadb {

/**
* @brief Mariadb driver.
*
* The normal cpphibernate context will be inherited from this class. So all methods
* defined here will be part of the context class.
*/
struct driver_t
{
public:
friend struct driver_impl_t;

private:
driver_impl_t _impl; //!< Driver implementation.
::cppmariadb::connection * _connection; //!< Mariadb connection to use for queries.
filter_t _filter; //!< Filter to use for read and update operations.

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.
*/
inline std::ostream& print(std::ostream& os) const;

/**
* @brief Get the connection currently assigned to the driver.
*/
inline ::cppmariadb::connection * connection() const;

/**
* @brief Set the connection to use for queries.
* This will invalidate all cached queries and strings.
*/
inline void connection(::cppmariadb::connection * p_connection);

/**
* @brief Set the include filter to use for update and read operations.
*
* @param[in] args Fileds and tables to use as include filter.
*/
template<typename... T_args>
inline void set_filter_inclusive(T_args&&... args);

/**
* @brief Set the exclude filter to use for update and read operations.
*
* @param[in] args Fileds and tables to use as exclude filter.
*/
template<typename... T_args>
inline void set_filter_exclusive(T_args&&... args);

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

protected:
/**
* @brief Get the imlementation object of the driver.
*/
inline auto& impl() const;
};

} }

+ 44
- 0
include/cpphibernate/driver/mariadb/driver.inl Целия файл

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




namespace cpphibernate {
namespace mariadb {

template<typename T_schema>
driver_t::driver_t(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
{ return _impl.schema->print(os); }

::cppmariadb::connection* driver_t::connection() const
{ return _connection; }

void driver_t::connection(::cppmariadb::connection * p_connection)
{ _connection = p_connection; }

template<typename... T_args>
void driver_t::set_filter_inclusive(T_args&&... args)
{ _filter.set_inclusive(_impl.schema, std::forward<T_args>(args)...); }

template<typename... T_args>
void driver_t::set_filter_exclusive(T_args&&... args)
{ _filter.set_exclusive(_impl.schema, std::forward<T_args>(args)...); }

void driver_t::clear_filter()
{ _filter.clear(); }

auto& driver_t::impl() const
{ return _impl; }

} }

+ 7
- 4
include/cpphibernate/driver/mariadb/helper.h Целия файл

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

#include <cpphibernate/driver/mariadb/helper/context.h>
#include <cpphibernate/driver/mariadb/helper/key_properties.h>
#include <cpphibernate/driver/mariadb/helper/transaction_lock.h>
#include <cpphibernate/driver/mariadb/helper/type_properties.h>
#include "helper/key_properties.h"
#include "helper/nullable_helper.h"
#include "helper/type_properties.h"

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

+ 27
- 0
include/cpphibernate/driver/mariadb/helper/container_helper.h Целия файл

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

namespace cpphibernate {
namespace mariadb {

/**
* @brief Helper class to manage operations on nullable types.
*/
template<typename T_container, typename = void>
struct container_helper
{
using container_type = T_container;
using value_type = typename container_type::value_type;

/**
* @brief Emplace a new dataset in the container.
*/
template<typename... X_args>
static inline value_type& emplace(container_type& container, X_args&&... args) = delete;

/**
* @brief Clear the whole container.
*/
static inline void clear(container_type& container) = delete;
};

} }

+ 43
- 0
include/cpphibernate/driver/mariadb/helper/container_helper.inl Целия файл

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

#include <list>
#include <vector>

#include "container_helper.h"

namespace cpphibernate {
namespace mariadb {

/* container_helper */

template<typename T_container>
struct container_helper<
T_container,
mp::enable_if_t<
mp::is_specialization_of_v<mp::decay_t<T_container>, std::list>
|| mp::is_specialization_of_v<mp::decay_t<T_container>, std::vector>
>>
{
using container_type = T_container;
using value_type = typename container_type::value_type;

/**
* @brief Emplace a new dataset in the container.
*/
template<typename... X_args>
static inline value_type& emplace(container_type& container, X_args&&... args)
{
container.emplace_back(std::forward<X_args>(args)...);
return container.back();
}

/**
* @brief Clear the whole container.
*/
static inline void clear(container_type& container)
{
container.clear();
}
};

} }

+ 0
- 218
include/cpphibernate/driver/mariadb/helper/context.h Целия файл

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

#include <cppmariadb.h>
#include <cpphibernate/misc.h>
#include <cpphibernate/config.h>
#include <cpphibernate/driver/mariadb/schema/field.fwd.h>
#include <cpphibernate/driver/mariadb/schema/table.fwd.h>
#include <cpphibernate/driver/mariadb/schema/filter.fwd.h>
#include <cpphibernate/driver/mariadb/schema/schema.fwd.h>

beg_namespace_cpphibernate_driver_mariadb
{

/* base_context */

struct base_context
{
const schema_t& schema;
::cppmariadb::connection& connection;

inline base_context(
const schema_t& p_schema,
::cppmariadb::connection& p_connection)
: schema (p_schema)
, connection(p_connection)
{ }
};


/* init_context */

struct init_context
: public base_context
{
bool recreate;

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

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;
}
};
}

constexpr decltype(auto) change_context = __impl::change_context_impl { };

/* data_context */

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

mutable size_t _dataset_id;
mutable void* _dataset;
mutable const table_t* _table;

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;

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)
{ }
};

/* filter_context */

struct filter_context
: public data_context
{
const filter_t& filter;

inline filter_context(
const schema_t& p_schema,
::cppmariadb::connection& p_connection,
const filter_t& p_filter)
: data_context (p_schema, p_connection)
, filter (p_filter)
{ }

template<typename T_data>
inline filter_context(
T_data& p_data,
const schema_t& p_schema,
::cppmariadb::connection& p_connection,
const filter_t& p_filter)
: data_context (p_data, p_schema, p_connection)
, filter (p_filter)
{ }
};

/* create_update_context */

struct create_update_context
: public filter_context
{
bool is_update;
const table_t* derived_table;
const field_t* owner_field;
std::string owner_key;
ssize_t index;

template<typename T_data>
inline create_update_context(
T_data& p_data,
const schema_t& p_schema,
::cppmariadb::connection& p_connection,
const filter_t& p_filter,
bool p_is_update)
: filter_context(p_data, p_schema, p_connection, p_filter)
, is_update (p_is_update)
, derived_table (nullptr)
, owner_field (nullptr)
, index (-1)
{ }
};

/* read_context */

struct read_context
: public filter_context
{
protected:
size_t base_dataset_id;

public:
bool is_dynamic;
std::string where;
std::string limit;
std::string order_by;

protected:
inline read_context(
const schema_t& p_schema,
::cppmariadb::connection& p_connection,
const filter_t& p_filter)
: filter_context (p_schema, p_connection, p_filter)
, is_dynamic (false)
, base_dataset_id (0)
{ }

public:
virtual ~read_context() = default;

template<typename T_dataset>
inline T_dataset& emplace(const table_t* table = nullptr) const;

void emplace() const
{ emplace_intern(nullptr, 0); }

void finish() const
{ finish_intern(); }

private:
virtual void* emplace_intern(void* data, size_t dataset_id) const = 0;
virtual void finish_intern () const = 0;
};

using read_context_ptr = std::unique_ptr<read_context>;

/* destroy_context */

struct destroy_context
: public data_context
{
std::string where;

template<typename T_data>
inline destroy_context(
T_data& p_data,
const schema_t& p_schema,
::cppmariadb::connection& p_connection)
: data_context(
p_data,
p_schema,
p_connection)
{ }
};

}
end_namespace_cpphibernate_driver_mariadb

+ 0
- 91
include/cpphibernate/driver/mariadb/helper/context.inl Целия файл

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

#include <cpphibernate/driver/mariadb/helper/context.h>

beg_namespace_cpphibernate_driver_mariadb
{

/* 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;
}

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

if (!_dataset)
throw misc::hibernate_exception("no data assigned!");

auto dataset_id = misc::get_type_id(hana::type_c<dataset_type>);
if (dataset_id != _dataset_id)
{
/* check table */
if (!_table)
_table = &schema.table(_dataset_id);
else if (_table->dataset_id != _dataset_id)
throw misc::hibernate_exception("invalid table!");

auto table = _table;
while(table && table->dataset_id != dataset_id)
table = table->base_table;

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 *static_cast<dataset_type*>(_dataset);
}

/* read_context */

template<typename T_dataset>
T_dataset& read_context
::emplace(const table_t* table) const
{
using dataset_type = mp::decay_t<T_dataset>;

// check table
auto dataset_id = misc::get_type_id(hana::type_c<dataset_type>);
if (!table)
table = &schema.table(dataset_id);
else if (table->dataset_id != dataset_id)
throw misc::hibernate_exception("wrong table passed!");

// check base
auto tbl = table;
while (tbl && tbl->dataset_id != base_dataset_id)
tbl = tbl->base_table;
if (!tbl)
{
throw misc::hibernate_exception(utl::type_helper<dataset_type>::name() +
" is not a derived type of dataset with id " + std::to_string(base_dataset_id));
}

// create dataset
auto ptr = std::make_unique<dataset_type>();
auto data = emplace_intern(ptr.get(), dataset_id);
if (!data)
throw misc::hibernate_exception("unable to store created dataset in context!");
ptr.release();
return *static_cast<dataset_type*>(data);
}

}
end_namespace_cpphibernate_driver_mariadb

+ 30
- 33
include/cpphibernate/driver/mariadb/helper/key_properties.h Целия файл

@@ -1,42 +1,39 @@
#pragma once

#include <cpphibernate/types.h>
#include <cpphibernate/config.h>
#include <cpputils/container/nullable.h>

beg_namespace_cpphibernate_driver_mariadb
{

/* key_properties */
namespace cpphibernate {
namespace mariadb {

/**
* @brief Key type properties for the passed type.
*
* @tparam T_key Type to get key properties for.
*/
template<typename T_key, typename = void>
struct key_properties;

template<>
struct key_properties<uuid, void>
{
using auto_generated = mp::c_false_t;
using key_type = uuid;

static constexpr decltype(auto) create_table_argument = "";
static constexpr decltype(auto) create_key_query = "SELECT Uuid()";

static bool is_default(const key_type& key)
{ return key == key_type(); }
};

template<typename T_key>
struct key_properties<T_key, mp::enable_if<mp::is_integral<T_key>>>
struct key_properties
{
using auto_generated = mp::c_true_t;
using key_type = T_key;

static constexpr decltype(auto) create_table_argument = "AUTO_INCREMENT";
static constexpr decltype(auto) create_key_query = "";

static bool is_default(const key_type& key)
{ return key == key_type(); }
using key_type = T_key;

/**
* @brief Check if the passed key value is the default value.
*/
static bool is_default(const key_type& key) = delete;

/**
* @brief Returns true if the key type is auto generated, false otherwise.
*/
static constexpr bool is_auto_generated() = delete;

/**
* @brief Returns extra arguments to use for creating the table.
*/
static constexpr const char * create_table_argument() = delete;

/**
* @brief Return the query to create a new key value.
*/
static constexpr const char * create_key_query() = delete;
};

}
end_namespace_cpphibernate_driver_mariadb
} }

+ 48
- 0
include/cpphibernate/driver/mariadb/helper/key_properties.inl Целия файл

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

#include "key_properties.h"

namespace cpphibernate {
namespace mariadb {

/* key_properties */

template<>
struct key_properties<uuid, void>
{
using key_type = uuid;

static bool is_default(const key_type& key)
{ return key == key_type(); }

static constexpr bool is_auto_generated()
{ return false; }

static constexpr const char * create_table_argument()
{ return nullptr; }

static constexpr const char * create_key_query()
{ return "SELECT Uuid()"; }
};

template<typename T_key>
struct key_properties<
T_key,
mp::enable_if_t<mp::is_integral_v<mp::decay_t<T_key>>>>
{
using key_type = mp::decay_t<T_key>;

static bool is_default(const key_type& key)
{ return key == key_type(); }

static constexpr bool is_auto_generated()
{ return true; }

static constexpr const char * create_table_argument()
{ return "AUTO_INCREMENT"; }

static constexpr const char * create_key_query()
{ return nullptr; }
};

} }

+ 31
- 0
include/cpphibernate/driver/mariadb/helper/nullable_helper.h Целия файл

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

namespace cpphibernate {
namespace mariadb {

/**
* @brief Helper class to manage operations on nullable types.
*/
template<typename T_nullable, typename = void>
struct nullable_helper
{
using nullable_type = T_nullable;
using value_type = real_dataset_t<nullable_type>;

/**
* @brief Get a pointer to the stored value of the nullable object.
*/
static value_type* get(const nullable_type&) = delete;

/**
* @brief Set the new value of the nullable object.
*/
static value_type& set(nullable_type&, const value_type&) = delete;

/**
* @brief Destroy the stored value of a nullable objec (clear the nullable object).
*/
static void clear(nullable_type&) = delete;
};

} }

+ 73
- 0
include/cpphibernate/driver/mariadb/helper/nullable_helper.inl Целия файл

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

#include "nullable_helper.h"

namespace cpphibernate {
namespace mariadb {


/* nullable_helper - cppcore::nullable */

template<typename T_value>
struct nullable_helper<cppcore::nullable<T_value>, void>
{
using nullable_type = cppcore::nullable<T_value>;
using value_type = T_value;

static inline value_type* get(nullable_type& x)
{ return x.has_value() ? &x.value() : nullptr; }

static inline const value_type* get(const nullable_type& x)
{ return x.has_value() ? &x.value() : nullptr; }

static inline value_type& set(nullable_type& x, const value_type* value)
{ return *(x = *value); }

static inline value_type& set(nullable_type& x, const value_type& value)
{ return *(x = value); }

static inline value_type& set(nullable_type& x, value_type&& value)
{ return *(x = std::move(value)); }

static void clear(nullable_type& x)
{ x.reset(); }
};

/* nullable_helper - std::unique_ptr/std::shared_ptr */

template<typename T>
struct nullable_helper<
T,
mp::enable_if_t<
mp::is_specialization_of_v<mp::decay_t<T>, std::unique_ptr>
|| mp::is_specialization_of_v<mp::decay_t<T>, std::shared_ptr>>>
{
using nullable_type = T;
using value_type = typename nullable_type::element_type;

static inline value_type* get(const nullable_type& x)
{ return x.get(); }

static inline value_type& set(nullable_type& x, value_type* value)
{
x.reset(value);
return *x;
}

static inline value_type& set(nullable_type& x, const value_type& value)
{
x.reset(new value_type(value));
return *x;
}

static inline value_type& set(nullable_type& x, value_type&& value)
{
x.reset(new value_type(std::move(value)));
return *x;
}

static void clear(nullable_type& x)
{ return x.reset(); }
};

} }

+ 0
- 93
include/cpphibernate/driver/mariadb/helper/transaction_lock.h Целия файл

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

#include <memory>
#include <iomanip>
#include <cppmariadb.h>
#include <cpphibernate/config.h>
#include <cpputils/misc/type_helper.h>

beg_namespace_cpphibernate_driver_mariadb
{

struct transaction_lock final
{
public:
inline transaction_lock(::cppmariadb::connection& con)
{ begin_transaction(*this, con); }

inline ~transaction_lock()
{ close_transaction(*this); }

inline bool commit()
{ return commit_transaction(*this); }

private:
using transaction_ptr_type = std::unique_ptr<::cppmariadb::transaction>;

#ifdef CPPHIBERNATE_DEBUG
# define debug_log(str) cpphibernate_debug_log( \
"transaction (id=" << std::setw(8) << std::setfill(' ') << lock.id << \
", counter=" << std::setw(2) << std::setfill(' ') << counter << ") " str)
struct counter { };
size_t id { utl::unique_counter<counter>::next() };
#else
# define debug_log(str) do { } while(0)
#endif

static size_t& ref_counter()
{
static size_t value = 0;
return value;
}

static transaction_ptr_type& ref_transaction_ptr()
{
static transaction_ptr_type value;
return value;
}

static void begin_transaction(const transaction_lock& lock, ::cppmariadb::connection& con)
{
auto& counter = ref_counter();
++counter;
debug_log("+++");
if (counter == 1)
{
debug_log("begin");
ref_transaction_ptr().reset(new ::cppmariadb::transaction(con));
}
}

static bool commit_transaction(const transaction_lock& lock)
{
auto& counter = ref_counter();
if (counter == 1)
{
debug_log("commit");
ref_transaction_ptr()->commit();
return true;
}
return false;
}

static void close_transaction(const transaction_lock& lock)
{
auto& counter = ref_counter();
debug_log("---");
if (counter <= 1)
{
debug_log("close");
counter = 0;
ref_transaction_ptr().reset();
}
else
{
--counter;
}
}
};

#undef debug_log

}
end_namespace_cpphibernate_driver_mariadb

+ 37
- 568
include/cpphibernate/driver/mariadb/helper/type_properties.h Целия файл

@@ -1,583 +1,52 @@
#pragma once

#include <cpputils/misc/enum.h>
#include <cpputils/misc/flags.h>
#include <cpputils/misc/string.h>
#include <memory>

#include <cpphibernate/misc.h>
#include <cpphibernate/types.h>
#include <cpphibernate/config.h>
#include <cpputils/container/nullable.h>

beg_namespace_cpphibernate_driver_mariadb
{

/* value_t */

using value_t = utl::nullable<std::string>;

/* type_properties */
namespace cpphibernate {
namespace mariadb {

/**
* @brief Type properties for the passed type.
*
* @tparam T Type to get properties for.
*/
template<typename T, typename = void>
struct type_properties
{
static constexpr void type () = delete;
static T convert_to (const value_t&) = delete;
static value_t convert_from (const T&) = delete;
static constexpr const char* convert_to_open () = delete;
static constexpr const char* convert_to_close () = delete;
static constexpr const char* convert_from_open () = delete;
static constexpr const char* convert_from_close() = delete;
};

template<>
struct type_properties<bool, void>
{
static constexpr decltype(auto) type()
{ return "BOOLEAN"; }

static inline bool convert_to(const value_t& value)
{ return utl::from_string<int>(*value); }

static inline value_t convert_from(const bool& value)
{ return utl::to_string(static_cast<int>(value)); }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<>
struct type_properties<uint8_t, void>
{
static constexpr decltype(auto) type()
{ return "TINYINT UNSIGNED"; }

static inline uint8_t convert_to(const value_t& value)
{ return static_cast<uint8_t>(utl::from_string<int>(*value)); }

static inline value_t convert_from(const uint8_t& value)
{ return utl::to_string(static_cast<int>(value)); }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<>
struct type_properties<int8_t, void>
{
static constexpr decltype(auto) type()
{ return "TINYINT"; }

static inline int8_t convert_to(const value_t& value)
{ return static_cast<int8_t>(utl::from_string<int>(*value)); }

static inline value_t convert_from(const int8_t& value)
{ return utl::to_string(static_cast<int>(value)); }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<>
struct type_properties<uint16_t, void>
{
static constexpr decltype(auto) type()
{ return "SMALLINT UNSIGNED"; }

static inline uint16_t convert_to(const value_t& value)
{ return utl::from_string<uint16_t>(*value); }

static inline value_t convert_from(const uint16_t& value)
{ return utl::to_string(value); }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<>
struct type_properties<int16_t, void>
{
static constexpr decltype(auto) type()
{ return "SMALLINT"; }

static inline int16_t convert_to(const value_t& value)
{ return utl::from_string<int16_t>(*value); }

static inline value_t convert_from(const int16_t& value)
{ return utl::to_string(value); }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<>
struct type_properties<uint32_t, void>
{
static constexpr decltype(auto) type()
{ return "INT UNSIGNED"; }

static inline uint32_t convert_to(const value_t& value)
{ return utl::from_string<uint32_t>(*value); }

static inline value_t convert_from(const uint32_t& value)
{ return utl::to_string(value); }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<>
struct type_properties<int32_t, void>
{
static constexpr decltype(auto) type()
{ return "INT"; }

static inline int32_t convert_to(const value_t& value)
{ return utl::from_string<int32_t>(*value); }

static inline value_t convert_from(const int32_t& value)
{ return utl::to_string(value); }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<>
struct type_properties<uint64_t, void>
{
static constexpr decltype(auto) type()
{ return "BIGINT UNSIGNED"; }

static inline uint64_t convert_to(const value_t& value)
{ return utl::from_string<uint64_t>(*value); }

static inline value_t convert_from(const uint64_t& value)
{ return utl::to_string(value); }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<>
struct type_properties<int64_t, void>
{
static constexpr decltype(auto) type()
{ return "BIGINT"; }

static inline int64_t convert_to(const value_t& value)
{ return utl::from_string<int64_t>(*value); }

static inline value_t convert_from(const int64_t& value)
{ return utl::to_string(value); }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<>
struct type_properties<float, void>
{
static constexpr decltype(auto) type()
{ return "FLOAT"; }

static inline float convert_to(const value_t& value)
{ return utl::from_string<float>(*value); }

static inline value_t convert_from(const float& value)
{ return utl::to_string(value); }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<>
struct type_properties<double, void>
{
static constexpr decltype(auto) type()
{ return "DOUBLE"; }

static inline double convert_to(const value_t& value)
{ return utl::from_string<double>(*value); }

static inline value_t convert_from(const double& value)
{ return utl::to_string(value); }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<>
struct type_properties<uuid, void>
{
static constexpr decltype(auto) type()
{ return "BINARY(16)"; }

static inline uuid convert_to(const value_t& value)
{ return utl::from_string<uuid>(*value); }

static inline value_t convert_from(const uuid& value)
{ return utl::to_string(value); }

static constexpr const char* convert_to_open()
{ return "UuidToBin("; }

static constexpr const char* convert_to_close()
{ return ")"; }

static constexpr const char* convert_from_open()
{ return "BinToUuid("; }

static constexpr const char* convert_from_close()
{ return ")"; }
};

template<>
struct type_properties<timestamp, void>
{
static constexpr decltype(auto) type()
{ return "BIGINT"; }

static inline timestamp convert_to(const value_t& value)
{ return timestamp(utl::from_string<uint64_t>(*value)); }

static inline value_t convert_from(const timestamp& value)
{ return utl::to_string(static_cast<uint64_t>(value)); }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<>
struct type_properties<std::string, void>
{
static constexpr decltype(auto) type()
{ return "VARCHAR(100)"; }

static inline std::string convert_to(const value_t& value)
{ return *value; }

static inline value_t convert_from(const std::string& value)
{ return value; }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<size_t N>
struct type_properties<string<N>, void>
{
static inline std::string make_type()
{ return std::string("VARCHAR(") + utl::to_string(N) + ")"; }

static inline decltype(auto) type()
{
static const std::string v = make_type();
return v;
}

static inline std::string convert_to(const value_t& value)
{ return *value; }

static inline value_t convert_from(const std::string& value)
{ return value; }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

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

static constexpr decltype(auto) type()
{ return value_type_props::type(); }

static inline nullable_type convert_to(const value_t& value)
{
nullable_type ret;
if (value.has_value())
nullable_helper_type::set(ret, value_type_props::convert_to(value));
return ret;
}

static inline value_t convert_from(const nullable_type& value)
{
value_t ret;
auto v = nullable_helper_type::get(value);
if (v)
ret = value_type_props::convert_from(*v);
return ret;
}

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<typename T>
struct type_properties<T, mp::enable_if<std::is_enum<mp::clean_type<T>>>>
{
using enum_type = T;
using base_type = typename std::underlying_type<enum_type>::type;

static std::string make_type()
{
std::ostringstream os;
os << "ENUM ( ";
auto e = enum_type::first;
while (e <= enum_type::last)
{
if (e != enum_type::first)
os << ", ";
os << "'" << utl::enum_conversion<enum_type>::to_string(e, false) << "'";
e = static_cast<enum_type>(static_cast<base_type>(e) + 1);
}
os << " )";
return os.str();
}

static inline decltype(auto) type()
{
static const std::string v = make_type();
return v;
}

static inline enum_type convert_to(const value_t& value)
{
enum_type ret;
if (!utl::enum_conversion<enum_type>::try_to_enum(*value, ret, false))
throw misc::hibernate_exception("unable to convert enum value!");
return ret;
}

static inline value_t convert_from(const enum_type& value)
{ return utl::enum_conversion<enum_type>::to_string(value, false); }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<typename T>
struct type_properties<T, mp::enable_if<mp::is_specialization_of<mp::clean_type<T>, utl::flags>>>
{
using flags_type = T;
using enum_type = typename flags_type::enum_type;
using base_type = typename std::underlying_type<enum_type>::type;

static inline std::string make_type()
{
std::ostringstream os;
os << "SET ( ";
auto e = enum_type::first;
while (e <= enum_type::last)
{
if (e != enum_type::first)
os << ", ";
os << "'" << utl::to_string(e) << "'";
e = static_cast<enum_type>(static_cast<base_type>(e) + 1);
}
os << " )";
return os.str();
}

static inline decltype(auto) type()
{
static const std::string v = make_type();
return v;
}
/**
* @brief Get the mariadb type.
*/
static constexpr const char * type() = delete;

static inline flags_type convert_to(const value_t& value)
{
auto s = *value;
auto c = s.c_str();
auto e = c + s.size();
auto p = c;
flags_type ret;
while (c <= e)
{
if (c == e || *c == ',')
{
if (c - p > 0)
ret.set(utl::enum_conversion<enum_type>::to_enum(std::string(p, static_cast<size_t>(c - p)), true));
p = c + 1;
}
++c;
}
return ret;
}
/**
* @brief Convert a value from the database to its actual type.
*/
static T convert_to(const value_t&) = delete;

static inline value_t convert_from(const flags_type& value)
{
std::ostringstream os;
bool first = true;
for (auto e : value)
{
if (first) first = false;
else os << ",";
os << utl::enum_conversion<enum_type>::to_string(e, false);
}
return os.str();
}
/**
* @brief Convert the actual value to a database value.
*/
static value_t convert_from(const T&) = delete;

static constexpr const char* convert_to_open()
{ return nullptr; }
/**
* @brief Get the string to start the "convert to" operation.
*/
static constexpr const char * convert_to_open() = delete;

static constexpr const char* convert_to_close()
{ return nullptr; }
/**
* @brief Get the string to end the "convert to" operation.
*/
static constexpr const char * convert_to_close() = delete;

static constexpr const char* convert_from_open()
{ return nullptr; }
/**
* @brief Get the string to start the "convert from" operation.
*/
static constexpr const char * convert_from_open() = delete;

static constexpr const char* convert_from_close()
{ return nullptr; }
/**
* @brief Get the string to end the "convert from" operation.
*/
static constexpr const char * convert_from_close() = delete;
};

}
end_namespace_cpphibernate_driver_mariadb
} }

+ 559
- 0
include/cpphibernate/driver/mariadb/helper/type_properties.inl Целия файл

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

#include "type_properties.h"

namespace cpphibernate {
namespace mariadb {

template<>
struct type_properties<bool, void>
{
static constexpr decltype(auto) type()
{ return "BOOLEAN"; }

static inline bool convert_to(const value_t& value)
{ return cppcore::from_string<int>(*value); }

static inline value_t convert_from(const bool& value)
{ return cppcore::to_string(static_cast<int>(value)); }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<>
struct type_properties<uint8_t, void>
{
static constexpr decltype(auto) type()
{ return "TINYINT UNSIGNED"; }

static inline uint8_t convert_to(const value_t& value)
{ return static_cast<uint8_t>(cppcore::from_string<int>(*value)); }

static inline value_t convert_from(const uint8_t& value)
{ return cppcore::to_string(static_cast<int>(value)); }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<>
struct type_properties<int8_t, void>
{
static constexpr decltype(auto) type()
{ return "TINYINT"; }

static inline int8_t convert_to(const value_t& value)
{ return static_cast<int8_t>(cppcore::from_string<int>(*value)); }

static inline value_t convert_from(const int8_t& value)
{ return cppcore::to_string(static_cast<int>(value)); }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<>
struct type_properties<uint16_t, void>
{
static constexpr decltype(auto) type()
{ return "SMALLINT UNSIGNED"; }

static inline uint16_t convert_to(const value_t& value)
{ return cppcore::from_string<uint16_t>(*value); }

static inline value_t convert_from(const uint16_t& value)
{ return cppcore::to_string(value); }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<>
struct type_properties<int16_t, void>
{
static constexpr decltype(auto) type()
{ return "SMALLINT"; }

static inline int16_t convert_to(const value_t& value)
{ return cppcore::from_string<int16_t>(*value); }

static inline value_t convert_from(const int16_t& value)
{ return cppcore::to_string(value); }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<>
struct type_properties<uint32_t, void>
{
static constexpr decltype(auto) type()
{ return "INT UNSIGNED"; }

static inline uint32_t convert_to(const value_t& value)
{ return cppcore::from_string<uint32_t>(*value); }

static inline value_t convert_from(const uint32_t& value)
{ return cppcore::to_string(value); }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<>
struct type_properties<int32_t, void>
{
static constexpr decltype(auto) type()
{ return "INT"; }

static inline int32_t convert_to(const value_t& value)
{ return cppcore::from_string<int32_t>(*value); }

static inline value_t convert_from(const int32_t& value)
{ return cppcore::to_string(value); }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<>
struct type_properties<uint64_t, void>
{
static constexpr decltype(auto) type()
{ return "BIGINT UNSIGNED"; }

static inline uint64_t convert_to(const value_t& value)
{ return cppcore::from_string<uint64_t>(*value); }

static inline value_t convert_from(const uint64_t& value)
{ return cppcore::to_string(value); }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<>
struct type_properties<int64_t, void>
{
static constexpr decltype(auto) type()
{ return "BIGINT"; }

static inline int64_t convert_to(const value_t& value)
{ return cppcore::from_string<int64_t>(*value); }

static inline value_t convert_from(const int64_t& value)
{ return cppcore::to_string(value); }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<>
struct type_properties<float, void>
{
static constexpr decltype(auto) type()
{ return "FLOAT"; }

static inline float convert_to(const value_t& value)
{ return cppcore::from_string<float>(*value); }

static inline value_t convert_from(const float& value)
{ return cppcore::to_string(value); }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<>
struct type_properties<double, void>
{
static constexpr decltype(auto) type()
{ return "DOUBLE"; }

static inline double convert_to(const value_t& value)
{ return cppcore::from_string<double>(*value); }

static inline value_t convert_from(const double& value)
{ return cppcore::to_string(value); }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<>
struct type_properties<uuid, void>
{
static constexpr decltype(auto) type()
{ return "BINARY(16)"; }

static inline uuid convert_to(const value_t& value)
{ return cppcore::from_string<uuid>(*value); }

static inline value_t convert_from(const uuid& value)
{ return cppcore::to_string(value); }

static constexpr const char* convert_to_open()
{ return "UuidToBin("; }

static constexpr const char* convert_to_close()
{ return ")"; }

static constexpr const char* convert_from_open()
{ return "BinToUuid("; }

static constexpr const char* convert_from_close()
{ return ")"; }
};

template<>
struct type_properties<timestamp, void>
{
static constexpr decltype(auto) type()
{ return "BIGINT"; }

static inline timestamp convert_to(const value_t& value)
{ return timestamp(cppcore::from_string<uint64_t>(*value)); }

static inline value_t convert_from(const timestamp& value)
{ return cppcore::to_string(static_cast<uint64_t>(value)); }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<>
struct type_properties<std::string, void>
{
static constexpr decltype(auto) type()
{ return "VARCHAR(100)"; }

static inline std::string convert_to(const value_t& value)
{ return *value; }

static inline value_t convert_from(const std::string& value)
{ return value; }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<size_t N>
struct type_properties<string<N>, void>
{
static inline std::string make_type()
{ return std::string("VARCHAR(") + cppcore::to_string(N) + ")"; }

static inline decltype(auto) type()
{
static const std::string v = make_type();
return v;
}

static inline std::string convert_to(const value_t& value)
{ return *value; }

static inline value_t convert_from(const std::string& value)
{ return value; }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<typename T>
struct type_properties<T, mp::enable_if_t<is_nullable_v<mp::decay_t<T>>>>
{
using nullable_type = T;
using nullable_helper_type = nullable_helper<nullable_type>;
using value_type = typename nullable_helper_type::value_type;

static constexpr decltype(auto) nullable = nullable_helper_type { };
static constexpr decltype(auto) value_props = type_properties<value_type> { };

static constexpr decltype(auto) type()
{ return value_props.type(); }

static inline decltype(auto) convert_to(const value_t& value)
{
nullable_type ret;
if (value.has_value())
nullable.set(ret, value_props.convert_to(value));
return ret;
}

static inline value_t convert_from(const nullable_type& value)
{
value_t ret;
auto v = nullable.get(value);
if (v)
ret = value_props.convert_from(*v);
return ret;
}

static constexpr const char* convert_to_open()
{ return value_props.convert_to_open(); }

static constexpr const char* convert_to_close()
{ return value_props.convert_to_close(); }

static constexpr const char* convert_from_open()
{ return value_props.convert_from_open(); }

static constexpr const char* convert_from_close()
{ return value_props.convert_from_close(); }
};

template<typename T>
struct type_properties<T, mp::enable_if_t<mp::is_enum_v<mp::decay_t<T>>>>
{
using enum_type = T;
using base_type = typename std::underlying_type<enum_type>::type;

static std::string make_type()
{
std::ostringstream os;
os << "ENUM ( ";
auto e = enum_type::first;
while (e <= enum_type::last)
{
if (e != enum_type::first)
os << ", ";
os << "'" << cppcore::enum_conversion<enum_type>::to_string(e, false) << "'";
e = static_cast<enum_type>(static_cast<base_type>(e) + 1);
}
os << " )";
return os.str();
}

static inline decltype(auto) type()
{
static const std::string v = make_type();
return v;
}

static inline enum_type convert_to(const value_t& value)
{
enum_type ret;
if (!cppcore::enum_conversion<enum_type>::try_to_enum(*value, ret, false))
throw exception("unable to convert enum value!");
return ret;
}

static inline value_t convert_from(const enum_type& value)
{ return cppcore::enum_conversion<enum_type>::to_string(value, false); }

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

template<typename T>
struct type_properties<T, mp::enable_if_t<mp::is_specialization_of_v<mp::decay_t<T>, cppcore::flags>>>
{
using flags_type = T;
using enum_type = typename flags_type::enum_type;
using base_type = typename std::underlying_type<enum_type>::type;

static inline std::string make_type()
{
std::ostringstream os;
os << "SET ( ";
auto e = enum_type::first;
while (e <= enum_type::last)
{
if (e != enum_type::first)
os << ", ";
os << "'" << cppcore::to_string(e) << "'";
e = static_cast<enum_type>(static_cast<base_type>(e) + 1);
}
os << " )";
return os.str();
}

static inline decltype(auto) type()
{
static const std::string v = make_type();
return v;
}

static inline flags_type convert_to(const value_t& value)
{
auto s = *value;
auto c = s.c_str();
auto e = c + s.size();
auto p = c;
flags_type ret;
while (c <= e)
{
if (c == e || *c == ',')
{
if (c - p > 0)
ret.set(cppcore::enum_conversion<enum_type>::to_enum(std::string(p, static_cast<size_t>(c - p)), true));
p = c + 1;
}
++c;
}
return ret;
}

static inline value_t convert_from(const flags_type& value)
{
std::ostringstream os;
bool first = true;
for (auto e : value)
{
if (first) first = false;
else os << ",";
os << cppcore::enum_conversion<enum_type>::to_string(e, false);
}
return os.str();
}

static constexpr const char* convert_to_open()
{ return nullptr; }

static constexpr const char* convert_to_close()
{ return nullptr; }

static constexpr const char* convert_from_open()
{ return nullptr; }

static constexpr const char* convert_from_close()
{ return nullptr; }
};

} }

+ 8
- 7
include/cpphibernate/driver/mariadb/impl.h Целия файл

@@ -1,10 +1,11 @@
#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/destroy.h"
#include "impl/driver_impl.h"
#include "impl/filter.h"

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

+ 10
- 113
include/cpphibernate/driver/mariadb/impl/create_update.h Целия файл

@@ -1,117 +1,14 @@
#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 */

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
{
using dataset_type = T_dataset;

static inline value_t apply(const create_update_context& context, bool strict = true)
{
value_t ret;

auto dataset_id = misc::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 (!strict)
{
auto update_context = context;
update_context.is_update = !update_context.is_update;
ret = table.create_update(update_context);
}
else if (context.is_update)
{
throw misc::hibernate_exception("can not update dataset with no primary key assigned!");
}
else
{
throw misc::hibernate_exception("can not create dataset with primary key assigned!");
}
}
else
{
ret = table.create_update(context);
}
trans.commit();
return ret;
}
};

/* create_update_impl_t - nullable */

template<typename T_dataset>
struct create_update_impl_t<
T_dataset,
mp::enable_if<misc::is_nullable<T_dataset>>>
{
using dataset_type = T_dataset;
using nullable_helper_type = misc::nullable_helper<dataset_type>;

static inline value_t apply(const create_update_context& context, bool strict = true)
{
value_t ret;
auto& dataset = context.get<dataset_type>();
auto* value = nullable_helper_type::get(dataset);

if (value)
{
using new_dataset_type = mp::decay_t<decltype(*value)>;
using new_create_update_impl_type = create_update_impl_t<new_dataset_type>;
ret = new_create_update_impl_type::apply(change_context(context, *value), strict);
}
else if (strict)
{
throw misc::hibernate_exception("can not create nullable type with no value!");
}
return ret;
}
};

/* create_update_impl_t - container */

template<typename T_dataset>
struct create_update_impl_t<
T_dataset,
mp::enable_if<misc::is_container<T_dataset>>>
{
using dataset_type = T_dataset;

static inline value_t apply(const create_update_context& context, bool strict = true)
{
value_t ret;
auto& connection = context.connection;
auto& dataset = context.get<dataset_type>();

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

}
end_namespace_cpphibernate_driver_mariadb
} }

+ 130
- 0
include/cpphibernate/driver/mariadb/impl/create_update.inl Целия файл

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

#include "create_update.h"

#include "../classes/schema/schema.inl"
#include "../helper/nullable_helper.inl"
#include "../context/create_update_context.inl"

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 = 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 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)
{
static const filter_t dummy;
ret = table.create_update(context.is_create()
? context.make_update_context(dummy)
: context.make_create_context());
}

/* 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 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 exception("can not create dataset with primary key assigned!");
}
}
else
{
ret = table.create_update(context);
}
trans.commit();
return ret;
}
};

/* create_update_impl_t - nullable */

template<typename T_dataset>
struct create_update_impl_t<
T_dataset,
mp::enable_if_t<is_nullable_v<T_dataset>>>
{
using dataset_type = T_dataset;
using nullable_helper_type = nullable_helper<dataset_type>;

static inline value_t apply(const create_update_context& context, bool strict = true)
{
value_t ret;
auto& dataset = context.get<dataset_type>();
auto* value = nullable_helper_type::get(dataset);

if (value)
{
using new_dataset_type = mp::decay_t<decltype(*value)>;
using new_create_update_impl_type = create_update_impl_t<new_dataset_type>;
ret = new_create_update_impl_type::apply(change_context(context, *value), strict);
}
else if (strict)
{
throw exception("can not create nullable type with no value!");
}
return ret;
}
};

/* create_update_impl_t - container */

template<typename T_dataset>
struct create_update_impl_t<
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>();

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

} }

+ 10
- 92
include/cpphibernate/driver/mariadb/impl/destroy.h Целия файл

@@ -1,96 +1,14 @@
#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
{

/* destroy_impl_t */

namespace cpphibernate {
namespace mariadb {

/**
* @brief Helper class to select the right implementation of the destroy operation for the passed datatype.
*
* @tparam T_dataset Dataset type to select implementation for.
*/
template<typename T_dataset, typename = void>
struct destroy_impl_t
{
using dataset_type = T_dataset;

static inline void apply(const destroy_context& context, bool strict = true)
{
auto dataset_id = misc::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))
{
table.destroy(context);
}
else if (strict)
{
throw misc::hibernate_exception("can not destroy dataset with no primary key assigned!");
}
trans.commit();
}
};

/* destroy_impl_t - nullable */

template<typename T_dataset>
struct destroy_impl_t<
T_dataset,
mp::enable_if<misc::is_nullable<T_dataset>>>
{
using dataset_type = T_dataset;
using nullable_helper_type = misc::nullable_helper<dataset_type>;

static inline void apply(const destroy_context& context, bool strict = true)
{
auto& dataset = context.get<dataset_type>();
auto* value = nullable_helper_type::get(dataset);

if (value)
{
using new_dataset_type = mp::decay_t<decltype(*value)>;
using new_destroy_impl_type = destroy_impl_t<new_dataset_type>;
auto new_context = change_context(context, *value);
new_destroy_impl_type::apply(new_context, strict);
}
else if (strict)
{
throw misc::hibernate_exception("can not destroy nullable type with no value!");
}
}
};

/* destroy_impl_t - container */

template<typename T_dataset>
struct destroy_impl_t<
T_dataset,
mp::enable_if<misc::is_container<T_dataset>>>
{
using dataset_type = T_dataset;

static inline void apply(const destroy_context& context, bool strict = true)
{
auto& connection = context.connection;
auto& dataset = context.get<dataset_type>();

transaction_lock trans(connection);
for (auto& x : dataset)
{
using new_dataset_type = mp::decay_t<decltype(x)>;
using new_destroy_impl_type = destroy_impl_t<new_dataset_type>;
auto new_context = change_context(context, x);
new_destroy_impl_type::apply(new_context, strict);
}
trans.commit();
}
};
struct destroy_impl_t;

}
end_namespace_cpphibernate_driver_mariadb
} }

+ 112
- 0
include/cpphibernate/driver/mariadb/impl/destroy.inl Целия файл

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

#include "destroy.h"

#include "../context/destroy_context.inl"

namespace cpphibernate {
namespace mariadb {

/* destroy_impl_t - default */

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

static inline void apply(const destroy_context& context, bool strict = true)
{
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);
::cppmariadb::transaction_lock trans(connection);
if (!table.primary_key_field->is_default(context))
{
auto& field = *table.primary_key_field;
auto primary_key = field.get(context);

assert(primary_key.has_value());

std::ostringstream os;
os << "WHERE `"
<< field.table.name
<< "`.`"
<< field.name
<< "`="
<< field.convert_to_open
<< "'"
<< connection.escape(*primary_key)
<< "'"
<< field.convert_to_close;

auto new_context = context;
new_context.where = os.str();
table.destroy(new_context);
}
else if (strict)
{
throw exception("can not destroy dataset with no primary key assigned!");
}
trans.commit();
}
};

/* destroy_impl_t - nullable */

template<typename T_dataset>
struct destroy_impl_t<
T_dataset,
mp::enable_if_t<is_nullable_v<T_dataset>>>
{
using dataset_type = T_dataset;
using nullable_helper_type = nullable_helper<dataset_type>;

static inline void apply(const destroy_context& context, bool strict = true)
{
auto& dataset = context.get<dataset_type>();
auto* value = nullable_helper_type::get(dataset);

if (value)
{
using new_dataset_type = mp::decay_t<decltype(*value)>;
using new_destroy_impl_type = destroy_impl_t<new_dataset_type>;
auto new_context = change_context(context, *value);
new_destroy_impl_type::apply(new_context, strict);
}
else if (strict)
{
throw exception("can not destroy nullable type with no value!");
}
}
};

/* destroy_impl_t - container */

template<typename T_dataset>
struct destroy_impl_t<
T_dataset,
mp::enable_if_t<is_container_v<T_dataset>>>
{
using dataset_type = T_dataset;

static inline void apply(const destroy_context& context, bool strict = true)
{
auto& connection = context.connection;
auto& dataset = context.get<dataset_type>();

::cppmariadb::transaction_lock trans(connection);
for (auto& x : dataset)
{
using new_dataset_type = mp::decay_t<decltype(x)>;
using new_destroy_impl_type = destroy_impl_t<new_dataset_type>;
auto new_context = change_context(context, x);
new_destroy_impl_type::apply(new_context, strict);
}
trans.commit();
}
};

} }

+ 72
- 0
include/cpphibernate/driver/mariadb/impl/driver_impl.h Целия файл

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

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

namespace cpphibernate {
namespace mariadb {

struct driver_t;

/**
* @brief Actual implementation of the mariadb driver.
*
* This class is used/owner by the mariadb driver class (as a member).
* The public interface of this class will not be part of the cpphibernate context.
*/
struct driver_impl_t
{
driver_t& owner;
schema_ptr_u schema;

/**
* @brief Constructor.

* @param[in] p_owner Object the driver implementation is owned by.
* @param[in] p_schema Cpphibernate schema to use with the driver.
*/
template<typename T_schema>
inline driver_impl_t(driver_t& p_owner, T_schema&& p_schema);

/**
* @brief Initialize the schema in the database.
*
* @param[in] recreate Recreate the whole schema (this will drop all existing data).
*/
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 the database.
*/
template<typename T_dataset>
inline void create(T_dataset& dataset) const;

/**
* @brief Read datasets from the database.
*
* @param[in] dataset Dataset to read from the database.
* @param[in] modifiers Modifiers to apply to the select query.
*/
template<typename T_dataset, typename T_modifiers>
inline void read(T_dataset& dataset, const T_modifiers& modifiers) const;

/**
* @brief Update an exsisting dataset in the database.
*
* @param[in] dataset Dataset to update in the database.
*/
template<typename T_dataset>
inline void update(T_dataset& dataset) const;

/**
* @brief Destroy an exsisting dataset in the database.
*
* @param[in] dataset Dataset to destroy in the database.
*/
template<typename T_dataset>
inline void destroy(T_dataset& dataset) const;
};

} }

+ 86
- 0
include/cpphibernate/driver/mariadb/impl/driver_impl.inl Целия файл

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

#include "../context/init_context.inl"
#include "../context/create_update_context.inl"
#include "../context/read_context.inl"
#include "../context/destroy_context.inl"

#include "driver_impl/where.inl"
#include "driver_impl/limit.inl"
#include "driver_impl/order_by.inl"

namespace cpphibernate {
namespace mariadb {

/* driver_impl_t */

template<typename T_schema>
driver_impl_t::driver_impl_t(driver_t& p_owner, T_schema&& p_schema)
: owner (p_owner)
, schema(make_schema(std::forward<T_schema>(p_schema)))
{ }

void driver_impl_t::init(bool recreate) const
{
auto * connection = owner.connection();
if (!connection)
throw exception("Cpphibernate mariadb driver is not connected to any database!");
::cppmariadb::transaction_lock trans(*connection);
schema->init(init_context(*schema, *connection, recreate));
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));
}

template<typename T_dataset, typename T_modifiers>
inline void driver_impl_t::read(T_dataset& dataset, const T_modifiers& modifiers) const
{
using dataset_type = mp::decay_t<T_dataset>;
using real_dataset_type = real_dataset_t<dataset_type>;

auto * connection = owner.connection();
if (!connection)
throw exception("Cpphibernate mariadb driver is not connected to any database!");

auto dataset_id = get_type_id(hana::type_c<real_dataset_type>);
auto& table = schema->table(dataset_id);
auto context = make_read_context(*schema, *connection, dataset, owner._filter);

context.where = build_where(*schema, modifiers).query(*connection);
context.limit = build_limit(modifiers).query(*connection);
context.order_by = build_order_by(*schema, modifiers).query(*connection);

::cppmariadb::transaction_lock trans(*connection);
table.read(context);
trans.commit();
}

template<typename T_dataset>
void driver_impl_t::update(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, owner._filter));
}

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

} }

include/cpphibernate/driver/mariadb/impl/limit.h → include/cpphibernate/driver/mariadb/impl/driver_impl/limit.inl Целия файл

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

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

beg_namespace_cpphibernate_driver_mariadb
{
namespace cpphibernate {
namespace mariadb {

/* limit_builder */

@@ -21,18 +20,18 @@ beg_namespace_cpphibernate_driver_mariadb

hana::for_each(p_modifier, [&limit, &offset](auto& x_modifier){
using modifier_type = mp::decay_t<decltype(x_modifier)>;
using is_limit_type = modifier::is_limit_modifier<modifier_type>;
using is_offset_type = modifier::is_offset<modifier_type>;
using is_limit_type = is_limit_modifier<modifier_type>;
using is_offset_type = is_offset_modifier<modifier_type>;
hana::eval_if(
is_limit_type { },
[&limit, &x_modifier](auto _){
limit = static_cast<ssize_t>(hana::value(_(x_modifier).value));
limit = static_cast<ssize_t>(hana::value(_(x_modifier)));
},
[&offset, &x_modifier](){
hana::eval_if(
is_offset_type { },
[&offset, &x_modifier](auto _){
offset = static_cast<ssize_t>(hana::value(_(x_modifier).value));
offset = static_cast<ssize_t>(hana::value(_(x_modifier)));
},
[]{
/* no-op */
@@ -61,5 +60,4 @@ beg_namespace_cpphibernate_driver_mariadb
return builder.statement;
}

}
end_namespace_cpphibernate_driver_mariadb
} }

include/cpphibernate/driver/mariadb/impl/order_by.h → include/cpphibernate/driver/mariadb/impl/driver_impl/order_by.inl Целия файл

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

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

beg_namespace_cpphibernate_driver_mariadb
{
namespace cpphibernate {
namespace mariadb {

/* order_by_builder */

@@ -30,20 +29,20 @@ beg_namespace_cpphibernate_driver_mariadb
size_t index = 0;
hana::for_each(modifiers, [&](auto& modifier){
using modifier_type = mp::decay_t<decltype(modifier)>;
using is_order_by_type = modifier::is_order_by<modifier_type>;
using is_order_by_type = is_order_by_modifier<modifier_type>;
hana::eval_if(
is_order_by_type { },
[&](auto _){
hana::for_each(_(modifier).fields, [&](auto& f){
using field_type = mp::decay_t<decltype(f)>;
using is_ascencing_type = modifier::is_ascending<field_type>;
hana::for_each(_(modifier).order_directions, [&](auto& dir){
using order_direction_type = mp::decay_t<decltype(dir)>;
using is_ascencing_type = is_ascending<order_direction_type>;
if (index++ == 0) os << "ORDER_BY ";
else os << ", ";
auto& field = schema.field(misc::get_type_id(f.wrapped_field));
auto& field = schema.field(get_type_id(dir.wrapped_field));
os << "`"
<< field.table_name
<< field.table.name
<< "`.`"
<< field.field_name
<< field.name
<< "` "
<< (is_ascencing_type::value
? "ASC"
@@ -79,5 +78,4 @@ beg_namespace_cpphibernate_driver_mariadb
return builder.assign(schema, modifiers);
}

}
end_namespace_cpphibernate_driver_mariadb
} }

include/cpphibernate/driver/mariadb/impl/where.h → include/cpphibernate/driver/mariadb/impl/driver_impl/where.inl Целия файл

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

#include <sstream>
#include <cpphibernate/config.h>
#include <cpphibernate/modifier.h>
#include <cpphibernate/driver/mariadb/schema/schema.h>
#include <cpphibernate/modifier/where.h>
#include <cpphibernate/modifier/where/equal.h>
#include <cpphibernate/modifier/where/negation.h>
#include <cpphibernate/modifier/where/conjunction.h>
#include <cpphibernate/modifier/where/disjunction.h>

beg_namespace_cpphibernate_driver_mariadb
{
namespace cpphibernate {
namespace mariadb {

/* where_builder */

@@ -27,7 +28,7 @@ beg_namespace_cpphibernate_driver_mariadb

template<typename T_clause>
inline auto build_clause(T_clause&& p_clause)
-> mp::enable_if<modifier::is_where_clause_and<mp::decay_t<T_clause>>>
-> mp::enable_if_t<is_and_v<mp::decay_t<T_clause>>>
{
os << "(";
build_clause(p_clause.clauses[hana::size_c<0>]);
@@ -43,7 +44,7 @@ beg_namespace_cpphibernate_driver_mariadb

template<typename T_clause>
inline auto build_clause(T_clause&& p_clause)
-> mp::enable_if<modifier::is_where_clause_or<mp::decay_t<T_clause>>>
-> mp::enable_if_t<is_or_v<mp::decay_t<T_clause>>>
{
os << "(";
build_clause(p_clause.clauses[hana::size_c<0>]);
@@ -59,7 +60,7 @@ beg_namespace_cpphibernate_driver_mariadb

template<typename T_clause>
inline auto build_clause(T_clause&& p_clause)
-> mp::enable_if<modifier::is_where_clause_not<mp::decay_t<T_clause>>>
-> mp::enable_if_t<is_not_v<mp::decay_t<T_clause>>>
{
os << "NOT (";
build_clause(p_clause.clause);
@@ -68,14 +69,14 @@ beg_namespace_cpphibernate_driver_mariadb

template<typename T_clause>
inline auto build_clause(T_clause&& p_clause)
-> mp::enable_if<modifier::is_where_clause_equal<mp::decay_t<T_clause>>>
-> mp::enable_if_t<is_equal_v<mp::decay_t<T_clause>>>
{
auto field_id = misc::get_type_id(hana::type_c<mp::decay_t<decltype(p_clause.field)>>);
auto field_id = get_type_id(hana::type_c<mp::decay_t<decltype(p_clause.field)>>);
auto& field = schema.field(field_id);
os << "`"
<< field.table_name
<< field.table.name
<< "`.`"
<< field.field_name
<< field.name
<< "`="
<< field.convert_to_open
<< "?\?"
@@ -87,7 +88,7 @@ beg_namespace_cpphibernate_driver_mariadb
size_t index = 0;
hana::for_each(modifiers, [&](auto& modifier){
using modifier_type = mp::decay_t<decltype(modifier)>;
using is_where_type = modifier::is_where<modifier_type>;
using is_where_type = is_where_modifier<modifier_type>;
hana::eval_if(
is_where_type { },
[&](auto _){
@@ -115,9 +116,9 @@ beg_namespace_cpphibernate_driver_mariadb

template<typename T_clause>
inline auto assign_clause(T_clause&& p_clause)
-> mp::enable_if_c<
modifier::is_where_clause_and<mp::decay_t<T_clause>>::value
|| modifier::is_where_clause_or <mp::decay_t<T_clause>>::value>
-> mp::enable_if_t<
is_and_v<mp::decay_t<T_clause>>
|| is_or_v <mp::decay_t<T_clause>>>
{
hana::for_each(std::forward<T_clause>(p_clause).clauses, [&](auto& x_clause) {
assign_clause(x_clause);
@@ -126,14 +127,14 @@ beg_namespace_cpphibernate_driver_mariadb

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

template<typename T_clause>
inline auto assign_clause(T_clause&& p_clause)
-> mp::enable_if<modifier::is_where_clause_equal<mp::decay_t<T_clause>>>
-> mp::enable_if_t<is_equal_v<mp::decay_t<T_clause>>>
{
statement.set(index, std::forward<T_clause>(p_clause).value);
++index;
@@ -143,7 +144,7 @@ beg_namespace_cpphibernate_driver_mariadb
{
hana::for_each(modifiers, [&](auto& modifier){
using modifier_type = mp::decay_t<decltype(modifier)>;
using is_where_type = modifier::is_where<modifier_type>;
using is_where_type = is_where_modifier<modifier_type>;
hana::eval_if(
is_where_type { },
[&](auto _){
@@ -178,5 +179,4 @@ beg_namespace_cpphibernate_driver_mariadb
return builder.assign(schema, modifiers);
}

}
end_namespace_cpphibernate_driver_mariadb
} }

+ 60
- 0
include/cpphibernate/driver/mariadb/impl/filter.h Целия файл

@@ -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();
};

} }

include/cpphibernate/driver/mariadb/schema/filter.inl → include/cpphibernate/driver/mariadb/impl/filter.inl Целия файл

@@ -1,33 +1,41 @@
#pragma once

#include <cpphibernate/driver/mariadb/schema/filter.h>
#include <cpphibernate/driver/mariadb/schema/schema.inl>
#include <cpphibernate/config.h>

beg_namespace_cpphibernate_driver_mariadb
{
#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 T, typename>
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 mariadb::filter_add_element(...)!"); }
{ 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_c<
schema::is_table<mp::decay_t<T_table>>::value>>
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 = misc::get_type_id(table.wrapped_dataset);
auto dataset_id = get_type_id(table.wrapped_dataset);
auto& t = schema.table(dataset_id);
filter.tables.emplace(&t);
for (auto& ptr : t.fields)
@@ -40,18 +48,20 @@ beg_namespace_cpphibernate_driver_mariadb
template<typename T_field>
struct filter_add_element_impl<
mp::list<filter_t&, const schema_t&, T_field>,
mp::enable_if_c<
schema::is_field<mp::decay_t<T_field>>::value>>
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 = misc::get_type_id(hana::type_c<mp::decay_t<T_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 */
@@ -77,7 +87,7 @@ beg_namespace_cpphibernate_driver_mariadb
{
clear();
exclusive = false;
cache_id = static_cast<size_t>(utl::get_unique_id<filter_t, mp::decay_t<T_args>...>());
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;
}
@@ -87,7 +97,7 @@ beg_namespace_cpphibernate_driver_mariadb
{
clear();
exclusive = true;
cache_id = static_cast<size_t>(utl::get_unique_id<filter_t, mp::decay_t<T_args>...>());
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;

@@ -118,5 +128,4 @@ beg_namespace_cpphibernate_driver_mariadb
tables.clear();
}

}
end_namespace_cpphibernate_driver_mariadb
} }

+ 0
- 69
include/cpphibernate/driver/mariadb/impl/modifier_tags.h Целия файл

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

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

beg_namespace_cpphibernate_driver_mariadb
{

namespace __impl
{

/* make_modifier_tags_impl */

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

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

}

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

namespace __impl
{

/* make_modifier_tags_impl */

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

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

}

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

}
end_namespace_cpphibernate_driver_mariadb

+ 0
- 265
include/cpphibernate/driver/mariadb/impl/read.h Целия файл

@@ -1,265 +0,0 @@
#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
{

namespace __impl
{

/* declaration */

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

/* normal datasets */

template<typename T_dataset, typename... T_args>
struct make_read_context_impl<
mp::list<T_dataset, T_args...>,
mp::enable_if_c<
!misc::is_container<mp::decay_t<T_dataset>>::value
&& !misc::is_nullable<mp::decay_t<T_dataset>>::value>>
{
using dataset_type = mp::decay_t<T_dataset>;

struct context_impl
: public read_context
{
private:
mutable size_t _count;
dataset_type& _dataset;

public:
template<typename... X_args>
context_impl(dataset_type& dataset, X_args&&... args)
: read_context (std::forward<X_args>(args)...)
, _count (0)
, _dataset (dataset)
{
is_dynamic = false;
base_dataset_id = misc::get_type_id(hana::type_c<dataset_type>);
}

private:
virtual void* emplace_intern(void* data, size_t dataset_id) const override
{
if (data || dataset_id != 0)
throw misc::hibernate_exception("Static datasets can not be assigned!");
++_count;
if (_count > 1)
throw misc::hibernate_exception("Expected exactly one dataset, but received more!");
return set(_dataset);
}

virtual void finish_intern() const override
{
if (_count < 1)
throw misc::hibernate_exception("Expected exactly one dataset, but received none!");
}
};

static constexpr decltype(auto) apply(dataset_type& dataset, T_args&&... args)
{ return context_impl(dataset, std::forward<T_args>(args)...); }
};

/* nullable datasets */

template<typename T_dataset, typename... T_args>
struct make_read_context_impl<
mp::list<T_dataset, T_args...>,
mp::enable_if_c<
!misc::is_container<mp::decay_t<T_dataset>>::value
&& misc::is_nullable<mp::decay_t<T_dataset>>::value>>
{
using dataset_type = mp::decay_t<T_dataset>;
using nullable_helper_type = misc::nullable_helper<dataset_type>;
using value_type = typename nullable_helper_type::value_type;

struct context_impl
: public read_context
{
private:
dataset_type& _dataset;
mutable size_t _count;

public:
template<typename... X_args>
context_impl(dataset_type& dataset, X_args&&... args)
: read_context (std::forward<X_args>(args)...)
, _dataset (dataset)
, _count (0)
{
is_dynamic = misc::is_pointer<dataset_type>::value;
base_dataset_id = misc::get_type_id(hana::type_c<value_type>);
nullable_helper_type::clear(_dataset);
}

private:
virtual void* emplace_intern(void* data, size_t dataset_id) const override
{
if (data && !misc::is_pointer<dataset_type>::value)
throw misc::hibernate_exception("None pointer type can not be assigned!");
++_count;
if (_count > 1)
throw misc::hibernate_exception("Expected exactly one dataset, but received more!");

if (data)
{
auto* cast = static_cast<value_type*>(data);
auto& value = nullable_helper_type::set(_dataset, cast);
if (cast != &value)
throw misc::hibernate_exception("Nullable pointer value has changed!");
return set(value, dataset_id);
}
else
{
auto& value = nullable_helper_type::set(_dataset, value_type { });
return set(value);
}
}

virtual void finish_intern() const override
{ }
};

static constexpr decltype(auto) apply(dataset_type& dataset, T_args&&... args)
{ return context_impl(dataset, std::forward<T_args>(args)...); }
};

/* container datasets */

template<typename T_dataset, typename... T_args>
struct make_read_context_impl<
mp::list<T_dataset, T_args...>,
mp::enable_if_c<
misc::is_container<mp::decay_t<T_dataset>>::value
&& !misc::is_nullable<mp::decay_t<T_dataset>>::value>>
{
using dataset_type = mp::decay_t<T_dataset>;
using real_dataset_type = misc::real_dataset_t<dataset_type>;
using container_helper_type = misc::container_helper<dataset_type>;
using value_type = typename container_helper_type::value_type;

struct context_impl
: public read_context
{
private:
dataset_type& _dataset;
mutable size_t _count;

public:
template<typename... X_args>
context_impl(dataset_type& dataset, X_args&&... args)
: read_context (std::forward<X_args>(args)...)
, _dataset (dataset)
, _count (0)
{
is_dynamic = misc::is_pointer<value_type>::value;
base_dataset_id = misc::get_type_id(hana::type_c<real_dataset_type>);
container_helper_type::clear(_dataset);
}

private:
virtual void* emplace_intern(void* data, size_t dataset_id) const override
{
return hana::eval_if(
misc::is_nullable<value_type> { },
[this, &data, &dataset_id](auto _){
using nullable_type = typename mp::decay_t<decltype(_(hana::type_c<value_type>))>::type;
using nullable_helper_type = misc::nullable_helper<nullable_type>;
using inner_value_type = typename nullable_helper_type::value_type;

if (!data)
throw misc::hibernate_exception("Expected dynamic data for pointer type!");
if (!misc::is_pointer<nullable_type>::value)
throw misc::hibernate_exception("None pointer type can not be assigned!");

auto& nullable = container_helper_type::emplace(this->_dataset);
auto* cast = static_cast<inner_value_type*>(data);
auto& value = nullable_helper_type::set(nullable, cast);
if (cast != &value)
throw misc::hibernate_exception("Nullable pointer value has changed!");
return set(value, dataset_id);
},
[this, &data, &dataset_id](){
if (data || dataset_id != 0)
throw misc::hibernate_exception("Static datasets can not be assigned!");
auto& value = container_helper_type::emplace(this->_dataset);
return this->set(value);
});
}

virtual void finish_intern() const override
{ }
};

static constexpr decltype(auto) apply(dataset_type& dataset, T_args&&... args)
{ return context_impl(dataset, std::forward<T_args>(args)...); }
};

}

constexpr decltype(auto) make_read_context = misc::make_generic_predicate<__impl::make_read_context_impl> { };

namespace __impl
{

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

template<typename T_wrapped_dataset, typename... T_args>
struct make_fake_context_impl<
mp::list<T_wrapped_dataset, T_args...>,
mp::enable_if_c<
hana::is_a_t<hana::type_tag, T_wrapped_dataset>::value>>
{
using wrapped_dataset_type = mp::decay_t<T_wrapped_dataset>;
using dataset_type = misc::unwrap_t<wrapped_dataset_type>;
using real_dataset_type = misc::real_dataset_t<dataset_type>;

struct context_impl
: public read_context
{
public:
template<typename... X_args>
context_impl(X_args&&... args)
: read_context (std::forward<X_args>(args)...)
{
is_dynamic = misc::is_pointer<dataset_type>::value;
base_dataset_id = misc::get_type_id(hana::type_c<real_dataset_type>);
}

private:
virtual void* emplace_intern(void* data, size_t dataset_id) const override
{ return nullptr; }

virtual void finish_intern() const override
{ }
};

static constexpr decltype(auto) apply(T_wrapped_dataset&&, T_args&&... args)
{ return context_impl(std::forward<T_args>(args)...); }
};

}

constexpr decltype(auto) make_fake_context = misc::make_generic_predicate<__impl::make_fake_context_impl> { };

}
end_namespace_cpphibernate_driver_mariadb

+ 0
- 120
include/cpphibernate/driver/mariadb/mariadb.h Целия файл

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

#include <cppmariadb.h>
#include <cpphibernate/config.h>
#include <cpphibernate/driver/mariadb/impl.h>
#include <cpphibernate/driver/mariadb/schema.h>
#include <cpphibernate/driver/mariadb/schema/filter.h>

beg_namespace_cpphibernate_driver_mariadb
{

struct mariadb_driver_t
{
public:
using lock_type = std::unique_ptr<transaction_lock>;

private:
::cppmariadb::connection* _connection;
schema_t _schema;
filter_t _filter;

public:
template<typename T_schema>
mariadb_driver_t(T_schema&& p_schema, ::cppmariadb::connection& p_connection)
: _connection (&p_connection)
, _schema (make_schema(std::forward<T_schema>(p_schema)))
{ }

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

inline const ::cppmariadb::connection& connection() const
{ return *_connection; }

inline void connection(::cppmariadb::connection& p_connection)
{ _connection = &p_connection; }

template<typename... T_args>
inline void set_filter_inclusive(T_args&&... args)
{ _filter.set_inclusive(_schema, std::forward<T_args>(args)...); }

template<typename... T_args>
inline void set_filter_exclusive(T_args&&... args)
{ _filter.set_exclusive(_schema, std::forward<T_args>(args)...); }

inline void clear_filter()
{ _filter.clear(); }

inline lock_type lock()
{ return std::make_unique<transaction_lock>(*_connection); }

template<typename T_modifiers>
inline std::string build_query(const std::string& query, T_modifiers&& modifiers) const
{
auto where = build_where(_schema, modifiers).query(*_connection);
std::ostringstream os;
os << query;
if (!where.empty())
os << " " << where;
return os.str();
}

protected:
inline void init_impl(bool recreate) const
{
transaction_lock trans(*_connection);
_schema.init(init_context(_schema, *_connection, recreate));
trans.commit();
}

template<typename T_dataset>
inline void create_impl(T_dataset& dataset) const
{
create_update_impl_t<T_dataset>::apply(
create_update_context(dataset, _schema, *_connection, _filter, false));
}

template<typename T_dataset, typename T_modifiers>
inline void read_impl(T_dataset& dataset, T_modifiers&& modifiers) const
{
using dataset_type = mp::decay_t<T_dataset>;
using real_dataset_type = misc::real_dataset_t<dataset_type>;

auto dataset_id = misc::get_type_id(hana::type_c<real_dataset_type>);
auto& table = _schema.table(dataset_id);
auto context = make_read_context(dataset, _schema, *_connection, _filter);
context.where = build_where(_schema, modifiers).query(*_connection);
context.limit = build_limit(modifiers).query(*_connection);
context.order_by = build_order_by(_schema, modifiers).query(*_connection);

transaction_lock trans(*_connection);
table.read(context);
trans.commit();
}

template<typename T_dataset>
inline void update_impl(T_dataset& dataset) const
{
create_update_impl_t<T_dataset>::apply(
create_update_context(dataset, _schema, *_connection, _filter, true));
}

template<typename T_dataset>
inline void destroy_impl(T_dataset& dataset) const
{
using dataset_type = mp::decay_t<T_dataset>;
using real_dataset_type = misc::real_dataset_t<dataset_type>;

auto dataset_id = misc::get_type_id(hana::type_c<real_dataset_type>);
auto& table = _schema.table(dataset_id);

destroy_context context(dataset, _schema, *_connection);
context.where = table.get_where_primary_key(context);

destroy_impl_t<T_dataset>::apply(context);
}
};

}
end_namespace_cpphibernate_driver_mariadb

+ 0
- 24
include/cpphibernate/driver/mariadb/schema.h Целия файл

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

#include <cpphibernate/driver/mariadb/schema/attributes.fwd.h>
#include <cpphibernate/driver/mariadb/schema/field.fwd.h>
#include <cpphibernate/driver/mariadb/schema/fields.fwd.h>
#include <cpphibernate/driver/mariadb/schema/schema.fwd.h>
#include <cpphibernate/driver/mariadb/schema/table.fwd.h>
#include <cpphibernate/driver/mariadb/schema/tables.fwd.h>

#include <cpphibernate/driver/mariadb/schema/attributes.h>
#include <cpphibernate/driver/mariadb/schema/field.h>
#include <cpphibernate/driver/mariadb/schema/fields.h>
#include <cpphibernate/driver/mariadb/schema/filter.h>
#include <cpphibernate/driver/mariadb/schema/schema.h>
#include <cpphibernate/driver/mariadb/schema/table.h>
#include <cpphibernate/driver/mariadb/schema/tables.h>

#include <cpphibernate/driver/mariadb/schema/attributes.inl>
#include <cpphibernate/driver/mariadb/schema/field.inl>
#include <cpphibernate/driver/mariadb/schema/fields.inl>
#include <cpphibernate/driver/mariadb/schema/filter.inl>
#include <cpphibernate/driver/mariadb/schema/schema.inl>
#include <cpphibernate/driver/mariadb/schema/table.inl>
#include <cpphibernate/driver/mariadb/schema/tables.inl>

+ 0
- 34
include/cpphibernate/driver/mariadb/schema/attributes.fwd.h Целия файл

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

#include <cpphibernate/config.h>

beg_namespace_cpphibernate_driver_mariadb
{
/* attribute_t */

enum class attribute_t
{
hex,
compress,
primary_key,
};

/* attributes_t */

struct attributes_t;

/* make_attributes */

namespace __impl
{

template<typename T, typename = void>
struct make_attributes_impl;

}

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

}
end_namespace_cpphibernate_driver_mariadb

+ 0
- 23
include/cpphibernate/driver/mariadb/schema/attributes.h Целия файл

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

#include <set>

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

beg_namespace_cpphibernate_driver_mariadb
{

/* attributes_t */

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

}
end_namespace_cpphibernate_driver_mariadb

+ 0
- 31
include/cpphibernate/driver/mariadb/schema/field.fwd.h Целия файл

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

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

beg_namespace_cpphibernate_driver_mariadb
{

/* field_t */

struct field_t;

/* field_ptr_t */

using field_ptr_t = std::unique_ptr<field_t>;

/* make_field */

namespace __impl
{

template<typename T, typename = void>
struct make_field_impl;

}

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

}
end_namespace_cpphibernate_driver_mariadb

+ 0
- 213
include/cpphibernate/driver/mariadb/schema/field.h Целия файл

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

#include <cpphibernate/misc.h>
#include <cpphibernate/config.h>
#include <cpphibernate/schema/field.h>
#include <cpphibernate/schema/table.h>
#include <cpphibernate/schema/schema.h>
#include <cpphibernate/driver/mariadb/helper.h>
#include <cpphibernate/driver/mariadb/schema/field.fwd.h>
#include <cpphibernate/driver/mariadb/schema/table.fwd.h>
#include <cpphibernate/driver/mariadb/schema/attributes.h>

beg_namespace_cpphibernate_driver_mariadb
{

/* field_t */

struct field_t
{
public:
size_t id { 0 }; // unique id of the field
size_t dataset_id { 0 }; // unique id of the dataset type
size_t real_dataset_id { 0 }; // unique id of the real/unwrapped dataset type
size_t value_id { 0 }; // unique id of the value type
size_t real_value_id { 0 }; // unique id of the real/unwrapped value type

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

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

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

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

attributes_t attributes; // attributes for the field

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

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

/* CRUD */
using read_context_ptr = std::unique_ptr<read_context>;

virtual value_t foreign_create_update (const create_update_context& context) const;
virtual read_context_ptr foreign_read (const read_context& context, bool fake_context) const;

/* properties */
virtual value_t get (const data_context& context) const;
virtual void set (const data_context& context, const value_t&) const;
virtual bool is_default (const data_context& context) const;
virtual std::string generate_value (::cppmariadb::connection& connection) const;

/* statements */
virtual ::cppmariadb::statement& get_statement_foreign_one_delete(bool key_known) const;
virtual ::cppmariadb::statement& get_statement_foreign_many_update() const;

protected:
using statement_ptr = std::unique_ptr<::cppmariadb::statement>;

::cppmariadb::statement& get_statement_foreign_one_delete_impl(bool key_known, statement_ptr& known, statement_ptr& unknown) const;
::cppmariadb::statement& get_statement_foreign_many_update_impl(statement_ptr& statement) const;
};

/* simple_field_t */

template<typename T_field>
struct simple_field_t
: public field_t
{
using base_type = field_t;
using field_type = mp::decay_t<T_field>;
using getter_type = typename field_type::getter_type;
using dataset_type = mp::decay_t<typename getter_type::dataset_type>;
using real_dataset_type = misc::real_dataset_t<dataset_type>;
using value_type = mp::decay_t<typename getter_type::value_type>;
using real_value_type = misc::real_dataset_t<value_type>;
using type_props = type_properties<value_type>;

const field_type& field;

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

virtual void update() override;
};

/* value_field_t */

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

using base_type::base_type;

static_assert(mp::is_same<dataset_type, real_dataset_type>::value, "internal error: dataset type mismatch!");

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

/* primary_key_field_t */

template<typename T_field>
struct primary_key_field_t
: public value_field_t<T_field>
{
using base_type = value_field_t<T_field>;
using field_type = typename base_type::field_type;
using dataset_type = typename base_type::dataset_type;
using value_type = typename base_type::value_type;
using key_props = key_properties<value_type>;

using base_type::base_type;

virtual void update () override;
virtual bool is_default (const data_context& context) const override;
virtual std::string generate_value(::cppmariadb::connection& connection) const override;
};

/* data_field_t */

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

using base_type::base_type;
};

/* foreign_table_field_t */

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

using base_type::base_type;

public:
/* CRUD */
virtual value_t foreign_create_update(const create_update_context& context) const override;
virtual read_context_ptr foreign_read (const read_context& context, bool fake_context) const override;

/* statements */
virtual ::cppmariadb::statement& get_statement_foreign_one_delete(bool key_known) const override;
virtual ::cppmariadb::statement& get_statement_foreign_many_update() const override;

private:
using statement_ptr = std::unique_ptr<::cppmariadb::statement>;

mutable statement_ptr _statement_foreign_one_delete_key_known;
mutable statement_ptr _statement_foreign_one_delete_key_unknown;
mutable statement_ptr _statement_foreign_many_update;
};

}
end_namespace_cpphibernate_driver_mariadb

+ 0
- 228
include/cpphibernate/driver/mariadb/schema/field.inl Целия файл

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

#include <cpphibernate/driver/mariadb/schema/field.h>
#include <cpphibernate/driver/mariadb/impl/create_update.h>

beg_namespace_cpphibernate_driver_mariadb
{

/* simple_field_t */

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

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

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

/* value_field_t */

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

this->type = type_props::type();

if (type_props::convert_to_open())
this->convert_to_open = this->convert_to_open + type_props::convert_to_open();
if (type_props::convert_to_close())
this->convert_to_close = type_props::convert_to_close() + this->convert_to_close;
if (type_props::convert_from_open())
this->convert_from_open = this->convert_from_open + type_props::convert_from_open();
if (type_props::convert_from_close())
this->convert_from_close = type_props::convert_from_close() + this->convert_from_close;
}

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

template<typename T_field>
void value_field_t<T_field>
::set(const data_context& context, const value_t& value) const
{
auto& dataset = context.get<dataset_type>();
this->field.setter(dataset, type_props::convert_to(value));
}

/* primary_key_field_t */

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

this->value_is_auto_incremented = key_props::auto_generated::value;
}

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

template<typename T_field>
std::string primary_key_field_t<T_field>
::generate_value(::cppmariadb::connection& connection) const
{
auto ret = connection.execute_used(key_props::create_key_query);
if (!ret || !ret->next())
throw misc::hibernate_exception("unable to generate key value!");
return ret->current()->at(0).template get<std::string>();
}

/* foreign_table_field_t */

template<typename T_field>
value_t foreign_table_field_t<T_field>
::foreign_create_update(const create_update_context& context) const
{
auto& dataset = context.get<dataset_type>();
auto& foreign = this->field.getter(dataset);
auto next_context = change_context(context, foreign);

using foreign_dataset_type = mp::decay_t<decltype(foreign)>;
return create_update_impl_t<foreign_dataset_type>::apply(
next_context,
false);
}

template<typename T_field>
read_context_ptr foreign_table_field_t<T_field>
::foreign_read(const read_context& context, bool fake_context) const
{
if (!fake_context)
{
auto& dataset = context.get<dataset_type>();
auto& member = this->field.getter(dataset);
auto new_context = make_read_context(member, context.schema, context.connection, context.filter);
using context_type = mp::decay_t<decltype(new_context)>;
return std::make_unique<context_type>(new_context);
}
else
{
auto new_context = make_fake_context(hana::type_c<value_type>, context.schema, context.connection, context.filter);
using context_type = mp::decay_t<decltype(new_context)>;
return std::make_unique<context_type>(new_context);
}
}

template<typename T_field>
::cppmariadb::statement& foreign_table_field_t<T_field>
::get_statement_foreign_one_delete(bool key_known) const
{
return base_type::get_statement_foreign_one_delete_impl(
key_known,
_statement_foreign_one_delete_key_known,
_statement_foreign_one_delete_key_unknown);
}

template<typename T_field>
::cppmariadb::statement& foreign_table_field_t<T_field>
::get_statement_foreign_many_update() const
{ return base_type::get_statement_foreign_many_update_impl(_statement_foreign_many_update); }

namespace __impl
{

/* is_primary_key_field */

template<typename T_field>
struct is_primary_key_field
: public mp::decay_t<decltype(
hana::contains(
std::declval<T_field>().attributes,
schema::attribute::primary_key))>
{ };

/* is_foreign_table_field */

template<typename T_schema, typename T_field>
struct is_foreign_table_field
: public mp::decay_t<decltype(
hana::contains(
hana::transform(
std::declval<T_schema>().tables,
schema::table::get_wrapped_dataset),
hana::type_c<misc::real_dataset_t<typename T_field::getter_type::value_type>>))>
{ };

/* field_type */

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

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

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

template<typename T_schema, typename T_field>
using field_type_t = typename field_type<T_schema, T_field>::type;

/* make_field_impl */

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

template<typename T_schema, typename T_table, typename T_field>
struct make_field_impl<
mp::list<T_schema, T_table, T_field>,
mp::enable_if_c<
schema::is_schema<mp::decay_t<T_schema>>::value
&& schema::is_table <mp::decay_t<T_table >>::value
&& schema::is_field <mp::decay_t<T_field >>::value>>
{
static constexpr decltype(auto) apply(const T_schema& schema, const T_table& table, const T_field& field)
{
using schema_type = mp::decay_t<T_schema>;
using field_type = mp::decay_t<T_field>;
using return_type = field_type_t<schema_type, field_type>;
using primary_key_type = primary_key_field_t<field_type>;
return_type ret(field);
ret.schema_name = schema.name;
ret.table_name = table.name;
ret.field_name = field.name;
ret.attributes = make_attributes(field.attributes);
hana::eval_if(
hana::equal(hana::type_c<return_type>, hana::type_c<primary_key_type>),
[&ret](){
ret.field_name = ret.table_name + "_" + ret.field_name;
}, [](){ });
return ret;
}
};

}

}
end_namespace_cpphibernate_driver_mariadb

+ 0
- 29
include/cpphibernate/driver/mariadb/schema/fields.fwd.h Целия файл

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

#include <vector>

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

beg_namespace_cpphibernate_driver_mariadb
{

/* fields_t */

struct fields_t;

/* make_fields */

namespace __impl
{

template<typename T, typename = void>
struct make_fields_impl;

}

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

}
end_namespace_cpphibernate_driver_mariadb

+ 0
- 25
include/cpphibernate/driver/mariadb/schema/fields.h Целия файл

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

#include <vector>

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

beg_namespace_cpphibernate_driver_mariadb
{

/* fields_t */

struct fields_t
: public std::vector<field_ptr_t>
{
using base_type = std::vector<field_ptr_t>;
using base_type::base_type;
};

}
end_namespace_cpphibernate_driver_mariadb

+ 0
- 55
include/cpphibernate/driver/mariadb/schema/fields.inl Целия файл

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

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

beg_namespace_cpphibernate_driver_mariadb
{

namespace __impl
{

/* make_fields_impl */

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

template<typename T_schema, typename T_table>
struct make_fields_impl<
mp::list<T_schema, T_table>,
mp::enable_if_c<
schema::is_schema<mp::decay_t<T_schema>>::value
&& schema::is_table <mp::decay_t<T_table >>::value>>
{
template<typename T_index>
static constexpr void emplace(fields_t& fields, const T_schema& schema, const T_table& table, T_index&& index)
{
decltype(auto) field = make_field(schema, table, table.fields[index]);
using field_type = mp::decay_t<decltype(field)>;
fields.emplace_back(new field_type(std::move(field)));
}

template<size_t... I>
static auto helper(const T_schema& schema, const T_table& table, std::index_sequence<I...>&&)
{
fields_t fields;
int dummy[] = {0, (emplace(fields, schema, table, hana::size_c<I>), void(), 0)...};
(void) dummy;
return fields;
}

static constexpr decltype(auto) apply(const T_schema& schema, const T_table& table)
{
using size = decltype(hana::size(table.fields));
return helper(schema, table, std::make_index_sequence<size::value> { });
}
};

}

}
end_namespace_cpphibernate_driver_mariadb

Някои файлове не бяха показани, защото твърде много файлове са промени

Зареждане…
Отказ
Запис