| @@ -1,15 +1,57 @@ | |||||
| # Initialize CMake ################################################################################ | # 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()); | connection c = database::connect("localhost", 3306, "testuser", "password", "", client_flags::empty()); | ||||
| /* create a hibernation context */ | /* 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 */ | /* initialize the database schema */ | ||||
| context.init(); /* CREATE SCHEMA IF NOT EXISTS `test_schema` DEFAULT CHARACTER SET utf8; | 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()); | connection c = database::connect("localhost", 3306, "testuser", "password", "", client_flags::empty()); | ||||
| /* create a hibernation context */ | /* 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 */ | /* initialize the database schema */ | ||||
| context.init(); | context.init(); | ||||
| @@ -405,4 +405,4 @@ int main(int argc, char** argv) | |||||
| ## License | ## 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 | #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 | #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 | #pragma once | ||||
| #include <cpphibernate/config.h> | #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 | #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 | namespace __impl | ||||
| { | { | ||||
| @@ -25,10 +28,10 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| struct attribute_converter<schema::attribute::primary_key_type> | struct attribute_converter<schema::attribute::primary_key_type> | ||||
| { static constexpr decltype(auto) value = attribute_t::primary_key; }; | { static constexpr decltype(auto) value = attribute_t::primary_key; }; | ||||
| /* make_attributes_impl */ | |||||
| /* attributes_builder */ | |||||
| template<typename T, typename> | template<typename T, typename> | ||||
| struct make_attributes_impl | |||||
| struct attributes_builder | |||||
| { | { | ||||
| template<typename... T_args> | template<typename... T_args> | ||||
| static constexpr decltype(auto) apply(T_args&&... args) | static constexpr decltype(auto) apply(T_args&&... args) | ||||
| @@ -36,10 +39,9 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| }; | }; | ||||
| template<typename T_attributes> | template<typename T_attributes> | ||||
| struct make_attributes_impl< | |||||
| struct attributes_builder< | |||||
| mp::list<T_attributes>, | 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> | template<size_t... I> | ||||
| static constexpr decltype(auto) helper(T_attributes&&, const std::index_sequence<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 | #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 | #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> | 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 | #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> | template<typename T, typename = void> | ||||
| struct type_properties | 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 | #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 | #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> | 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 | #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> | 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 | #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 */ | /* limit_builder */ | ||||
| @@ -21,18 +20,18 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| hana::for_each(p_modifier, [&limit, &offset](auto& x_modifier){ | hana::for_each(p_modifier, [&limit, &offset](auto& x_modifier){ | ||||
| using modifier_type = mp::decay_t<decltype(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( | hana::eval_if( | ||||
| is_limit_type { }, | is_limit_type { }, | ||||
| [&limit, &x_modifier](auto _){ | [&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](){ | [&offset, &x_modifier](){ | ||||
| hana::eval_if( | hana::eval_if( | ||||
| is_offset_type { }, | is_offset_type { }, | ||||
| [&offset, &x_modifier](auto _){ | [&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 */ | /* no-op */ | ||||
| @@ -61,5 +60,4 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| return builder.statement; | return builder.statement; | ||||
| } | } | ||||
| } | |||||
| end_namespace_cpphibernate_driver_mariadb | |||||
| } } | |||||
| @@ -1,12 +1,11 @@ | |||||
| #pragma once | #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 */ | /* order_by_builder */ | ||||
| @@ -30,20 +29,20 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| size_t index = 0; | size_t index = 0; | ||||
| hana::for_each(modifiers, [&](auto& modifier){ | hana::for_each(modifiers, [&](auto& modifier){ | ||||
| using modifier_type = mp::decay_t<decltype(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( | hana::eval_if( | ||||
| is_order_by_type { }, | is_order_by_type { }, | ||||
| [&](auto _){ | [&](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 "; | if (index++ == 0) os << "ORDER_BY "; | ||||
| else os << ", "; | else os << ", "; | ||||
| auto& field = schema.field(misc::get_type_id(f.wrapped_field)); | |||||
| auto& field = schema.field(get_type_id(dir.wrapped_field)); | |||||
| os << "`" | os << "`" | ||||
| << field.table_name | |||||
| << field.table.name | |||||
| << "`.`" | << "`.`" | ||||
| << field.field_name | |||||
| << field.name | |||||
| << "` " | << "` " | ||||
| << (is_ascencing_type::value | << (is_ascencing_type::value | ||||
| ? "ASC" | ? "ASC" | ||||
| @@ -79,5 +78,4 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| return builder.assign(schema, modifiers); | return builder.assign(schema, modifiers); | ||||
| } | } | ||||
| } | |||||
| end_namespace_cpphibernate_driver_mariadb | |||||
| } } | |||||
| @@ -1,12 +1,13 @@ | |||||
| #pragma once | #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 */ | /* where_builder */ | ||||
| @@ -27,7 +28,7 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| template<typename T_clause> | template<typename T_clause> | ||||
| inline auto build_clause(T_clause&& p_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 << "("; | os << "("; | ||||
| build_clause(p_clause.clauses[hana::size_c<0>]); | build_clause(p_clause.clauses[hana::size_c<0>]); | ||||
| @@ -43,7 +44,7 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| template<typename T_clause> | template<typename T_clause> | ||||
| inline auto build_clause(T_clause&& p_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 << "("; | os << "("; | ||||
| build_clause(p_clause.clauses[hana::size_c<0>]); | build_clause(p_clause.clauses[hana::size_c<0>]); | ||||
| @@ -59,7 +60,7 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| template<typename T_clause> | template<typename T_clause> | ||||
| inline auto build_clause(T_clause&& p_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 ("; | os << "NOT ("; | ||||
| build_clause(p_clause.clause); | build_clause(p_clause.clause); | ||||
| @@ -68,14 +69,14 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| template<typename T_clause> | template<typename T_clause> | ||||
| inline auto build_clause(T_clause&& p_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); | auto& field = schema.field(field_id); | ||||
| os << "`" | os << "`" | ||||
| << field.table_name | |||||
| << field.table.name | |||||
| << "`.`" | << "`.`" | ||||
| << field.field_name | |||||
| << field.name | |||||
| << "`=" | << "`=" | ||||
| << field.convert_to_open | << field.convert_to_open | ||||
| << "?\?" | << "?\?" | ||||
| @@ -87,7 +88,7 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| size_t index = 0; | size_t index = 0; | ||||
| hana::for_each(modifiers, [&](auto& modifier){ | hana::for_each(modifiers, [&](auto& modifier){ | ||||
| using modifier_type = mp::decay_t<decltype(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( | hana::eval_if( | ||||
| is_where_type { }, | is_where_type { }, | ||||
| [&](auto _){ | [&](auto _){ | ||||
| @@ -115,9 +116,9 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| template<typename T_clause> | template<typename T_clause> | ||||
| inline auto assign_clause(T_clause&& p_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) { | hana::for_each(std::forward<T_clause>(p_clause).clauses, [&](auto& x_clause) { | ||||
| assign_clause(x_clause); | assign_clause(x_clause); | ||||
| @@ -126,14 +127,14 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| template<typename T_clause> | template<typename T_clause> | ||||
| inline auto assign_clause(T_clause&& p_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); | assign_clause(std::forward<T_clause>(p_clause).clause); | ||||
| } | } | ||||
| template<typename T_clause> | template<typename T_clause> | ||||
| inline auto assign_clause(T_clause&& p_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); | statement.set(index, std::forward<T_clause>(p_clause).value); | ||||
| ++index; | ++index; | ||||
| @@ -143,7 +144,7 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| { | { | ||||
| hana::for_each(modifiers, [&](auto& modifier){ | hana::for_each(modifiers, [&](auto& modifier){ | ||||
| using modifier_type = mp::decay_t<decltype(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( | hana::eval_if( | ||||
| is_where_type { }, | is_where_type { }, | ||||
| [&](auto _){ | [&](auto _){ | ||||
| @@ -178,5 +179,4 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| return builder.assign(schema, modifiers); | 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 | #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 | namespace __impl | ||||
| { | { | ||||
| /* filter_add_element_impl */ | /* filter_add_element_impl */ | ||||
| template<typename T, typename> | |||||
| template<typename X, typename = void> | |||||
| struct filter_add_element_impl | struct filter_add_element_impl | ||||
| { | { | ||||
| template<typename... T_args> | template<typename... T_args> | ||||
| static constexpr decltype(auto) apply(T_args&&... 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> | template<typename T_table> | ||||
| struct filter_add_element_impl< | struct filter_add_element_impl< | ||||
| mp::list<filter_t&, const schema_t&, T_table>, | 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) | 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); | auto& t = schema.table(dataset_id); | ||||
| filter.tables.emplace(&t); | filter.tables.emplace(&t); | ||||
| for (auto& ptr : t.fields) | for (auto& ptr : t.fields) | ||||
| @@ -40,18 +48,20 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| template<typename T_field> | template<typename T_field> | ||||
| struct filter_add_element_impl< | struct filter_add_element_impl< | ||||
| mp::list<filter_t&, const schema_t&, T_field>, | 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) | 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); | auto& f = schema.field(field_id); | ||||
| filter.fields.emplace(&f); | filter.fields.emplace(&f); | ||||
| filter.tables.emplace(f.table); | filter.tables.emplace(f.table); | ||||
| } | } | ||||
| }; | }; | ||||
| constexpr decltype(auto) filter_add_element = ::cppmp::generic_predicate<__impl::filter_add_element_impl> { }; | |||||
| } | } | ||||
| /* filter_t */ | /* filter_t */ | ||||
| @@ -77,7 +87,7 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| { | { | ||||
| clear(); | clear(); | ||||
| exclusive = false; | 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)... }; | int dummy[] = { 0, (__impl::filter_add_element(*this, schema, std::forward<T_args>(args)), void(), 0)... }; | ||||
| (void)dummy; | (void)dummy; | ||||
| } | } | ||||
| @@ -87,7 +97,7 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| { | { | ||||
| clear(); | clear(); | ||||
| exclusive = true; | 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)... }; | int dummy[] = { 0, (__impl::filter_add_element(*this, schema, std::forward<T_args>(args)), void(), 0)... }; | ||||
| (void)dummy; | (void)dummy; | ||||
| @@ -118,5 +128,4 @@ beg_namespace_cpphibernate_driver_mariadb | |||||
| tables.clear(); | 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 | |||||