| @@ -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 ) | |||
| @@ -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 | |||
| @@ -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 ( ) | |||
| @@ -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 ( ) | |||
| @@ -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 ( ) | |||
| @@ -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 | |||
| @@ -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") | |||
| @@ -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 ) | |||
| @@ -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 @@ | |||
| Subproject commit b125a1a176ae0aada1cd2ec90919061d202dcea9 | |||
| Subproject commit 1a32531aef2deeebd5637b1873bc4e976628801c | |||
| @@ -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 ) | |||
| @@ -1 +0,0 @@ | |||
| #cmakedefine CPPHIBERNATE_DEBUG | |||
| @@ -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" | |||
| @@ -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 | |||
| @@ -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" | |||
| @@ -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); | |||
| } | |||
| @@ -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)...)); | |||
| } | |||
| } | |||
| @@ -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 | |||
| @@ -0,0 +1,6 @@ | |||
| #pragma once | |||
| #include "classes/attributes.h" | |||
| #include "classes/fields.h" | |||
| #include "classes/tables.h" | |||
| #include "classes/schema.h" | |||
| @@ -0,0 +1,5 @@ | |||
| #pragma once | |||
| #include "attributes/attributes.h" | |||
| #include "attributes/attributes.inl" | |||
| @@ -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> { }; | |||
| } } | |||
| @@ -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 | |||
| } } | |||
| @@ -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" | |||
| @@ -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> { }; | |||
| } } | |||
| @@ -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); | |||
| } | |||
| }; | |||
| } | |||
| } } | |||
| @@ -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); | |||
| }; | |||
| } } | |||
| @@ -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) | |||
| { } | |||
| } } | |||
| @@ -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; | |||
| }; | |||
| } } | |||
| @@ -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)); | |||
| } | |||
| } | |||
| } } | |||
| @@ -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; | |||
| }; | |||
| } } | |||
| @@ -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>(); | |||
| } | |||
| } } | |||
| @@ -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); | |||
| }; | |||
| } } | |||
| @@ -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) | |||
| { } | |||
| } } | |||
| @@ -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; | |||
| }; | |||
| } } | |||
| @@ -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)); | |||
| } | |||
| } } | |||
| @@ -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> { }; | |||
| } } | |||
| @@ -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> { }); | |||
| } | |||
| }; | |||
| } | |||
| } } | |||
| @@ -0,0 +1,5 @@ | |||
| #pragma once | |||
| #include "schema/schema.h" | |||
| #include "schema/schema.inl" | |||
| @@ -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> { }; | |||
| } } | |||
| @@ -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); } | |||
| }; | |||
| } | |||
| } } | |||
| @@ -0,0 +1 @@ | |||
| #pragma once | |||
| @@ -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> { }; | |||
| } } | |||
| @@ -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 { }); | |||
| } | |||
| }; | |||
| } | |||
| } } | |||
| @@ -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; | |||
| }; | |||
| } } | |||
| @@ -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); | |||
| }); | |||
| } | |||
| } } | |||
| @@ -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&&); | |||
| }; | |||
| } } | |||
| @@ -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) | |||
| { } | |||
| } } | |||
| @@ -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> { }; | |||
| } } | |||
| @@ -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> { }); | |||
| } | |||
| }; | |||
| } | |||
| } } | |||
| @@ -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" | |||
| @@ -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); | |||
| }; | |||
| } } | |||
| @@ -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) | |||
| { } | |||
| } } | |||
| @@ -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; | |||
| }; | |||
| } } | |||
| @@ -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); } | |||
| } } | |||
| @@ -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; | |||
| }; | |||
| } } | |||
| @@ -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; | |||
| } | |||
| }; | |||
| } | |||
| } } | |||
| @@ -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); | |||
| }; | |||
| } } | |||
| @@ -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) | |||
| { } | |||
| } } | |||
| @@ -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); | |||
| }; | |||
| } } | |||
| @@ -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) | |||
| { } | |||
| } } | |||
| @@ -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> { }; | |||
| } } | |||
| @@ -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)...); } | |||
| }; | |||
| } | |||
| } } | |||
| @@ -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; | |||
| }; | |||
| } } | |||
| @@ -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; } | |||
| } } | |||
| @@ -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" | |||
| @@ -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; | |||
| }; | |||
| } } | |||
| @@ -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(); | |||
| } | |||
| }; | |||
| } } | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| } } | |||
| @@ -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; } | |||
| }; | |||
| } } | |||
| @@ -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; | |||
| }; | |||
| } } | |||
| @@ -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(); } | |||
| }; | |||
| } } | |||
| @@ -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 | |||
| @@ -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 | |||
| } } | |||
| @@ -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; } | |||
| }; | |||
| } } | |||
| @@ -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" | |||
| @@ -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 | |||
| } } | |||
| @@ -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; | |||
| } | |||
| }; | |||
| } } | |||
| @@ -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 | |||
| } } | |||
| @@ -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(); | |||
| } | |||
| }; | |||
| } } | |||
| @@ -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; | |||
| }; | |||
| } } | |||
| @@ -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)); | |||
| } | |||
| } } | |||
| @@ -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 | |||
| } } | |||
| @@ -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 | |||
| } } | |||
| @@ -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 | |||
| } } | |||
| @@ -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(); | |||
| }; | |||
| } } | |||
| @@ -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 | |||
| } } | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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> | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||