From 059d13658c1e6108363a809e0f509685fb8e2285 Mon Sep 17 00:00:00 2001 From: bergmann Date: Mon, 15 Oct 2018 21:34:53 +0200 Subject: [PATCH] * Added readme and license files * Fixed cmake files --- .gitignore | 2 + .gitmodules | 3 + CMakeLists.txt | 4 +- LICENSE.txt | 21 +++ README.md | 279 +++++++++++++++++++++++++++++++++++++ cmake/Findcppmariadb.cmake | 46 ++++++ cmake/Findcpputils.cmake | 46 ++++++ cmake/Findmariadb.cmake | 34 +++++ cmake/modules | 1 + 9 files changed, 435 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 cmake/Findcppmariadb.cmake create mode 100644 cmake/Findcpputils.cmake create mode 100644 cmake/Findmariadb.cmake create mode 160000 cmake/modules diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..608b1d4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.vscode/ +build/ \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..a89889c --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "cmake/modules"] + path = cmake/modules + url = b3rgmann@git.bergmann89.de:cpp/CmakeModules.git diff --git a/CMakeLists.txt b/CMakeLists.txt index aa2756a..1de3577 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,9 @@ 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}/../../../inc/cmake/") +Set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/" ) # Projects ######################################################################################## diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..aa0da62 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Erik Junghanns (aka Bergmann89) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..4ba0e72 --- /dev/null +++ b/README.md @@ -0,0 +1,279 @@ +# cpphibernate + +A C++17 library to serialize and deserialize C++ objects to a MYSQL/MARIADB database. + +## Getting Started + +### Prerequisites + +Before you can use cpphibernate you need to download and install [the official mariadb C connector](https://downloads.mariadb.org/connector-c/)) and [the boost/hana library](https://github.com/boostorg/hana). And if you want to run the tests you additionally need [the google testing framework](https://github.com/google/googletest). + +[The cpputils libary](https://git.bergmann89.de/cpp/cpputils) and [the cppmariadb library](https://github.com/Bergmann89/cppmariadb) will be automatically downladed during the build. + +### Small Usage Example + +```cpp +#include +#include +#include +#include +#include +#include +#include + +/* define a test enum */ + +enum class test_enum +{ + test0, + test1, + test2, + test3, + + first = test0, + last = test3, +}; + +/* define the enum to string mapping for the test enum */ + +DEFINE_ENUM_TO_STRING_MAP( + test_enum, + { test_enum::test0, "test0" }, + { test_enum::test1, "test1" }, + { test_enum::test2, "test2" }, + { test_enum::test3, "test3" } +); + +DEFINE_STRING_TO_ENUM_MAP( + test_enum, + invariant_string_less, + { "test0", test_enum::test0 }, + { "test1", test_enum::test1 }, + { "test2", test_enum::test2 }, + { "test3", test_enum::test3 } +); + +/* define some normal C++ structs/classes */ + +struct test1 +{ + size_t id; + std::string str_data; + ::cpphibernate::string<64> str64_data; + + utl::nullable u32_nullable; + std::unique_ptr u32_ptr_u; + std::shared_ptr u32_ptr_s; +}; + +struct test2 +{ + size_t id; + uint8_t u8_data; + int8_t i8_data; + uint16_t u16_data; + int16_t i16_data; +}; + +struct test3 +{ + size_t id; + uint32_t u32_data; + int32_t i32_data; + uint64_t u64_data; + int64_t i64_data; +}; + +struct base +{ + ::cpphibernate::uuid id; + std::string name; + + virtual ~base() = default; +}; + +struct derived1 + : public base +{ + ::cpphibernate::uuid derived1_id; + test1 test1_data; + test_enum enum_data; +}; + +struct derived2 + : public base +{ + ::cpphibernate::uuid derived2_id; + utl::nullable test2_nullable; + std::unique_ptr test2_ptr_u; + std::shared_ptr test2_ptr_s; +}; + +struct derived3 + : public derived2 +{ + ::cpphibernate::uuid derived3_id; + std::list test3_list; + std::vector test3_vector; +}; + +/* create the database schema */ + +constexpr decltype(auto) test_schema = cpphibernate_make_schema( + test, // this is the schema name + cpphibernate_make_table_name( + tbl_test1, // this is the table name + test1, // this is the referenced class + 1, // a unique id for the table + cpphibernate_make_id (&test1::id), // pointer to the ID member + cpphibernate_make_field (test1, str_data), // define a normal member field + cpphibernate_make_field (test1, str64_data), // [...] + cpphibernate_make_field (test1, u32_nullable), // [...] + cpphibernate_make_field (test1, u32_ptr_u), // [...] + cpphibernate_make_field (test1, u32_ptr_s) // [...] + ), + cpphibernate_make_table_name( + tbl_test2, + test2, + 2, + cpphibernate_make_id (&test2::id), + cpphibernate_make_field (test2, u8_data), + cpphibernate_make_field (test2, i8_data), + cpphibernate_make_field (test2, u16_data), + cpphibernate_make_field (test2, i16_data) + ), + cpphibernate_make_table_name( + tbl_test3, + test3, + 3, + cpphibernate_make_id (&test3::id), + cpphibernate_make_field (test3, u32_data), + cpphibernate_make_field (test3, i32_data), + cpphibernate_make_field (test3, u64_data), + cpphibernate_make_field (test3, i64_data) + ), + + cpphibernate_make_table_name( + tbl_base, + base, + 10, + cpphibernate_make_id (&base::id), + cpphibernate_make_field (base, name) + ), + cpphibernate_make_table_name( + tbl_derived1, + derived1, + 11, + cpphibernate_make_id (&derived1::derived1_id), + cpphibernate_make_field (derived1, test1_data), + cpphibernate_make_field (derived1, enum_data) + ), + cpphibernate_make_table_name( + tbl_derived2, + derived2, + 12, + cpphibernate_make_id (&derived2::derived2_id), + cpphibernate_make_field (derived2, test2_nullable), + cpphibernate_make_field (derived2, test2_ptr_u), + cpphibernate_make_field (derived2, test2_ptr_s) + ), + cpphibernate_make_table_name( + tbl_derived3, + derived3, + 13, + cpphibernate_make_id (&derived3::derived3_id), + cpphibernate_make_field (derived3, test3_list), + cpphibernate_make_field (derived3, test3_vector) + ) +); + +int main(int argc, char** argv) +{ + try + { + using namespace ::cppmariadb; + using namespace ::cpphibernate; + + /* establish connection to database */ + connection c = database::connect("localhost", 3306, "testuser", "password", "", client_flags::empty()); + + /* create a hibernation context */ + auto context = make_context_ptr(test_schema, c); + + /* initialize the database schema */ + context.init(); + + /* create some test data */ + derived3 d3; + d3.name = "derived3"; + d3.test3_list.emplace_back(); + d3.test3_list.back().u32_data = 100; + d3.test3_list.back().i32_data = 101; + d3.test3_list.back().u64_data = 102; + d3.test3_list.back().i64_data = 103; + d3.test3_list.emplace_back(); + d3.test3_list.back().u32_data = 110; + d3.test3_list.back().i32_data = 111; + d3.test3_list.back().u64_data = 112; + d3.test3_list.back().i64_data = 113; + d3.test3_vector.emplace_back(); + d3.test3_vector.back().u32_data = 200; + d3.test3_vector.back().i32_data = 201; + d3.test3_vector.back().u64_data = 202; + d3.test3_vector.back().i64_data = 203; + d3.test3_vector.emplace_back(); + d3.test3_vector.back().u32_data = 210; + d3.test3_vector.back().i32_data = 211; + d3.test3_vector.back().u64_data = 212; + d3.test3_vector.back().i64_data = 213; + d3.test3_vector.emplace_back(); + d3.test3_vector.back().u32_data = 220; + d3.test3_vector.back().i32_data = 221; + d3.test3_vector.back().u64_data = 222; + d3.test3_vector.back().i64_data = 223; + + /* create a new dataset in the database: + * the new IDs of the object are stored in the corresponding members */ + context.create(d3); + + /* read back the created object: + * if no selector is passed here, the ID member of the object is used */ + context.read(d3); + + /* if we pass a pointer to the read method, the suitable object is created automatically */ + using namespace ::boost::hana::literals; + using namespace ::cpphibernate::modifier; + using base_ptr_u = std::unique_ptr; + + base_ptr_u b; + constexpr decltype(auto) base_key_field = test_schema.tables[3_c].fields[0_c]; + + context.read(b, where(equal(base_key_field, d3.id))); + auto * d3_ptr = dynamic_cast(b.get()); + if (d3_ptr) + { + /* do something with the data */ + } + + /* this also works for containers of pointers */ + using base_vector = std::vector; + base_vector vec; + context.read(vec); + for (auto& ptr : vec) + { + /* do something with the data */ + } + + return 0; + } + catch(const std::exception& ex) + { + std::cout << ex.what() << std::endl; + } + return 1 +} +``` + +## License + +This project is licensed under the MIT License - see the [LICENSE.txt](LICENSE.txt) file for details \ No newline at end of file diff --git a/cmake/Findcppmariadb.cmake b/cmake/Findcppmariadb.cmake new file mode 100644 index 0000000..a13a828 --- /dev/null +++ b/cmake/Findcppmariadb.cmake @@ -0,0 +1,46 @@ +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= + -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 ( ) \ No newline at end of file diff --git a/cmake/Findcpputils.cmake b/cmake/Findcpputils.cmake new file mode 100644 index 0000000..1fac201 --- /dev/null +++ b/cmake/Findcpputils.cmake @@ -0,0 +1,46 @@ +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= + -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 ( ) \ No newline at end of file diff --git a/cmake/Findmariadb.cmake b/cmake/Findmariadb.cmake new file mode 100644 index 0000000..8f934a6 --- /dev/null +++ b/cmake/Findmariadb.cmake @@ -0,0 +1,34 @@ +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 ( ) diff --git a/cmake/modules b/cmake/modules new file mode 160000 index 0000000..b125a1a --- /dev/null +++ b/cmake/modules @@ -0,0 +1 @@ +Subproject commit b125a1a176ae0aada1cd2ec90919061d202dcea9