diff --git a/.docker/Dockerfile b/.docker/Dockerfile index b894c62ae3953b96aca1e3a88da795d4c8f13a69..df8ef0a9f18f5754eae33686e832bd88f37da9de 100644 --- a/.docker/Dockerfile +++ b/.docker/Dockerfile @@ -1,9 +1,9 @@ -FROM debian:buster-backports +FROM debian:bullseye RUN apt-get update -RUN apt-get install -y cmake/buster-backports +RUN apt-get install -y cmake RUN apt-get install -y lcov -RUN apt-get install -y doxygen +RUN apt-get install -y doxygen graphviz RUN apt-get install -y clang-format-11 clang-tidy-11 RUN apt-get install -y python3-pip RUN apt-get install -y git diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 334ff10baab25ac2ea08bec30592858282f6c3d2..ff1db6df2ede12b6254e3c9ad1841fe1a3603061 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -85,9 +85,6 @@ test: - mkdir build - cd build - conan install .. -s "compiler.libcxx=libstdc++11" - - FILE_TO_BE_PATCHED="$(grep "std::unique_ptr<ContextAllocator> context_allocator) {}" -l -r $(conan config home))" - - echo "FILE_TO_BE_PATCHED=$FILE_TO_BE_PATCHED" - - sed -e "s|std::unique_ptr<ContextAllocator> context_allocator) {}|std::unique_ptr<ContextAllocator> /*context_allocator*/) {}|" -i $FILE_TO_BE_PATCHED - cmake -DCMAKE_BUILD_TYPE=Debug .. - cmake --build . -j - cmake --build . -j --target unit_test_coverage @@ -143,12 +140,8 @@ trigger_inttest: tags: [ cached-dind ] stage: deploy script: - - mkdir -p build - - cd build - - conan install .. -s "compiler.libcxx=libstdc++11" - - cmake .. - - cmake --build . --target doc-sphinx - - cp -r doc/sphinx_out ../public + - make doc + - cp -r build/doc/sphinx_out ./public test_pages: <<: *pages_prepare diff --git a/.gitlab/merge_request_templates/Default.md b/.gitlab/merge_request_templates/Default.md deleted file mode 100644 index 2edadf6ab65b6adf75ab11af00b4d3e6eaf0be75..0000000000000000000000000000000000000000 --- a/.gitlab/merge_request_templates/Default.md +++ /dev/null @@ -1,49 +0,0 @@ -# Summary - - Insert a meaningful description for this merge request here. What is the - new/changed behavior? Which bug has been fixed? Are there related Issues? - -# Focus - - Point the reviewer to the core of the code change. Where should they start - reading? What should they focus on (e.g. security, performance, - maintainability, user-friendliness, compliance with the specs, finding more - corner cases, concrete questions)? - -# Test Environment - - How to set up a test environment for manual testing? - -# Check List for the Author - -Please, prepare your MR for a review. Be sure to write a summary and a -focus and create gitlab comments for the reviewer. They should guide the -reviewer through the changes, explain your changes and also point out open -questions. For further good practices have a look at [our review -guidelines](https://gitlab.com/caosdb/caosdb/-/blob/dev/REVIEW_GUIDELINES.md) - -- [ ] All automated tests pass -- [ ] Reference related Issues -- [ ] Up-to-date CHANGELOG.md -- [ ] Annotations in code (Gitlab comments) - - Intent of new code - - Problems with old code - - Why this implementation? - - -# Check List for the Reviewer - - -- [ ] I understand the intent of this MR -- [ ] All automated tests pass -- [ ] Up-to-date CHANGELOG.md -- [ ] The test environment setup works and the intended behavior is - reproducible in the test environment -- [ ] In-code documentation and comments are up-to-date. -- [ ] Check: Are there specifications? Are they satisfied? - -For further good practices have a look at [our review guidelines](https://gitlab.com/caosdb/caosdb/-/blob/dev/REVIEW_GUIDELINES.md). - - -/assign me -/target_branch dev diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 3bdcb8c0730e90929ce25970850b0c801f1f6d09..0000000000000000000000000000000000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,28 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [0.0.13 - Unreleased] - -### Added - -* New functions getEnumNameFromValue() and getEnumValueFromName(). -* Extern C now supports the full C++ functionalities. - -### Changed - -* Integer values are 32 bit now. - -### Deprecated - -### Removed - -### Fixed - -* #11 - Transaction::GetResultSet() now always returns a valid reference. -* #25 - Compiles on MacOS with LLVM now. - -### Security diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 120000 index 0000000000000000000000000000000000000000..52021680982ec168143600ae885f4a944616be7f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1 @@ +doc/CHANGELOG.md \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 0176a56635fbd890d3e71f8161ba2cc736aa27e9..7ee6d193f6814d1d24eb8cb35e3658a87d00e601 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,11 +20,11 @@ cmake_minimum_required(VERSION 3.13) -set(libcaosdb_VERSION 0.0.20) +set(libcaosdb_VERSION 0.1.3) set(libcaosdb_COMPATIBLE_SERVER_VERSION_MAJOR 0) -set(libcaosdb_COMPATIBLE_SERVER_VERSION_MINOR 5) -set(libcaosdb_COMPATIBLE_SERVER_VERSION_PATCH 0) -set(libcaosdb_COMPATIBLE_SERVER_VERSION_PRE_RELEASE "GRPC${libcaosdb_VERSION}") +set(libcaosdb_COMPATIBLE_SERVER_VERSION_MINOR 7) +set(libcaosdb_COMPATIBLE_SERVER_VERSION_PATCH 3) +set(libcaosdb_COMPATIBLE_SERVER_VERSION_PRE_RELEASE "") project(libcaosdb VERSION ${libcaosdb_VERSION} @@ -79,8 +79,8 @@ add_subdirectory(doc) # Protobuf/Grpc source files set(PROTO_FILES - ${PROJECT_SOURCE_DIR}/proto/proto/caosdb/info/v1alpha1/main.proto - ${PROJECT_SOURCE_DIR}/proto/proto/caosdb/entity/v1alpha1/main.proto + ${PROJECT_SOURCE_DIR}/proto/proto/caosdb/info/v1/main.proto + ${PROJECT_SOURCE_DIR}/proto/proto/caosdb/entity/v1/main.proto ) set(PROTO_PATH ${PROJECT_SOURCE_DIR}/proto/proto) @@ -157,6 +157,8 @@ if("${CMAKE_BUILD_TYPE}" MATCHES "Debug") $<BUILD_INTERFACE:${libcaosdb_BINARY_DIR}/include> $<INSTALL_INTERFACE:include> + ) + target_include_directories(caosdb_grpc SYSTEM PUBLIC ${CONAN_INCLUDE_DIRS} ) else() @@ -166,30 +168,47 @@ else() endif() target_link_libraries(caosdb ${CONAN_LIBS} + stdc++fs ) target_include_directories(caosdb PUBLIC $<BUILD_INTERFACE:${libcaosdb_SOURCE_DIR}/include> $<BUILD_INTERFACE:${libcaosdb_BINARY_DIR}/include> $<INSTALL_INTERFACE:include> +) +target_include_directories(caosdb SYSTEM PUBLIC ${CONAN_INCLUDE_DIRS} ) add_library(ccaosdb SHARED src/ccaosdb.cpp) target_link_libraries(ccaosdb - ${LIBCAOSDB} ${CONAN_LIBS} + ${LIBCAOSDB} + stdc++fs ) +target_include_directories(ccaosdb PUBLIC + $<BUILD_INTERFACE:${libcaosdb_SOURCE_DIR}/include> + $<BUILD_INTERFACE:${libcaosdb_BINARY_DIR}/include> + $<INSTALL_INTERFACE:include> +) +target_include_directories(ccaosdb SYSTEM PUBLIC + ${CONAN_INCLUDE_DIRS} +) + add_executable(ccaosdbcli EXCLUDE_FROM_ALL src/ccaosdbcli.c) target_include_directories(ccaosdbcli PUBLIC $<BUILD_INTERFACE:${libcaosdb_SOURCE_DIR}/include> $<BUILD_INTERFACE:${libcaosdb_BINARY_DIR}/include> $<INSTALL_INTERFACE:include> +) +target_include_directories(ccaosdbcli SYSTEM PUBLIC ${CONAN_INCLUDE_DIRS} ) + target_link_libraries(ccaosdbcli - ccaosdb ${CONAN_LIBS} + ${LIBCAOSDB} + ccaosdb ) add_executable(cxxcaosdbcli EXCLUDE_FROM_ALL src/cxxcaosdbcli.cpp) @@ -197,6 +216,8 @@ target_include_directories(cxxcaosdbcli PUBLIC $<BUILD_INTERFACE:${libcaosdb_SOURCE_DIR}/include> $<BUILD_INTERFACE:${libcaosdb_BINARY_DIR}/include> $<INSTALL_INTERFACE:include> +) +target_include_directories(cxxcaosdbcli SYSTEM PUBLIC ${CONAN_INCLUDE_DIRS} ) target_link_libraries(cxxcaosdbcli @@ -302,7 +323,7 @@ if(_LINTING) else() message(STATUS "clang-tidy: ${clang_tidy}") set(_CMAKE_CXX_CLANG_TIDY_CHECKS - "--checks=*,-fuchsia-*,-llvmlibc-*,-readability-convert-member-functions-to-static,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-hicpp-no-array-decay,-llvm-else-after-return,-readability-else-after-return,-modernize-use-trailing-return-type,-bugprone-branch-clone") + "--checks=*,-fuchsia-*,-llvmlibc-*,-readability-convert-member-functions-to-static,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-hicpp-no-array-decay,-llvm-else-after-return,-readability-else-after-return,-modernize-use-trailing-return-type,-bugprone-branch-clone,-altera-*") set(_CMAKE_C_CLANG_TIDY_CHECKS "${_CMAKE_CXX_CLANG_TIDY_CHECKS}") set(_CMAKE_CXX_CLANG_TIDY "${clang_tidy}" "--header-filter=caosdb/.*[^\(\.pb\.h\)]$" diff --git a/DEPENDENCIES.md b/DEPENDENCIES.md deleted file mode 100644 index 55949748d9d513367c2fbb98b5354bd95d97713e..0000000000000000000000000000000000000000 --- a/DEPENDENCIES.md +++ /dev/null @@ -1,30 +0,0 @@ -# GENERAL - -* >=conan-1.37.2 (e.g. with `pip install conan`) -* >=cmake-3.13 -* >=gcc-10.2.0 | >=clang-11 - -# OPTIONAL - -* For checking the schema of a json configuration file: >=jsonschema-3.2.0 - -# BUILD DOCS - -* doxygen -* >=python-3.7 -* >=pip-21.0.1 -* python packages from the `doc/requirements.txt` file. - -# BUILD AND RUN TESTS - -* >=clang-tidy-11 -* >=gtest-1.10.0 - -# COVERAGE - -* >=gcc-10.2.0 -* >=lcov-1.15 - -# FORMATTING - -* >=clang-formatting-11 diff --git a/DEPENDENCIES.md b/DEPENDENCIES.md new file mode 120000 index 0000000000000000000000000000000000000000..afcb4b6000019170e46b6dde462897bacd9855e1 --- /dev/null +++ b/DEPENDENCIES.md @@ -0,0 +1 @@ +doc/DEPENDENCIES.md \ No newline at end of file diff --git a/FEATURES.md b/FEATURES.md deleted file mode 100644 index 8b137891791fe96927ad78e64b0aad7bded08bdc..0000000000000000000000000000000000000000 --- a/FEATURES.md +++ /dev/null @@ -1 +0,0 @@ - diff --git a/FEATURES.md b/FEATURES.md new file mode 120000 index 0000000000000000000000000000000000000000..213554994c440ff06075f1cd7c36b68eb8fd7f99 --- /dev/null +++ b/FEATURES.md @@ -0,0 +1 @@ +doc/FEATURES.md \ No newline at end of file diff --git a/Makefile b/Makefile index 819b9ca2910ce5571f1a80412f655f41afa023e5..544c8039b4f27ccef8b379d1009bfe9173666bc3 100644 --- a/Makefile +++ b/Makefile @@ -58,9 +58,28 @@ conan-install: conan install . -s $(CONAN_SETTINGS) --build=missing) .PHONY: conan-install +conan-install-debug: + conan install . -s $(CONAN_SETTINGS) -s build_type=Debug || \ + (echo "'conan install' failed, trying to build from sources..."; \ + conan install . -s $(CONAN_SETTINGS) -s build_type=Debug --build=missing) +.PHONY: conan-install-debug + conan-create: conan create . -s $(CONAN_SETTINGS) .PHONY: conan-create +conan-create-debug: + conan create . -s $(CONAN_SETTINGS) -s build_type=Debug +.PHONY: conan-create-debug + conan: conan-install conan-create .PHONY: conan + +doc: + mkdir -p build && cd build && conan install .. -s $(CONAN_SETTINGS) \ + && cmake .. && cmake --build . --target doc-sphinx \ + && echo "The documentation starts at build/doc/sphinx_out/index.html ." +.PHONY: doc + +conan-debug: conan-install-debug conan-create-debug +.PHONY: conan-debug diff --git a/README.md b/README.md index 633c19e4aac1d84928bdc63f951b290923925da6..7a8326a9059e11e1c3eb99729123634a3a3758ed 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,8 @@ for CaosDB and a part of the CaosDB project. ## Setup -Please read the [README_SETUP.md](README_SETUP.md) for instructions on how to -develop, build and use this code. +Please read the installation notes [online](https://docs.indiscale.com/caosdb-cpplib/Install_develop.html) or [in the source repository](doc/Install_develop.md) for instructions +on how to build, use and develop this code. ## Further Reading @@ -20,7 +20,7 @@ Please read [CONTRIBUTING.md](CONTRIBUTING.md). ## License -* Copyright (C) 2021 Indiscale GmbH <info@indiscale.com> +* Copyright (C) 2022 Indiscale GmbH <info@indiscale.com> All files in this repository are licensed under a [GNU Affero General Public License](LICENCE.md) (version 3 or later). diff --git a/README_SETUP.md b/README_SETUP.md deleted file mode 120000 index c5c7270fb583274df037848bfb735cdb48829d28..0000000000000000000000000000000000000000 --- a/README_SETUP.md +++ /dev/null @@ -1 +0,0 @@ -doc/README_SETUP.md \ No newline at end of file diff --git a/RELEASE_GUIDELINES.md b/RELEASE_GUIDELINES.md index dc43a2fc1d32170dd4ff774ea893e29ac0f24767..c725ec86fd0fb5f8019da955bbe5999ff47afe25 100644 --- a/RELEASE_GUIDELINES.md +++ b/RELEASE_GUIDELINES.md @@ -13,20 +13,32 @@ guidelines of the CaosDB Project ## Steps -1. Create a release branch from the dev branch. This prevents further changes - to the code base and a never ending release process. Naming: `release-<VERSION>` +1. Create a release branch from the dev branch. This prevents further changes to + the code base and a never ending release process. Naming: + `release-<VERSION>`. Also create a branch with the same name in cppinttests. 2. Update CHANGELOG.md 3. Check all general prerequisites. -4. Prepare [CMakeLists.txt](./CMakeLists.txt): Check the `MAJOR`, `MINOR`, `PATCH` - version variables. +4. Update version numbers: + 1. In [CMakeLists.txt](./CMakeLists.txt): Check the version variables and + make sure that the compatible caosdb-server version is set correctly. + 2. In `conanfile.py`: Update the `version` variable. + 3. In `caosdb-cppinttest/conanfile.py`: Update the version 5. Merge the release branch into the main branch. -6. Tag the latest commit of the main branch with `v<VERSION>`. +6. Tag the latest commit of the main branch with `v<VERSION>`. Push the tag and the main branch. -7. Delete the release branch. +7. Create release in Gitlab: + 1. On [Releases](https://gitlab.indiscale.com/caosdb/src/caosdb-cpplib/-/releases), click "New release" + 2. Choose tag, type release title (same as tag), no milestone, possibly short release note, no + manual assets are necessary, possibly link to documentation. -8. TODO... +8. Delete the release branch. + +9. Release cppinttests with updated cpplib version + +10. Merge `main` back into `dev` and increase patch version by one to begin next + release cycle. Do the same in cppintest. diff --git a/cmake/CodeCoverage.cmake b/cmake/CodeCoverage.cmake index 27c6028d70eb608de54f879d4d6e4b59d070f2aa..8a26b4117b567dea4b5c3bb095964c2125ced813 100644 --- a/cmake/CodeCoverage.cmake +++ b/cmake/CodeCoverage.cmake @@ -136,6 +136,18 @@ include(CMakeParseArguments) option(CODE_COVERAGE_VERBOSE "Verbose information" FALSE) +option(SKIP_CODE_COVERAGE "Skip code coverage" OFF) + +if (SKIP_CODE_COVERAGE) + return() +endif() + +find_library(covlib NAMES gcov lcov) +message(STATUS "covlib: >${covlib}<") +if (${covlib} STREQUAL "covlib-NOTFOUND") + message(STATUS "lcov or gcov libraries not found, skipping code coverage.") + return() +endif() # Check prereqs find_program( GCOV_PATH gcov ) diff --git a/conanfile.py b/conanfile.py index 04d2b1f527b0c5936c0c9a5c7d6d20a98446f1bb..a773f501212cb23d3649aae31c644bd66a259516 100644 --- a/conanfile.py +++ b/conanfile.py @@ -3,7 +3,7 @@ from conans import ConanFile, CMake, tools class CaosdbConan(ConanFile): name = "caosdb" - version = "0.0.20" + version = "0.2.0-dev" license = "AGPL-3.0-or-later" author = "Timm C. Fitschen <t.fitschen@indiscale.com>" url = "https://gitlab.indiscale.com/caosdb/src/caosdb-cpplib.git" @@ -14,11 +14,16 @@ class CaosdbConan(ConanFile): default_options = {"shared": False, "fPIC": True} generators = "cmake" requires = [ - ("boost/1.76.0"), + ("grpc/1.39.1"), + ] + build_requires = [ + ("boost/1.77.0"), ("gtest/1.11.0"), - ("grpc/1.38.0"), ] - exports = "*.cpp", "*.h", "*.cmake", "*CMakeLists.txt", "*.in", "*.proto", "*.c" + exports = ("*.cmake", "*CMakeLists.txt", "*.in", + "*.h", "*.proto", "*.c", "*.cpp", + "*.rst", "*.md", + ) exports_sources = "src", "doc", "include", "test", "cmake", "proto" def config_options(self): diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md new file mode 100644 index 0000000000000000000000000000000000000000..fd3083fe290b51f78c12838c94bb3cf5b7a5a066 --- /dev/null +++ b/doc/CHANGELOG.md @@ -0,0 +1,53 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added + +### Changed + +* Removed boost from the headers. Boost is only a build dependency from now on. + +### Deprecated + +### Removed + +### Fixed + +* Calling "GetFileDescriptor().wrapped->path()" after retrieval leads to SegFault. +- #41 Updated Conan version in CI pipeline. + +### Security + +### Documentation + +## [0.1.2] - 2022-05-31 +(Florian Spreckelsen) + +### Fixed + +- #41 Updated Conan version in CI pipeline. + +## [0.1.1 - 2022-04-12] + +### Security + +- Bumped zlib dependency to 1.2.12. + +## [0.1.0 - 2021-12-11] + +Initial Release. + +Please review [FEATURES.md](./FEATURES.md) for an overview of the features of +this library. Apart from that, the API documentation for +[C++](https://docs.indiscale.com/caosdb-cpplib/cppapi/index.html) and [plain +old C](https://docs.indiscale.com/caosdb-cpplib/capi/index.html) specify the +public API. + +Note that this is still a pre-stable release as indicated by the major version +number. The API is still under development and is likely to change. diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 4255ab7d0f5531187491de7586a8c7b6c61545f7..e2bebee45ccb7a709387dfe275c00d90e8296c6c 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -18,6 +18,7 @@ # along with this program. If not, see <https://www.gnu.org/licenses/>. # +cmake_minimum_required(VERSION 3.13) find_package(Doxygen) if (DOXYGEN_FOUND) @@ -83,18 +84,22 @@ if (DOXYGEN_FOUND) sphinx_out DEPENDS doc-doxygen Examples.rst - README_SETUP.md + Install_develop.rst + FEATURES.md + CHANGELOG.md WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Generating API documentation with Sphinx" VERBATIM ) # Copying files is necessary: https://stackoverflow.com/a/45808534/232888 - # TODO fix for docs - #FILE(COPY - #Examples.rst - #README_SETUP.md + file(COPY + Examples.rst + Install_develop.rst + DEPENDENCIES.md + CHANGELOG.md + FEATURES.md # Tutorial.rst - #DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") + DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") else () message("Sphinx need to be installed to generate the sphinx documentation") endif () diff --git a/doc/DEPENDENCIES.md b/doc/DEPENDENCIES.md new file mode 100644 index 0000000000000000000000000000000000000000..690c7305d587bd2ef7a9219b0aa307bcb15c1ce3 --- /dev/null +++ b/doc/DEPENDENCIES.md @@ -0,0 +1,42 @@ +# Dependencies # + +## General ## + +``` +>=conan-1.43 (e.g. with `pip install conan`) +>=cmake-3.13 +>=gcc-10.2.0 | >=clang-11 +``` + +## Optional ## + +* For checking the schema of a json configuration file: `>=jsonschema-3.2.0` + +## Build docs ## + +``` +doxygen +>=python-3.7 +>=pip-21.0.1 +python packages from the `doc/requirements.txt` file +``` + +## Build and run tests ## + +``` +>=clang-tidy-11 +>=gtest-1.10.0 +``` + +## Coverage ## + +``` +>=gcc-10.2.0 +>=lcov-1.15 +``` + +## Formatting ## + +``` +>=clang-formatting-11 +``` diff --git a/doc/Examples.rst b/doc/Examples.rst index ddb24e0bdd6fd7a4f4881a8eb163cb63184b0bb8..1bf62f31a05bccd9e168be22a1c2d12d6873f325 100644 --- a/doc/Examples.rst +++ b/doc/Examples.rst @@ -5,10 +5,10 @@ Examples Connect to a CaosDB server -------------------------- -See also the hints on how to :doc:`get started<README_SETUP>`, and set-up of -libcaosdb. In order to connect to a CaosDB server with libcaosdb you first have to configure the -connection via a configuration file as explained in the :ref:`configuration section <Client Configuration>`. Once the configuration is set up, connecting to the server is -as easy as +See also the hints on how to :doc:`get started<Install_develop>`, and set-up of libcaosdb. In order +to connect to a CaosDB server with libcaosdb you first have to configure the connection via a +configuration file as explained in the :ref:`"Client Configuration" section <Client +Configuration>`. Once the configuration is set up, connecting to the server is as easy as .. code:: cpp @@ -19,6 +19,7 @@ You can print the full version of the server that you are connected to (and therby test the connection) via: .. code:: cpp + // get version info of the server connection.RetrieveVersionInfo() const auto &v_info = connection->GetVersionInfo(); @@ -57,8 +58,9 @@ you want to retrieve an Entity with id=123. This is done via You can then use the getter methods like :cpp:any:`GetId<caosdb::entity::Entity::GetId>`, -:cpp:any:`GetParents<caosdb::entity::Entity::GetParents>`, or :cpp:any:`GetProperties`<caosdb::entity::Entity::GetProperties>` to get the -name, the parents, or the properties of the retrieved entity. +:cpp:any:`GetParents<caosdb::entity::Entity::GetParents>`, or +:cpp:any:`GetProperties`<caosdb::entity::Entity::GetProperties>` to get the name, the parents, or +the properties of the retrieved entity. Retrieving multiple entities works in the same way. Type @@ -83,9 +85,9 @@ transaction manually. This is done by transaction->RetrieveById("1233"); auto status = transaction->Execute(); -A result set can be obtained -via :cpp:any:`GetResultSet`<caosdb::transaction::Transaction::GetResultSet>` which contains the resulting entities -and can, e.g., be checked for length. +A result set can be obtained via +:cpp:any:`GetResultSet`<caosdb::transaction::Transaction::GetResultSet>` which contains the +resulting entities and can, e.g., be checked for length. Execute queries --------------- @@ -147,6 +149,7 @@ Insert, update and delete operations function the same way. The respective task is added to a transaction and the transaction is executed. .. code:: cpp + const auto &connection = caosdb::connection::ConnectionManager::GetDefaultConnection(); @@ -202,7 +205,7 @@ task is added to a transaction and the transaction is executed. Up- and Download a file ---------------- +----------------------- .. code:: cpp diff --git a/doc/FEATURES.md b/doc/FEATURES.md new file mode 100644 index 0000000000000000000000000000000000000000..8ca4a13956a6ae5ea25a91c21253c4b68cc7b481 --- /dev/null +++ b/doc/FEATURES.md @@ -0,0 +1,39 @@ +# Features + +This library provides a client for communication with a CaosDB server over the +CaosDB GRPC-APIs. The client supports + +* Transaction of entities and file transmission. +* Authentication via Username/Password. +* Secure communication via TLS. +* Multiple connections with different servers. +* Logging. +* File-based configuration. + +The core is written in C++ and makes heavy use of object-oriented patterns. It +results in a c++ library -- libcaosdb. + +For using the library in a plain C context, a thin wrapper is included +-- libccaosdb. It wrapps the C++ classes into structs and the member methods +into functions which operate on the wrapped C++ instances. + +Minimal testing executables in C++ and C are included as well, but they only +serve as just that -- minimal testing. + +## CaosDB Entitiy API + +This library implements a subset of the CaosDB Entitiy API (caosdb.entity.v1) as a client. + +Current limitations: The implementation does not support mixing retrievals with write-transactions. + +## CaosDB Info API + +This library implements the CaosDB Info API (caosdb.info.v1) as a client without limitations. + +## Thread-safety and Concurrency + +Currently, the library should not be considered thread-safe. + +The `caosdb::transaction::Transaction` class is designed with an with an +interface ready for concurrent and asyncronous transactions. However, the +functions are actually implemented in a blocking, synchronous way. diff --git a/doc/Install_develop.rst b/doc/Install_develop.rst new file mode 100644 index 0000000000000000000000000000000000000000..2a882fab45c77a0712220dd27cc182c42450c35b --- /dev/null +++ b/doc/Install_develop.rst @@ -0,0 +1,222 @@ +How to use and develop libcaosdb +================================ + +Dependencies +------------ + +- See the `dependencies <DEPENDENCIES.md>`__ file. + +Build +----- + +Building with ``make`` +~~~~~~~~~~~~~~~~~~~~~~ + +Make sure that the dependencies (see above) are fulfilled. On systems +which have ``make`` installed, type this in your command line terminal: + +.. code:: console + + make conan + +Manual build +~~~~~~~~~~~~ + +We use `cmake <https://cmake.org>`__ as build tool, with Conan as +package manager. The compiler must support the C++17 standard. + +1. clone/update the subrepo ``git submodule update --init proto`` +2. ``mkdir build && cd build`` +3. ``conan install .. -s "compiler.libcxx=libstdc++11"`` +4. ``cmake -B . ..`` +5. ``cmake --build .`` + +You may also want to install libcaosdb system-wide to +``CMAKE_INSTALL_PREFIX/lib`` by + +1. ``cmake --install .`` + +The default install prefix is ``~/.local``. It can be set by adding +``-DCMAKE_INSTALL_PREFIX=/path/to/install/prefix`` to the first cmake +command (3.). + +.. Note:: + + The C++ CaosDB library links against other libraries which are installed by Conan. So if you want + to switch to newer versions of those libraries (possible reasons may be security releases or bug + fixes), it is not sufficient to update your system libraries, but you have to update your Conan + content and then rebuild libcaosdb. + +If you want to build or install libcaosdb without the use of Conan, feel +free to rewrite the CMakeLists.txt as needed. The CaosDB project is open +to merge requests which support multiple ways of installation. + +How to build on MacOS +~~~~~~~~~~~~~~~~~~~~~ + +If you use apple-clang as the compiler: Instead of the above conan +command (2.) use + +1. ``conan install .. -s "compiler.cppstd=17"`` + +and continue as you would when building on a Linux system. You may have +to add ``build/lib/`` (or, alternatively after installation, +``CMAKE_INSTALL_PREFIX/lib``) to your ``DYLD_LIBRARY_PATH`` +environmental variable. + +Problems and solutions +^^^^^^^^^^^^^^^^^^^^^^ + +- Make sure that your Conan version supports your XCode version. A + typical symptom of version mismatch is for example conan complaining + about incompatible ``compiler.version`` settings. You may need to + rerun any conan and cmake commands (and delete cache files first) + after compiler updates. + +How to build on Windows +~~~~~~~~~~~~~~~~~~~~~~~ + +We use `Visual Studio +2019 <https://visualstudio.microsoft.com/de/vs/features/cplusplus/>`__ +as compiler. We use `cmake <https://cmake.org/download/>`__ as build +tool. + +1. clone/update the subrepo ``git submodule update --init proto`` +2. ``mkdir build`` +3. ``cd build`` +4. ``conan install .. -g visual_studio -s arch=x86_64 -s build_type=Release -s compiler.toolset=v142 -s compiler.version=16 -s compiler.runtime=MD --build=missing --update`` +5. ``cmake -B . ..`` +6. open ``libcaosdb.sln`` with Visual Studio, change the buildtype to + ``Release`` and build the project. (You can open Tools/Command + Line/Developer Command Prompt and execute + ``msbuild libcaosdb.sln /property:Configuration=Release``) + +Known problems +^^^^^^^^^^^^^^ + +- Linking dynamic libraries currently fails on Windows. So probably + other CaosDB libraries which make use of libcaosdb also will not + build. This is a known bug and we hope to fix this in the next + release. See + `#34 <https://gitlab.indiscale.com/caosdb/src/caosdb-cpplib/-/issues/34>`__ + +Troubleshooting +~~~~~~~~~~~~~~~ + +``conan install`` fails due to missing prebuilts +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +When ``conan install`` fails during the installation of the dependencies +because a precompiled package is not available for your specific +settings, try adding the ``--build=missing`` option: +``conan install .. [ other options ] --build=missing``. This should +download and compile the sources of the dependencies. + +cmake fails when using the debug flag +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Depending on the clang version it might be necessary to additionally use +the following flag: ``-DCMAKE_CXX_FLAGS="-Wno-unused-parameter"`` + +conan uses outdated cppstd during install +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If you experience compiler errors during a ``conan install`` process due +to, e.g., ``std::string_view`` being unavailable, try specifying the cpp +standard manually by +``conan install .. [other options] -s "compiler.cppstd=17"``. + +Client Configuration +-------------------- + +You can use a json file for the configuration of the client. See +``test/test_data/test_caosdb_client.json`` for an example. You may use +``caosdb-client-configuration-schema.json`` to validate your schema. +Typically, you will need to provide the path to your SSL certificate. + +The client will load the configuration file from the first existing file +in the following locations (precedence from highest to lowest): + +1. A file specified by the environment variable + ``$CAOSDB_CLIENT_CONFIGURATION``. +2. ``$PWD/caosdb_client.json`` +3. ``$PWD/caosdb-client.json`` +4. ``$PWD/.caosdb_client.json`` +5. ``$PWD/.caosdb-client.json`` +6. ``$HOME/caosdb_client.json`` +7. ``$HOME/caosdb-client.json`` +8. ``$HOME/.caosdb_client.json`` +9. ``$HOME/.caosdb-client.json`` + +Develop +------- + +Unit tests +~~~~~~~~~~ + +.. _build-1: + +Build +^^^^^ + +For the tests there is a slightly different setup required (with option +``-D CMAKE_BUILD_TYPE=Debug``) + +1. ``mkdir build && cd build/`` +2. ``conan install ..`` (with gcc, append + ``-s "compiler.libcxx=libstdc++11"``, with apple-clang, append + ``-s compiler.cppstd=17``) +3. ``cmake -B . -D CMAKE_BUILD_TYPE=Debug ..`` + - If your clang-format version is too old, formatting, linting etc. can + be skipped: + ``cmake -B . -D CMAKE_BUILD_TYPE=Debug -D SKIP_LINTING=ON ..`` + - Depending on the clang version it may be necessary to also add + ``-DCMAKE_CXX_FLAGS="-Wno-unused-parameter"`` +4. ``cmake --build .`` + +Run +^^^ + +In the build directory, run ``ctest`` + +Framework +^^^^^^^^^ + +We use `GoogleTest <https://google.github.io/googletest/>`__ for unit +testing. + +Test coverage +^^^^^^^^^^^^^ + +We use `gcov <https://gcc.gnu.org/onlinedocs/gcc/Gcov.html>`__ and +`lcov <https://github.com/linux-test-project/lcov>`__ for generating +test coverage reports. + +In the build directory, generate the coverage report by running +``cmake --build . --target unit_test_coverage``. + +Note that this special target will run the tests again. Thus it is not +necessary to run ``ctest`` prior to this target. + +The coverage report can be viewed in a browser by opening +``<build_directory>/unit_test_coverage/index.html``. + +Code formatting +~~~~~~~~~~~~~~~ + +- install clang-format on your system. +- ``clang-format -i --verbose $(find test/ src/ include/ -type f -iname "*.cpp" -o -iname "*.h" -o -iname "*.h.in")`` + +Naming conventions +~~~~~~~~~~~~~~~~~~ + +Please adhere to `Google’s C++ naming +conventions <https://google.github.io/styleguide/cppguide.html#Naming>`__. + +Documentation +~~~~~~~~~~~~~ + +To build the documentation, run in the build directory + +- ``cmake --build . --target doc-doxygen`` (generate Doxygen) +- ``cmake --build . --target doc-sphinx`` (generate Sphinx) diff --git a/doc/README_SETUP.md b/doc/README_SETUP.md deleted file mode 100644 index c0b56bfe627596b4765084d1cf4457acfb7e7545..0000000000000000000000000000000000000000 --- a/doc/README_SETUP.md +++ /dev/null @@ -1,150 +0,0 @@ -# How to Develop and Use Libcaosdb - -## Dependencies - -* See [DEPENDENCIES.md](Dependencies.md) - -## Build - -We use [cmake](https://cmake.org) as build tool. - -0. clone/update the subrepo `git submodule update --init proto` -1. `mkdir build && cd build` -2. `conan install .. -s "compiler.libcxx=libstdc++11"` -3. `cmake -B . ..` -4. `cmake --build .` - -You may also want to install libcaosdb system-wide to -`CMAKE_INSTALL_PREFIX/lib` by - -5. `cmake --install .` - -The default install prefix is `~/.local`. It can be set by adding -`-DCMAKE_INSTALL_PREFIX=/path/to/install/prefix` to the first cmake -command (3.). - -### How to build on MacOS - -Instead of the above conan command (2.) use - -2. `conan install .. -s "compiler.cppstd=17"` - -and continue as you would when building on a Linux system. You may -have to add `build/lib/` (or, alternatively after installation, -`CMAKE_INSTALL_PREFIX/lib`) to your `DYLD_LIBRARY_PATH` environmental -variable. - -#### Problems and solutions #### - -- Make sure that your conan version supports your XCode version. A typical symptom of version - mismatch is for example conan complaining about incompatible `compiler.version` settings. You may - need to rerun any conan and cmake commands (and delete cache files first) after compiler updates. - -### How to build on Windows - -We use [Visual Studio 2019](https://visualstudio.microsoft.com/de/vs/features/cplusplus/) -as compiler. We use [cmake](https://cmake.org/download/) as build tool. - -0. clone/update the subrepo `git submodule update --init proto` -1. `mkdir build` -2. `cd build` -3. `conan install .. -g visual_studio -s arch=x86_64 -s build_type=Release -s compiler.toolset=v142 -s compiler.version=16 -s compiler.runtime=MD --build=missing --update` -4. `cmake -B . ..` -5. open ` libcaosdb.sln` with Visual Studio, change the buildtype to `Release` - and build the project. (You can open Tools/Command Line/Developer Command - Prompt and execute `msbuild libcaosdb.sln /property:Configuration=Release`) - -### Creating a Local Conan Package ## - -Building and installing libcaosdb with Conan is just a single command: `make conan` - -For MacOS, you probably should adjust the option as mentioned above. - -### Troubleshooting - -#### `conan install` Fails Due to Missing Prebuilts - -When `conan install` fails during the installation of the dependencies because -a precompiled package is not available for your specific settings, try adding -the `--build=missing` option: `conan install .. [ other options -] --build=missing`. This should download and compile the sources of the -dependencies. - -#### cmake fails when using the Debug flag -Depending on the clang version it might be necessary to use additionally the following flag: -`-DCMAKE_CXX_FLAGS="-Wno-unused-parameter"` - -## Unit Tests - -### Build - -For the tests there is a slightly different setup required (with option `-D CMAKE_BUILD_TYPE=Debug`) - -1. `mkdir build && cd build/` -2. `conan install .. -s "compiler.libcxx=libstdc++11"` -3. `cmake -B . -D CMAKE_BUILD_TYPE=Debug ..` - * If your clang-format version is too old, formatting, linting etc. can be skipped: - `cmake -B . -D CMAKE_BUILD_TYPE=Debug -D SKIP_LINTING=ON ..` - * Depending on the clang version it might be necessary to also add - `-DCMAKE_CXX_FLAGS="-Wno-unused-parameter"` -5. `cmake --build .` - -### Run - -In the build directory, run `ctest` - -### Framework - -We use [GoogleTest](https://google.github.io/googletest/) for unit testing. - -### Coverage - -We use [gcov](https://gcc.gnu.org/onlinedocs/gcc/Gcov.html) and -[lcov](https://github.com/linux-test-project/lcov) for generating test coverage -reports. - -In the build directory, generate the coverage report by running -`cmake --build . --target unit_test_coverage`. - -Note that this special target will run the tests again. Thus it is not -necessary to run `ctest` prior to this target. - -The coverage report can be viewed in a browser by opening -`<build_directory>/unit_test_coverage/index.html`. - -## Code Formatting - -* install clang-format on your system. -* `clang-format -i --verbose $(find test/ src/ include/ -type f -iname "*.cpp" -o -iname "*.h" -o -iname "*.h.in")` - -## Naming Convention - -Please adhere to [Google's C++ naming conventions](https://google.github.io/styleguide/cppguide.html#Naming). - -## Client Configuration - -You can use a json file for the configuration of the client. See -`test/test_data/test_caosdb_client.json` for an example. You may use -`caosdb-client-configuration-schema.json` to validate your schema. -Typically, you will need to provide the path to your SSL certificate. - -The client will load the configuration file from the first existing -file in the following locations (precedence from highest to lowest): - -1. A file specified by the environment variable - `$CAOSDB_CLIENT_CONFIGURATION`. -2. `$PWD/caosdb_client.json` -3. `$PWD/caosdb-client.json` -4. `$PWD/.caosdb_client.json` -5. `$PWD/.caosdb-client.json` -6. `$HOME/caosdb_client.json` -7. `$HOME/caosdb-client.json` -8. `$HOME/.caosdb_client.json` -9. `$HOME/.caosdb-client.json` - -## Documentation - -In the build directory, run - -* `cmake --build . --target doc-doxygen` (generate Doxygen) -* `cmake --build . --target doc-sphinx` (generate Sphinx) diff --git a/doc/capi/index.rst.in b/doc/capi/index.rst.in index dad5482336472aa01355467687b2441b0a282a7b..71c78372ceebba9d03d77fcefe2d33b01ae1d757 100644 --- a/doc/capi/index.rst.in +++ b/doc/capi/index.rst.in @@ -21,19 +21,25 @@ .. _capi_root: -C API -===== +======= + C API +======= + +.. warning:: + + The C API is intended for developers of other libraries. Special carre needs to be taken for + correct memory management. .. note:: - When working with libcaosdb's C API keep the following in - mind. Delete all objects (transactions, entities, properties, - parents, ...) that you created using a `caosdb_..._create_...` - function or released using a `caosdb_..._release_...` and only - those. This means, that any objects set by a `caosdb_..._get_...` - function, are managed by another owning object (e.g., a connection - object managed by the connection manager) should not be deleted - manually. + When working with libcaosdb's C API keep the following in mind: + + Delete all objects (transactions, entities, properties, parents, ...) that you created using a + call to ``caosdb_..._create_...`` or released using ``caosdb_..._release_...`` and only those. + + Specifically, any objects set by a ``caosdb_..._get_...`` function are managed by another owning + object (e.g., a connection object is managed by the connection manager) and thus should not be + deleted manually. The underlying reason is that all C++ objects are realized in the Extern C interface as mutable structs containing a void pointer to diff --git a/doc/conf.py.in b/doc/conf.py.in index c359c11e4d785a840761e50e93c2787d86312a43..0490a20abe04a6ad027eff36fcc9d1fe4939cb4e 100644 --- a/doc/conf.py.in +++ b/doc/conf.py.in @@ -18,7 +18,7 @@ # -- Project information ----------------------------------------------------- project = '@CMAKE_PROJECT_NAME@' -copyright = '2021 IndiScale GmbH' +copyright = '2022 IndiScale GmbH' author = 'Timm Fitschen' version = '@CMAKE_PROJECT_VERSION@' release = '@CMAKE_PROJECT_VERSION@' @@ -46,7 +46,7 @@ extensions = [ 'sphinx_sitemap', 'sphinx.ext.inheritance_diagram', 'breathe', - "recommonmark" # For markdown files. + "recommonmark", # For markdown files. ] # Add any paths that contain templates here, relative to this directory. diff --git a/doc/cppapi/index.rst.in b/doc/cppapi/index.rst.in index c9780a92355ab99e7bbdb9cfc1c405c33c3efd30..67e96fa6014ad1de0da6bec4b33ca5a40b2a6e80 100644 --- a/doc/cppapi/index.rst.in +++ b/doc/cppapi/index.rst.in @@ -21,8 +21,13 @@ .. _cppapi_root: -C++ API -======= +========= + C++ API +========= + +This is the C++ library for connecting to CaosDB. If you are interested in code examples, please +refer to the corresponding :doc:`documentation section<examples.rst>`. + .. toctree:: :glob: diff --git a/doc/index.rst.in b/doc/index.rst.in index 47b16c95efa3da4aee32a1c6f2b559e5295377e3..b6fdaaf592f8fe4e36008a509204a10d23d3e320 100644 --- a/doc/index.rst.in +++ b/doc/index.rst.in @@ -30,9 +30,12 @@ Welcome to |PROJECT_NAME|'s documentation! :caption: Contents: Welcome <self> - Getting Started <README_SETUP> + Getting Started <Install_develop> Examples.rst cppapi/index capi/index + Changelog <CHANGELOG> + Dependencies <DEPENDENCIES> + Features <FEATURES> * :ref:`genindex` diff --git a/doc/legacy.rst b/doc/legacy.rst new file mode 100644 index 0000000000000000000000000000000000000000..485397ea116c6d06b1defa99d4f4bbc31853ab4b --- /dev/null +++ b/doc/legacy.rst @@ -0,0 +1,6 @@ +Legacy code +=========== + +- Older GCC compilers (before gcc-9) need explicit linking against libstdc++fs.a. The related + specifications can be removed from the CMakeLists.txt files once no such compilers are expected in + the wild anymore. diff --git a/doc/requirements.txt b/doc/requirements.txt index 1a306c69d3e8c80b51e0a0824da0d66ca378ad11..458d5d584d3a8020543e287c651b521e0479b713 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -16,13 +16,13 @@ pytz==2021.1 requests==2.25.1 six==1.16.0 snowballstemmer==2.1.0 -Sphinx==4.0.1 -sphinx-rtd-theme==0.5.2 +Sphinx==4.5.0 +sphinx-rtd-theme==1.0.0 sphinx-sitemap==2.2.0 sphinxcontrib-applehelp==1.0.2 sphinxcontrib-devhelp==1.0.2 -sphinxcontrib-htmlhelp==1.0.3 +sphinxcontrib-htmlhelp==2.0.0 sphinxcontrib-jsmath==1.0.1 sphinxcontrib-qthelp==1.0.3 -sphinxcontrib-serializinghtml==1.1.4 -urllib3==1.26.4 +sphinxcontrib-serializinghtml==1.1.5 +urllib3==1.26.7 diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index d480ec17b4ad33498ca1a845ebc0fb1a622cb04a..784e2e04ae3baa8aacffbacbba2ecc55c1c0af6a 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -28,6 +28,7 @@ set(libcaosdb_INCL ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/data_type.h ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/entity.h ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/exceptions.h + ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/file_descriptor.h ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/handler_interface.h ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/info.h ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/log_level.h diff --git a/include/caosdb/authentication.h b/include/caosdb/authentication.h index 070346c9366d89e7476f125b74feaea4ceb40a32..8e98a17e6d94fe118cf2fc478efbbf77733be4a6 100644 --- a/include/caosdb/authentication.h +++ b/include/caosdb/authentication.h @@ -28,10 +28,10 @@ * @brief Configuration and setup of the client authentication. */ #include "caosdb/utility.h" // for base64_encode -#include "grpcpp/impl/codegen/interceptor.h" // for Status -#include "grpcpp/impl/codegen/security/auth_context.h" // for AuthContext -#include "grpcpp/impl/codegen/status.h" // for Status -#include "grpcpp/impl/codegen/string_ref.h" // for string_ref +#include <grpcpp/impl/codegen/interceptor.h> // for Status +#include <grpcpp/impl/codegen/security/auth_context.h> // for AuthContext +#include <grpcpp/impl/codegen/status.h> // for Status +#include <grpcpp/impl/codegen/string_ref.h> // for string_ref #include <grpcpp/security/credentials.h> // for CallCredentials #include <map> // for multimap #include <memory> // for shared_ptr diff --git a/include/caosdb/certificate_provider.h b/include/caosdb/certificate_provider.h index e7d7a156efeaf05435fd3ccb8029549a82e38442..a2cb5b5a1e407d93f3aa0ac774c26aac5ff31f83 100644 --- a/include/caosdb/certificate_provider.h +++ b/include/caosdb/certificate_provider.h @@ -22,9 +22,9 @@ #ifndef CAOSDB_CERTIFICATE_PROVIDER_H #define CAOSDB_CERTIFICATE_PROVIDER_H -#include "boost/filesystem/path.hpp" // for path +#include <filesystem> // for path namespace caosdb::configuration { -using boost::filesystem::path; +using std::filesystem::path; class CertificateProvider { public: @@ -46,7 +46,7 @@ private: std::string certificate_provider; public: - explicit PemCertificateProvider(const std::string &certificate_provider); + explicit PemCertificateProvider(std::string certificate_provider); [[nodiscard]] auto GetCertificatePem() const -> std::string override; }; } // namespace caosdb::configuration diff --git a/include/caosdb/configuration.h b/include/caosdb/configuration.h index 2c521e7b0f36c351dabd6f7341ea3bb393fd402c..053888672ab3e1649a060553264fe8d26fda9907 100644 --- a/include/caosdb/configuration.h +++ b/include/caosdb/configuration.h @@ -21,33 +21,29 @@ #ifndef CAOSDB_CONFIGURATION_H #define CAOSDB_CONFIGURATION_H -#include "boost/filesystem/operations.hpp" // for exists -#include "boost/filesystem/path.hpp" // for path -#include "boost/json/object.hpp" // for object -#include "boost/json/value.hpp" // for value -#include "boost/json/value_ref.hpp" // IWYU pragma: keep -// IWYU pragma: no_include "boost/json/fwd.hpp" -#include "caosdb/authentication.h" // for Authenticator, PlainPassw... -#include "caosdb/certificate_provider.h" // for CertificateProvider, path -#include "caosdb/exceptions.h" // for ConfigurationError -#include "caosdb/logging.h" -#include "caosdb/utility.h" // for load_json_file -#include "grpcpp/security/credentials.h" // for ChannelCredentials -#include <iosfwd> // for ostream -#include <memory> // for unique_ptr, shared_ptr -#include <string> // for string + +#include "caosdb/authentication.h" // for Authenticator, PlainPassw... +#include "caosdb/certificate_provider.h" // for CertificateProvider, path +#include "caosdb/exceptions.h" // for ConfigurationError +#include "caosdb/utility.h" // for load_json_file +#include <google/protobuf/arena.h> // for Arena +#include <google/protobuf/extension_set.h> // for Arena +#include <grpcpp/security/credentials.h> // for ChannelCredentials +#include <filesystem> // for path, exists +#include <iosfwd> // for ostream +#include <memory> // for shared_ptr, unique_ptr +#include <string> // for string namespace caosdb::configuration { -using boost::filesystem::exists; -using boost::filesystem::path; -using boost::json::array; -using boost::json::object; -using boost::json::value; using caosdb::authentication::Authenticator; using caosdb::authentication::PlainPasswordAuthenticator; using caosdb::exceptions::ConfigurationError; +using caosdb::utility::JsonValue; using caosdb::utility::load_json_file; +using google::protobuf::Arena; using grpc::ChannelCredentials; +using std::filesystem::exists; +using std::filesystem::path; const std::string logger_name = "caosdb::configuration"; @@ -60,7 +56,7 @@ private: int port; public: - ConnectionConfiguration(const std::string &host, int port); + ConnectionConfiguration(std::string host, int port); virtual ~ConnectionConfiguration() = default; friend auto operator<<(std::ostream &out, const ConnectionConfiguration &configuration) -> std::ostream &; @@ -99,69 +95,6 @@ public: [[nodiscard]] auto ToString() const -> std::string override; }; -/** - * Helper class (no state, just member functions) which should only be used by - * the ConfigurationManager to initialize the logging framework from the stored - * configuration. - */ -class LoggingConfigurationHelper { -public: - friend class ConfigurationManager; - -private: - auto ConvertLogLevel(const std::string &string_level) const -> int; - auto CreateConsoleSinkConfiguration(const object &from, const std::string &name, int level) const - -> std::shared_ptr<caosdb::logging::SinkConfiguration>; - auto CreateSyslogSinkConfiguration(const object &from, const std::string &name, int level) const - -> std::shared_ptr<caosdb::logging::SinkConfiguration>; - auto CreateFileSinkConfiguration(const object &from, const std::string &name, int level) const - -> std::shared_ptr<caosdb::logging::SinkConfiguration>; - auto CreateSinkConfiguration(const object &from, const std::string &name, int default_level) const - -> std::shared_ptr<caosdb::logging::SinkConfiguration>; - auto CreateLoggingConfiguration(const object &from) const - -> caosdb::logging::LoggingConfiguration; -}; - -/** - * Helper class (no state, just member functions) which should only be used by - * the ConfigurationManager to construct Connection instances from the stored - * configuration. - */ -class ConnectionConfigurationHelper { -public: - friend class ConfigurationManager; - -private: - /** - * @param from - a single connection configuration. - */ - auto CreateCertificateProvider(const object &from) const -> std::unique_ptr<CertificateProvider>; - - /** - * @param from - a single connection configuration. - */ - auto CreateAuthenticator(const object &from) const -> std::unique_ptr<Authenticator>; - - /** - * @param from - a single connection configuration. - */ - auto CreateConnectionConfiguration(const bool tls, const std::string &host, const int port, - const CertificateProvider *certificate_provider, - const Authenticator *authenticator) const - -> std::unique_ptr<ConnectionConfiguration>; - - /** - * @param from - a single connection configuration. - */ - auto IsTls(const object &from) const -> bool; - - /** - * @param from - a single connection configuration. - */ - auto CreateConnectionConfiguration(const object &from) const - -> std::unique_ptr<ConnectionConfiguration>; -}; - /** * Reads the configuration file and keeps the configuration. Singleton. * @@ -218,14 +151,16 @@ public: ConfigurationManager(ConfigurationManager const &) = delete; void operator=(ConfigurationManager const &) = delete; + inline static auto GetArena() -> Arena * { return &GetInstance().arena; } + private: - value json_configuration; - ConnectionConfigurationHelper connection_configuration_helper; - LoggingConfigurationHelper logging_configuration_helper; + Arena arena; + JsonValue json_configuration; - inline ConfigurationManager(){ - // InitializeDefaults(); - }; + inline ConfigurationManager() + : json_configuration(nullptr){ + // InitializeDefaults(); + }; /** * Initialize this ConfigurationManager with the defaults. @@ -236,22 +171,6 @@ private: */ auto InitializeDefaults() -> int; - /** - * Return a json object representing the current configuration. - */ - auto GetConfiguration() const -> const object &; - - /** - * Return the connection configurations. - */ - auto GetConnections() const -> const object &; - - /** - * Return the configuration for the connection with the given name (as a json - * object). - */ - auto GetConnection(const std::string &name) const -> const object &; - /** * Reset this ConfigurationManager. * diff --git a/include/caosdb/connection.h b/include/caosdb/connection.h index d3ed0945e0022f29e6097fb4ea2d9207c3258987..ac1d05a419816ac21bd0a70ceafaf97428bd08da 100644 --- a/include/caosdb/connection.h +++ b/include/caosdb/connection.h @@ -27,29 +27,29 @@ * @date 2021-05-18 * @brief Configuration and setup of the connection. */ -#include <map> // for map -#include <memory> // for shared_ptr, unique_ptr -#include <string> // for string, basic_string -#include "boost/filesystem/path.hpp" // for path -#include "caosdb/authentication.h" // for Authenticator -#include "caosdb/configuration.h" // for ConnectionConfigura... -#include "caosdb/entity/v1alpha1/main.grpc.pb.h" // for EntityTransactionSe... -#include "caosdb/info.h" // for VersionInfo -#include "caosdb/info/v1alpha1/main.grpc.pb.h" // for GeneralInfoService:... -#include "caosdb/transaction.h" // for Transaction -#include "caosdb/transaction_status.h" // for TransactionStatus -#include "grpcpp/channel.h" // for Channel +#include "caosdb/authentication.h" // for Authenticator +#include "caosdb/configuration.h" // for ConnectionConfigura... +#include "caosdb/entity/v1/main.grpc.pb.h" // for EntityTransactionSe... +#include "caosdb/info.h" // for VersionInfo +#include "caosdb/info/v1/main.grpc.pb.h" // for GeneralInfoService:... +#include "caosdb/transaction.h" // for Transaction +#include "caosdb/transaction_status.h" // for TransactionStatus +#include <filesystem> // for path +#include <grpcpp/channel.h> // for Channel +#include <map> // for map +#include <memory> // for shared_ptr, unique_ptr +#include <string> // for string, basic_string namespace caosdb::connection { -using boost::filesystem::path; using caosdb::authentication::Authenticator; using caosdb::configuration::ConnectionConfiguration; -using caosdb::entity::v1alpha1::EntityTransactionService; -using caosdb::entity::v1alpha1::FileTransmissionService; +using caosdb::entity::v1::EntityTransactionService; +using caosdb::entity::v1::FileTransmissionService; using caosdb::info::VersionInfo; -using caosdb::info::v1alpha1::GeneralInfoService; +using caosdb::info::v1::GeneralInfoService; using caosdb::transaction::Transaction; using caosdb::transaction::TransactionStatus; +using std::filesystem::path; /** * @brief A reusable connection to a CaosDBServer. diff --git a/include/caosdb/constants.h.in b/include/caosdb/constants.h.in index bfec36bfbebf91fcd3e9eed38dd9ff305afc7a74..2661806d63a23b419da44de664f087b3c95c9a87 100644 --- a/include/caosdb/constants.h.in +++ b/include/caosdb/constants.h.in @@ -22,22 +22,25 @@ #ifndef CAOSDB_CONSTANTS_H #define CAOSDB_CONSTANTS_H +#ifndef __GNUC__ +#define __attribute__(x) +#endif #ifdef __cplusplus namespace caosdb { #endif // clang-format off -const int LIBCAOSDB_VERSION_MAJOR = @libcaosdb_VERSION_MAJOR@; -const int LIBCAOSDB_VERSION_MINOR = @libcaosdb_VERSION_MINOR@; -const int LIBCAOSDB_VERSION_PATCH = @libcaosdb_VERSION_PATCH@; -const int COMPATIBLE_SERVER_VERSION_MAJOR = @libcaosdb_COMPATIBLE_SERVER_VERSION_MAJOR@; -const int COMPATIBLE_SERVER_VERSION_MINOR = @libcaosdb_COMPATIBLE_SERVER_VERSION_MINOR@; -const int COMPATIBLE_SERVER_VERSION_PATCH = @libcaosdb_COMPATIBLE_SERVER_VERSION_PATCH@; -const char* COMPATIBLE_SERVER_VERSION_PRE_RELEASE = "@libcaosdb_COMPATIBLE_SERVER_VERSION_PRE_RELEASE@"; +static const int LIBCAOSDB_VERSION_MAJOR = @libcaosdb_VERSION_MAJOR@; +static const int LIBCAOSDB_VERSION_MINOR = @libcaosdb_VERSION_MINOR@; +static const int LIBCAOSDB_VERSION_PATCH = @libcaosdb_VERSION_PATCH@; +static const int COMPATIBLE_SERVER_VERSION_MAJOR = @libcaosdb_COMPATIBLE_SERVER_VERSION_MAJOR@; +static const int COMPATIBLE_SERVER_VERSION_MINOR = @libcaosdb_COMPATIBLE_SERVER_VERSION_MINOR@; +static const int COMPATIBLE_SERVER_VERSION_PATCH = @libcaosdb_COMPATIBLE_SERVER_VERSION_PATCH@; +__attribute__((unused)) static const char* COMPATIBLE_SERVER_VERSION_PRE_RELEASE = "@libcaosdb_COMPATIBLE_SERVER_VERSION_PRE_RELEASE@"; /** * Precedence of configuration files from highest to lowest. */ -const char* LIBCAOSDB_CONFIGURATION_FILES_PRECEDENCE[] = { +__attribute__((unused)) static const char* LIBCAOSDB_CONFIGURATION_FILES_PRECEDENCE[] = { "$CAOSDB_CLIENT_CONFIGURATION", "caosdb_client.json", "caosdb-client.json", diff --git a/include/caosdb/data_type.h b/include/caosdb/data_type.h index c084a338272532db652b4d7df85cfa42940c6bb1..11909c012e3105ed29185637b3f32801f1613ccf 100644 --- a/include/caosdb/data_type.h +++ b/include/caosdb/data_type.h @@ -28,17 +28,17 @@ #ifndef CAOSDB_DATA_TYPE_H #define CAOSDB_DATA_TYPE_H -#include "caosdb/protobuf_helper.h" // for ProtoMessageWrapper -#include "caosdb/entity/v1alpha1/main.pb.h" // for RepeatedPtrField, Message -#include <memory> // for unique_ptr -#include <string> // for string +#include "caosdb/protobuf_helper.h" // for ProtoMessageWrapper +#include "caosdb/entity/v1/main.pb.h" // for RepeatedPtrField, Message +#include <memory> // for unique_ptr +#include <string> // for string namespace caosdb::entity { -using ProtoAtomicDataType = caosdb::entity::v1alpha1::AtomicDataType; -using ProtoDataType = caosdb::entity::v1alpha1::DataType; -using ProtoListDataType = caosdb::entity::v1alpha1::ListDataType; -using ProtoReferenceDataType = caosdb::entity::v1alpha1::ReferenceDataType; -using DataTypeCase = caosdb::entity::v1alpha1::DataType::DataTypeCase; -using ListDataTypeCase = caosdb::entity::v1alpha1::ListDataType::ListDataTypeCase; +using ProtoAtomicDataType = caosdb::entity::v1::AtomicDataType; +using ProtoDataType = caosdb::entity::v1::DataType; +using ProtoListDataType = caosdb::entity::v1::ListDataType; +using ProtoReferenceDataType = caosdb::entity::v1::ReferenceDataType; +using DataTypeCase = caosdb::entity::v1::DataType::DataTypeCase; +using ListDataTypeCase = caosdb::entity::v1::ListDataType::ListDataTypeCase; using caosdb::utility::ProtoMessageWrapper; using caosdb::utility::ScalarProtoMessageWrapper; @@ -181,6 +181,8 @@ public: } } + ~DataType() = default; + inline static auto ListOf(const AtomicDataType &atomic_data_type) -> DataType { return DataType(atomic_data_type, true); } diff --git a/include/caosdb/entity.h b/include/caosdb/entity.h index 2f6e4ed96670f3c3e16749f3a2a590d491b29abe..52a69e05083670a302a71b883993ae28122e7655 100644 --- a/include/caosdb/entity.h +++ b/include/caosdb/entity.h @@ -29,47 +29,40 @@ #ifndef CAOSDB_ENTITY_H #define CAOSDB_ENTITY_H -#include "caosdb/data_type.h" // for DataType -#include "caosdb/entity/v1alpha1/main.pb.h" // for RepeatedPtrField -#include "caosdb/logging.h" // for CAOSDB_LOG_WARN -#include "caosdb/message_code.h" // for get_message_code -#include "caosdb/protobuf_helper.h" // for get_arena -#include "caosdb/status_code.h" // for StatusCode -#include "caosdb/value.h" // for Value -#include <boost/filesystem/operations.hpp> // for exists, is_di... -#include <boost/filesystem/path.hpp> // for path -#include <boost/log/core/record.hpp> // for record -#include <boost/log/detail/attachable_sstream_buf.hpp> // for basic_ostring... -#include <boost/log/sources/record_ostream.hpp> // for basic_record_... -#include <boost/preprocessor/seq/limits/enum_256.hpp> // for BOOST_PP_SEQ_... -#include <boost/preprocessor/seq/limits/size_256.hpp> // for BOOST_PP_SEQ_... -#include <cstdint> // for int64_t -#include <google/protobuf/message.h> // for RepeatedPtrField -#include <iosfwd> // for streamsize -#include <iterator> // for iterator, output_iterato... -#include <map> // for map -#include <random> // for mt19937, rand... -#include <stdexcept> // for out_of_range -#include <string> // for string, basic... -#include <utility> // for move -#include <vector> // for vector +#include "caosdb/data_type.h" // for DataType +#include "caosdb/entity/v1/main.pb.h" // for RepeatedPtrField +#include "caosdb/file_descriptor.h" // for FileDescriptor +#include "caosdb/logging.h" // for CAOSDB_LOG_WARN +#include "caosdb/message_code.h" // for get_message_code +#include "caosdb/protobuf_helper.h" // for get_arena +#include "caosdb/status_code.h" // for StatusCode +#include "caosdb/value.h" // for Value +#include <cstdint> // for int64_t +#include <filesystem> // for path +#include <google/protobuf/arena.h> // for Arena +#include <google/protobuf/message.h> // for RepeatedPtrField +#include <iterator> // for iterator, output_iterato... +#include <map> // for map +#include <stdexcept> // for out_of_range +#include <string> // for string, basic... +#include <utility> // for move +#include <vector> // for vector namespace caosdb::entity { -using boost::filesystem::exists; -using boost::filesystem::is_directory; -using caosdb::entity::v1alpha1::IdResponse; -using ProtoParent = caosdb::entity::v1alpha1::Parent; -using ProtoProperty = caosdb::entity::v1alpha1::Property; -using ProtoEntity = caosdb::entity::v1alpha1::Entity; -using ProtoFileDescriptor = caosdb::entity::v1alpha1::FileDescriptor; -using ProtoMessage = caosdb::entity::v1alpha1::Message; -using ProtoValue = caosdb::entity::v1alpha1::Value; -using ProtoDataType = caosdb::entity::v1alpha1::DataType; -using caosdb::entity::v1alpha1::EntityRole; -using ProtoImportance = caosdb::entity::v1alpha1::Importance; +using caosdb::entity::v1::IdResponse; +using std::filesystem::exists; +using std::filesystem::is_directory; +using ProtoParent = caosdb::entity::v1::Parent; +using ProtoProperty = caosdb::entity::v1::Property; +using ProtoEntity = caosdb::entity::v1::Entity; +using ProtoMessage = caosdb::entity::v1::Message; +using ProtoValue = caosdb::entity::v1::Value; +using ProtoDataType = caosdb::entity::v1::DataType; +using caosdb::entity::v1::EntityRole; +using ProtoImportance = caosdb::entity::v1::Importance; using caosdb::StatusCode; -using caosdb::entity::v1alpha1::EntityResponse; -using caosdb::entity::v1alpha1::FileTransmissionId; +using caosdb::entity::v1::EntityResponse; +using caosdb::entity::v1::FileTransmissionId; using caosdb::utility::get_arena; using caosdb::utility::ProtoMessageWrapper; using ::google::protobuf::RepeatedPtrField; @@ -110,12 +103,6 @@ const std::map<Role, std::string> role_names = {{Role::UNSPECIFIED, "UNSPECIFIED {Role::PROPERTY, "PROPERTY"}, {Role::FILE, "FILE"}}; -struct FileDescriptor { - FileTransmissionId *file_transmission_id; - ProtoFileDescriptor *wrapped; - boost::filesystem::path local_path; -}; - /** * Abstract base class for Messages, Properties and Parents container classes. * @@ -372,6 +359,9 @@ private: inline Messages() : RepeatedPtrFieldWrapper<Message, ProtoMessage>(){}; }; +/////////////////////////////////////////////////////////////////////////////// +// class Parent /////////////////////////////////////////////////////////////// + /** * Parent of an Entity. * @@ -383,6 +373,37 @@ class Parent : public ScalarProtoMessageWrapper<ProtoParent> { public: explicit inline Parent(ProtoParent *wrapped) : ScalarProtoMessageWrapper<ProtoParent>(wrapped){}; Parent() : ScalarProtoMessageWrapper<ProtoParent>(){}; + ~Parent() = default; + + /** + * Copy constructor. + */ + inline Parent(const Parent &other) + : Parent(ProtoMessageWrapper<ProtoParent>::CopyProtoMessage(other.wrapped)) {} + + /** + * Move constructor. + */ + inline Parent(Parent &&other) : Parent(other.wrapped) { other.wrapped = nullptr; } + + /** + * Copy assignment operator. + */ + inline auto operator=(const Parent &other) -> Parent & { + if (this != &other) { + this->wrapped->CopyFrom(*other.wrapped); + } + return *this; + } + + /** + * Move assignment operator. + */ + inline auto operator=(Parent &&other) -> Parent & { + this->wrapped = other.wrapped; + other.wrapped = nullptr; + return *this; + } /** * Return the id of the parent entity. @@ -454,11 +475,13 @@ public: private: inline Parents() : RepeatedPtrFieldWrapper<Parent, ProtoParent>(){}; - explicit inline Parents( - ::google::protobuf::RepeatedPtrField<caosdb::entity::v1alpha1::Parent> *wrapped) + explicit inline Parents(::google::protobuf::RepeatedPtrField<caosdb::entity::v1::Parent> *wrapped) : RepeatedPtrFieldWrapper<Parent, ProtoParent>(wrapped){}; }; +/////////////////////////////////////////////////////////////////////////////// +// class Property ///////////////////////////////////////////////////////////// + /** * Property of an Entity. * @@ -497,6 +520,8 @@ public: : ScalarProtoMessageWrapper<ProtoProperty>(), value(static_cast<ProtoValue *>(nullptr)), data_type(static_cast<ProtoDataType *>(nullptr)){}; + ~Property() = default; + /** * Return the id of this property */ @@ -639,6 +664,9 @@ private: : RepeatedPtrFieldWrapper<Property, ProtoProperty>(wrapped){}; }; +/////////////////////////////////////////////////////////////////////////////// +// class Entity /////////////////////////////////////////////////////////////// + /** * Entity is the central and basic data object of CaosDB. * @@ -648,14 +676,17 @@ private: * Overview of the Constructors: * * <li> Entity() - Calls Entity(ProtoEntity *) with a fresh ProtoEntity - * <li> Entity(Entity) - Copy constructor, calls Entity(ProtoEntity *) after copying wrapped - * ProtoEntity of the original, then also copies all Messages. <li> Entity(ProtoEntity *) - The - * workhorse of the constructors. Initializes everything and does not call other Entity - * constructors. <li> Entity(EntityResponse *) - Constructor which is used by the Transaction class - * to create an Entity from the server's response, calls Entity(ProtoEntity). <li> Entity(IdResponse - * *) - Constructor which is used by the Transaction class to create an Entity from the servers's - * response. calls Entity(), then moves the data to the wrapped ProtoEntity. - * + * <li> Entity(const Entity&) - Copy constructor, calls Entity(ProtoEntity *) after + * copying wrapped ProtoEntity of the original, then also copies all Messages. + * <li> Entity(ProtoEntity *) - The workhorse of the constructors. Initializes + * everything and does not call other Entity constructors. + * <li> Entity(EntityResponse *) - Constructor which is used by the Transaction class + * to create an Entity from the server's response, calls Entity(ProtoEntity). + * <li> Entity(IdResponse *) - Constructor which is used by the Transaction + * class to create an Entity from the servers's response. calls Entity(), + * then moves the data to the wrapped ProtoEntity. + * <li> Entity(Entity&&) - Move constructor, calls Entity(ProtoEntity *), then + * moves the messages and resets the original, */ class Entity : public ScalarProtoMessageWrapper<ProtoEntity> { public: @@ -676,8 +707,11 @@ public: : static_cast<ProtoDataType *>(nullptr)) { properties.wrapped = this->wrapped->mutable_properties(); parents.wrapped = this->wrapped->mutable_parents(); + if (this->wrapped->has_file_descriptor()) { + file_descriptor.wrapped = this->wrapped->mutable_file_descriptor(); + } }; - explicit inline Entity(EntityResponse *response) : Entity(response->release_entity()) { + explicit inline Entity(EntityResponse *response) : Entity(response->mutable_entity()) { this->errors.wrapped->Swap(response->mutable_errors()); this->warnings.wrapped->Swap(response->mutable_warnings()); this->infos.wrapped->Swap(response->mutable_infos()); @@ -698,6 +732,8 @@ public: parents.wrapped = this->wrapped->mutable_parents(); }; + ~Entity() = default; + /** * Move constructor. */ @@ -705,8 +741,8 @@ public: original.wrapped = nullptr; original.value.wrapped = nullptr; original.data_type.wrapped = nullptr; - this->properties = std::move(original.properties); - this->parents = std::move(original.parents); + original.properties.wrapped = nullptr; + original.parents.wrapped = nullptr; this->errors = std::move(original.errors); this->warnings = std::move(original.warnings); this->infos = std::move(original.infos); @@ -738,7 +774,7 @@ public: this->value = other.value; this->properties = other.properties; this->parents = other.parents; - this->file_descriptor.local_path = boost::filesystem::path(other.file_descriptor.local_path); + this->file_descriptor.local_path = std::filesystem::path(other.file_descriptor.local_path); this->file_descriptor.file_transmission_id->CopyFrom( *other.file_descriptor.file_transmission_id); this->file_descriptor.wrapped->CopyFrom(*other.file_descriptor.wrapped); @@ -825,19 +861,17 @@ public: auto SetFilePath(const std::string &path) -> void; inline auto HasFile() const -> bool { return !this->file_descriptor.local_path.empty(); } - auto SetFileTransmissionRegistrationId(const std::string ®istration_id) -> void; inline auto SetFileTransmissionId(FileTransmissionId *file_transmission_id) -> void { - file_transmission_id->set_file_id(GetNextFileId()); file_descriptor.file_transmission_id = file_transmission_id; } inline auto GetFileDescriptor() -> FileDescriptor & { return this->file_descriptor; } - inline auto GetLocalPath() const noexcept -> const boost::filesystem::path & { + inline auto GetLocalPath() const noexcept -> const std::filesystem::path & { return this->file_descriptor.local_path; } - inline auto SetLocalPath(const boost::filesystem::path &local_path) noexcept -> StatusCode { + inline auto SetLocalPath(const std::filesystem::path &local_path) noexcept -> StatusCode { if (GetRole() != Role::FILE) { CAOSDB_LOG_WARN(logger_name) << "Entity::SetLocalPath failed. This is not a file entity."; return StatusCode::NOT_A_FILE_ENTITY; @@ -874,20 +908,10 @@ public: } private: - inline auto GetNextFileId() -> std::string { - std::string str = "0123456789abcdef"; - std::mt19937 generator(std::random_device{}()); - std::uniform_int_distribution<int> distribution(0, str.size() - 1); - std::string result(10, '\0'); - - for (auto &dis : result) { - dis = str[distribution(generator)]; - } - return result; - } static auto CreateMessagesField() -> RepeatedPtrField<ProtoMessage> *; auto SetId(const std::string &id) -> void; auto SetVersionId(const std::string &id) -> void; + auto inline GetArena() const -> Arena * { return get_arena(); } private: FileDescriptor file_descriptor; diff --git a/include/caosdb/exceptions.h b/include/caosdb/exceptions.h index 304216679200329660c5068362fa9e089f089235..415d0722580e1199f014358f524caf75f9d68b32 100644 --- a/include/caosdb/exceptions.h +++ b/include/caosdb/exceptions.h @@ -101,12 +101,12 @@ public: }; /** - * @brief The connection isn't known to the ConnectionManager under this name. + * @brief Exception for errors during the configuration of the connection. */ -class UnknownConnectionError : public Exception { +class ConnectionConfigurationError : public Exception { public: - explicit UnknownConnectionError(const std::string &what_arg) - : Exception(StatusCode::UNKNOWN_CONNECTION_ERROR, what_arg) {} + explicit ConnectionConfigurationError(const std::string &what_arg) + : Exception(StatusCode::CONNECTION_CONFIGURATION_ERROR, what_arg) {} }; } // namespace caosdb::exceptions diff --git a/include/caosdb/file_descriptor.h b/include/caosdb/file_descriptor.h new file mode 100644 index 0000000000000000000000000000000000000000..c6d6784c6cc73632dfdd871720c241a59ab03079 --- /dev/null +++ b/include/caosdb/file_descriptor.h @@ -0,0 +1,46 @@ +/* + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2022 Timm Fitschen <t.fitschen@indiscale.com> + * Copyright (C) 2022 IndiScale GmbH <info@indiscale.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +/** + * @brief File descriptors are used to represent directories, links and files + * of the caosdb file system and their meta data. + * @file caosdb/entity.h + * @author Timm Fitchen + * @date 2022-01-21 + */ +#ifndef CAOSDB_FILE_DESCRIPTOR_H +#define CAOSDB_FILE_DESCRIPTOR_H + +#include "caosdb/entity/v1/main.pb.h" // for RepeatedPtrField +#include <filesystem> // for path + +namespace caosdb::entity { +using ProtoFileDescriptor = caosdb::entity::v1::FileDescriptor; +using caosdb::entity::v1::FileTransmissionId; + +struct FileDescriptor { + FileTransmissionId *file_transmission_id; + ProtoFileDescriptor *wrapped; + std::filesystem::path local_path; +}; + +} // namespace caosdb::entity +#endif diff --git a/include/caosdb/file_transmission/download_request_handler.h b/include/caosdb/file_transmission/download_request_handler.h index cd3d05b4144acc54bcf39d8a584a1e5d4466a7fa..965db6419de180f46e1a712d4a4d5795857599ab 100644 --- a/include/caosdb/file_transmission/download_request_handler.h +++ b/include/caosdb/file_transmission/download_request_handler.h @@ -49,11 +49,12 @@ #ifndef CAOSDB_FILE_TRANSMISSION_DOWNLOAD_REQUEST_HANDLER_H #define CAOSDB_FILE_TRANSMISSION_DOWNLOAD_REQUEST_HANDLER_H -#include "caosdb/entity.h" // for FileDescriptor -#include "caosdb/entity/v1alpha1/main.grpc.pb.h" // for FileTransmissionS... -#include "caosdb/entity/v1alpha1/main.pb.h" // for FileDownloadResponse +#include "caosdb/file_descriptor.h" // for FileDescriptor +#include "caosdb/entity/v1/main.grpc.pb.h" // for FileTransmissionS... +#include "caosdb/entity/v1/main.pb.h" // for FileDownloadResponse #include "caosdb/file_transmission/file_writer.h" // for FileWriter #include "caosdb/handler_interface.h" // for HandlerTag, Handl... +#include <cstdint> // for uint64_t #include <grpcpp/impl/codegen/async_stream.h> // for ClientAsyncReader #include <grpcpp/impl/codegen/client_context.h> // for ClientContext #include <grpcpp/impl/codegen/completion_queue.h> // for CompletionQueue @@ -62,9 +63,9 @@ namespace caosdb::transaction { using caosdb::entity::FileDescriptor; -using caosdb::entity::v1alpha1::FileDownloadRequest; -using caosdb::entity::v1alpha1::FileDownloadResponse; -using caosdb::entity::v1alpha1::FileTransmissionService; +using caosdb::entity::v1::FileDownloadRequest; +using caosdb::entity::v1::FileDownloadResponse; +using caosdb::entity::v1::FileTransmissionService; using caosdb::transaction::HandlerInterface; using caosdb::transaction::HandlerTag; @@ -119,7 +120,7 @@ protected: FileDescriptor file_descriptor_; - unsigned long long bytesReceived_; + uint64_t bytesReceived_; }; } // namespace caosdb::transaction diff --git a/include/caosdb/file_transmission/file_reader.h b/include/caosdb/file_transmission/file_reader.h index 67c1247fa97cc43e28064b4e0da81812f41b231a..380b6a838b77e9f80f91f93c84eb0b0f888de2e0 100644 --- a/include/caosdb/file_transmission/file_reader.h +++ b/include/caosdb/file_transmission/file_reader.h @@ -49,20 +49,20 @@ #ifndef CAOSDB_FILE_TRANSMISSION_FILE_READER_H #define CAOSDB_FILE_TRANSMISSION_FILE_READER_H -#include <boost/filesystem/fstream.hpp> // for ifstream -#include <boost/filesystem/operations.hpp> // for exists -#include <boost/filesystem/path.hpp> // for path -#include <fstream> // for ifstream, size_t -#include <string> // for string +#include <cstddef> // for size_t +#include <cstdint> // for uint64_t +#include <filesystem> // for path, exists +#include <fstream> // for ifstream +#include <string> // for string namespace caosdb::transaction { -using boost::filesystem::exists; -using boost::filesystem::ifstream; -using boost::filesystem::path; +using std::ifstream; +using std::filesystem::exists; +using std::filesystem::path; class FileReader final { public: - FileReader(boost::filesystem::path filename); + FileReader(std::filesystem::path filename); ~FileReader() = default; @@ -72,7 +72,7 @@ public: FileReader(FileReader &&) = default; FileReader &operator=(FileReader &&) = default; - unsigned long long fileSize() const { return size_; } + uint64_t fileSize() const { return size_; } std::size_t read(std::string &buffer); @@ -80,8 +80,8 @@ private: void openFile(); std::ifstream stream_; - boost::filesystem::path filename_; - unsigned long long size_; + std::filesystem::path filename_; + uint64_t size_; }; } // namespace caosdb::transaction diff --git a/include/caosdb/file_transmission/file_writer.h b/include/caosdb/file_transmission/file_writer.h index 801d74b9547951d2a3b86ed4b333bfb4b7035aa9..165178b1e3b44f9d3208220d1422af1bb61d0833 100644 --- a/include/caosdb/file_transmission/file_writer.h +++ b/include/caosdb/file_transmission/file_writer.h @@ -49,15 +49,15 @@ #ifndef CAOSDB_FILE_TRANSMISSION_FILE_WRITER_H #define CAOSDB_FILE_TRANSMISSION_FILE_WRITER_H -#include <boost/filesystem/path.hpp> // for path -#include <fstream> // for ofstream -#include <string> // for string +#include <filesystem> // for path +#include <fstream> // for ofstream +#include <string> // for string namespace caosdb::transaction { class FileWriter final { public: - FileWriter(boost::filesystem::path filename); + FileWriter(std::filesystem::path filename); ~FileWriter() = default; @@ -73,7 +73,7 @@ private: void openFile(); std::ofstream stream_; - boost::filesystem::path filename_; + std::filesystem::path filename_; }; } // namespace caosdb::transaction diff --git a/include/caosdb/file_transmission/register_file_upload_handler.h b/include/caosdb/file_transmission/register_file_upload_handler.h index f4586220980b056891effb142c4d736efc809fcf..37df2dbf0fb895cd77f63bab2596a0b124c48b9c 100644 --- a/include/caosdb/file_transmission/register_file_upload_handler.h +++ b/include/caosdb/file_transmission/register_file_upload_handler.h @@ -49,9 +49,9 @@ #ifndef CAOSDB_FILE_TRANSMISSION_REGISTER_FILE_UPLOAD_H #define CAOSDB_FILE_TRANSMISSION_REGISTER_FILE_UPLOAD_H -#include "caosdb/entity/v1alpha1/main.grpc.pb.h" // for FileTransmissionS... -#include "caosdb/entity/v1alpha1/main.pb.h" // for FileDownloadResponse -#include "caosdb/handler_interface.h" // for HandlerTag, Handl... +#include "caosdb/entity/v1/main.grpc.pb.h" // for FileTransmissionS... +#include "caosdb/entity/v1/main.pb.h" // for FileDownloadResponse +#include "caosdb/handler_interface.h" // for HandlerTag, Handl... #include "caosdb/unary_rpc_handler.h" #include <grpcpp/impl/codegen/async_unary_call.h> // for ClientAsyncRespons... #include <grpcpp/impl/codegen/completion_queue.h> // for CompletionQueue @@ -59,9 +59,9 @@ namespace caosdb::transaction { -using caosdb::entity::v1alpha1::FileTransmissionService; -using caosdb::entity::v1alpha1::RegisterFileUploadRequest; -using caosdb::entity::v1alpha1::RegisterFileUploadResponse; +using caosdb::entity::v1::FileTransmissionService; +using caosdb::entity::v1::RegisterFileUploadRequest; +using caosdb::entity::v1::RegisterFileUploadResponse; class RegisterFileUploadHandler final : public UnaryRpcHandler { public: diff --git a/include/caosdb/file_transmission/upload_request_handler.h b/include/caosdb/file_transmission/upload_request_handler.h index 81d84fac70c2a45ad6f4f18a65ee4374dfd31c71..099e39e62a087111308f7afdf77631a3e42c5d09 100644 --- a/include/caosdb/file_transmission/upload_request_handler.h +++ b/include/caosdb/file_transmission/upload_request_handler.h @@ -49,9 +49,9 @@ #ifndef CAOSDB_FILE_TRANSMISSION_UPLOAD_REQUEST_HANDLER_H #define CAOSDB_FILE_TRANSMISSION_UPLOAD_REQUEST_HANDLER_H -#include "caosdb/entity.h" // for FileDescriptor -#include "caosdb/entity/v1alpha1/main.grpc.pb.h" // for FileTransmissionS... -#include "caosdb/entity/v1alpha1/main.pb.h" // for FileUploadRequest +#include "caosdb/entity/v1/main.grpc.pb.h" // for FileTransmissionS... +#include "caosdb/entity/v1/main.pb.h" // for FileUploadRequest +#include "caosdb/file_descriptor.h" // for FileDescriptor #include "caosdb/file_transmission/file_reader.h" // for FileReader #include "caosdb/handler_interface.h" // for HandlerTag, Handl... #include <cstdint> // for uint64_t @@ -63,9 +63,9 @@ namespace caosdb::transaction { using caosdb::entity::FileDescriptor; -using caosdb::entity::v1alpha1::FileTransmissionService; -using caosdb::entity::v1alpha1::FileUploadRequest; -using caosdb::entity::v1alpha1::FileUploadResponse; +using caosdb::entity::v1::FileTransmissionService; +using caosdb::entity::v1::FileUploadRequest; +using caosdb::entity::v1::FileUploadResponse; using caosdb::transaction::HandlerInterface; using caosdb::transaction::HandlerTag; diff --git a/include/caosdb/info.h b/include/caosdb/info.h index cf2c879120becd8db211e85df39d62ac9ba1434e..0c4132f770d7bd68f10a74743246c0c037364f01 100644 --- a/include/caosdb/info.h +++ b/include/caosdb/info.h @@ -27,13 +27,13 @@ * @date 2021-07-02 * @brief General information about the CaosDBServer. */ -#include "caosdb/info/v1alpha1/main.pb.h" // for VersionInfo -#include <cstdint> // for uint32_t -#include <string> // for string +#include "caosdb/info/v1/main.pb.h" // for VersionInfo +#include <cstdint> // for uint32_t +#include <string> // for string namespace caosdb::info { -using ProtoVersionInfo = caosdb::info::v1alpha1::VersionInfo; +using ProtoVersionInfo = caosdb::info::v1::VersionInfo; /** * A read-only version object which represents the version of the server. diff --git a/include/caosdb/logging.h b/include/caosdb/logging.h index 896b16d9091b7e4fff10f5157fa97a029e55f9af..1524b0d424f188acdb51c797b68f73bfab4087f5 100644 --- a/include/caosdb/logging.h +++ b/include/caosdb/logging.h @@ -24,16 +24,7 @@ #define CAOSDB_LOGGING_H #include "caosdb/log_level.h" // for CAOSDB_LOG_... -#include <boost/log/sources/global_logger_storage.hpp> // for BOOST_LOG_I... -#include <boost/log/sources/record_ostream.hpp> // IWYU pragma: keep -#include <boost/log/sources/severity_channel_logger.hpp> // for BOOST_LOG_C... -#include <boost/log/utility/setup/settings.hpp> // for settings -#include <boost/smart_ptr/intrusive_ptr.hpp> // for intrusive_ptr -#include <boost/smart_ptr/intrusive_ref_counter.hpp> // for intrusive_p... -#include <boost/log/core/record.hpp> // for record -#include <boost/log/detail/attachable_sstream_buf.hpp> // for basic_ostri... -#include <boost/preprocessor/seq/limits/enum_256.hpp> // for BOOST_PP_SE... -#include <boost/preprocessor/seq/limits/size_256.hpp> // for BOOST_PP_SE... +#include <cstdint> // for uint64_t #include <iosfwd> // for streamsize #include <memory> // for shared_ptr #include <string> // for string @@ -43,9 +34,24 @@ namespace caosdb::logging { const std::string logger_name = "caosdb::logging"; -typedef boost::log::sources::severity_channel_logger_mt<int, std::string> boost_logger_class; +class LoggerOutputStream { +public: + LoggerOutputStream(std::string channel, int level); + auto operator<<(int msg) -> LoggerOutputStream &; + auto operator<<(uint64_t msg) -> LoggerOutputStream &; + auto operator<<(int64_t msg) -> LoggerOutputStream &; + auto operator<<(std::streambuf *msg) -> LoggerOutputStream &; + auto operator<<(const char *msg) -> LoggerOutputStream &; + auto operator<<(const std::string &msg) -> LoggerOutputStream &; + auto operator<<(void *msg) -> LoggerOutputStream &; + static auto get(const std::string &channel, int level) -> LoggerOutputStream { + return LoggerOutputStream(channel, level); + } -BOOST_LOG_GLOBAL_LOGGER(logger, boost_logger_class) +private: + std::string channel; + int level; +}; /** * Helper class for logging the entering and leaving of a function or method. @@ -132,7 +138,7 @@ public: friend auto initialize_logging(const LoggingConfiguration &logging_configuration) -> void; protected: - virtual auto Configure(boost::log::settings &settings) const -> void; + virtual auto Configure(void *settings) const -> void; private: std::string name; @@ -148,7 +154,7 @@ public: protected: typedef SinkConfiguration sink_configuration; - virtual auto Configure(boost::log::settings &settings) const -> void override; + virtual auto Configure(void *settings) const -> void override; private: const std::string destination = "Console"; @@ -171,7 +177,7 @@ public: protected: typedef SinkConfiguration sink_configuration; - virtual auto Configure(boost::log::settings &settings) const -> void override; + virtual auto Configure(void *settings) const -> void override; private: const std::string destination = "TextFile"; @@ -216,17 +222,17 @@ void caosdb_log_trace(const char *channel, const char *msg); } // namespace caosdb::logging #define CAOSDB_LOG_FATAL(Channel) \ - BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), Channel, CAOSDB_LOG_LEVEL_FATAL) + caosdb::logging::LoggerOutputStream::get(Channel, CAOSDB_LOG_LEVEL_FATAL) #define CAOSDB_LOG_ERROR(Channel) \ - BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), Channel, CAOSDB_LOG_LEVEL_ERROR) + caosdb::logging::LoggerOutputStream::get(Channel, CAOSDB_LOG_LEVEL_ERROR) #define CAOSDB_LOG_WARN(Channel) \ - BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), Channel, CAOSDB_LOG_LEVEL_WARN) + caosdb::logging::LoggerOutputStream::get(Channel, CAOSDB_LOG_LEVEL_WARN) #define CAOSDB_LOG_INFO(Channel) \ - BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), Channel, CAOSDB_LOG_LEVEL_INFO) + caosdb::logging::LoggerOutputStream::get(Channel, CAOSDB_LOG_LEVEL_INFO) #define CAOSDB_LOG_DEBUG(Channel) \ - BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), Channel, CAOSDB_LOG_LEVEL_DEBUG) + caosdb::logging::LoggerOutputStream::get(Channel, CAOSDB_LOG_LEVEL_DEBUG) #define CAOSDB_LOG_TRACE(Channel) \ - BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), Channel, CAOSDB_LOG_LEVEL_TRACE) + caosdb::logging::LoggerOutputStream::get(Channel, CAOSDB_LOG_LEVEL_TRACE) #define CAOSDB_LOG_TRACE_ENTER_AND_LEAVE(Channel, FunctionName) \ const caosdb::logging::TraceEnterLeaveLogger trace_enter_leave_logger(Channel, FunctionName); diff --git a/include/caosdb/message_code.h b/include/caosdb/message_code.h index a277656cd3848931bdc6dff6d3a802dab8da3282..ce539c188eabfa0d20762eac9fbe1083185286ea 100644 --- a/include/caosdb/message_code.h +++ b/include/caosdb/message_code.h @@ -22,7 +22,7 @@ #ifndef CAOSDB_MESSAGE_CODE_H #define CAOSDB_MESSAGE_CODE_H -#include "caosdb/entity/v1alpha1/main.pb.h" // for Entity, RepeatedField +#include "caosdb/entity/v1/main.pb.h" // for Entity, RepeatedField /** * MessageCodes for entity messages. @@ -38,16 +38,68 @@ namespace caosdb::entity { +#define _MAP_MESSAGE_CODE(name) name = caosdb::entity::v1::MessageCode::MESSAGE_CODE_##name + enum MessageCode { - UNSPECIFIED = caosdb::entity::v1alpha1::MessageCode::MESSAGE_CODE_UNSPECIFIED, - UNKNOWN = caosdb::entity::v1alpha1::MessageCode::MESSAGE_CODE_UNKNOWN, - ENTITY_DOES_NOT_EXIST = caosdb::entity::v1alpha1::MessageCode::MESSAGE_CODE_ENTITY_DOES_NOT_EXIST, - ENTITY_HAS_NO_PROPERTIES = - caosdb::entity::v1alpha1::MessageCode::MESSAGE_CODE_ENTITY_HAS_NO_PROPERTIES, - INTEGER_VALUE_OUT_OF_RANGE = - caosdb::entity::v1alpha1::MessageCode::MESSAGE_CODE_INTEGER_VALUE_OUT_OF_RANGE, - ENTITY_HAS_BEEN_DELETED_SUCCESSFULLY = - caosdb::entity::v1alpha1::MessageCode::MESSAGE_CODE_ENTITY_HAS_BEEN_DELETED_SUCCESSFULLY, + _MAP_MESSAGE_CODE(UNSPECIFIED), + _MAP_MESSAGE_CODE(UNKNOWN), + _MAP_MESSAGE_CODE(ENTITY_DOES_NOT_EXIST), + _MAP_MESSAGE_CODE(ENTITY_HAS_NO_PROPERTIES), + _MAP_MESSAGE_CODE(ENTITY_HAS_BEEN_DELETED_SUCCESSFULLY), + _MAP_MESSAGE_CODE(ENTITY_HAS_UNQUALIFIED_PROPERTIES), + _MAP_MESSAGE_CODE(ENTITY_HAS_UNQUALIFIED_PARENTS), + _MAP_MESSAGE_CODE(ENTITY_HAS_NO_ID), + _MAP_MESSAGE_CODE(REQUIRED_BY_PERSISTENT_ENTITY), + _MAP_MESSAGE_CODE(PROPERTY_HAS_NO_DATA_TYPE), + _MAP_MESSAGE_CODE(ENTITY_HAS_NO_DESCRIPTION), + _MAP_MESSAGE_CODE(ENTITY_HAS_NO_NAME), + _MAP_MESSAGE_CODE(OBLIGATORY_PROPERTY_MISSING), + _MAP_MESSAGE_CODE(ENTITY_HAS_NO_PARENTS), + _MAP_MESSAGE_CODE(FILE_HAS_NO_TARGET_PATH), + _MAP_MESSAGE_CODE(TARGET_PATH_NOT_ALLOWED), + _MAP_MESSAGE_CODE(TARGET_PATH_EXISTS), + _MAP_MESSAGE_CODE(PROPERTY_HAS_NO_UNIT), + _MAP_MESSAGE_CODE(CANNOT_PARSE_VALUE), + _MAP_MESSAGE_CODE(CHECKSUM_TEST_FAILED), + _MAP_MESSAGE_CODE(SIZE_TEST_FAILED), + _MAP_MESSAGE_CODE(CANNOT_CREATE_PARENT_FOLDER), + _MAP_MESSAGE_CODE(FILE_HAS_NOT_BEEN_UPLOAED), + _MAP_MESSAGE_CODE(CANNOT_MOVE_FILE_TO_TARGET_PATH), + _MAP_MESSAGE_CODE(CANNOT_PARSE_DATETIME_VALUE), + _MAP_MESSAGE_CODE(CANNOT_PARSE_DOUBLE_VALUE), + _MAP_MESSAGE_CODE(CANNOT_PARSE_INT_VALUE), + _MAP_MESSAGE_CODE(CANNOT_PARSE_BOOL_VALUE), + _MAP_MESSAGE_CODE(FILE_NOT_FOUND), + _MAP_MESSAGE_CODE(WARNING_OCCURED), + _MAP_MESSAGE_CODE(ENTITY_NAME_IS_NOT_UNIQUE), + _MAP_MESSAGE_CODE(QUERY_EXCEPTION), + _MAP_MESSAGE_CODE(TRANSACTION_ROLL_BACK), + _MAP_MESSAGE_CODE(UNKNOWN_UNIT), + _MAP_MESSAGE_CODE(AUTHORIZATION_ERROR), + _MAP_MESSAGE_CODE(REFERENCE_IS_NOT_ALLOWED_BY_DATA_TYPE), + _MAP_MESSAGE_CODE(ENTITY_NAME_DUPLICATES), + _MAP_MESSAGE_CODE(DATA_TYPE_NAME_DUPLICATES), + _MAP_MESSAGE_CODE(ENTITY_HAS_NO_NAME_OR_ID), + _MAP_MESSAGE_CODE(AFFILIATION_ERROR), + _MAP_MESSAGE_CODE(QUERY_PARSING_ERROR), + _MAP_MESSAGE_CODE(NAME_PROPERTIES_MUST_BE_TEXT), + _MAP_MESSAGE_CODE(PARENT_DUPLICATES_WARNING), + _MAP_MESSAGE_CODE(PARENT_DUPLICATES_ERROR), + _MAP_MESSAGE_CODE(ATOMICITY_ERROR), + _MAP_MESSAGE_CODE(NO_SUCH_ENTITY_ROLE), + _MAP_MESSAGE_CODE(REQUIRED_BY_UNQUALIFIED), + _MAP_MESSAGE_CODE(ENTITY_HAS_UNQUALIFIED_REFERENCE), + _MAP_MESSAGE_CODE(REFERENCED_ENTITY_DOES_NOT_EXIST), + _MAP_MESSAGE_CODE(REFERENCE_NAME_DUPLICATES), + _MAP_MESSAGE_CODE(DATA_TYPE_INHERITANCE_AMBIGUOUS), + _MAP_MESSAGE_CODE(DATA_TYPE_DOES_NOT_ACCEPT_COLLECTION_VALUES), + _MAP_MESSAGE_CODE(CANNOT_PARSE_UNIT), + _MAP_MESSAGE_CODE(ADDITIONAL_PROPERTY), + _MAP_MESSAGE_CODE(PROPERTY_WITH_DATA_TYPE_OVERRIDE), + _MAP_MESSAGE_CODE(PROPERTY_WITH_DESCRIPTION_OVERRIDE), + _MAP_MESSAGE_CODE(PROPERTY_WITH_NAME_OVERRIDE), + _MAP_MESSAGE_CODE(INTEGER_VALUE_OUT_OF_RANGE), + _MAP_MESSAGE_CODE(INTEGRITY_VIOLATION), }; [[nodiscard]] inline auto get_message_code(int code) noexcept -> MessageCode { @@ -57,12 +109,65 @@ enum MessageCode { MessageCode::UNKNOWN, MessageCode::ENTITY_DOES_NOT_EXIST, MessageCode::ENTITY_HAS_NO_PROPERTIES, - MessageCode::INTEGER_VALUE_OUT_OF_RANGE, MessageCode::ENTITY_HAS_BEEN_DELETED_SUCCESSFULLY, + MessageCode::ENTITY_HAS_UNQUALIFIED_PROPERTIES, + MessageCode::ENTITY_HAS_UNQUALIFIED_PARENTS, + MessageCode::ENTITY_HAS_NO_ID, + MessageCode::REQUIRED_BY_PERSISTENT_ENTITY, + MessageCode::PROPERTY_HAS_NO_DATA_TYPE, + MessageCode::ENTITY_HAS_NO_DESCRIPTION, + MessageCode::ENTITY_HAS_NO_NAME, + MessageCode::OBLIGATORY_PROPERTY_MISSING, + MessageCode::ENTITY_HAS_NO_PARENTS, + MessageCode::FILE_HAS_NO_TARGET_PATH, + MessageCode::TARGET_PATH_NOT_ALLOWED, + MessageCode::TARGET_PATH_EXISTS, + MessageCode::PROPERTY_HAS_NO_UNIT, + MessageCode::CANNOT_PARSE_VALUE, + MessageCode::CHECKSUM_TEST_FAILED, + MessageCode::SIZE_TEST_FAILED, + MessageCode::CANNOT_CREATE_PARENT_FOLDER, + MessageCode::FILE_HAS_NOT_BEEN_UPLOAED, + MessageCode::CANNOT_MOVE_FILE_TO_TARGET_PATH, + MessageCode::CANNOT_PARSE_DATETIME_VALUE, + MessageCode::CANNOT_PARSE_DOUBLE_VALUE, + MessageCode::CANNOT_PARSE_INT_VALUE, + MessageCode::CANNOT_PARSE_BOOL_VALUE, + MessageCode::FILE_NOT_FOUND, + MessageCode::WARNING_OCCURED, + MessageCode::ENTITY_NAME_IS_NOT_UNIQUE, + MessageCode::QUERY_EXCEPTION, + MessageCode::TRANSACTION_ROLL_BACK, + MessageCode::UNKNOWN_UNIT, + MessageCode::AUTHORIZATION_ERROR, + MessageCode::REFERENCE_IS_NOT_ALLOWED_BY_DATA_TYPE, + MessageCode::ENTITY_NAME_DUPLICATES, + MessageCode::DATA_TYPE_NAME_DUPLICATES, + MessageCode::ENTITY_HAS_NO_NAME_OR_ID, + MessageCode::AFFILIATION_ERROR, + MessageCode::QUERY_PARSING_ERROR, + MessageCode::NAME_PROPERTIES_MUST_BE_TEXT, + MessageCode::PARENT_DUPLICATES_WARNING, + MessageCode::PARENT_DUPLICATES_ERROR, + MessageCode::ATOMICITY_ERROR, + MessageCode::NO_SUCH_ENTITY_ROLE, + MessageCode::REQUIRED_BY_UNQUALIFIED, + MessageCode::ENTITY_HAS_UNQUALIFIED_REFERENCE, + MessageCode::REFERENCED_ENTITY_DOES_NOT_EXIST, + MessageCode::REFERENCE_NAME_DUPLICATES, + MessageCode::DATA_TYPE_INHERITANCE_AMBIGUOUS, + MessageCode::DATA_TYPE_DOES_NOT_ACCEPT_COLLECTION_VALUES, + MessageCode::CANNOT_PARSE_UNIT, + MessageCode::ADDITIONAL_PROPERTY, + MessageCode::PROPERTY_WITH_DATA_TYPE_OVERRIDE, + MessageCode::PROPERTY_WITH_DESCRIPTION_OVERRIDE, + MessageCode::PROPERTY_WITH_NAME_OVERRIDE, + MessageCode::INTEGER_VALUE_OUT_OF_RANGE, + MessageCode::INTEGRITY_VIOLATION, }; for (MessageCode known_code : all_codes) { - if (known_code == code) { + if (static_cast<int>(known_code) == code) { return known_code; } } diff --git a/include/caosdb/protobuf_helper.h b/include/caosdb/protobuf_helper.h index 63b2c54cdfaae5eef33705ac7074e11c1caf3653..ef4cb8383eb384cd058a3f210c9d27f99b199658 100644 --- a/include/caosdb/protobuf_helper.h +++ b/include/caosdb/protobuf_helper.h @@ -22,9 +22,8 @@ #ifndef CAOSDB_PROTOBUF_HELPER_H #define CAOSDB_PROTOBUF_HELPER_H -#include <google/protobuf/arena.h> // for Arena -// IWYU pragma: no_include "google/protobuf/extension_set.h" -// IWYU pragma: no_include "google/protobuf/generated_message_util.h" +// IWYU pragma: no_include <google/protobuf/extension_set.h> +#include <google/protobuf/arena.h> // for Arena #include <google/protobuf/util/json_util.h> // for JsonOptions, MessageToJs... #include <string> // for string @@ -41,6 +40,7 @@ namespace caosdb::utility { using google::protobuf::Arena; auto get_arena() -> Arena *; +auto reset_arena() -> void; /** * Abstract wrapper class for Protobuf messages. diff --git a/include/caosdb/status_code.h b/include/caosdb/status_code.h index e458b1727af51720451cbc057d4e40cee35a4a4e..41dad5bddd918ac5cc42e577798676bcf8b6bea4 100644 --- a/include/caosdb/status_code.h +++ b/include/caosdb/status_code.h @@ -62,12 +62,12 @@ enum StatusCode { GENERIC_ERROR = 21, GENERIC_TRANSACTION_ERROR = 22, CONFIGURATION_ERROR = 23, - UNKNOWN_CONNECTION_ERROR = 24, + CONNECTION_CONFIGURATION_ERROR = 24, TRANSACTION_STATUS_ERROR = 25, TRANSACTION_TYPE_ERROR = 26, UNSUPPORTED_FEATURE = 27, ORIGINAL_ENTITY_MISSING_ID = 28, - EXTERN_C_ASSIGNMENT_ERROR = 29, + // EXTERN_C_ASSIGNMENT_ERROR = 29, ENTITY_CANNOT_HAVE_A_DATA_TYPE = 30, ENTITY_CANNOT_HAVE_A_VALUE = 31, NOT_A_FILE_ENTITY = 32, diff --git a/include/caosdb/transaction.h b/include/caosdb/transaction.h index b1aed999b7556c35a4139b32db80a7ccbf7572b4..ddb3f271d4b9b5643e62a6a7b58b9b8f39496377 100644 --- a/include/caosdb/transaction.h +++ b/include/caosdb/transaction.h @@ -22,8 +22,9 @@ #define CAOSDB_TRANSACTION_H #include "caosdb/entity.h" // for Entity, FileDe... -#include "caosdb/entity/v1alpha1/main.grpc.pb.h" // for EntityTransact... -#include "caosdb/entity/v1alpha1/main.pb.h" // for MultiTransacti... +#include "caosdb/entity/v1/main.grpc.pb.h" // for EntityTransact... +#include "caosdb/entity/v1/main.pb.h" // for MultiTransacti... +#include "caosdb/file_descriptor.h" // for FileDescriptor #include "caosdb/handler_interface.h" // for HandlerInterface #include "caosdb/transaction_handler.h" // for EntityTransactionHandler #include "caosdb/logging.h" // for CAOSDB_LOG_ERR... @@ -31,10 +32,6 @@ #include "caosdb/status_code.h" // for StatusCode #include "caosdb/transaction_status.h" // for StatusCode #include <algorithm> // for max -#include <boost/log/core/record.hpp> // for record -#include <boost/log/sources/record_ostream.hpp> // for basic_record_o... -#include <boost/preprocessor/seq/limits/enum_256.hpp> // for BOOST_PP_SEQ_E... -#include <boost/preprocessor/seq/limits/size_256.hpp> // for BOOST_PP_SEQ_S... #include <future> // for async, future #include <google/protobuf/arena.h> // for Arena #include <google/protobuf/util/json_util.h> // for MessageToJsonS... @@ -58,12 +55,12 @@ return StatusCode::TRANSACTION_STATUS_ERROR; \ } \ switch (this->transaction_type) { \ - case NONE: \ + case TransactionType::NONE: \ this->transaction_type = TransactionType::READ_ONLY; \ break; \ - case READ_ONLY: \ + case TransactionType::READ_ONLY: \ break; \ - case MIXED_READ_AND_WRITE: \ + case TransactionType::MIXED_READ_AND_WRITE: \ break; \ default: \ CAOSDB_LOG_ERROR_AND_RETURN_STATUS( \ @@ -95,11 +92,11 @@ return StatusCode::TRANSACTION_STATUS_ERROR; \ } \ switch (this->transaction_type) { \ - case NONE: \ + case TransactionType::NONE: \ this->transaction_type = TransactionType::MIXED_WRITE; \ - case DELETE: \ - case MIXED_WRITE: \ - case MIXED_READ_AND_WRITE: \ + case TransactionType::DELETE_ONLY: \ + case TransactionType::MIXED_WRITE: \ + case TransactionType::MIXED_READ_AND_WRITE: \ break; \ default: \ CAOSDB_LOG_ERROR_AND_RETURN_STATUS( \ @@ -118,11 +115,11 @@ return StatusCode::TRANSACTION_STATUS_ERROR; \ } \ switch (this->transaction_type) { \ - case NONE: \ + case TransactionType::NONE: \ this->transaction_type = TransactionType::MIXED_WRITE; \ - case INSERT: \ - case MIXED_WRITE: \ - case MIXED_READ_AND_WRITE: \ + case TransactionType::INSERT_ONLY: \ + case TransactionType::MIXED_WRITE: \ + case TransactionType::MIXED_READ_AND_WRITE: \ break; \ default: \ CAOSDB_LOG_ERROR_AND_RETURN_STATUS( \ @@ -141,11 +138,11 @@ return StatusCode::TRANSACTION_STATUS_ERROR; \ } \ switch (this->transaction_type) { \ - case NONE: \ + case TransactionType::NONE: \ this->transaction_type = TransactionType::MIXED_WRITE; \ - case UPDATE: \ - case MIXED_WRITE: \ - case MIXED_READ_AND_WRITE: \ + case TransactionType::UPDATE_ONLY: \ + case TransactionType::MIXED_WRITE: \ + case TransactionType::MIXED_READ_AND_WRITE: \ break; \ default: \ CAOSDB_LOG_ERROR_AND_RETURN_STATUS( \ @@ -169,23 +166,21 @@ namespace caosdb::transaction { using caosdb::entity::Entity; using caosdb::entity::FileDescriptor; -using caosdb::entity::v1alpha1::EntityResponse; -using caosdb::entity::v1alpha1::EntityTransactionService; -using caosdb::entity::v1alpha1::FileDownloadRequest; -using caosdb::entity::v1alpha1::FileDownloadResponse; -using caosdb::entity::v1alpha1::FileTransmissionId; -using caosdb::entity::v1alpha1::FileTransmissionService; -using caosdb::entity::v1alpha1::FileUploadRequest; -using caosdb::entity::v1alpha1::FileUploadResponse; -using caosdb::entity::v1alpha1::IdResponse; -using caosdb::entity::v1alpha1::MultiTransactionRequest; -using caosdb::entity::v1alpha1::MultiTransactionResponse; -using caosdb::entity::v1alpha1::RegisterFileUploadRequest; -using caosdb::entity::v1alpha1::RegisterFileUploadResponse; -using caosdb::entity::v1alpha1::RetrieveResponse; +using caosdb::entity::v1::EntityResponse; +using caosdb::entity::v1::EntityTransactionService; +using caosdb::entity::v1::FileDownloadRequest; +using caosdb::entity::v1::FileDownloadResponse; +using caosdb::entity::v1::FileTransmissionId; +using caosdb::entity::v1::FileTransmissionService; +using caosdb::entity::v1::FileUploadRequest; +using caosdb::entity::v1::FileUploadResponse; +using caosdb::entity::v1::IdResponse; +using caosdb::entity::v1::MultiTransactionRequest; +using caosdb::entity::v1::MultiTransactionResponse; +using caosdb::entity::v1::RegisterFileUploadRequest; +using caosdb::entity::v1::RegisterFileUploadResponse; using caosdb::transaction::TransactionStatus; -using TransactionResponseCase = - caosdb::entity::v1alpha1::TransactionResponse::TransactionResponseCase; +using TransactionResponseCase = caosdb::entity::v1::TransactionResponse::TransactionResponseCase; using caosdb::utility::get_arena; using google::protobuf::Arena; @@ -295,9 +290,9 @@ public: enum TransactionType { NONE, //!< Unspecified or not specified yet. READ_ONLY, //!< Only retrievals (by id, by query) - INSERT, //!< Only insertions - UPDATE, //!< Only updates - DELETE, //!< Only deletions + INSERT_ONLY, //!< Only insertions + UPDATE_ONLY, //!< Only updates + DELETE_ONLY, //!< Only deletions MIXED_WRITE, //!< Only insertions, deletions, updates MIXED_READ_AND_WRITE //!< all kind of transaction. }; @@ -410,7 +405,7 @@ public: * Instead, do Execute() or WaitForIt() and only call this method afterwards. */ [[nodiscard]] inline auto GetResultSet() const noexcept -> const ResultSet & { - if (!this->result_set) { + if (this->result_set == nullptr) { CAOSDB_LOG_ERROR(logger_name) << "GetResultSet was called before the transaction has terminated. This is a programming " "error of the code which uses the transaction."; @@ -528,11 +523,6 @@ private: std::vector<FileDescriptor> upload_files; std::map<std::string, FileDescriptor> download_files; - // auto RegisterUploadFile(RegisterFileUploadResponse *response) -> void; - auto UploadFile(FileUploadResponse *response, const FileDescriptor &file_descriptor, - const std::string ®istration_id) -> void; - auto DownloadFile(FileDownloadResponse *response, const FileTransmissionId &file_transmission_id) - -> void; bool has_query = false; TransactionType transaction_type = TransactionType::NONE; mutable std::unique_ptr<ResultSet> result_set; diff --git a/include/caosdb/transaction_handler.h b/include/caosdb/transaction_handler.h index 18cb5fcfcaa87a924ff0f36b0c5356d10fc9f70b..6fa386be32628d5d0ae80a90dda1e1293d1eae70 100644 --- a/include/caosdb/transaction_handler.h +++ b/include/caosdb/transaction_handler.h @@ -1,6 +1,6 @@ #pragma once -#include "caosdb/entity/v1alpha1/main.grpc.pb.h" // for FileTransmissionS... -#include "caosdb/entity/v1alpha1/main.pb.h" // for FileDownloadResponse +#include "caosdb/entity/v1/main.grpc.pb.h" // for FileTransmissionS... +#include "caosdb/entity/v1/main.pb.h" // for FileDownloadResponse #include "caosdb/handler_interface.h" // for HandlerTag #include "caosdb/unary_rpc_handler.h" // for HandlerTag, Handl... #include <grpcpp/impl/codegen/async_unary_call.h> // for ClientAsyncRespons... @@ -9,9 +9,9 @@ namespace caosdb::transaction { -using caosdb::entity::v1alpha1::EntityTransactionService; -using caosdb::entity::v1alpha1::MultiTransactionRequest; -using caosdb::entity::v1alpha1::MultiTransactionResponse; +using caosdb::entity::v1::EntityTransactionService; +using caosdb::entity::v1::MultiTransactionRequest; +using caosdb::entity::v1::MultiTransactionResponse; class EntityTransactionHandler final : public UnaryRpcHandler { public: diff --git a/include/caosdb/utility.h b/include/caosdb/utility.h index 5af1b491c0b5b9d48606ba6b46130b3ef3de1d9c..13e3dfeb99dc5415a733d5b6dcea852705b1662d 100644 --- a/include/caosdb/utility.h +++ b/include/caosdb/utility.h @@ -21,42 +21,23 @@ #ifndef CAOSDB_UTILS_H #define CAOSDB_UTILS_H -#include "caosdb/data_type.h" // for AtomicDataType -#include "caosdb/entity.h" // for Importance, Role -#include <boost/beast/core/detail/base64.hpp> // for encoded_size -#include <boost/beast/core/detail/base64.ipp> // for encode -#include <boost/filesystem/operations.hpp> // for exists -#include <boost/filesystem/path.hpp> // for path -#include <boost/filesystem/fstream.hpp> // for basic_ifstream, ifstream -#include <boost/filesystem/string_file.hpp> // for load_string_file -#include <boost/json/stream_parser.hpp> // for stream_parser -#include <boost/json/value.hpp> // for value -#include <boost/lexical_cast.hpp> // for lexical_cast -#include <cassert> // for assert -#include <cstdlib> // for getenv -#include <fstream> // for basic_istream<>::__ist... -#include <memory> // for allocator, unique_ptr -#include <stdexcept> // for logic_error -#include <string> // for string, operator+, cha... -#include <type_traits> // for underlying_type_t -#include <typeinfo> // for type_info +#include "caosdb/data_type.h" // for AtomicDataType +#include "caosdb/entity.h" // for Importance, Role +#include <cstdlib> // for getenv +#include <filesystem> // for path +#include <fstream> // for basic_istream<>::__ist... +#include <memory> // for shared_ptr +#include <string> // for string, operator+, cha... namespace caosdb::utility { -using boost::filesystem::exists; -using boost::filesystem::ifstream; -using boost::filesystem::path; -using boost::json::stream_parser; -using boost::json::value; +using std::ifstream; +using std::filesystem::exists; +using std::filesystem::path; /** * @brief Get the name of the enum value. May be useful for higher-order CaosDB clients. */ -template <typename Enum> auto getEnumNameFromValue(Enum v) -> std::string { - if (std::is_same_v<std::underlying_type_t<Enum>, int>) { - return boost::lexical_cast<std::string>(static_cast<int>(v)); - } - throw std::logic_error(std::string("Enum type ") + typeid(v).name() + " not implemented."); -} +template <typename Enum> auto getEnumNameFromValue(Enum v) -> std::string; // Forward declaration of specializations template <> @@ -86,11 +67,7 @@ auto getEnumValueFromName<caosdb::entity::Role>(const std::string &name) -> caos /** * @brief Read a text file into a string and return the file's content. */ -inline auto load_string_file(const path &path) -> std::string { - std::string result; - boost::filesystem::load_string_file(path, result); - return result; -} +auto load_string_file(const path &file_path) -> std::string; /** * @brief Return the environment variable KEY, or FALLBACK if it does not exist. @@ -117,37 +94,82 @@ inline auto get_env_fallback(const std::string &key, const std::string &fallback } /** - * @brief Encode string as base64 + * @brief JsonValue is a thin wrapper around a implementation specific + * third-party json object (e.g. boost). */ -inline auto base64_encode(const std::string &plain) -> std::string { - auto size_plain = plain.size(); - auto size_encoded = boost::beast::detail::base64::encoded_size(size_plain); - - std::unique_ptr<char[]> encoded(new char[size_encoded]); - boost::beast::detail::base64::encode(encoded.get(), plain.c_str(), size_plain); - - // the encoded char[] is not null terminated, so explicitely set the length - return std::string(encoded.get(), encoded.get() + size_encoded); -} - -inline auto load_json_file(const path &json_file) -> value { - assert(exists(json_file)); +class JsonValue { +public: + /** + * Default Constructor. + * + * Creates an empty wrapper where `wrapped` is nullptr. + */ + JsonValue() : JsonValue(nullptr) {} + /** + * Constructor. + * + * By calling this constructor the ownership of the `wrapped` parameter is + * transferred to this object. + */ + JsonValue(void *wrapped); + /** + * Destructor. + * + * Also deletes the `wrapped` object. + */ + ~JsonValue(); + + /** + * Copy Constructor. + * + * Also copies the `wrapped` object. + */ + JsonValue(const JsonValue &other); + + /** + * Copy Assigment. + * + * Also copies the `wrapped` object. + */ + auto operator=(const JsonValue &other) -> JsonValue &; + + /** + * Move Constructor. + * + * Also moves the `wrapped` object. + */ + JsonValue(JsonValue &&other) noexcept; + + /** + * Move Assigment. + * + * Also moves the `wrapped` object. + */ + auto operator=(JsonValue &&other) noexcept -> JsonValue &; + + /** + * Reset this object. + * + * Also deletes `wrapped` sets it to the nullptr. + */ + auto Reset() -> void; + + /** + * An object which represents a JSON value. The object's class is an + * implementation detail. + */ + std::shared_ptr<void> wrapped; +}; - constexpr auto buffer_size = std::size_t(4096); - auto stream = ifstream(json_file); - stream.exceptions(std::ios_base::badbit); - - stream_parser parser; - auto result = std::string(); - auto buffer = std::string(buffer_size, '\0'); - while (stream.read(&buffer[0], buffer_size)) { - parser.write(buffer.c_str(), stream.gcount()); - } - parser.write(buffer.c_str(), stream.gcount()); +/** + * @brief Load json object from a json file and return it. + */ +auto load_json_file(const path &json_file) -> JsonValue; - assert(parser.done()); - return parser.release(); -} +/** + * @brief Encode string as base64 + */ +auto base64_encode(const std::string &plain) -> std::string; inline auto get_home_directory() -> const path { const auto *const home = getenv("HOME"); diff --git a/include/caosdb/value.h b/include/caosdb/value.h index 8296be311a8262339b58de06d49940100fc183f3..a92847a82d3cd15ad2dda61e64c6843b99ac6d75 100644 --- a/include/caosdb/value.h +++ b/include/caosdb/value.h @@ -21,14 +21,14 @@ #ifndef CAOSDB_VALUE_H #define CAOSDB_VALUE_H -#include "caosdb/protobuf_helper.h" // for ProtoMessageWrapper -#include "caosdb/entity/v1alpha1/main.pb.h" // for RepeatedPtrField, Message -#include <cstdint> // for int64_t -#include <google/protobuf/arena.h> // for Arena -#include <memory> // for unique_ptr -#include <string> // for string, operator== -#include <utility> // for move -#include <vector> // for vector +#include "caosdb/protobuf_helper.h" // for ProtoMessageWrapper +#include "caosdb/entity/v1/main.pb.h" // for RepeatedPtrField, Message +#include <cstdint> // for int64_t +#include <google/protobuf/arena.h> // for Arena +#include <memory> // for unique_ptr +#include <string> // for string, operator== +#include <utility> // for move +#include <vector> // for vector #define LIST_VALUE_CONSTRUCTOR(TYPE, SETTER) \ explicit inline Value(const std::vector<TYPE> &values) \ @@ -43,11 +43,11 @@ using caosdb::utility::get_arena; using caosdb::utility::ProtoMessageWrapper; using caosdb::utility::ScalarProtoMessageWrapper; using google::protobuf::Arena; -using ProtoSpecialValue = caosdb::entity::v1alpha1::SpecialValue; -using ProtoValue = caosdb::entity::v1alpha1::Value; -using ProtoScalarValue = caosdb::entity::v1alpha1::ScalarValue; -using ValueCase = caosdb::entity::v1alpha1::Value::ValueCase; -using ScalarValueCase = caosdb::entity::v1alpha1::ScalarValue::ScalarValueCase; +using ProtoSpecialValue = caosdb::entity::v1::SpecialValue; +using ProtoValue = caosdb::entity::v1::Value; +using ProtoScalarValue = caosdb::entity::v1::ScalarValue; +using ValueCase = caosdb::entity::v1::Value::ValueCase; +using ScalarValueCase = caosdb::entity::v1::ScalarValue::ScalarValueCase; class ScalarValue; class Value; diff --git a/include/ccaosdb.h b/include/ccaosdb.h index 4d1b99dd151fbf09a53d9b80c0963ee3d3368c67..48d0da757351508ed194e52635670d0c24e53164 100644 --- a/include/ccaosdb.h +++ b/include/ccaosdb.h @@ -20,10 +20,14 @@ * */ -#include <cstdint> // for int64_t - +#ifndef CCAOSDB_H +#define CCAOSDB_H #ifdef __cplusplus +#include <cstdint> // for int64_t extern "C" { +#else +#include <stdint.h> // for int64_t +#include <stdbool.h> // for bool #endif /** @@ -70,7 +74,7 @@ int caosdb_status_code_OTHER_CLIENT_ERROR(); */ typedef struct caosdb_connection_connection { void *wrapped_connection; - bool _deletable = false; + bool _deletable; } caosdb_connection_connection; /** @@ -82,7 +86,7 @@ typedef struct caosdb_connection_connection { */ typedef struct caosdb_connection_connection_configuration { void *wrapped_connection_configuration; - bool _deletable = false; + bool _deletable; } caosdb_connection_connection_configuration; /** @@ -102,12 +106,12 @@ typedef struct caosdb_info_version_info { typedef struct caosdb_connection_certificate_provider { void *wrapped_certificate_provider; - bool _deletable = false; + bool _deletable; } caosdb_connection_certificate_provider; typedef struct caosdb_authentication_authenticator { void *wrapped_authenticator; - bool _deletable = false; + bool _deletable; } caosdb_authentication_authenticator; /** @@ -266,7 +270,7 @@ int caosdb_connection_connection_manager_get_connection(caosdb_connection_connec typedef struct caosdb_transaction_transaction { void *wrapped_transaction; - bool _deletable = false; + bool _deletable; } caosdb_transaction_transaction; /** @@ -292,12 +296,12 @@ int caosdb_transaction_transaction_execute(caosdb_transaction_transaction *trans typedef struct caosdb_transaction_result_set { void *wrapped_result_set; - bool _deletable = false; + bool _deletable; } caosdb_transaction_result_set; typedef struct caosdb_entity_entity { void *wrapped_entity; - bool _deletable = false; + bool _deletable; } caosdb_entity_entity; int caosdb_transaction_transaction_get_result_set(caosdb_transaction_transaction *transaction, @@ -348,27 +352,27 @@ int caosdb_transaction_transaction_delete_by_id(caosdb_transaction_transaction * typedef struct caosdb_entity_property { void *wrapped_property; - bool _deletable = false; + bool _deletable; } caosdb_entity_property; typedef struct caosdb_entity_parent { void *wrapped_parent; - bool _deletable = false; + bool _deletable; } caosdb_entity_parent; typedef struct caosdb_entity_message { void *wrapped_message; - bool _deletable = false; + bool _deletable; } caosdb_entity_message; typedef struct caosdb_entity_value { void *wrapped_value; - bool _deletable = false; + bool _deletable; } caosdb_entity_value; typedef struct caosdb_entity_datatype { void *wrapped_datatype; - bool _deletable = false; + bool _deletable; } caosdb_entity_datatype; // GETTERS FOR EVERYTHING @@ -494,3 +498,4 @@ int caosdb_entity_parent_set_name(caosdb_entity_parent *parent, const char *name #ifdef __cplusplus } #endif +#endif diff --git a/proto b/proto index 73d85fb20bb16902c0a89dda697eed17994712bc..0b301401cf28d7a3edeb2c55e418f072b83cf5a7 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 73d85fb20bb16902c0a89dda697eed17994712bc +Subproject commit 0b301401cf28d7a3edeb2c55e418f072b83cf5a7 diff --git a/requirements.txt b/requirements.txt index 4bf95a29fc3c9d28931a25664c2456f22041be3f..171a4c323631116bbd3cfc3019035d77cc1cad6e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,28 +1,29 @@ attrs==21.2.0 bottle==0.12.19 -certifi==2021.5.30 +certifi==2021.10.8 chardet==4.0.0 +charset-normalizer==2.0.7 colorama==0.4.4 -conan==1.40.3 -deprecation==2.0.7 -distro==1.5.0 +conan==1.48.0 +deprecation==2.1.0 +distro==1.6.0 fasteners==0.16.3 future==0.18.2 -idna==2.10 -Jinja2==2.11.3 -jsonschema==3.2.0 +idna==3.2 +Jinja2==3.1.1 +jsonschema==4.1.0 MarkupSafe==2.0.1 node-semver==0.6.1 -packaging==20.9 +packaging==21.0 patch-ng==1.17.4 pluginbase==1.0.1 -Pygments==2.9.0 +Pygments==2.10.0 PyJWT==1.7.1 pyparsing==2.4.7 pyrsistent==0.18.0 -python-dateutil==2.8.1 +python-dateutil==2.8.2 PyYAML==5.4.1 -requests==2.25.1 -six==1.15.0 -tqdm==4.61.1 -urllib3==1.25.11 +requests==2.26.0 +six==1.16.0 +tqdm==4.62.3 +urllib3==1.26.7 diff --git a/src/caosdb/authentication.cpp b/src/caosdb/authentication.cpp index 50ff24455ac87227f475775974abae1228fc50d3..ecfbe35344f557671d8529770f73a3987c389ab0 100644 --- a/src/caosdb/authentication.cpp +++ b/src/caosdb/authentication.cpp @@ -19,13 +19,15 @@ * */ #include "caosdb/authentication.h" -#include "grpcpp/security/credentials.h" // for MetadataCredentialsPlugin -#include <grpcpp/impl/codegen/status.h> // for Status, Status::OK -#include <grpcpp/impl/codegen/string_ref.h> // for string_ref -#include <map> // for multimap -#include <memory> // for allocator, shared_ptr -#include <string> // for basic_string, operator+ -#include <utility> // for pair, move, make_pair +#include <grpcpp/impl/codegen/interceptor.h> // for Status +#include <grpcpp/impl/codegen/security/auth_context.h> // for AuthContext +#include <grpcpp/impl/codegen/status.h> // for Status, Status::OK +#include <grpcpp/impl/codegen/string_ref.h> // for string_ref +#include <grpcpp/security/credentials.h> // for MetadataCredentialsPlugin +#include <map> // for multimap +#include <memory> // for allocator, shared_ptr +#include <string> // for basic_string, operator+ +#include <utility> // for pair, move, make_pair namespace caosdb::authentication { using caosdb::utility::base64_encode; diff --git a/src/caosdb/configuration.cpp b/src/caosdb/configuration.cpp index edce302e00bcb5645d734e2ff577be23d0a8bd67..e1ffb23b3b1a2db5ecea79588c237bb36e79b1e1 100644 --- a/src/caosdb/configuration.cpp +++ b/src/caosdb/configuration.cpp @@ -19,36 +19,57 @@ * */ #include "caosdb/configuration.h" -#include "boost/iterator/iterator_facade.hpp" // for iterator_facad... -#include "boost/json/impl/object.hpp" // for object::at -#include "boost/json/string.hpp" // for string -#include "boost/json/string_view.hpp" // for string_view -#include "boost/log/core/record.hpp" // for record -#include "boost/log/detail/attachable_sstream_buf.hpp" // for basic_ostring... -#include "boost/log/sources/record_ostream.hpp" // for basic_record_o... -#include "boost/preprocessor/seq/limits/enum_256.hpp" // for BOOST_PP_SEQ_E... -#include "boost/preprocessor/seq/limits/size_256.hpp" // for BOOST_PP_SEQ_S... -#include "caosdb/authentication.h" // for Authenticator -#include "caosdb/connection.h" // for ConnectionManager -#include "caosdb/constants.h" // for LIBCAOSDB_CONF... -#include "caosdb/exceptions.h" // for ConfigurationE... -#include "caosdb/log_level.h" // for CAOSDB_DEFAULT... -#include "caosdb/status_code.h" // for StatusCode -#include "caosdb/utility.h" // for get_home_direc... -#include <cassert> // for assert -#include <cstdlib> // for getenv -#include <cstring> // for strcmp -#include <exception> // IWYU pragma: keep +#include "caosdb/authentication.h" // for Authenticator +#include "caosdb/connection.h" // for ConnectionManager +#include "caosdb/constants.h" // for LIBCAOSDB_CONF... +#include "caosdb/exceptions.h" // for ConfigurationE... +#include "caosdb/log_level.h" // for CAOSDB_DEFAULT... +#include "caosdb/logging.h" // for SinkConfiguration, Loggin... +#include "caosdb/status_code.h" // for StatusCode +#include "caosdb/utility.h" // for get_home_direc... +#include <boost/json/impl/object.hpp> // for object::at +#include <boost/json/object.hpp> // for object, objec... +#include <boost/json/string.hpp> // for string +#include <boost/json/string_view.hpp> // for string_view +#include <boost/json/value.hpp> // for value, key_va... +#include <boost/json/value_ref.hpp> // for object +#include <cassert> // for assert +#include <cstdlib> // for getenv +#include <cstring> // for strcmp +#include <exception> // IWYU pragma: keep // IWYU pragma: no_include <bits/exception.h> #include <grpcpp/security/credentials.h> // for SslCredentials #include <iterator> // for next #include <map> // for map #include <stdexcept> // for out_of_range #include <string> // for string, operator+ +#include <utility> // for move + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define WRAPPED_JSON_CONFIGURATION(obj) \ + (static_cast<value *>((obj)->json_configuration.wrapped.get())) + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define GET_CONNECTIONS \ + if (!this->json_configuration.wrapped) { \ + throw ConfigurationError("This CaosDB client has not been configured."); \ + } \ + assert(WRAPPED_JSON_CONFIGURATION(this)->is_object()); \ + const auto &configuration = WRAPPED_JSON_CONFIGURATION(this)->as_object(); \ + if (!configuration.contains("connections")) { \ + throw ConfigurationError("This CaosDB client hasn't any configured connections."); \ + } \ + const auto &connections_value = configuration.at("connections"); \ + if (connections_value.is_null()) { \ + throw ConfigurationError("This CaosDB client hasn't any configured connections."); \ + } \ + assert(connections_value.is_object()); \ + const auto &connections = connections_value.as_object(); \ + if (connections.empty()) { \ + throw ConfigurationError("This CaosDB client hasn't any configured connections."); \ + } namespace caosdb::configuration { -using boost::filesystem::exists; -using boost::filesystem::path; using boost::json::object; using boost::json::value; using caosdb::authentication::Authenticator; @@ -66,6 +87,8 @@ using caosdb::utility::load_string_file; using grpc::InsecureChannelCredentials; using grpc::SslCredentials; using grpc::SslCredentialsOptions; +using std::filesystem::exists; +using std::filesystem::path; PemFileCertificateProvider::PemFileCertificateProvider(const path &path) { this->certificate_provider = load_string_file(path); @@ -75,18 +98,15 @@ auto PemFileCertificateProvider::GetCertificatePem() const -> std::string { return this->certificate_provider; } -PemCertificateProvider::PemCertificateProvider(const std::string &certificate_provider) { - this->certificate_provider = certificate_provider; -} +PemCertificateProvider::PemCertificateProvider(std::string certificate_provider) + : certificate_provider(std::move(certificate_provider)) {} auto PemCertificateProvider::GetCertificatePem() const -> std::string { return this->certificate_provider; } -ConnectionConfiguration::ConnectionConfiguration(const std::string &host, int port) { - this->host = host; - this->port = port; -} +ConnectionConfiguration::ConnectionConfiguration(std::string host, int port) + : host(std::move(host)), port(port) {} auto ConnectionConfiguration::GetHost() const -> std::string { return this->host; } @@ -156,8 +176,7 @@ auto TlsConnectionConfiguration::ToString() const -> std::string { "," + this->certificate_provider + ")"; } -auto ConnectionConfigurationHelper::CreateCertificateProvider(const object &from) const - -> std::unique_ptr<CertificateProvider> { +auto CreateCertificateProvider(const object &from) -> std::unique_ptr<CertificateProvider> { std::unique_ptr<CertificateProvider> certificate_provider; if (from.contains("server_certificate_path")) { const value &path_str = from.at("server_certificate_path"); @@ -173,8 +192,7 @@ auto ConnectionConfigurationHelper::CreateCertificateProvider(const object &from return certificate_provider; } -auto ConnectionConfigurationHelper::CreateAuthenticator(const object &from) const - -> std::unique_ptr<Authenticator> { +auto CreateAuthenticator(const object &from) -> std::unique_ptr<Authenticator> { std::unique_ptr<Authenticator> authenticator; if (from.contains("authentication")) { assert(from.at("authentication").is_object()); @@ -202,9 +220,9 @@ auto ConnectionConfigurationHelper::CreateAuthenticator(const object &from) cons return authenticator; } -auto ConnectionConfigurationHelper::CreateConnectionConfiguration( - const bool tls, const std::string &host, const int port, - const CertificateProvider *certificate_provider, const Authenticator *authenticator) const +auto CreateConnectionConfiguration(const bool tls, const std::string &host, const int port, + const CertificateProvider *certificate_provider, + const Authenticator *authenticator) -> std::unique_ptr<ConnectionConfiguration> { if (tls) { if (certificate_provider != nullptr && authenticator != nullptr) { @@ -225,7 +243,7 @@ auto ConnectionConfigurationHelper::CreateConnectionConfiguration( } } -auto ConnectionConfigurationHelper::IsTls(const object &from) const -> bool { +auto IsTls(const object &from) -> bool { bool tls = true; if (from.contains("tls")) { auto tls_switch = from.at("tls"); @@ -235,8 +253,7 @@ auto ConnectionConfigurationHelper::IsTls(const object &from) const -> bool { return tls; } -auto ConnectionConfigurationHelper::CreateConnectionConfiguration(const object &from) const - -> std::unique_ptr<ConnectionConfiguration> { +auto CreateConnectionConfiguration(const object &from) -> std::unique_ptr<ConnectionConfiguration> { assert(from.contains("host")); const auto &host = from.at("host"); assert(host.is_string()); @@ -256,25 +273,19 @@ auto ConnectionConfigurationHelper::CreateConnectionConfiguration(const object & certificate_provider.get(), authenticator.get()); } -auto LoggingConfigurationHelper::CreateConsoleSinkConfiguration(const object & /*from*/, - const std::string &name, - int level) const +auto CreateConsoleSinkConfiguration(const object & /*from*/, const std::string &name, int level) -> std::shared_ptr<caosdb::logging::SinkConfiguration> { auto result = std::make_shared<ConsoleSinkConfiguration>(name, level); return result; } -auto LoggingConfigurationHelper::CreateSyslogSinkConfiguration(const object & /*from*/, - const std::string &name, - int level) const +auto CreateSyslogSinkConfiguration(const object & /*from*/, const std::string &name, int level) -> std::shared_ptr<caosdb::logging::SinkConfiguration> { auto result = std::make_shared<SyslogSinkConfiguration>(name, level); return result; } -auto LoggingConfigurationHelper::CreateFileSinkConfiguration(const object &from, - const std::string &name, - int level) const +auto CreateFileSinkConfiguration(const object &from, const std::string &name, int level) -> std::shared_ptr<caosdb::logging::SinkConfiguration> { auto result = std::make_shared<FileSinkConfiguration>(name, level); if (from.contains("directory")) { @@ -283,9 +294,21 @@ auto LoggingConfigurationHelper::CreateFileSinkConfiguration(const object &from, return result; } -auto LoggingConfigurationHelper::CreateSinkConfiguration(const object &from, - const std::string &name, - int default_level) const +auto ConvertLogLevel(const std::string &string_level) -> int { + static std::map<std::string, int> log_level_names = { + {"", CAOSDB_DEFAULT_LOG_LEVEL}, {"off", CAOSDB_LOG_LEVEL_OFF}, + {"fatal", CAOSDB_LOG_LEVEL_FATAL}, {"error", CAOSDB_LOG_LEVEL_ERROR}, + {"warn", CAOSDB_LOG_LEVEL_WARN}, {"info", CAOSDB_LOG_LEVEL_INFO}, + {"debug", CAOSDB_LOG_LEVEL_DEBUG}, {"trace", CAOSDB_LOG_LEVEL_TRACE}, + {"all", CAOSDB_LOG_LEVEL_ALL}}; + try { + return log_level_names.at(string_level); + } catch (const std::out_of_range &exc) { + throw ConfigurationError("Unknown log level: " + string_level); + } +} + +auto CreateSinkConfiguration(const object &from, const std::string &name, int default_level) -> std::shared_ptr<caosdb::logging::SinkConfiguration> { assert(from.contains("destination")); const auto &destination = std::string(from.at("destination").as_string().c_str()); @@ -304,22 +327,7 @@ auto LoggingConfigurationHelper::CreateSinkConfiguration(const object &from, } } -auto LoggingConfigurationHelper::ConvertLogLevel(const std::string &string_level) const -> int { - static std::map<std::string, int> log_level_names = { - {"", CAOSDB_DEFAULT_LOG_LEVEL}, {"off", CAOSDB_LOG_LEVEL_OFF}, - {"fatal", CAOSDB_LOG_LEVEL_FATAL}, {"error", CAOSDB_LOG_LEVEL_ERROR}, - {"warn", CAOSDB_LOG_LEVEL_WARN}, {"info", CAOSDB_LOG_LEVEL_INFO}, - {"debug", CAOSDB_LOG_LEVEL_DEBUG}, {"trace", CAOSDB_LOG_LEVEL_TRACE}, - {"all", CAOSDB_LOG_LEVEL_ALL}}; - try { - return log_level_names.at(string_level); - } catch (const std::out_of_range &exc) { - throw ConfigurationError("Unknown log level: " + string_level); - } -} - -auto LoggingConfigurationHelper::CreateLoggingConfiguration(const object &from) const - -> LoggingConfiguration { +auto CreateLoggingConfiguration(const object &from) -> LoggingConfiguration { auto default_level_str = from.contains("level") ? std::string(from.at("level").as_string().c_str()) : ""; int default_level = ConvertLogLevel(default_level_str); @@ -361,7 +369,7 @@ auto ConfigurationManager::mReset() noexcept -> int { auto ConfigurationManager::mClear() noexcept -> int { try { - json_configuration = value(nullptr); + json_configuration.Reset(); ConnectionManager::Reset(); return StatusCode::SUCCESS; } catch (const caosdb::exceptions::Exception &exc) { @@ -374,7 +382,7 @@ auto ConfigurationManager::mClear() noexcept -> int { } auto ConfigurationManager::mLoadSingleJSONConfiguration(const path &json_file) -> void { - if (!json_configuration.is_null()) { + if (json_configuration.wrapped) { throw ConfigurationError("This CaosDB client has already been configured."); } if (!exists(json_file)) { @@ -386,22 +394,27 @@ auto ConfigurationManager::mLoadSingleJSONConfiguration(const path &json_file) - auto ConfigurationManager::mGetConnectionConfiguration(const std::string &name) const -> std::unique_ptr<ConnectionConfiguration> { - auto connection_json = GetConnection(name); - return connection_configuration_helper.CreateConnectionConfiguration(connection_json); + GET_CONNECTIONS + if (connections.contains(name)) { + const auto &result_connection = connections.at(name); + assert(result_connection.is_object()); + return CreateConnectionConfiguration(result_connection.as_object()); + } + throw ConfigurationError("The connection '" + name + "' has not been defined."); } auto ConfigurationManager::mGetDefaultConnectionName() const -> std::string { - auto connections = GetConnections(); + GET_CONNECTIONS if (connections.contains("default")) { auto default_connection = connections.at("default"); if (default_connection.is_object()) { // the name is actually "default" - return std::string("default"); + return {"default"}; } else { assert(default_connection.is_string()); auto default_connection_name = default_connection.as_string(); // return the string value of connections.default - return std::string(default_connection_name.c_str()); + return {default_connection_name.c_str()}; } } if (connections.size() == 1) { @@ -411,41 +424,6 @@ auto ConfigurationManager::mGetDefaultConnectionName() const -> std::string { throw ConfigurationError("Could not determine the default connection."); } -auto ConfigurationManager::GetConfiguration() const -> const object & { - if (json_configuration.is_null()) { - throw ConfigurationError("This CaosDB client has not been configured."); - } - assert(json_configuration.is_object()); - return json_configuration.as_object(); -} - -auto ConfigurationManager::GetConnections() const -> const object & { - const auto &configuration = GetConfiguration(); - if (!configuration.contains("connections")) { - throw ConfigurationError("This CaosDB client hasn't any configured connections."); - } - const auto &connections_value = configuration.at("connections"); - if (connections_value.is_null()) { - throw ConfigurationError("This CaosDB client hasn't any configured connections."); - } - assert(connections_value.is_object()); - const auto &connections_object = connections_value.as_object(); - if (connections_object.empty()) { - throw ConfigurationError("This CaosDB client hasn't any configured connections."); - } - return connections_object; -} - -auto ConfigurationManager::GetConnection(const std::string &name) const -> const object & { - const auto &connections = GetConnections(); - if (connections.contains(name)) { - const auto &result_connection = connections.at(name); - assert(result_connection.is_object()); - return result_connection.as_object(); - } - throw ConfigurationError("The connection '" + name + "' has not been defined."); -} - // TODO(tf) This has apparently a cognitive complexity of 34>25 (threshold). auto ConfigurationManager::InitializeDefaults() -> int { // NOLINT @@ -471,12 +449,12 @@ auto ConfigurationManager::InitializeDefaults() -> int { // NOLINT configuration_file_path = std::make_unique<path>(); const path raw(configuration_file); // resolve home directory - for (auto segment = raw.begin(); segment != raw.end(); ++segment) { - if (segment->string() == "$HOME") { + for (const auto &segment : raw) { + if (segment.string() == "$HOME") { path expanded_home(get_home_directory()); *configuration_file_path /= expanded_home; } else { - *configuration_file_path /= *segment; + *configuration_file_path /= segment; } } if (exists(*configuration_file_path)) { @@ -493,11 +471,10 @@ auto ConfigurationManager::InitializeDefaults() -> int { // NOLINT } // Logging in the configuration leads to additional content. - if (this->json_configuration.is_object() && - this->json_configuration.as_object().contains("logging")) { + if (this->json_configuration.wrapped && WRAPPED_JSON_CONFIGURATION(this)->is_object() && + WRAPPED_JSON_CONFIGURATION(this)->as_object().contains("logging")) { LoggingConfiguration logging_configuration = - logging_configuration_helper.CreateLoggingConfiguration( - json_configuration.at("logging").as_object()); + CreateLoggingConfiguration(WRAPPED_JSON_CONFIGURATION(this)->at("logging").as_object()); logging::initialize_logging(logging_configuration); } else { logging::initialize_logging_defaults(); @@ -505,8 +482,9 @@ auto ConfigurationManager::InitializeDefaults() -> int { // NOLINT "We are using the default configuration"; } - if (configuration_file_path != nullptr && this->json_configuration.is_object()) { - CAOSDB_LOG_INFO(logger_name) << "Loaded configuration from " << *(configuration_file_path.get()) + if (configuration_file_path != nullptr && this->json_configuration.wrapped && + WRAPPED_JSON_CONFIGURATION(this)->is_object()) { + CAOSDB_LOG_INFO(logger_name) << "Loaded configuration from " << *(configuration_file_path) << "."; } diff --git a/src/caosdb/connection.cpp b/src/caosdb/connection.cpp index d6782f8ffa42238888998bdff65dc666fbf55c18..02c190ee1beff00fc3cbffa950628a67b5ffa32d 100644 --- a/src/caosdb/connection.cpp +++ b/src/caosdb/connection.cpp @@ -23,8 +23,8 @@ #include "caosdb/configuration.h" // for ConnectionConfigur... #include "caosdb/exceptions.h" // for ConfigurationError #include "caosdb/info.h" // for VersionInfo -#include "caosdb/info/v1alpha1/main.grpc.pb.h" // for GeneralInfoService -#include "caosdb/info/v1alpha1/main.pb.h" // for GetVersionInfoRequest +#include "caosdb/info/v1/main.grpc.pb.h" // for GeneralInfoService +#include "caosdb/info/v1/main.pb.h" // for GetVersionInfoRequest #include "caosdb/transaction.h" // for Transaction #include "caosdb/transaction_status.h" // for TransactionStatus #include "grpcpp/impl/codegen/status_code_enum.h" // for StatusCode, UNAUTH... @@ -36,12 +36,12 @@ namespace caosdb::connection { using caosdb::configuration::ConfigurationManager; using caosdb::configuration::ConnectionConfiguration; -using caosdb::entity::v1alpha1::EntityTransactionService; -using caosdb::entity::v1alpha1::FileTransmissionService; +using caosdb::entity::v1::EntityTransactionService; +using caosdb::entity::v1::FileTransmissionService; using caosdb::info::VersionInfo; -using caosdb::info::v1alpha1::GeneralInfoService; -using caosdb::info::v1alpha1::GetVersionInfoRequest; -using caosdb::info::v1alpha1::GetVersionInfoResponse; +using caosdb::info::v1::GeneralInfoService; +using caosdb::info::v1::GetVersionInfoRequest; +using caosdb::info::v1::GetVersionInfoResponse; using caosdb::transaction::Transaction; using caosdb::transaction::TransactionStatus; @@ -109,8 +109,8 @@ auto ConnectionManager::mGetConnection(const std::string &name) const auto connection = ConfigurationManager::GetConnectionConfiguration(name); connections[name] = std::make_shared<Connection>(*connection.release()); } catch (const caosdb::exceptions::ConfigurationError &exc) { - throw caosdb::exceptions::UnknownConnectionError("No connection named '" + name + - "' present."); + throw caosdb::exceptions::ConnectionConfigurationError("Error with the connection named '" + + name + "': " + exc.what()); } } return this->connections.at(name); diff --git a/src/caosdb/entity.cpp b/src/caosdb/entity.cpp index a3872e4cb2be380adca644b7c7a109c0fec2b3c2..568cc5d97c38c8af0bf8fd632d93cb9b9bc4b2f1 100644 --- a/src/caosdb/entity.cpp +++ b/src/caosdb/entity.cpp @@ -20,21 +20,20 @@ * */ #include "caosdb/entity.h" -#include "caosdb/data_type.h" // for DataType -#include "caosdb/entity/v1alpha1/main.pb.h" // for Messages -#include "caosdb/protobuf_helper.h" // for get_arena -#include "caosdb/value.h" // for Value -#include <google/protobuf/arena.h> // for Arena -#include <new> // for operator new +#include "caosdb/data_type.h" // for DataType +#include "caosdb/entity/v1/main.pb.h" // for Messages +#include "caosdb/protobuf_helper.h" // for get_arena +#include "caosdb/value.h" // for Value +#include <google/protobuf/arena.h> // for Arena namespace caosdb::entity { -using ProtoParent = caosdb::entity::v1alpha1::Parent; -using ProtoProperty = caosdb::entity::v1alpha1::Property; -using ProtoEntity = caosdb::entity::v1alpha1::Entity; -using ProtoImportance = caosdb::entity::v1alpha1::Importance; -using caosdb::entity::v1alpha1::EntityRole; -using ProtoMessage = caosdb::entity::v1alpha1::Message; -using ProtoFileDescriptor = caosdb::entity::v1alpha1::FileDescriptor; +using ProtoParent = caosdb::entity::v1::Parent; +using ProtoProperty = caosdb::entity::v1::Property; +using ProtoEntity = caosdb::entity::v1::Entity; +using ProtoImportance = caosdb::entity::v1::Importance; +using caosdb::entity::v1::EntityRole; +using ProtoMessage = caosdb::entity::v1::Message; +using ProtoFileDescriptor = caosdb::entity::v1::FileDescriptor; using caosdb::utility::get_arena; using google::protobuf::Arena; diff --git a/src/caosdb/file_transmission/download_request_handler.cpp b/src/caosdb/file_transmission/download_request_handler.cpp index 6cc234ba535fbaa577b3ebe864aba5889cc054bd..e079d28390b59cd439efa7476c5df672a63c1ecc 100644 --- a/src/caosdb/file_transmission/download_request_handler.cpp +++ b/src/caosdb/file_transmission/download_request_handler.cpp @@ -47,25 +47,19 @@ * > DEALINGS IN THE SOFTWARE. */ #include "caosdb/file_transmission/download_request_handler.h" -#include "caosdb/logging.h" // for CAOSDB_LOG_TRACE -#include "caosdb/protobuf_helper.h" // for get_arena -#include "caosdb/status_code.h" // for GENERIC_RPC_E... -#include "caosdb/transaction_status.h" // for TransactionStatus -#include <boost/filesystem/path.hpp> // for operator<<, path -#include <boost/log/core/record.hpp> // for record -#include <boost/log/detail/attachable_sstream_buf.hpp> // for basic_ostring... -#include <boost/log/sources/record_ostream.hpp> // for basic_record_... -#include <boost/preprocessor/seq/limits/enum_256.hpp> // for BOOST_PP_SEQ_... -#include <boost/preprocessor/seq/limits/size_256.hpp> // for BOOST_PP_SEQ_... -#include <exception> // IWYU pragma: keep +#include "caosdb/logging.h" // for CAOSDB_LOG_TRACE +#include "caosdb/protobuf_helper.h" // for get_arena +#include "caosdb/status_code.h" // for GENERIC_RPC_E... +#include "caosdb/transaction_status.h" // for TransactionStatus +#include <exception> // IWYU pragma: keep // IWYU pragma: no_include <bits/exception.h> +#include <filesystem> // for operator<<, path #include <google/protobuf/arena.h> // for Arena #include <grpcpp/impl/codegen/async_stream.h> // for ClientAsyncRe... #include <grpcpp/impl/codegen/client_context.h> // for ClientContext #include <grpcpp/impl/codegen/completion_queue.h> // for CompletionQueue #include <grpcpp/impl/codegen/status.h> // for Status #include <grpcpp/impl/codegen/status_code_enum.h> // for OK, UNAUTHENT... -#include <iostream> // for char_traits #include <stdexcept> // for runtime_error #include <string> // for string, opera... #include <utility> // for move @@ -133,7 +127,8 @@ void DownloadRequestHandler::handleNewCallState() { << ", download_id = " << file_descriptor_.file_transmission_id; fileWriter_ = std::make_unique<FileWriter>(file_descriptor_.local_path); - request_->mutable_file_transmission_id()->CopyFrom(*(file_descriptor_.file_transmission_id)); + auto *tid = request_->mutable_file_transmission_id(); + tid->CopyFrom(*(file_descriptor_.file_transmission_id)); rpc_ = stub_->PrepareAsyncFileDownload(&ctx_, *request_, cq_); diff --git a/src/caosdb/file_transmission/file_reader.cpp b/src/caosdb/file_transmission/file_reader.cpp index 1a78e5a76513ae0aaf94b2ae4967af5d7b66e0c0..3f82b8c8c775d38f2a75e2a995ce7cfa8bb7cceb 100644 --- a/src/caosdb/file_transmission/file_reader.cpp +++ b/src/caosdb/file_transmission/file_reader.cpp @@ -48,13 +48,12 @@ */ #include "caosdb/file_transmission/file_reader.h" #include "caosdb/file_transmission/file_error.h" // for FileIOError -#include <boost/filesystem/path.hpp> // for path +#include <filesystem> // for path #include <utility> // for move namespace caosdb::transaction { -FileReader::FileReader(boost::filesystem::path filename) - : filename_(std::move(filename)), size_(0) { +FileReader::FileReader(std::filesystem::path filename) : filename_(std::move(filename)), size_(0) { this->openFile(); } @@ -79,7 +78,7 @@ std::size_t FileReader::read(std::string &buffer) { if (bufferSize > 0) { // TODO(henrik): fix nolint if (!stream_.read(&buffer[0], bufferSize)) { // NOLINT - throw FileIOError("Can't read file: " + filename_.string()); + throw FileIOError("Can't read data from file: " + filename_.string()); } bytesRead = static_cast<std::size_t>(stream_.gcount()); diff --git a/src/caosdb/file_transmission/file_writer.cpp b/src/caosdb/file_transmission/file_writer.cpp index 2c7f2a6000718366f846a4be61dd5c2144370a65..0f0161fbcafe1df7f6ffa271dcce8af9cc10fe82 100644 --- a/src/caosdb/file_transmission/file_writer.cpp +++ b/src/caosdb/file_transmission/file_writer.cpp @@ -48,12 +48,12 @@ */ #include "caosdb/file_transmission/file_writer.h" #include "caosdb/file_transmission/file_error.h" // for FileIOError -#include <boost/filesystem/path.hpp> // for path +#include <filesystem> // for path #include <utility> // for move namespace caosdb::transaction { -FileWriter::FileWriter(boost::filesystem::path filename) : filename_(std::move(filename)) { +FileWriter::FileWriter(std::filesystem::path filename) : filename_(std::move(filename)) { this->openFile(); } diff --git a/src/caosdb/file_transmission/register_file_upload_handler.cpp b/src/caosdb/file_transmission/register_file_upload_handler.cpp index 7b5c18c83729060768d882132067c5c8dd496d67..9460d187e883d843dae21c9e4e3ba00376ecbb01 100644 --- a/src/caosdb/file_transmission/register_file_upload_handler.cpp +++ b/src/caosdb/file_transmission/register_file_upload_handler.cpp @@ -47,13 +47,9 @@ * > DEALINGS IN THE SOFTWARE. */ #include "caosdb/file_transmission/register_file_upload_handler.h" -#include "caosdb/logging.h" // for CAOSDB_LOG_TRACE -#include <boost/log/core/record.hpp> // for record -#include <boost/log/sources/record_ostream.hpp> // for basic_record_... -#include <boost/preprocessor/seq/limits/enum_256.hpp> // for BOOST_PP_SEQ_... -#include <boost/preprocessor/seq/limits/size_256.hpp> // for BOOST_PP_SEQ_... -#include <grpcpp/impl/codegen/async_unary_call.h> // for ClientAsyncRes... -#include <grpcpp/impl/codegen/completion_queue.h> // for CompletionQueue +#include "caosdb/logging.h" // for CAOSDB_LOG_TRACE +#include <grpcpp/impl/codegen/async_unary_call.h> // for ClientAsyncRes... +#include <grpcpp/impl/codegen/completion_queue.h> // for CompletionQueue namespace caosdb::transaction { diff --git a/src/caosdb/file_transmission/upload_request_handler.cpp b/src/caosdb/file_transmission/upload_request_handler.cpp index c3ec8219e21f3845068e8cf5f1afafd52b2064e3..e4fb985b70b73e25869f54e635cb089901bb41a1 100644 --- a/src/caosdb/file_transmission/upload_request_handler.cpp +++ b/src/caosdb/file_transmission/upload_request_handler.cpp @@ -47,20 +47,15 @@ * > DEALINGS IN THE SOFTWARE. */ #include "caosdb/file_transmission/upload_request_handler.h" -#include "caosdb/logging.h" // for CAOSDB_LOG_ERROR -#include "caosdb/protobuf_helper.h" // for get_arena -#include "caosdb/status_code.h" // for GENERIC_RPC_E... -#include "caosdb/transaction_status.h" // for TransactionStatus -#include <algorithm> // for min -#include <boost/filesystem/path.hpp> // for operator<<, path -#include <boost/log/core/record.hpp> // for record -#include <boost/log/detail/attachable_sstream_buf.hpp> // for basic_ostring... -#include <boost/log/sources/record_ostream.hpp> // for basic_record_... -#include <boost/preprocessor/seq/limits/enum_256.hpp> // for BOOST_PP_SEQ_... -#include <boost/preprocessor/seq/limits/size_256.hpp> // for BOOST_PP_SEQ_... -#include <cstdint> // for uint64_t -#include <exception> // IWYU pragma: keep +#include "caosdb/logging.h" // for CAOSDB_LOG_ERROR +#include "caosdb/protobuf_helper.h" // for get_arena +#include "caosdb/status_code.h" // for GENERIC_RPC_E... +#include "caosdb/transaction_status.h" // for TransactionStatus +#include <algorithm> // for min +#include <cstdint> // for uint64_t +#include <exception> // IWYU pragma: keep // IWYU pragma: no_include <bits/exception.h> +#include <filesystem> // for operator<<, path #include <google/protobuf/arena.h> // for Arena #include <grpcpp/impl/codegen/async_stream.h> // for ClientAsyncWr... #include <grpcpp/impl/codegen/call_op_set.h> // for WriteOptions @@ -68,7 +63,6 @@ #include <grpcpp/impl/codegen/completion_queue.h> // for CompletionQueue #include <grpcpp/impl/codegen/status.h> // for Status #include <grpcpp/impl/codegen/status_code_enum.h> // for OK, UNAUTHENT... -#include <iostream> // for endl, streamsize #include <string> // for basic_string #include <utility> // for move @@ -157,7 +151,7 @@ void UploadRequestHandler::handleSendingHeaderState() { } void UploadRequestHandler::handleSendingFileState() { - const uint64_t DefaultChunkSize = 4 * 1024; // 4K + const auto DefaultChunkSize = static_cast<uint64_t>(4 * 1024); // 4K auto chunkSize = std::min(DefaultChunkSize, bytesToSend_); diff --git a/src/caosdb/logging.cpp b/src/caosdb/logging.cpp index 4070786b2bb4073da5800f4a57b9c0dfcff5d6ac..cdd505877850bc0adc06b15a85f80fdc9ce3a653 100644 --- a/src/caosdb/logging.cpp +++ b/src/caosdb/logging.cpp @@ -19,35 +19,93 @@ * */ #include "caosdb/logging.h" -#include "boost/core/swap.hpp" // for swap -#include "boost/iterator/iterator_facade.hpp" -#include "boost/log/attributes/clock.hpp" -#include "boost/log/core/core.hpp" // for core -#include "boost/log/core/record.hpp" -#include "boost/log/sources/record_ostream.hpp" -#include "boost/log/utility/setup/from_settings.hpp" -#include "boost/log/utility/setup/settings.hpp" -#include "boost/move/utility_core.hpp" // for move -#include "boost/multi_index/detail/bidir_node_iterator.hpp" -#include "boost/operators.hpp" -#include "boost/preprocessor/seq/limits/enum_256.hpp" -#include "boost/preprocessor/seq/limits/size_256.hpp" -#include "boost/property_tree/detail/exception_implementation.hpp" -#include "boost/smart_ptr/shared_ptr.hpp" -#include "boost/tuple/detail/tuple_basic.hpp" // for get #include "caosdb/log_level.h" +#include <boost/core/swap.hpp> // for swap +#include <boost/iterator/iterator_facade.hpp> +#include <boost/log/attributes/clock.hpp> +#include <boost/log/core/core.hpp> // for core +#include <boost/log/core/record.hpp> +#include <boost/log/detail/attachable_sstream_buf.hpp> +#include <boost/log/sources/record_ostream.hpp> +#include <boost/log/sources/severity_channel_logger.hpp> +#include <boost/log/utility/setup/from_settings.hpp> +#include <boost/log/utility/setup/settings.hpp> +#include <boost/multi_index/detail/bidir_node_iterator.hpp> +#include <boost/operators.hpp> +#include <boost/preprocessor/seq/limits/enum_256.hpp> +#include <boost/preprocessor/seq/limits/size_256.hpp> +#include <boost/property_tree/detail/exception_implementation.hpp> +#include <boost/smart_ptr/intrusive_ptr.hpp> +#include <boost/smart_ptr/intrusive_ref_counter.hpp> +#include <boost/smart_ptr/shared_ptr.hpp> +#include <cstdint> // for uint64_t #include <memory> +#include <ostream> // for ostream #include <sstream> #include <string> #include <utility> // for move #include <vector> namespace caosdb::logging { +using boost_logger_class = boost::log::sources::severity_channel_logger_mt<int, std::string>; -BOOST_LOG_GLOBAL_LOGGER_INIT(logger, boost_logger_class) { - boost_logger_class lg; - return lg; +class logger { +public: + static auto get() -> boost_logger_class & { return logger::GetInstance()._logger_instance; } + +private: + static logger &GetInstance() { + static logger instance; + return instance; + } + boost_logger_class _logger_instance; +}; + +LoggerOutputStream::LoggerOutputStream(std::string channel, int level) + : channel(std::move(channel)), level(level) {} + +auto LoggerOutputStream::operator<<(std::streambuf *msg) -> LoggerOutputStream & { + BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), channel, this->level) << msg; + + return *this; +} + +auto LoggerOutputStream::operator<<(int msg) -> LoggerOutputStream & { + BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), channel, this->level) << msg; + + return *this; +} + +auto LoggerOutputStream::operator<<(int64_t msg) -> LoggerOutputStream & { + BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), channel, this->level) << msg; + + return *this; +} + +auto LoggerOutputStream::operator<<(uint64_t msg) -> LoggerOutputStream & { + BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), channel, this->level) << msg; + + return *this; } + +auto LoggerOutputStream::operator<<(const char *msg) -> LoggerOutputStream & { + BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), channel, this->level) << msg; + + return *this; +} + +auto LoggerOutputStream::operator<<(const std::string &msg) -> LoggerOutputStream & { + BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), channel, this->level) << msg; + + return *this; +} + +auto LoggerOutputStream::operator<<(void *msg) -> LoggerOutputStream & { + BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), channel, this->level) << msg; + + return *this; +} + LoggingConfiguration::LoggingConfiguration(int level) : LevelConfiguration(level) {} auto LoggingConfiguration::AddSink(const std::shared_ptr<SinkConfiguration> &sink) -> void { @@ -64,13 +122,14 @@ SinkConfiguration::SinkConfiguration(std::string name, int level) [[nodiscard]] auto SinkConfiguration::GetName() const -> const std::string & { return this->name; } -auto SinkConfiguration::Configure(boost::log::settings &settings) const -> void { - CAOSDB_LOG_TRACE(logger_name) << "Enter SinkConfiguration::Configure(&settings)"; +auto SinkConfiguration::Configure(void *settings) const -> void { + CAOSDB_LOG_TRACE(logger_name) << "Enter SinkConfiguration::Configure(*settings)"; auto sink = "Sinks." + GetName(); - settings[sink]["Destination"] = GetDestination(); - settings[sink]["Filter"] = "%Severity% >= " + std::to_string(GetLevel()); - settings[sink]["AutoFlush"] = true; - settings[sink]["Format"] = "[%TimeStamp%][%Severity%] %Channel% - %Message%"; + auto *boost_settings = static_cast<boost::log::settings *>(settings); + (*boost_settings)[sink]["Destination"] = GetDestination(); + (*boost_settings)[sink]["Filter"] = "%Severity% >= " + std::to_string(GetLevel()); + (*boost_settings)[sink]["AutoFlush"] = true; + (*boost_settings)[sink]["Format"] = "[%TimeStamp%][%Severity%] %Channel% - %Message%"; } ConsoleSinkConfiguration::ConsoleSinkConfiguration(const std::string &name, int level) @@ -81,8 +140,8 @@ ConsoleSinkConfiguration::ConsoleSinkConfiguration(const std::string &name, int return this->destination; } -auto ConsoleSinkConfiguration::Configure(boost::log::settings &settings) const -> void { - CAOSDB_LOG_TRACE(logger_name) << "Enter ConsoleSinkConfiguration::Configure(&settings)"; +auto ConsoleSinkConfiguration::Configure(void *settings) const -> void { + CAOSDB_LOG_TRACE(logger_name) << "Enter ConsoleSinkConfiguration::Configure(*settings)"; sink_configuration::Configure(settings); } @@ -98,10 +157,11 @@ auto FileSinkConfiguration::SetDirectory(const std::string &directory) -> void { this->directory = std::string(directory); } -auto FileSinkConfiguration::Configure(boost::log::settings &settings) const -> void { - CAOSDB_LOG_TRACE(logger_name) << "Enter FileSinkConfiguration::Configure(&settings)"; +auto FileSinkConfiguration::Configure(void *settings) const -> void { + CAOSDB_LOG_TRACE(logger_name) << "Enter FileSinkConfiguration::Configure(*settings)"; sink_configuration::Configure(settings); - settings["Sink." + GetName() + ".Target"] = this->directory; + auto *boost_settings = static_cast<boost::log::settings *>(settings); + (*boost_settings)["Sink." + GetName() + ".Target"] = this->directory; } SyslogSinkConfiguration::SyslogSinkConfiguration(const std::string &name, int level) @@ -114,9 +174,12 @@ SyslogSinkConfiguration::SyslogSinkConfiguration(const std::string &name, int le // Called if no custom logging settings are specified. auto initialize_logging_defaults() -> int { // first: turn everything off - boost::log::settings off_settings; - off_settings["Core.DisableLogging"] = true; - boost::log::init_from_settings(off_settings); + auto core = boost::log::core::get(); + if (core->get_logging_enabled()) { + core->flush(); + core->remove_all_sinks(); + core->set_logging_enabled(false); + } // now set everything up const static std::vector<std::shared_ptr<SinkConfiguration>> default_sinks = { @@ -127,11 +190,10 @@ auto initialize_logging_defaults() -> int { default_settings["Core.DisableLogging"] = false; for (const auto &sink : default_sinks) { - sink->Configure(default_settings); + sink->Configure(&default_settings); } boost::log::init_from_settings(default_settings); - auto core = boost::log::core::get(); core->add_global_attribute("TimeStamp", boost::log::attributes::local_clock()); CAOSDB_LOG_DEBUG(logger_name) << "Initialized default settings."; @@ -142,22 +204,24 @@ auto initialize_logging_defaults() -> int { // Called if custom logging settings are specified. auto initialize_logging(const LoggingConfiguration &configuration) -> void { // first: turn everything off - boost::log::settings off_settings; - off_settings["Core.DisableLogging"] = true; - boost::log::init_from_settings(off_settings); - - // now set everything up - boost::log::settings new_settings; + auto core = boost::log::core::get(); + if (core->get_logging_enabled()) { + core->flush(); + core->remove_all_sinks(); + core->set_logging_enabled(false); + } if (configuration.GetLevel() == CAOSDB_LOG_LEVEL_OFF) { - new_settings["Core.DisableLogging"] = true; + // it is off return; - } else { - new_settings["Core.DisableLogging"] = false; } + // now set everything up + boost::log::settings new_settings; + new_settings["Core.DisableLogging"] = false; + for (const auto &sink : configuration.GetSinks()) { - sink->Configure(new_settings); + sink->Configure(&new_settings); } boost::log::init_from_settings(new_settings); @@ -166,27 +230,27 @@ auto initialize_logging(const LoggingConfiguration &configuration) -> void { } void caosdb_log_fatal(const char *channel, const char *msg) { - BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), channel, CAOSDB_LOG_LEVEL_FATAL) << msg; + LoggerOutputStream::get(channel, CAOSDB_LOG_LEVEL_FATAL) << msg; } void caosdb_log_error(const char *channel, const char *msg) { - BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), channel, CAOSDB_LOG_LEVEL_ERROR) << msg; + LoggerOutputStream::get(channel, CAOSDB_LOG_LEVEL_ERROR) << msg; } void caosdb_log_warn(const char *channel, const char *msg) { - BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), channel, CAOSDB_LOG_LEVEL_WARN) << msg; + LoggerOutputStream::get(channel, CAOSDB_LOG_LEVEL_WARN) << msg; } void caosdb_log_info(const char *channel, const char *msg) { - BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), channel, CAOSDB_LOG_LEVEL_INFO) << msg; + LoggerOutputStream::get(channel, CAOSDB_LOG_LEVEL_INFO) << msg; } void caosdb_log_debug(const char *channel, const char *msg) { - BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), channel, CAOSDB_LOG_LEVEL_DEBUG) << msg; + LoggerOutputStream::get(channel, CAOSDB_LOG_LEVEL_DEBUG) << msg; } void caosdb_log_trace(const char *channel, const char *msg) { - BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), channel, CAOSDB_LOG_LEVEL_TRACE) << msg; + LoggerOutputStream::get(channel, CAOSDB_LOG_LEVEL_TRACE) << msg; } } // namespace caosdb::logging diff --git a/src/caosdb/protobuf_helper.cpp b/src/caosdb/protobuf_helper.cpp index 418d14b9c847bc204582f6165fae81bf6adcc156..2b5847687d4926324cbbd5d4f49caca4131dc951 100644 --- a/src/caosdb/protobuf_helper.cpp +++ b/src/caosdb/protobuf_helper.cpp @@ -19,15 +19,15 @@ * */ #include "caosdb/protobuf_helper.h" +#include "caosdb/configuration.h" #include <google/protobuf/arena.h> // for Arena namespace caosdb::utility { using google::protobuf::Arena; -auto get_arena() -> Arena * { - static Arena arena; - return &arena; -} +auto get_arena() -> Arena * { return caosdb::configuration::ConfigurationManager::GetArena(); } + +auto reset_arena() -> void { get_arena()->Reset(); } } // namespace caosdb::utility diff --git a/src/caosdb/status_code_description.cpp b/src/caosdb/status_code_description.cpp index d5e08e7820ca0f7380723087570f838465a9c261..d1f651257bc1a682870ffb52650a42c4d16ec642 100644 --- a/src/caosdb/status_code_description.cpp +++ b/src/caosdb/status_code_description.cpp @@ -131,8 +131,9 @@ auto get_status_description(int code) -> const std::string & { "The transaction terminated unsuccessfully with transaction errors."}, {StatusCode::CONFIGURATION_ERROR, "An error occurred during the configuration of the ConfigurationManager."}, - {StatusCode::UNKNOWN_CONNECTION_ERROR, - "The ConnectionManager does not know any connection of this name."}, + {StatusCode::CONNECTION_CONFIGURATION_ERROR, + "Either there is no connection of the given name or the given connection has a faulty " + "configuration"}, {StatusCode::TRANSACTION_STATUS_ERROR, "The Transaction is in a wrong state for the attempted action."}, {StatusCode::TRANSACTION_TYPE_ERROR, @@ -151,9 +152,9 @@ auto get_status_description(int code) -> const std::string & { {StatusCode::FILE_UPLOAD_ERROR, "The transaction failed during the upload of the files"}, {StatusCode::UNSUPPORTED_FEATURE, "This feature is not available in the this client implementation."}, - {StatusCode::EXTERN_C_ASSIGNMENT_ERROR, - "You tried to assign a new object to the wrapped void pointer. You have " - "to delete the old pointee first."}, + //{StatusCode::EXTERN_C_ASSIGNMENT_ERROR, + //"You tried to assign a new object to the wrapped void pointer. You have " + //"to delete the old pointee first."}, {StatusCode::ENUM_MAPPING_ERROR, "The role, importance, or datatype you specified does not exist."}, {StatusCode::SPOILED, diff --git a/src/caosdb/transaction.cpp b/src/caosdb/transaction.cpp index b9a96f56a8178c8543f3f96177fc77fd3e579804..14cc40cb8e1d07d18ce648cb72d10412b579ff22 100644 --- a/src/caosdb/transaction.cpp +++ b/src/caosdb/transaction.cpp @@ -18,8 +18,9 @@ * */ #include "caosdb/transaction.h" -#include "caosdb/entity/v1alpha1/main.grpc.pb.h" // for EntityTransac... -#include "caosdb/entity/v1alpha1/main.pb.h" // for TransactionRe... +#include "caosdb/entity/v1/main.grpc.pb.h" // for EntityTransac... +#include "caosdb/entity/v1/main.pb.h" // for TransactionRe... + #include "caosdb/file_transmission/download_request_handler.h" // Download... #include "caosdb/file_transmission/file_reader.h" // for path #include "caosdb/file_transmission/register_file_upload_handler.h" // for RegisterFileUploadHandler @@ -29,14 +30,9 @@ #include "caosdb/transaction_handler.h" // for EntityTransactionHandler #include <algorithm> // for max // IWYU pragma: no_include <bits/exception.h> -#include <boost/filesystem/path.hpp> // for operator<<, path -#include <boost/log/core/record.hpp> // for record -#include <boost/log/detail/attachable_sstream_buf.hpp> // for basic_ostring... -#include <boost/log/sources/record_ostream.hpp> // for basic_record_... -#include <boost/preprocessor/seq/limits/enum_256.hpp> // for BOOST_PP_SEQ_... -#include <boost/preprocessor/seq/limits/size_256.hpp> // for BOOST_PP_SEQ_... // IWYU pragma: no_include <cxxabi.h> #include <exception> // IWYU pragma: keep +#include <filesystem> // for operator<<, path #include <future> // for async, future #include <google/protobuf/arena.h> // for Arena #include <google/protobuf/generated_message_util.h> // for CreateMessage... @@ -45,22 +41,24 @@ #include <iosfwd> // for streamsize #include <map> // for map, operator!= #include <memory> // for unique_ptr +#include <random> // for mt19937, rand... #include <system_error> // for std::system_error #include <utility> // for move, pair namespace caosdb::transaction { -using caosdb::entity::v1alpha1::EntityTransactionService; -using caosdb::entity::v1alpha1::FileTransmissionService; -using caosdb::entity::v1alpha1::MultiTransactionRequest; -using caosdb::entity::v1alpha1::MultiTransactionResponse; -using TransactionResponseCase = - caosdb::entity::v1alpha1::TransactionResponse::TransactionResponseCase; -using RetrieveResponseCase = caosdb::entity::v1alpha1::RetrieveResponse::RetrieveResponseCase; -using RetrieveResponse = caosdb::entity::v1alpha1::RetrieveResponse; -using ProtoEntity = caosdb::entity::v1alpha1::Entity; +using caosdb::entity::v1::EntityTransactionService; +using caosdb::entity::v1::FileTransmissionService; +using caosdb::entity::v1::MultiTransactionRequest; +using caosdb::entity::v1::MultiTransactionResponse; +using TransactionResponseCase = caosdb::entity::v1::TransactionResponse::TransactionResponseCase; +using RetrieveResponseCase = caosdb::entity::v1::RetrieveResponse::RetrieveResponseCase; +using RetrieveResponse = caosdb::entity::v1::RetrieveResponse; +using ProtoEntity = caosdb::entity::v1::Entity; +using caosdb::entity::v1::EntityRequest; + using google::protobuf::Arena; using NextStatus = grpc::CompletionQueue::NextStatus; -using RegistrationStatus = caosdb::entity::v1alpha1::RegistrationStatus; +using RegistrationStatus = caosdb::entity::v1::RegistrationStatus; ResultSet::iterator::iterator(const ResultSet *result_set_param, int index) : current_index(index), result_set(result_set_param) {} @@ -93,12 +91,9 @@ MultiResultSet::MultiResultSet(std::vector<std::unique_ptr<Entity>> result_set) Transaction::Transaction(std::shared_ptr<EntityTransactionService::Stub> entity_service, std::shared_ptr<FileTransmissionService::Stub> file_service) - : request(Arena::CreateMessage<MultiTransactionRequest>(GetArena())), - response(Arena::CreateMessage<MultiTransactionResponse>(GetArena())) { - this->entity_service = std::move(entity_service); - this->file_service = std::move(file_service); - this->query_count = -1; -} + : entity_service(std::move(entity_service)), file_service(std::move(file_service)), + request(Arena::CreateMessage<MultiTransactionRequest>(GetArena())), + response(Arena::CreateMessage<MultiTransactionResponse>(GetArena())), query_count(-1) {} auto Transaction::RetrieveById(const std::string &id) noexcept -> StatusCode { ASSERT_CAN_ADD_RETRIEVAL @@ -148,20 +143,39 @@ auto Transaction::DeleteById(const std::string &id) noexcept -> StatusCode { return this->status.GetCode(); } -auto Transaction::InsertEntity(Entity *entity) noexcept -> StatusCode { - ASSERT_CAN_ADD_INSERTION +auto get_next_file_id() -> std::string { + const std::string str = "0123456789abcdef"; + std::mt19937 generator(std::random_device{}()); + std::uniform_int_distribution<int> distribution(0, 15); // NOLINT + std::string result(10, '\0'); // NOLINT - auto *entity_request = - this->request->add_requests()->mutable_insert_request()->mutable_entity_request(); - auto *proto_entity = entity_request->mutable_entity(); + for (auto &dis : result) { + dis = str[distribution(generator)]; + } + return result; +} - // copy the original entity for the transaction +// only used in the next two functions. +auto add_entity_to_request(Entity *entity, EntityRequest *entity_request, + std::vector<FileDescriptor> *upload_files) -> void { + auto *proto_entity = entity_request->mutable_entity(); entity->CopyTo(proto_entity); if (entity->HasFile()) { auto *file_transmission_id = entity_request->mutable_upload_id(); + file_transmission_id->set_file_id(get_next_file_id()); entity->SetFileTransmissionId(file_transmission_id); - upload_files.push_back(entity->GetFileDescriptor()); + upload_files->push_back(entity->GetFileDescriptor()); } +} + +auto Transaction::InsertEntity(Entity *entity) noexcept -> StatusCode { + ASSERT_CAN_ADD_INSERTION + + auto *entity_request = + this->request->add_requests()->mutable_insert_request()->mutable_entity_request(); + + add_entity_to_request(entity, entity_request, &upload_files); + this->status = TransactionStatus::GO_ON(); return this->status.GetCode(); } @@ -171,14 +185,9 @@ auto Transaction::UpdateEntity(Entity *entity) noexcept -> StatusCode { auto *entity_request = this->request->add_requests()->mutable_update_request()->mutable_entity_request(); - auto *proto_entity = entity_request->mutable_entity(); - entity->CopyTo(proto_entity); - if (entity->HasFile()) { - auto *file_transmission_id = entity_request->mutable_upload_id(); - entity->SetFileTransmissionId(file_transmission_id); - upload_files.push_back(entity->GetFileDescriptor()); - } + add_entity_to_request(entity, entity_request, &upload_files); + this->status = TransactionStatus::GO_ON(); return this->status.GetCode(); } @@ -256,8 +265,9 @@ auto Transaction::DoExecuteTransaction() noexcept -> StatusCode { auto *entity_response = sub_response.mutable_retrieve_response()->mutable_entity_response(); auto entity_id = entity_response->entity().id(); - download_files[entity_id].file_transmission_id = entity_response->release_download_id(); - // TODO(tf) handle error + download_files[entity_id].file_transmission_id = + Arena::CreateMessage<FileTransmissionId>(GetArena()); + download_files[entity_id].file_transmission_id->CopyFrom(entity_response->download_id()); } } } @@ -356,24 +366,24 @@ auto Transaction::ProcessTerminated() const noexcept -> TransactionStatus { break; // break TransactionResponseCase::kRetrieveResponse } case TransactionResponseCase::kInsertResponse: { - auto *inserted_id_response = sub_response.mutable_insert_response()->release_id_response(); + auto *inserted_id_response = sub_response.mutable_insert_response()->mutable_id_response(); result = std::make_unique<Entity>(inserted_id_response); break; } case TransactionResponseCase::kDeleteResponse: { - auto *deleted_id_response = sub_response.mutable_delete_response()->release_id_response(); + auto *deleted_id_response = sub_response.mutable_delete_response()->mutable_id_response(); result = std::make_unique<Entity>(deleted_id_response); break; } case TransactionResponseCase::kUpdateResponse: { - auto *updated_id_response = sub_response.mutable_update_response()->release_id_response(); + auto *updated_id_response = sub_response.mutable_update_response()->mutable_id_response(); result = std::make_unique<Entity>(updated_id_response); break; } default: CAOSDB_LOG_FATAL(logger_name) << "Received invalid TransactionResponseCase."; break; - } + } // default to sub_response.transaction_response_case() if (result != nullptr) { if (result->HasErrors()) { set_error = true; diff --git a/src/caosdb/transaction_handler.cpp b/src/caosdb/transaction_handler.cpp index d6cc8d3270949b0bb79e6cc2828c75ad9d772ae9..cbcbf76332f437712ea3883be72c347370f75924 100644 --- a/src/caosdb/transaction_handler.cpp +++ b/src/caosdb/transaction_handler.cpp @@ -1,15 +1,9 @@ #include "caosdb/transaction_handler.h" -#include "caosdb/logging.h" // for CAOSDB_LOG_TRACE -#include <boost/log/core/record.hpp> // for record -#include <boost/log/detail/attachable_sstream_buf.hpp> // for basic_ostring... -#include <boost/log/sources/record_ostream.hpp> // for basic_record_... -#include <boost/preprocessor/seq/limits/enum_256.hpp> // for BOOST_PP_SEQ_... -#include <boost/preprocessor/seq/limits/size_256.hpp> // for BOOST_PP_SEQ_... -#include <exception> // IWYU pragma: keep +#include "caosdb/logging.h" // for CAOSDB_LOG_TRACE +#include <exception> // IWYU pragma: keep // IWYU pragma: no_include <bits/exception.h> #include <grpcpp/impl/codegen/async_unary_call.h> // for ClientAsyncRes... #include <grpcpp/impl/codegen/completion_queue.h> // for CompletionQueue -#include <iosfwd> // for streamsize namespace caosdb::transaction { diff --git a/src/caosdb/unary_rpc_handler.cpp b/src/caosdb/unary_rpc_handler.cpp index 4db2a949cc2667b4f145a7ef012bbfa68eb2c193..6770cae1981fa193105d5af9af4934d90a6b0aca 100644 --- a/src/caosdb/unary_rpc_handler.cpp +++ b/src/caosdb/unary_rpc_handler.cpp @@ -47,19 +47,13 @@ * > DEALINGS IN THE SOFTWARE. */ #include "caosdb/unary_rpc_handler.h" -#include "caosdb/logging.h" // for CAOSDB_LOG_TRACE -#include "caosdb/status_code.h" // for GENERIC_RPC_E... -#include <boost/log/core/record.hpp> // for record -#include <boost/log/detail/attachable_sstream_buf.hpp> // for basic_ostring... -#include <boost/log/sources/record_ostream.hpp> // for basic_record_... -#include <boost/preprocessor/seq/limits/enum_256.hpp> // for BOOST_PP_SEQ_... -#include <boost/preprocessor/seq/limits/size_256.hpp> // for BOOST_PP_SEQ_... +#include "caosdb/logging.h" // for CAOSDB_LOG_TRACE +#include "caosdb/status_code.h" // for GENERIC_RPC_E... // IWYU pragma: no_include <bits/exception.h> #include <exception> // IWYU pragma: keep #include <grpcpp/impl/codegen/client_context.h> // for ClientContext #include <grpcpp/impl/codegen/status.h> // for Status #include <grpcpp/impl/codegen/status_code_enum.h> // for OK, UNAUTHENT... -#include <iosfwd> // for streamsize #include <string> // for string, opera... namespace caosdb::transaction { diff --git a/src/caosdb/utility.cpp b/src/caosdb/utility.cpp index a4ed293adb6bd4fbfb10860e03185aeb567de163..ca7e1cbe9102763ed54763f7ca1dd271ed0b06db 100644 --- a/src/caosdb/utility.cpp +++ b/src/caosdb/utility.cpp @@ -19,18 +19,35 @@ * */ #include "caosdb/utility.h" -#include "caosdb/data_type.h" // for AtomicDataType, atomicdatatype_names -#include "caosdb/entity.h" // for Importance, Role, importance_names -#include <map> // for map, operator!=, _Rb_tree_const_iterator -#include <utility> // for pair +#include "caosdb/data_type.h" // for AtomicDataType, atomicdatatype_names +#include "caosdb/entity.h" // for Importance, Role, importance_names +#include <boost/beast/core/detail/base64.hpp> // for encoded_size +#include <boost/beast/core/detail/base64.ipp> // for encode +#include <boost/filesystem/string_file.hpp> // for load_string_file +#include <boost/json/stream_parser.hpp> // for stream_parser +#include <boost/json/value.hpp> // for value +#include <cassert> // for assert +#include <map> // for map, operator!=, _Rb_tree_const_iterator +#include <memory> // for allocator, unique_ptr +#include <stdexcept> // for logic_error +#include <type_traits> // for underlying_type_t +#include <typeinfo> // for type_info +#include <utility> // for pair namespace caosdb::utility { +using boost::json::stream_parser; +using boost::json::value; using caosdb::entity::AtomicDataType; using caosdb::entity::Importance; using caosdb::entity::Role; -// using emap = std::map<int, std::string>; // enum mapping +template <typename Enum> auto getEnumNameFromValue(Enum v) -> std::string { + if (std::is_same_v<std::underlying_type_t<Enum>, int>) { + return std::to_string(static_cast<int>(v)); + } + throw std::logic_error(std::string("Enum type ") + typeid(v).name() + " not implemented."); +} // Enum helper template specializations ////////////////////////////////////// template <> auto getEnumNameFromValue<Importance>(Importance v) -> std::string { @@ -87,4 +104,82 @@ template <> auto getEnumValueFromName<Role>(const std::string &name) -> Role { // End of template specialization ///////////////////////////////////////////// +auto load_string_file(const path &file_path) -> std::string { + std::string result; + boost::filesystem::load_string_file(file_path.string(), result); + return result; +} + +auto base64_encode(const std::string &plain) -> std::string { + auto size_plain = plain.size(); + auto size_encoded = boost::beast::detail::base64::encoded_size(size_plain); + + std::string result = std::string(size_encoded, '\0'); + boost::beast::detail::base64::encode(&result[0], plain.c_str(), size_plain); + + return result; +} + +auto _load_json_file(const path &json_file) -> value { + assert(exists(json_file)); + + constexpr auto buffer_size = std::size_t(4096); + auto stream = ifstream(json_file); + stream.exceptions(std::ios_base::badbit); + + stream_parser parser; + auto result = std::string(); + auto buffer = std::string(buffer_size, '\0'); + while (stream.read(&buffer[0], buffer_size)) { + parser.write(buffer.c_str(), stream.gcount()); + } + parser.write(buffer.c_str(), stream.gcount()); + + assert(parser.done()); + return parser.release(); +} + +auto load_json_file(const path &json_file) -> JsonValue { + return {new value(_load_json_file(json_file))}; +} + +JsonValue::JsonValue(void *wrapped) { this->wrapped.reset(static_cast<value *>(wrapped)); } + +JsonValue::~JsonValue() = default; + +auto JsonValue::Reset() -> void { + if (this->wrapped) { + this->wrapped.reset(); + } +} + +JsonValue::JsonValue(const JsonValue &other) { + if (other.wrapped) { + this->wrapped.reset(static_cast<value *>(other.wrapped.get())); + } +} + +auto JsonValue::operator=(const JsonValue &other) -> JsonValue & { + if (this != &other) { + if (other.wrapped) { + this->wrapped = std::make_shared<value>(*(static_cast<value *>(other.wrapped.get()))); + } + } + return *this; +} + +JsonValue::JsonValue(JsonValue &&other) noexcept { + if (other.wrapped) { + this->wrapped = std::move(other.wrapped); + } +} + +auto JsonValue::operator=(JsonValue &&other) noexcept -> JsonValue & { + if (this != &other) { + Reset(); + this->wrapped = std::move(other.wrapped); + } + return *this; +} + } // namespace caosdb::utility diff --git a/src/ccaosdb.cpp b/src/ccaosdb.cpp index 77759fce1d216f215dfccd343aa8202b2ec911fa..ae1a728f62b7cdfb293eb347d1a1966b86bfd3b2 100644 --- a/src/ccaosdb.cpp +++ b/src/ccaosdb.cpp @@ -58,11 +58,6 @@ extern "C" { #define ENUM_VALUE_FROM_NAME(arg, etype) \ caosdb::utility::getEnumValueFromName<caosdb::entity::etype>(arg) -#define RETURN_ASSIGNEMENT_ERROR_IF_DELETABLE(name) \ - if (name->_deletable) { \ - return caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR; \ - } - /* * Macro for wrapping every function into a try-catch clause. If an exception * occurs, the given StatusCode is being returned. @@ -163,7 +158,6 @@ extern "C" { #define CREATE_VALUE(fname, arg) \ ERROR_RETURN_CODE(GENERIC_ERROR, \ int caosdb_entity_create_##fname(caosdb_entity_value *out, arg), { \ - RETURN_ASSIGNEMENT_ERROR_IF_DELETABLE(out) \ out->wrapped_value = new caosdb::entity::Value(value); \ out->_deletable = true; \ return 0; \ @@ -175,9 +169,6 @@ extern "C" { ERROR_RETURN_CODE( \ GENERIC_ERROR, \ int caosdb_entity_create_##fname(caosdb_entity_value *out, arg, const int length), { \ - if (out->_deletable) { \ - return caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR; \ - } \ std::vector<type> value_vec; \ for (int i = 0; i < length; i++) { \ value_vec.push_back(assign); \ @@ -245,9 +236,6 @@ ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_connection_create_pem_file_certificate_provider( caosdb_connection_certificate_provider *out, const char *path), { - if (out->_deletable) { - return caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR; - } out->wrapped_certificate_provider = new caosdb::configuration::PemFileCertificateProvider(std::string(path)); out->_deletable = true; @@ -258,10 +246,11 @@ ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_connection_delete_certificate_provider( caosdb_connection_certificate_provider *provider), { - if (provider->_deletable) { + if (provider->_deletable && provider->wrapped_certificate_provider) { delete static_cast<caosdb::configuration::CertificateProvider *>( provider->wrapped_certificate_provider); } + provider->wrapped_certificate_provider = nullptr; provider->_deletable = false; return 0; }) @@ -271,9 +260,6 @@ ERROR_RETURN_CODE(GENERIC_ERROR, caosdb_authentication_authenticator *out, const char *username, const char *password), { - if (out->_deletable) { - return caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR; - } out->wrapped_authenticator = new caosdb::authentication::PlainPasswordAuthenticator(std::string(username), std::string(password)); @@ -285,10 +271,11 @@ ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_authentication_delete_authenticator( caosdb_authentication_authenticator *authenticator), { - if (authenticator->_deletable) { + if (authenticator->_deletable && authenticator->wrapped_authenticator) { delete static_cast<caosdb::authentication::Authenticator *>( authenticator->wrapped_authenticator); } + authenticator->wrapped_authenticator = nullptr; authenticator->_deletable = false; return 0; }) @@ -300,9 +287,6 @@ ERROR_RETURN_CODE( caosdb_authentication_authenticator *authenticator, caosdb_connection_certificate_provider *provider), { - if (out->_deletable) { - return caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR; - } auto host_str = std::string(host); if (authenticator != nullptr && provider != nullptr) { auto wrapped_provider = static_cast<caosdb::configuration::CertificateProvider *>( @@ -334,9 +318,6 @@ ERROR_RETURN_CODE(GENERIC_ERROR, caosdb_connection_connection_configuration *out, const char *host, const int port), { - if (out->_deletable) { - return caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR; - } out->wrapped_connection_configuration = new caosdb::configuration::InsecureConnectionConfiguration(host, port); out->_deletable = true; @@ -347,10 +328,12 @@ ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_connection_delete_connection_configuration( caosdb_connection_connection_configuration *configuration), { - if (configuration->_deletable) { + if (configuration->_deletable && + configuration->wrapped_connection_configuration) { delete static_cast<caosdb::configuration::ConnectionConfiguration *>( configuration->wrapped_connection_configuration); } + configuration->wrapped_connection_configuration = nullptr; configuration->_deletable = false; return 0; }) @@ -360,9 +343,6 @@ ERROR_RETURN_CODE(GENERIC_ERROR, caosdb_connection_connection *out, const caosdb_connection_connection_configuration *configuration), { - if (out->_deletable) { - return caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR; - } caosdb::configuration::ConnectionConfiguration *config = static_cast<caosdb::configuration::ConnectionConfiguration *>( configuration->wrapped_connection_configuration); @@ -374,10 +354,11 @@ ERROR_RETURN_CODE(GENERIC_ERROR, ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_connection_delete_connection(caosdb_connection_connection *connection), { - if (connection->_deletable) { + if (connection->_deletable && connection->wrapped_connection) { delete static_cast<caosdb::connection::Connection *>( connection->wrapped_connection); } + connection->wrapped_connection = nullptr; connection->_deletable = false; return 0; }) @@ -417,9 +398,6 @@ ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_connection_connection_manager_get_default_connection( caosdb_connection_connection *out), { - if (out->_deletable) { - return caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR; - } out->wrapped_connection = caosdb::connection::ConnectionManager::GetDefaultConnection().get(); out->_deletable = false; @@ -430,9 +408,6 @@ ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_connection_connection_manager_get_connection( caosdb_connection_connection *out, const char *name), { - if (out->_deletable) { - return caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR; - } out->wrapped_connection = caosdb::connection::ConnectionManager::GetConnection(std::string(name)).get(); // managed by the connection manager now, so not @@ -448,9 +423,6 @@ ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_connection_connection_create_transaction( caosdb_connection_connection *connection, caosdb_transaction_transaction *out), { - if (out->_deletable) { - return caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR; - } auto *wrapped_connection = static_cast<caosdb::connection::Connection *>(connection->wrapped_connection); out->wrapped_transaction = wrapped_connection->CreateTransaction().release(); @@ -461,9 +433,11 @@ ERROR_RETURN_CODE(GENERIC_ERROR, ERROR_RETURN_CODE( GENERIC_ERROR, int caosdb_transaction_delete_transaction(caosdb_transaction_transaction *transaction), { - if (transaction->_deletable) { + if (transaction->_deletable && transaction->wrapped_transaction) { delete static_cast<caosdb::transaction::Transaction *>(transaction->wrapped_transaction); } + transaction->wrapped_transaction = nullptr; + transaction->_deletable = false; return 0; }) @@ -553,9 +527,6 @@ ERROR_RETURN_CODE( int caosdb_transaction_transaction_get_result_set(caosdb_transaction_transaction *transaction, caosdb_transaction_result_set *out), { - if (out->_deletable) { - return caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR; - } auto *wrapped_transaction = static_cast<caosdb::transaction::Transaction *>(transaction->wrapped_transaction); out->wrapped_result_set = (void *)(&(wrapped_transaction->GetResultSet())); @@ -568,9 +539,6 @@ ERROR_RETURN_CODE( int caosdb_transaction_transaction_release_result_set(caosdb_transaction_transaction *transaction, caosdb_transaction_result_set *out), { - if (out->_deletable) { - return caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR; - } auto *wrapped_transaction = static_cast<caosdb::transaction::Transaction *>(transaction->wrapped_transaction); out->wrapped_result_set = (void *)(wrapped_transaction->ReleaseResultSet()); @@ -582,9 +550,10 @@ ERROR_RETURN_CODE( ERROR_RETURN_CODE( GENERIC_ERROR, int caosdb_transaction_delete_result_set(caosdb_transaction_result_set *result_set), { - if (result_set->_deletable) { + if (result_set->_deletable && result_set->wrapped_result_set) { delete static_cast<caosdb::entity::Entity *>(result_set->wrapped_result_set); } + result_set->wrapped_result_set = nullptr; result_set->_deletable = false; return 0; }) @@ -615,9 +584,6 @@ ERROR_RETURN_CODE( int caosdb_transaction_result_set_release_at(caosdb_transaction_result_set *result_set, caosdb_entity_entity *entity, int index), { - if (entity->_deletable) { - return caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR; - } auto *wrapped_result_set = static_cast<caosdb::transaction::MultiResultSet *>(result_set->wrapped_result_set); entity->wrapped_entity = wrapped_result_set->release_at(index); @@ -638,52 +604,46 @@ ERROR_RETURN_CODE(GENERIC_ERROR, }) ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_entity_create_entity(caosdb_entity_entity *out), { - if (out->_deletable) { - return caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR; - } out->wrapped_entity = new caosdb::entity::Entity(); out->_deletable = true; return 0; }) ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_entity_delete_entity(caosdb_entity_entity *out), { - if (out->_deletable) { + if (out->_deletable && out->wrapped_entity) { delete static_cast<caosdb::entity::Entity *>(out->wrapped_entity); } + out->wrapped_entity = nullptr; out->_deletable = false; return 0; }) ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_entity_create_property(caosdb_entity_property *out), { - if (out->_deletable) { - return caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR; - } out->wrapped_property = new caosdb::entity::Property(); out->_deletable = true; return 0; }) ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_entity_delete_property(caosdb_entity_property *out), { - if (out->_deletable) { + if (out->_deletable && out->wrapped_property) { delete static_cast<caosdb::entity::Property *>(out->wrapped_property); } + out->wrapped_property = nullptr; out->_deletable = false; return 0; }) ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_entity_create_parent(caosdb_entity_parent *out), { - if (out->_deletable) { - return caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR; - } out->wrapped_parent = new caosdb::entity::Parent(); out->_deletable = true; return 0; }) ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_entity_delete_parent(caosdb_entity_parent *out), { - if (out->_deletable) { + if (out->_deletable && out->wrapped_parent) { delete static_cast<caosdb::entity::Parent *>(out->wrapped_parent); } + out->wrapped_parent = nullptr; out->_deletable = false; return 0; }) @@ -692,7 +652,6 @@ ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_entity_create_atomic_datatype(caosdb_entity_datatype *out, const char *name), { - RETURN_ASSIGNEMENT_ERROR_IF_DELETABLE(out) try { auto enum_value = ENUM_VALUE_FROM_NAME(std::string(name), AtomicDataType); out->wrapped_datatype = new caosdb::entity::DataType(enum_value); @@ -707,7 +666,6 @@ ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_entity_create_reference_datatype(caosdb_entity_datatype *out, const char *name), { - RETURN_ASSIGNEMENT_ERROR_IF_DELETABLE(out) out->wrapped_datatype = new caosdb::entity::DataType(std::string(name)); out->_deletable = true; return 0; @@ -716,7 +674,6 @@ ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_entity_create_atomic_list_datatype(caosdb_entity_datatype *out, const char *name), { - RETURN_ASSIGNEMENT_ERROR_IF_DELETABLE(out) try { auto enum_value = ENUM_VALUE_FROM_NAME(std::string(name), AtomicDataType); out->wrapped_datatype = @@ -732,7 +689,6 @@ ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_entity_create_reference_list_datatype(caosdb_entity_datatype *out, const char *name), { - RETURN_ASSIGNEMENT_ERROR_IF_DELETABLE(out) out->wrapped_datatype = new caosdb::entity::DataType( caosdb::entity::DataType::ListOf(std::string(name))); out->_deletable = true; @@ -740,9 +696,10 @@ ERROR_RETURN_CODE(GENERIC_ERROR, }) ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_entity_delete_datatype(caosdb_entity_datatype *out), { - if (out->_deletable) { + if (out->_deletable && out->wrapped_datatype) { delete WRAPPED_DATATYPE_CAST(out); } + out->wrapped_datatype = nullptr; out->_deletable = false; return 0; }) @@ -757,9 +714,10 @@ CREATE_VECTOR_VALUE(double_vector_value, double, const double *value, value[i]) CREATE_VECTOR_VALUE(bool_vector_value, bool, const bool *value, value[i]) ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_entity_delete_value(caosdb_entity_value *out), { - if (out->_deletable) { + if (out->_deletable && out->wrapped_value) { delete WRAPPED_VALUE_CAST(out); } + out->wrapped_value = nullptr; out->_deletable = false; return 0; }) @@ -793,7 +751,6 @@ ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_entity_entity_get_datatype(caosdb_entity_entity *entity, caosdb_entity_datatype *out), { - RETURN_ASSIGNEMENT_ERROR_IF_DELETABLE(out) auto *wrapped_entity = WRAPPED_ENTITY_CAST(entity); out->wrapped_datatype = (void *)(&(wrapped_entity->GetDataType())); out->_deletable = false; @@ -803,7 +760,6 @@ ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_entity_entity_get_value(caosdb_entity_entity *entity, caosdb_entity_value *out), { - RETURN_ASSIGNEMENT_ERROR_IF_DELETABLE(out) auto *wrapped_entity = WRAPPED_ENTITY_CAST(entity); out->wrapped_value = (void *)(&(wrapped_entity->GetValue())); out->_deletable = false; @@ -826,9 +782,6 @@ ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_entity_entity_get_error(caosdb_entity_entity *entity, caosdb_entity_message *out, int index), { - if (out->_deletable) { - return caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR; - } auto *wrapped_entity = static_cast<caosdb::entity::Entity *>(entity->wrapped_entity); out->wrapped_message = wrapped_entity->GetErrors().mutable_at(index); @@ -850,9 +803,6 @@ ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_entity_entity_get_warning(caosdb_entity_entity *entity, caosdb_entity_message *out, int index), { - if (out->_deletable) { - return caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR; - } auto *wrapped_entity = static_cast<caosdb::entity::Entity *>(entity->wrapped_entity); out->wrapped_message = wrapped_entity->GetWarnings().mutable_at(index); @@ -872,9 +822,6 @@ ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_entity_entity_get_info(caosdb_entity_entity *entity, caosdb_entity_message *out, int index), { - if (out->_deletable) { - return caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR; - } auto *wrapped_entity = static_cast<caosdb::entity::Entity *>(entity->wrapped_entity); out->wrapped_message = wrapped_entity->GetInfos().mutable_at(index); @@ -896,9 +843,6 @@ ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_entity_entity_get_property(caosdb_entity_entity *entity, caosdb_entity_property *out, int index), { - if (out->_deletable) { - return caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR; - } auto *wrapped_entity = static_cast<caosdb::entity::Entity *>(entity->wrapped_entity); out->wrapped_property = wrapped_entity->GetProperties().mutable_at(index); @@ -919,9 +863,6 @@ ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_entity_entity_get_parent(caosdb_entity_entity *entity, caosdb_entity_parent *out, int index), { - if (out->_deletable) { - return caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR; - } auto *wrapped_entity = static_cast<caosdb::entity::Entity *>(entity->wrapped_entity); out->wrapped_parent = wrapped_entity->GetParents().mutable_at(index); @@ -954,7 +895,6 @@ ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_entity_property_get_datatype(caosdb_entity_property *property, caosdb_entity_datatype *out), { - RETURN_ASSIGNEMENT_ERROR_IF_DELETABLE(out) auto *wrapped_property = WRAPPED_PROPERTY_CAST(property); out->wrapped_datatype = (void *)(&(wrapped_property->GetDataType())); out->_deletable = false; @@ -964,7 +904,6 @@ ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_entity_property_get_value(caosdb_entity_property *property, caosdb_entity_value *out), { - RETURN_ASSIGNEMENT_ERROR_IF_DELETABLE(out) auto *wrapped_property = WRAPPED_PROPERTY_CAST(property); out->wrapped_value = (void *)(&(wrapped_property->GetValue())); out->_deletable = false; @@ -1092,9 +1031,6 @@ ERROR_RETURN_CODE(GENERIC_ERROR, caosdb_entity_value *out, const int index), { - if (out->_deletable) { - return caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR; - } auto *wrapped_value = WRAPPED_VALUE_CAST(value); out->wrapped_value = (void *)(&(wrapped_value->GetAsVector().at(index))); out->_deletable = false; @@ -1115,7 +1051,7 @@ ERROR_RETURN_CODE(GENERIC_ERROR, }) CAOSDB_ENTITY_SET(name, name, wrapped_entity->SetName(std::string(name));) CAOSDB_ENTITY_SET(local_path, local_path, - return wrapped_entity->SetLocalPath(boost::filesystem::path(local_path));) + return wrapped_entity->SetLocalPath(std::filesystem::path(local_path));) CAOSDB_ENTITY_SET(file_path, file_path, wrapped_entity->SetFilePath(std::string(file_path));) CAOSDB_ENTITY_SET(description, description, wrapped_entity->SetDescription(std::string(description));) diff --git a/src/cxxcaosdbcli.cpp b/src/cxxcaosdbcli.cpp index bb60696e8a0f3b10d2b29e54cac034b89907f9c3..e6e5cee66e6c90ab7719434d7667cd6ad20ccbb8 100644 --- a/src/cxxcaosdbcli.cpp +++ b/src/cxxcaosdbcli.cpp @@ -21,16 +21,23 @@ */ // A simple caosdb client -#include "caosdb/connection.h" // for Connection, ConnectionManager -#include "caosdb/constants.h" // for LIBCAOSDB_VERSION_MINOR, LIBCAOSDB_V... -#include "caosdb/entity.h" // for Entity -#include "caosdb/exceptions.h" // for ConfigurationError -#include "caosdb/info.h" // for VersionInfo -#include "caosdb/logging.h" // for CAOSDB_LOG_TRACE -#include "caosdb/transaction.h" // for Transaction, ResultSet -#include <iostream> // for operator<<, basic_ostream, basic_ost... -#include <memory> // for unique_ptr, allocator, __shared_ptr_... -#include <string> // for operator<<, char_traits +#include "caosdb/connection.h" // for Connection, ConnectionManager +#include "caosdb/constants.h" // for LIBCAOSDB_VERSION_MINOR, LIBCAOSDB_V... +#include "caosdb/entity.h" // for Entity +#include "caosdb/exceptions.h" // for ConfigurationError +#include "caosdb/info.h" // for VersionInfo +#include "caosdb/logging.h" // for CAOSDB_LOG_TRACE +#include "caosdb/transaction.h" // for Transaction, ResultSet +#include "caosdb/transaction_status.h" // for TransactionSt... +#include <boost/log/core/record.hpp> // for record +#include <boost/log/detail/attachable_sstream_buf.hpp> // for basic_ostring... +#include <boost/log/sources/record_ostream.hpp> // for operator<< +#include <boost/preprocessor/seq/limits/enum_256.hpp> // for BOOST_PP_SEQ_... +#include <boost/preprocessor/seq/limits/size_256.hpp> // for BOOST_PP_SEQ_... +#include <exception> // for exception +#include <iostream> // for operator<<, basic_ostream, basic_ost... +#include <memory> // for unique_ptr, allocator, __shared_ptr_... +#include <string> // for operator<<, char_traits const auto logger_name = "libcaosdb"; @@ -53,24 +60,14 @@ auto main() -> int { // retrieve an entity auto transaction(connection->CreateTransaction()); - transaction->RetrieveById("120"); + transaction->RetrieveById("21"); transaction->ExecuteAsynchronously(); auto t_stat = transaction->WaitForIt(); CAOSDB_LOG_INFO(logger_name) << "status: " << t_stat.GetCode() << " // " << t_stat.GetDescription(); const auto &result_set = transaction->GetResultSet(); - if (result_set.size() > 0) { - // print information - const auto &ent = result_set.at(0); - const auto &props = ent.GetProperties(); - std::cout << "Entity Name: " << ent.GetName() << std::endl; - std::cout << "Entity Description: " << ent.GetDescription() << std::endl; - std::cout << "Entity Properties: " << std::endl; - for (const auto &prop : props) { - std::cout << "----------\n" << prop.ToString() << std::endl; - } - } else { - std::cout << "No entity \"120\" retrieved, maybe it does not exist?\n" << std::endl; + for (const auto &entity : result_set) { + std::cout << entity.ToString() << std::endl; } // execute a query @@ -82,6 +79,11 @@ auto main() -> int { t_stat = q_transaction->WaitForIt(); CAOSDB_LOG_INFO(logger_name) << "status: " << t_stat.GetCode() << " // " << t_stat.GetDescription(); + const auto &result_set_2 = q_transaction->GetResultSet(); + for (const auto &entity : result_set_2) { + std::cout << entity.ToString() << std::endl; + } + return 0; } catch (const caosdb::exceptions::ConfigurationError &exc) { std::cout << "ConfigurationError: " << exc.what() << std::endl; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index aefe6846d23f2cc3a145cbf6158101e7e1bb3df4..12741c41d4e31e12548711f14dc716b4eb7f65c8 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -41,7 +41,7 @@ set(test_cases # special linting for tests set(_CMAKE_CXX_CLANG_TIDY_TEST_CHECKS - "${_CMAKE_CXX_CLANG_TIDY_CHECKS},-cert-err58-cpp,-cppcoreguidelines-avoid-non-const-global-variables,-cppcoreguidelines-owning-memory,-modernize-use-trailing-return-type,-google-readability-avoid-underscore-in-googletest-name,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-cppcoreguidelines-avoid-goto,-hicpp-avoid-goto,-readability-function-cognitive-complexity,-cppcoreguidelines-non-private-member-variables-in-classes,-misc-non-private-member-variables-in-classes" + "${_CMAKE_CXX_CLANG_TIDY_CHECKS},-cert-err58-cpp,-cppcoreguidelines-avoid-non-const-global-variables,-cppcoreguidelines-owning-memory,-modernize-use-trailing-return-type,-google-readability-avoid-underscore-in-googletest-name,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-cppcoreguidelines-avoid-goto,-hicpp-avoid-goto,-readability-function-cognitive-complexity,-cppcoreguidelines-non-private-member-variables-in-classes,-misc-non-private-member-variables-in-classes,-clang-analyzer-cplusplus.Move" ) # add special cmake functions for gtest @@ -110,5 +110,10 @@ if (LCOV_PATH) set_target_properties(ccaosdb PROPERTIES COMPILE_FLAGS "${TARGET_CCAOSDB_COMPILE_FLAGS}") else () - message(WARNING "Could not generate code coverage report. Please install lcov.") + if (NOT SKIP_CODE_COVERAGE) + message(WARNING "Could not generate code coverage report. Please install lcov.") + add_custom_target(unit_test_coverage ctest -L caosdb-cpplib-unit-tests + DEPENDS caosdb ccaosdb ${test_cases} + ) + endif() endif () diff --git a/test/test_ccaosdb.cpp b/test/test_ccaosdb.cpp index 1059f161525d513389efd4df95cdd04ec5a088db..71c2a829316b5b5418702686c6ea0fdfa48e5198 100644 --- a/test/test_ccaosdb.cpp +++ b/test/test_ccaosdb.cpp @@ -386,8 +386,8 @@ TEST_F(test_ccaosdb, test_entity) { EXPECT_EQ(return_code, 0); // cannot be created again without deletion - return_code = caosdb_entity_create_entity(&entity); - EXPECT_EQ(return_code, caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR); + // return_code = caosdb_entity_create_entity(&entity); + // EXPECT_EQ(return_code, caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR); // deletion and re-creation is ok return_code = caosdb_entity_delete_entity(&entity); @@ -431,8 +431,8 @@ TEST_F(test_ccaosdb, test_entity) { caosdb_entity_entity_set_datatype(&entity, &in_type); // verify that this doesn't work ... - return_code = caosdb_entity_entity_get_datatype(&entity, &in_type); - EXPECT_EQ(return_code, caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR); + // return_code = caosdb_entity_entity_get_datatype(&entity, &in_type); + // EXPECT_EQ(return_code, caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR); caosdb_entity_datatype out_type; // ... but does with a clean property return_code = caosdb_entity_entity_get_datatype(&entity, &out_type); @@ -827,8 +827,8 @@ TEST_F(test_ccaosdb, test_entity_with_parent_and_property) { char *out = nullptr; // NOLINT // cannot assign an already assigned property - return_code = caosdb_entity_entity_get_property(&entity, &input_property, 0); - EXPECT_EQ(return_code, caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR); + // return_code = caosdb_entity_entity_get_property(&entity, &input_property, 0); + // EXPECT_EQ(return_code, caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR); caosdb_entity_property output_property; return_code = caosdb_entity_entity_get_property(&entity, &output_property, 0); EXPECT_EQ(return_code, 0); diff --git a/test/test_connection.cpp b/test/test_connection.cpp index 99391536edf031fbe4a326f56e24f68e5a50b5d3..00c3bcf58e605e112a404fdfe6ece62e829562ea 100644 --- a/test/test_connection.cpp +++ b/test/test_connection.cpp @@ -22,11 +22,11 @@ #include "caosdb/certificate_provider.h" // for PemCertificateProvider #include "caosdb/configuration.h" // for InsecureConnectionConfigura... #include "caosdb/connection.h" // for ConnectionManager -#include "caosdb/exceptions.h" // for UnknownConnectionError +#include "caosdb/exceptions.h" // for ConnectionConfigurationError #include "caosdb_test_utility.h" // for EXPECT_THROW_MESSAGE, TEST_... #include <gtest/gtest-message.h> // for Message #include <gtest/gtest-test-part.h> // for SuiteApiResolver, TestPartR... -#include "gtest/gtest_pred_impl.h" // for AssertionResult, TestInfo +#include <gtest/gtest_pred_impl.h> // for AssertionResult, TestInfo #include <memory> // for allocator, operator!=, shar... #include <string> // for operator+, string @@ -65,9 +65,16 @@ TEST_F(test_connection, configure_ssl_localhost_8080) { } TEST_F(test_connection, connection_manager_unknown_connection) { - EXPECT_THROW_MESSAGE(ConnectionManager::GetConnection("test"), - caosdb::exceptions::UnknownConnectionError, - "No connection named 'test' present."); + EXPECT_THROW_MESSAGE( + ConnectionManager::GetConnection("test"), caosdb::exceptions::ConnectionConfigurationError, + "Error with the connection named 'test': The connection 'test' has not been defined."); +} + +TEST_F(test_connection, connection_missing_certificate) { + EXPECT_THROW_MESSAGE(ConnectionManager::GetConnection("missing"), + caosdb::exceptions::ConnectionConfigurationError, + std::string("Error with the connection named 'missing': ") + + "File does not exist (server_certificate_path): /missing"); } TEST_F(test_connection, connection_manager_get_default_connection) { diff --git a/test/test_data/test_caosdb_client.json b/test/test_data/test_caosdb_client.json index 2007413021b332c3bd32686363e241804a8d62ab..276c542f75353090b28918ab0ef9b33f9f0815e1 100644 --- a/test/test_data/test_caosdb_client.json +++ b/test/test_data/test_caosdb_client.json @@ -13,6 +13,16 @@ "local-caosdb": { "host": "localhost", "port": 8443, + "authentication": { + "type": "plain", + "username": "me", + "password": "secret!" + } + }, + "missing": { + "host": "localhost", + "port": 8443, + "server_certificate_path": "/missing", "authentication": { "type": "plain", "username": "me", diff --git a/test/test_data_type.cpp b/test/test_data_type.cpp index 78e5100f3ce984ece46918df4aca9ffb8f1d2522..6b7b8b6ea3d36135164d73c90e8f45693a49b1cc 100644 --- a/test/test_data_type.cpp +++ b/test/test_data_type.cpp @@ -20,29 +20,23 @@ * */ -#include "caosdb/data_type.h" // for DataType, AtomicDataType -#include "caosdb/entity.h" // for Entity -#include "caosdb/entity/v1alpha1/main.pb.h" // for DataType, Ato... -#include "caosdb/logging.h" // for CAOSDB_LOG_DEBUG -#include "caosdb/protobuf_helper.h" // for CAOSDB_DEBUG_... -#include <boost/log/core/record.hpp> // for record -#include <boost/log/detail/attachable_sstream_buf.hpp> // for basic_ostring... -#include <boost/log/sources/record_ostream.hpp> // for operator<< -#include <boost/preprocessor/seq/limits/enum_256.hpp> // for BOOST_PP_SEQ_... -#include <boost/preprocessor/seq/limits/size_256.hpp> // for BOOST_PP_SEQ_... -#include <gtest/gtest-message.h> // for Message -#include <gtest/gtest-test-part.h> // for TestPartResult, SuiteApi... -#include <gtest/gtest_pred_impl.h> // for AssertionResult, Test -#include <iosfwd> // for streamsize -#include <map> // for map, operator!= -#include <string> // for allocator -#include <utility> // for pair +#include "caosdb/data_type.h" // for DataType, AtomicDataType +#include "caosdb/entity.h" // for Entity +#include "caosdb/entity/v1/main.pb.h" // for DataType, Ato... +#include "caosdb/logging.h" // for CAOSDB_LOG_DEBUG +#include "caosdb/protobuf_helper.h" // for CAOSDB_DEBUG_... +#include <gtest/gtest-message.h> // for Message +#include <gtest/gtest-test-part.h> // for TestPartResult, SuiteApi... +#include <gtest/gtest_pred_impl.h> // for AssertionResult, Test +#include <map> // for map, operator!= +#include <string> // for allocator +#include <utility> // for pair namespace caosdb::entity { -using ProtoEntity = caosdb::entity::v1alpha1::Entity; -using ProtoParent = caosdb::entity::v1alpha1::Parent; -using ProtoDataType = caosdb::entity::v1alpha1::DataType; -using ProtoAtomicDataType = caosdb::entity::v1alpha1::AtomicDataType; +using ProtoEntity = caosdb::entity::v1::Entity; +using ProtoParent = caosdb::entity::v1::Parent; +using ProtoDataType = caosdb::entity::v1::DataType; +using ProtoAtomicDataType = caosdb::entity::v1::AtomicDataType; TEST(test_data_type, test_atomic) { ProtoDataType proto_data_type; @@ -65,6 +59,7 @@ TEST(test_data_type, test_atomic) { EXPECT_TRUE(data_type.IsAtomic()); EXPECT_EQ(data_type.GetAsAtomic(), map_el.first); } + caosdb::utility::reset_arena(); } TEST(test_data_type, test_reference) { @@ -129,4 +124,54 @@ TEST(test_data_type, test_data_type_to_string) { EXPECT_EQ(data_type3.ToString(), "{\n \"atomicDataType\": \"ATOMIC_DATA_TYPE_INTEGER\"\n}\n"); } +TEST(test_data_type, data_type_copy_constructor) { + DataType data_type("person", true); + const auto dt_string = data_type.ToString(); + + // copy + const DataType copy_data_type(data_type); // NOLINT (explicit copy) + EXPECT_EQ(copy_data_type, data_type); + EXPECT_EQ(dt_string, copy_data_type.ToString()); +} + +TEST(test_data_type, data_type_move_constructor) { + DataType data_type("person", true); + const auto dt_string = data_type.ToString(); + + // copy for testing + const DataType copy_data_type(data_type); + // move + const DataType move_data_type(std::move(data_type)); // NOLINT + EXPECT_NE(data_type, copy_data_type); // NOLINT + EXPECT_NE(data_type.ToString(), dt_string); // NOLINT + + EXPECT_EQ(copy_data_type, move_data_type); + EXPECT_EQ(move_data_type.ToString(), dt_string); +} + +TEST(test_data_type, data_type_copy_assignment) { + DataType data_type("person", true); + const auto dt_string = data_type.ToString(); + + // copy + DataType copy_data_type = data_type; // NOLINT (explicit copy) + EXPECT_EQ(copy_data_type, data_type); + EXPECT_EQ(dt_string, copy_data_type.ToString()); +} + +TEST(test_data_type, data_type_move_assignment) { + DataType data_type("person", true); + const auto dt_string = data_type.ToString(); + + // copy for testing + const DataType copy_data_type(data_type); + // move + DataType move_data_type = std::move(data_type); // NOLINT + EXPECT_NE(data_type, copy_data_type); // NOLINT + EXPECT_NE(data_type.ToString(), dt_string); // NOLINT + + EXPECT_EQ(copy_data_type, move_data_type); + EXPECT_EQ(move_data_type.ToString(), dt_string); +} + } // namespace caosdb::entity diff --git a/test/test_entity.cpp b/test/test_entity.cpp index 2b9a8d900864617abc23bdd1d05782a1eb65c60b..5f5aaaab4a5f6727f38ea30c0205ea8d79a925b1 100644 --- a/test/test_entity.cpp +++ b/test/test_entity.cpp @@ -20,35 +20,35 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ -#include "caosdb/data_type.h" // for DataType, AtomicDat... -#include "caosdb/entity.h" // for Entity, Property -#include "caosdb/entity/v1alpha1/main.grpc.pb.h" // for EntityTransactionSe... -#include "caosdb/entity/v1alpha1/main.pb.h" // for IdResponse, Message -#include "caosdb/message_code.h" // for MessageCode, ENTITY... -#include "caosdb/protobuf_helper.h" // for get_arena -#include "caosdb/status_code.h" // for StatusCode, FILE_DO... -#include "caosdb/transaction.h" // for Transaction -#include "caosdb/value.h" // for Value -#include "caosdb_test_utility.h" // for TEST_DATA_DIR -#include <google/protobuf/arena.h> // for Arena -#include <gtest/gtest-message.h> // for Message -#include <gtest/gtest-test-part.h> // for TestPartResult, Sui... -#include <gtest/gtest_pred_impl.h> // for Test, EXPECT_EQ -#include <iostream> // for operator<<, basic_o... -#include <memory> // for allocator, shared_ptr -#include <stdexcept> // for out_of_range -#include <string> // for operator+, to_string -#include <utility> // for move +#include "caosdb/data_type.h" // for DataType, AtomicDat... +#include "caosdb/entity.h" // for Entity, Property +#include "caosdb/entity/v1/main.grpc.pb.h" // for EntityTransactionSe... +#include "caosdb/entity/v1/main.pb.h" // for IdResponse, Message +#include "caosdb/message_code.h" // for MessageCode, ENTITY... +#include "caosdb/protobuf_helper.h" // for get_arena +#include "caosdb/status_code.h" // for StatusCode, FILE_DO... +#include "caosdb/transaction.h" // for Transaction +#include "caosdb/value.h" // for Value +#include "caosdb_test_utility.h" // for TEST_DATA_DIR +#include <google/protobuf/arena.h> // for Arena +#include <gtest/gtest-message.h> // for Message +#include <gtest/gtest-test-part.h> // for TestPartResult, Sui... +#include <gtest/gtest_pred_impl.h> // for Test, EXPECT_EQ +#include <iostream> // for operator<<, basic_o... +#include <memory> // for allocator, shared_ptr +#include <stdexcept> // for out_of_range +#include <string> // for operator+, to_string +#include <utility> // for move namespace caosdb::entity { -using caosdb::entity::v1alpha1::IdResponse; -using ProtoEntity = caosdb::entity::v1alpha1::Entity; -using ProtoParent = caosdb::entity::v1alpha1::Parent; -using ProtoProperty = caosdb::entity::v1alpha1::Property; -using ProtoAtomicDataType = caosdb::entity::v1alpha1::AtomicDataType; -using caosdb::entity::v1alpha1::EntityResponse; +using caosdb::entity::v1::IdResponse; +using ProtoEntity = caosdb::entity::v1::Entity; +using ProtoParent = caosdb::entity::v1::Parent; +using ProtoProperty = caosdb::entity::v1::Property; +using ProtoAtomicDataType = caosdb::entity::v1::AtomicDataType; +using caosdb::entity::v1::EntityResponse; using caosdb::utility::get_arena; -using ProtoEntityRole = caosdb::entity::v1alpha1::EntityRole; +using ProtoEntityRole = caosdb::entity::v1::EntityRole; TEST(test_entity, test_parent_setters) { auto parent = Parent(); @@ -142,34 +142,35 @@ TEST(test_entity, test_append_property) { EXPECT_EQ(prop.GetDataType(), same_prop.GetDataType()); } -TEST(test_entity, test_copy_constructor) { - ProtoParent parent; - parent.set_description("the parent desc"); - parent.set_id("the parent id"); - parent.set_name("the parent name"); - ProtoProperty property; - property.set_id("the-prop-id"); - property.set_description("the prop-desc"); - property.set_name("the-prop-name"); - property.mutable_value()->mutable_list_values()->mutable_values()->Add()->set_double_value(25.5); - property.mutable_data_type()->mutable_list_data_type()->set_atomic_data_type( +TEST(test_entity, entity_copy_constructor) { + Arena arena; + auto *parent = Arena::CreateMessage<ProtoParent>(&arena); + parent->set_description("the parent desc"); + parent->set_id("the parent id"); + parent->set_name("the parent name"); + auto *property = Arena::CreateMessage<ProtoProperty>(&arena); + property->set_id("the-prop-id"); + property->set_description("the prop-desc"); + property->set_name("the-prop-name"); + property->mutable_value()->mutable_list_values()->mutable_values()->Add()->set_double_value(25.5); + property->mutable_data_type()->mutable_list_data_type()->set_atomic_data_type( ProtoAtomicDataType::ATOMIC_DATA_TYPE_DOUBLE); - EntityResponse entity_response; - entity_response.mutable_entity()->set_id("the-id"); - entity_response.mutable_entity()->set_name("the-name"); - entity_response.mutable_entity()->set_role(ProtoEntityRole::ENTITY_ROLE_RECORD); - entity_response.mutable_entity()->set_description("the description"); - entity_response.mutable_entity()->set_unit("the-unit"); - entity_response.mutable_entity()->mutable_value()->mutable_scalar_value()->set_string_value( + auto *entity_response = Arena::CreateMessage<EntityResponse>(&arena); + entity_response->mutable_entity()->set_id("the-id"); + entity_response->mutable_entity()->set_name("the-name"); + entity_response->mutable_entity()->set_role(ProtoEntityRole::ENTITY_ROLE_RECORD); + entity_response->mutable_entity()->set_description("the description"); + entity_response->mutable_entity()->set_unit("the-unit"); + entity_response->mutable_entity()->mutable_value()->mutable_scalar_value()->set_string_value( "the-value"); - entity_response.mutable_entity()->mutable_version()->set_id("version-id"); - entity_response.mutable_entity()->mutable_data_type()->mutable_reference_data_type()->set_name( + entity_response->mutable_entity()->mutable_version()->set_id("version-id"); + entity_response->mutable_entity()->mutable_data_type()->mutable_reference_data_type()->set_name( "refname"); - entity_response.mutable_entity()->mutable_file_descriptor(); - entity_response.mutable_entity()->mutable_properties()->Add()->CopyFrom(property); - entity_response.mutable_entity()->mutable_parents()->Add()->CopyFrom(parent); + entity_response->mutable_entity()->mutable_file_descriptor(); + entity_response->mutable_entity()->mutable_properties()->Add()->CopyFrom(*property); + entity_response->mutable_entity()->mutable_parents()->Add()->CopyFrom(*parent); - Entity this_entity(&entity_response); + Entity this_entity(entity_response); Entity copy_entity(this_entity); EXPECT_EQ(this_entity, copy_entity); @@ -197,40 +198,41 @@ TEST(test_entity, test_copy_constructor) { EXPECT_NE(this_entity.ToString(), copy_entity.ToString()); } -TEST(test_entity, test_move_constructor) { - ProtoParent parent; - parent.set_description("the parent desc"); - parent.set_id("the parent id"); - parent.set_name("the parent name"); - ProtoProperty property; - property.set_id("the-prop-id"); - property.set_description("the prop-desc"); - property.set_name("the-prop-name"); - property.mutable_value()->mutable_list_values()->mutable_values()->Add()->set_double_value(25.5); - property.mutable_data_type()->mutable_list_data_type()->set_atomic_data_type( +TEST(test_entity, entity_move_constructor) { + Arena arena; + auto *parent = Arena::CreateMessage<ProtoParent>(&arena); + parent->set_description("the parent desc"); + parent->set_id("the parent id"); + parent->set_name("the parent name"); + auto *property = Arena::CreateMessage<ProtoProperty>(&arena); + property->set_id("the-prop-id"); + property->set_description("the prop-desc"); + property->set_name("the-prop-name"); + property->mutable_value()->mutable_list_values()->mutable_values()->Add()->set_double_value(25.5); + property->mutable_data_type()->mutable_list_data_type()->set_atomic_data_type( ProtoAtomicDataType::ATOMIC_DATA_TYPE_DOUBLE); - EntityResponse entity_response; - entity_response.mutable_errors()->Add()->set_code(25); - entity_response.mutable_errors()->Mutable(0)->set_description("asdf"); - entity_response.mutable_warnings()->Add()->set_code(23); - entity_response.mutable_warnings()->Mutable(0)->set_description("asdgsafdg"); - entity_response.mutable_infos()->Add()->set_code(235); - entity_response.mutable_infos()->Mutable(0)->set_description("asdfsad"); - entity_response.mutable_entity()->set_id("the-id"); - entity_response.mutable_entity()->set_name("the-name"); - entity_response.mutable_entity()->set_role(ProtoEntityRole::ENTITY_ROLE_RECORD); - entity_response.mutable_entity()->set_description("the description"); - entity_response.mutable_entity()->set_unit("the-unit"); - entity_response.mutable_entity()->mutable_value()->mutable_scalar_value()->set_string_value( + auto *entity_response = Arena::CreateMessage<EntityResponse>(&arena); + entity_response->mutable_errors()->Add()->set_code(25); + entity_response->mutable_errors()->Mutable(0)->set_description("asdf"); + entity_response->mutable_warnings()->Add()->set_code(23); + entity_response->mutable_warnings()->Mutable(0)->set_description("asdgsafdg"); + entity_response->mutable_infos()->Add()->set_code(235); + entity_response->mutable_infos()->Mutable(0)->set_description("asdfsad"); + entity_response->mutable_entity()->set_id("the-id"); + entity_response->mutable_entity()->set_name("the-name"); + entity_response->mutable_entity()->set_role(ProtoEntityRole::ENTITY_ROLE_RECORD); + entity_response->mutable_entity()->set_description("the description"); + entity_response->mutable_entity()->set_unit("the-unit"); + entity_response->mutable_entity()->mutable_value()->mutable_scalar_value()->set_string_value( "the-value"); - entity_response.mutable_entity()->mutable_version()->set_id("version-id"); - entity_response.mutable_entity()->mutable_data_type()->mutable_reference_data_type()->set_name( + entity_response->mutable_entity()->mutable_version()->set_id("version-id"); + entity_response->mutable_entity()->mutable_data_type()->mutable_reference_data_type()->set_name( "refname"); - entity_response.mutable_entity()->mutable_file_descriptor(); - entity_response.mutable_entity()->mutable_properties()->Add()->CopyFrom(property); - entity_response.mutable_entity()->mutable_parents()->Add()->CopyFrom(parent); + entity_response->mutable_entity()->mutable_file_descriptor(); + entity_response->mutable_entity()->mutable_properties()->Add()->CopyFrom(*property); + entity_response->mutable_entity()->mutable_parents()->Add()->CopyFrom(*parent); - Entity this_entity(&entity_response); + Entity this_entity(entity_response); std::string original_string = this_entity.ToString(); Entity copy_entity(this_entity); EXPECT_EQ(this_entity, copy_entity); @@ -263,7 +265,7 @@ TEST(test_entity, test_move_constructor) { EXPECT_NE(move_entity.ToString(), copy_entity.ToString()); } -TEST(test_entity, test_property_copy_constructor) { +TEST(test_entity, property_copy_constructor) { Property prop; prop.SetName("prop_name"); prop.SetId("prop_id"); @@ -283,7 +285,7 @@ TEST(test_entity, test_property_copy_constructor) { EXPECT_EQ(prop.GetDataType(), other_prop.GetDataType()); } -TEST(test_entity, test_property_copy_assignment) { +TEST(test_entity, property_copy_assignment) { Property prop; prop.SetName("prop_name"); prop.SetId("prop_id"); @@ -308,7 +310,7 @@ TEST(test_entity, test_property_copy_assignment) { EXPECT_EQ(other_prop.GetName(), "other_prop_name"); } -TEST(test_entity, test_property_move_assignment) { +TEST(test_entity, property_move_assignment) { Property prop; prop.SetName("prop_name"); prop.SetId("prop_id"); @@ -321,7 +323,7 @@ TEST(test_entity, test_property_move_assignment) { // we compare the moved one with this one const Property copy_prop(prop); - Property other_prop = std::move(prop); + Property other_prop = std::move(prop); // NOLINT EXPECT_NE(prop, copy_prop); // NOLINT EXPECT_NE(prop, other_prop); // NOLINT EXPECT_NE(prop.ToString(), prop_string); // NOLINT @@ -343,6 +345,127 @@ TEST(test_entity, test_property_move_assignment) { EXPECT_EQ(other_prop.GetName(), "other_prop_name"); } +TEST(test_entity, property_move_constructor) { + Property prop; + prop.SetName("prop_name"); + prop.SetId("prop_id"); + prop.SetImportance(Importance::RECOMMENDED); + prop.SetValue("prop_value"); + prop.SetUnit("prop_unit"); + prop.SetDataType("prop_dtype"); + const auto prop_string = prop.ToString(); + + // we compare the moved one with this one + const Property copy_prop(prop); + + Property other_prop(std::move(prop)); + EXPECT_NE(prop, copy_prop); // NOLINT + EXPECT_NE(prop, other_prop); // NOLINT + EXPECT_NE(prop.ToString(), prop_string); // NOLINT + + EXPECT_EQ(copy_prop.ToString(), prop_string); + EXPECT_EQ(other_prop.ToString(), prop_string); + EXPECT_EQ(copy_prop, other_prop); + EXPECT_EQ(copy_prop.GetName(), other_prop.GetName()); + EXPECT_EQ(copy_prop.GetId(), other_prop.GetId()); + EXPECT_EQ(copy_prop.GetImportance(), other_prop.GetImportance()); + EXPECT_EQ(copy_prop.GetValue().ToString(), other_prop.GetValue().ToString()); + EXPECT_EQ(copy_prop.GetUnit(), other_prop.GetUnit()); + EXPECT_EQ(copy_prop.GetDataType(), other_prop.GetDataType()); + + other_prop.SetName("other_prop_name"); + EXPECT_NE(copy_prop, other_prop); + EXPECT_NE(copy_prop.GetName(), other_prop.GetName()); + EXPECT_EQ(copy_prop.GetName(), "prop_name"); + EXPECT_EQ(other_prop.GetName(), "other_prop_name"); +} + +TEST(test_entity, parent_copy_constructor) { + Parent parent; + parent.SetId("par_id"); + parent.SetName("par_name"); + + // copy + const Parent copy_parent(parent); + EXPECT_EQ(copy_parent, parent); + EXPECT_EQ(copy_parent.GetId(), parent.GetId()); + EXPECT_EQ(copy_parent.GetName(), parent.GetName()); + + // change something + parent.SetName("new_name"); + EXPECT_NE(copy_parent, parent); + EXPECT_EQ(copy_parent.GetId(), parent.GetId()); + EXPECT_NE(copy_parent.GetName(), parent.GetName()); +} + +TEST(test_entity, parent_move_constructor) { + Parent parent; + parent.SetId("par_id"); + parent.SetName("par_name"); + const auto parent_string = parent.ToString(); + + // copy for testing + const Parent copy_parent = parent; + // move + Parent move_parent(std::move(parent)); + EXPECT_NE(parent, copy_parent); // NOLINT + EXPECT_NE(parent, move_parent); // NOLINT + EXPECT_NE(parent.ToString(), parent_string); // NOLINT + + EXPECT_EQ(copy_parent, move_parent); + EXPECT_EQ(copy_parent.GetId(), move_parent.GetId()); + EXPECT_EQ(copy_parent.GetName(), move_parent.GetName()); + + // change something + move_parent.SetName("new_name"); + EXPECT_NE(copy_parent, move_parent); + EXPECT_EQ(copy_parent.GetId(), move_parent.GetId()); + EXPECT_NE(copy_parent.GetName(), move_parent.GetName()); +} + +TEST(test_entity, parent_copy_assignment) { + Parent parent; + parent.SetId("par_id"); + parent.SetName("par_name"); + + // copy + const Parent copy_parent = parent; + EXPECT_EQ(copy_parent, parent); + EXPECT_EQ(copy_parent.GetId(), parent.GetId()); + EXPECT_EQ(copy_parent.GetName(), parent.GetName()); + + // change something + parent.SetName("new_name"); + EXPECT_NE(copy_parent, parent); + EXPECT_EQ(copy_parent.GetId(), parent.GetId()); + EXPECT_NE(copy_parent.GetName(), parent.GetName()); +} + +TEST(test_entity, parent_move_assignment) { + Parent parent; + parent.SetId("par_id"); + parent.SetName("par_name"); + const auto parent_string = parent.ToString(); + + // copy for testing + const Parent copy_parent = parent; + // move + Parent move_parent = std::move(parent); + EXPECT_NE(parent, copy_parent); // NOLINT + EXPECT_NE(parent, move_parent); // NOLINT + EXPECT_NE(parent.ToString(), parent_string); // NOLINT + + EXPECT_EQ(copy_parent, move_parent); + EXPECT_EQ(copy_parent.GetId(), move_parent.GetId()); + EXPECT_EQ(copy_parent.GetName(), move_parent.GetName()); + + // change something + move_parent.SetName("new_name"); + EXPECT_NE(copy_parent, move_parent); + EXPECT_EQ(copy_parent.GetId(), move_parent.GetId()); + EXPECT_NE(copy_parent.GetName(), move_parent.GetName()); +} + TEST(test_entity, test_copy_to) { auto entity = Entity(); entity.SetRole(Role::RECORD); @@ -670,10 +793,11 @@ TEST(test_entity, test_description) { entity.SetDescription("desc entity"); property.SetDescription("desc property"); - // Parent has not setter - ProtoParent protoParent; - protoParent.set_description("desc parent"); - parent = Parent(&protoParent); + // Parent has no setter + Arena arena; + auto *protoParent = Arena::CreateMessage<ProtoParent>(&arena); + protoParent->set_description("desc parent"); + parent = Parent(protoParent); EXPECT_EQ(entity.GetDescription(), "desc entity"); EXPECT_EQ(property.GetDescription(), "desc property"); @@ -693,7 +817,7 @@ TEST(test_entity, test_add_file) { EXPECT_EQ(entity.SetLocalPath(TEST_DATA_DIR + "/test.json"), StatusCode::SUCCESS); } -TEST(test_entity, test_move_assign) { +TEST(test_entity, entity_move_assignment) { Entity entity1; entity1.SetRole(Role::RECORD_TYPE); entity1.SetName("E1"); @@ -757,8 +881,8 @@ TEST(test_entity, test_property_to_string) { EXPECT_EQ(property.ToString(), "{}\n"); property.SetDataType(AtomicDataType::DOUBLE); - EXPECT_EQ(property.ToString(), - "{\n \"dataType\": {\n \"atomicDataType\": \"ATOMIC_DATA_TYPE_DOUBLE\"\n }\n}\n"); + EXPECT_EQ(property.ToString(), "{\n \"dataType\": {\n \"atomicDataType\": " + "\"ATOMIC_DATA_TYPE_DOUBLE\"\n }\n}\n"); } TEST(test_entity, test_parents_to_string) { @@ -780,13 +904,14 @@ TEST(test_entity, test_parent_to_string) { } TEST(test_entity, test_messages_to_string) { - IdResponse idResponse; - idResponse.set_id("entity_id"); - auto *error = idResponse.add_errors(); + Arena arena; + auto *idResponse = Arena::CreateMessage<IdResponse>(&arena); + idResponse->set_id("entity_id"); + auto *error = idResponse->add_errors(); error->set_code(MessageCode::ENTITY_DOES_NOT_EXIST); error->set_description("error_desc"); - Entity entity(&idResponse); + Entity entity(idResponse); // Messages are not printed, currently. EXPECT_EQ(entity.ToString(), "{\n \"id\": \"entity_id\",\n \"version\": {}\n}\n"); @@ -795,13 +920,14 @@ TEST(test_entity, test_messages_to_string) { } TEST(test_entity, test_message_to_string) { - IdResponse idResponse; - idResponse.set_id("entity_id"); - auto *error = idResponse.add_errors(); + Arena arena; + auto *idResponse = Arena::CreateMessage<IdResponse>(&arena); + idResponse->set_id("entity_id"); + auto *error = idResponse->add_errors(); error->set_code(MessageCode::ENTITY_DOES_NOT_EXIST); error->set_description("error_desc"); - Entity entity(&idResponse); + Entity entity(idResponse); // Messages are not printed, currently. EXPECT_EQ(entity.ToString(), "{\n \"id\": \"entity_id\",\n \"version\": {}\n}\n"); diff --git a/test/test_file_transmission.cpp b/test/test_file_transmission.cpp index 7c5eb745e8f451b0282fa844510dc71ad402ed18..c5847a0842ae8a3bb46a8126e42b31bb5b1d6451 100644 --- a/test/test_file_transmission.cpp +++ b/test/test_file_transmission.cpp @@ -19,15 +19,14 @@ */ #include "caosdb/file_transmission/file_writer.h" #include "caosdb/file_transmission/file_reader.h" -#include <boost/filesystem/operations.hpp> // for exists, file_size, remove -#include <boost/filesystem/path.hpp> // for path -#include <boost/filesystem/path_traits.hpp> // for filesystem -#include <gtest/gtest-message.h> // for Message -#include <gtest/gtest-test-part.h> // for TestPartResult, SuiteApiResolver -#include <gtest/gtest_pred_impl.h> // for Test, EXPECT_EQ, AssertionResult -#include <string> // for string - -namespace fs = boost::filesystem; +#include <chrono> // for filesystem +#include <filesystem> // for path +#include <gtest/gtest-message.h> // for Message +#include <gtest/gtest-test-part.h> // for TestPartResult, SuiteApiResolver +#include <gtest/gtest_pred_impl.h> // for Test, EXPECT_EQ, AssertionResult +#include <string> // for string + +namespace fs = std::filesystem; namespace caosdb::transaction { diff --git a/test/test_info.cpp b/test/test_info.cpp index a95870200ac51343f86b7bb5ff4c0c433d692f0c..4331219ab02ae5c60e165bee7992c6466d4889f2 100644 --- a/test/test_info.cpp +++ b/test/test_info.cpp @@ -20,15 +20,15 @@ * */ -#include "caosdb/info.h" // for VersionInfo -#include "caosdb/info/v1alpha1/main.pb.h" // for VersionInfo -#include <gtest/gtest-message.h> // for Message -#include <gtest/gtest-test-part.h> // for TestPartResult, SuiteApiRe... -#include "gtest/gtest_pred_impl.h" // for Test, EXPECT_EQ, TEST -#include <memory> // for allocator +#include "caosdb/info.h" // for VersionInfo +#include "caosdb/info/v1/main.pb.h" // for VersionInfo +#include <gtest/gtest-message.h> // for Message +#include <gtest/gtest-test-part.h> // for TestPartResult, SuiteApiRe... +#include "gtest/gtest_pred_impl.h" // for Test, EXPECT_EQ, TEST +#include <memory> // for allocator namespace caosdb::info { -using ProtoVersionInfo = caosdb::info::v1alpha1::VersionInfo; +using ProtoVersionInfo = caosdb::info::v1::VersionInfo; TEST(test_info, create_info_from_proto_info) { auto *origial = new ProtoVersionInfo(); diff --git a/test/test_list_properties.cpp b/test/test_list_properties.cpp index bc82896f5e7623643cb249979f381f3a7097d40d..8e69ba381c20808fa4112eca06270c8bda5fa351 100644 --- a/test/test_list_properties.cpp +++ b/test/test_list_properties.cpp @@ -20,23 +20,23 @@ * */ -#include "caosdb/data_type.h" // for DataType, AtomicDataType -#include "caosdb/entity.h" // for Entity -#include "caosdb/entity/v1alpha1/main.pb.h" // for AtomicDataType, DataType -#include "caosdb/value.h" // for Value -#include <cstdint> // for int64_t -#include <gtest/gtest-message.h> // for Message -#include <gtest/gtest-test-part.h> // for TestPartResult, SuiteApi... -#include <gtest/gtest_pred_impl.h> // for AssertionResult, Test -#include <memory> // for allocator_traits<>::valu... -#include <string> // for string -#include <vector> // for vector +#include "caosdb/data_type.h" // for DataType, AtomicDataType +#include "caosdb/entity.h" // for Entity +#include "caosdb/entity/v1/main.pb.h" // for AtomicDataType, DataType +#include "caosdb/value.h" // for Value +#include <cstdint> // for int64_t +#include <gtest/gtest-message.h> // for Message +#include <gtest/gtest-test-part.h> // for TestPartResult, SuiteApi... +#include <gtest/gtest_pred_impl.h> // for AssertionResult, Test +#include <memory> // for allocator_traits<>::valu... +#include <string> // for string +#include <vector> // for vector namespace caosdb::entity { -using ProtoEntity = caosdb::entity::v1alpha1::Entity; -using ProtoParent = caosdb::entity::v1alpha1::Parent; -using ProtoDataType = caosdb::entity::v1alpha1::DataType; -using ProtoAtomicDataType = caosdb::entity::v1alpha1::AtomicDataType; +using ProtoEntity = caosdb::entity::v1::Entity; +using ProtoParent = caosdb::entity::v1::Parent; +using ProtoDataType = caosdb::entity::v1::DataType; +using ProtoAtomicDataType = caosdb::entity::v1::AtomicDataType; TEST(test_list_property, test_list_of_text) { Property list_property; diff --git a/test/test_protobuf.cpp b/test/test_protobuf.cpp index 6f9bda0740487db475f1e34757e4a612c59061f9..42e1e574437e47f0129cb30b336ab336613daede 100644 --- a/test/test_protobuf.cpp +++ b/test/test_protobuf.cpp @@ -19,89 +19,94 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ -#include "caosdb/data_type.h" // for DataType, ReferenceDataType -#include "caosdb/entity.h" // for Entity -#include "caosdb/entity/v1alpha1/main.pb.h" // for RepeatedPtrField, Message -#include <gtest/gtest-message.h> // for Message -#include <gtest/gtest-test-part.h> // for SuiteApiResolver, TestPa... -#include <gtest/gtest_pred_impl.h> // for Test, TestInfo, TEST -#include <memory> // for allocator +#include "caosdb/data_type.h" // for DataType, ReferenceDataType +#include "caosdb/entity.h" // for Entity +#include "caosdb/entity/v1/main.pb.h" // for RepeatedPtrField, Message +#include <google/protobuf/arena.h> // for Arena +#include <gtest/gtest-message.h> // for Message +#include <gtest/gtest-test-part.h> // for SuiteApiResolver, TestPa... +#include <gtest/gtest_pred_impl.h> // for Test, TestInfo, TEST +#include <memory> // for allocator namespace caosdb { -using ProtoEntity = caosdb::entity::v1alpha1::Entity; +using ProtoEntity = caosdb::entity::v1::Entity; using caosdb::entity::Entity; -using caosdb::entity::v1alpha1::Message; +using caosdb::entity::v1::Message; +using google::protobuf::Arena; TEST(test_protobuf, test_swap_trivial) { - Message message_source; - message_source.set_code(1234); - message_source.set_description("desc"); + Arena arena; + auto *message_source = Arena::CreateMessage<Message>(&arena); + message_source->set_code(1234); + message_source->set_description("desc"); - Message message_destination; + auto *message_destination = Arena::CreateMessage<Message>(&arena); - EXPECT_EQ(message_source.code(), 1234); - EXPECT_EQ(message_source.description(), "desc"); - EXPECT_EQ(message_destination.code(), 0); - EXPECT_EQ(message_destination.description(), ""); + EXPECT_EQ(message_source->code(), 1234); + EXPECT_EQ(message_source->description(), "desc"); + EXPECT_EQ(message_destination->code(), 0); + EXPECT_EQ(message_destination->description(), ""); - message_source.Swap(&message_destination); + message_source->Swap(message_destination); - EXPECT_EQ(message_source.code(), 0); - EXPECT_EQ(message_source.description(), ""); - EXPECT_EQ(message_destination.code(), 1234); - EXPECT_EQ(message_destination.description(), "desc"); + EXPECT_EQ(message_source->code(), 0); + EXPECT_EQ(message_source->description(), ""); + EXPECT_EQ(message_destination->code(), 1234); + EXPECT_EQ(message_destination->description(), "desc"); } TEST(test_protobuf, test_swap_nested) { - ProtoEntity entity_source; - entity_source.set_id("entity_id"); - auto *version_source = entity_source.mutable_version(); + Arena arena; + auto *entity_source = Arena::CreateMessage<ProtoEntity>(&arena); + entity_source->set_id("entity_id"); + auto *version_source = entity_source->mutable_version(); version_source->set_id("version_id"); - ProtoEntity entity_destination; - auto *version_destination = entity_destination.mutable_version(); + auto *entity_destination = Arena::CreateMessage<ProtoEntity>(&arena); + auto *version_destination = entity_destination->mutable_version(); - EXPECT_EQ(entity_source.id(), "entity_id"); - EXPECT_EQ(entity_source.version().id(), "version_id"); + EXPECT_EQ(entity_source->id(), "entity_id"); + EXPECT_EQ(entity_source->version().id(), "version_id"); EXPECT_EQ(version_source->id(), "version_id"); - EXPECT_EQ(entity_destination.id(), ""); - EXPECT_EQ(entity_destination.version().id(), ""); + EXPECT_EQ(entity_destination->id(), ""); + EXPECT_EQ(entity_destination->version().id(), ""); EXPECT_EQ(version_destination->id(), ""); - entity_source.Swap(&entity_destination); + entity_source->Swap(entity_destination); - EXPECT_EQ(entity_source.id(), ""); - EXPECT_EQ(entity_source.version().id(), ""); - EXPECT_EQ(entity_destination.id(), "entity_id"); - EXPECT_EQ(entity_destination.version().id(), "version_id"); + EXPECT_EQ(entity_source->id(), ""); + EXPECT_EQ(entity_source->version().id(), ""); + EXPECT_EQ(entity_destination->id(), "entity_id"); + EXPECT_EQ(entity_destination->version().id(), "version_id"); // has not been swapped! EXPECT_EQ(version_source->id(), "version_id"); EXPECT_EQ(version_destination->id(), ""); // Member pointers to nested messages have been swapped - EXPECT_EQ(entity_source.mutable_version(), version_destination); - EXPECT_EQ(entity_destination.mutable_version(), version_source); + EXPECT_EQ(entity_source->mutable_version(), version_destination); + EXPECT_EQ(entity_destination->mutable_version(), version_source); } TEST(test_protobuf, test_copy_nested) { - ProtoEntity entity_source; - auto *data_type_source = entity_source.mutable_data_type(); + Arena arena; + auto *entity_source = Arena::CreateMessage<ProtoEntity>(&arena); + auto *data_type_source = entity_source->mutable_data_type(); data_type_source->mutable_reference_data_type()->set_name("src_per"); - ProtoEntity entity_destination; - auto *data_type_destination = entity_destination.mutable_data_type(); + auto *entity_destination = Arena::CreateMessage<ProtoEntity>(&arena); + auto *data_type_destination = entity_destination->mutable_data_type(); data_type_destination->mutable_reference_data_type()->set_name("dest_per"); - EXPECT_EQ(entity_source.data_type().reference_data_type().name(), "src_per"); - EXPECT_EQ(entity_destination.data_type().reference_data_type().name(), "dest_per"); + EXPECT_EQ(entity_source->data_type().reference_data_type().name(), "src_per"); + EXPECT_EQ(entity_destination->data_type().reference_data_type().name(), "dest_per"); - entity_destination.CopyFrom(entity_source); + entity_destination->CopyFrom(*entity_source); - EXPECT_EQ(entity_source.data_type().reference_data_type().name(), "src_per"); - EXPECT_EQ(entity_destination.data_type().reference_data_type().name(), "src_per"); + EXPECT_EQ(entity_source->data_type().reference_data_type().name(), "src_per"); + EXPECT_EQ(entity_destination->data_type().reference_data_type().name(), "src_per"); - Entity entity(&entity_destination); + Entity entity(entity_destination); EXPECT_EQ(entity.GetDataType().GetAsReference().GetName(), "src_per"); const Entity ©_entity(entity); diff --git a/test/test_transaction.cpp b/test/test_transaction.cpp index eff94329bd47d08675095f39c818e6cc38a10127..df87f74314ed88a7609aa27265d6bbc20edb36d1 100644 --- a/test/test_transaction.cpp +++ b/test/test_transaction.cpp @@ -17,16 +17,18 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -#include "caosdb/configuration.h" // for InsecureConnectionConfig... -#include "caosdb/connection.h" // for Connection -#include "caosdb/entity.h" // for Entity -#include "caosdb/entity/v1alpha1/main.pb.h" // for Entity -#include "caosdb/exceptions.h" // for ConnectionError -#include "caosdb/status_code.h" +#include "caosdb/configuration.h" // for InsecureConnectionConfig... +#include "caosdb/connection.h" // for Connection +#include "caosdb/entity.h" // for Entity +#include "caosdb/entity/v1/main.pb.h" // for Entity +#include "caosdb/exceptions.h" // for ConnectionError +#include "caosdb/status_code.h" // for StatusCode #include "caosdb/transaction.h" // for Transaction #include "caosdb/transaction_handler.h" // for MultiTransactionResponse #include "caosdb/transaction_status.h" // for ConnectionError #include "caosdb_test_utility.h" // for EXPECT_THROW_MESSAGE +#include <algorithm> // for max +#include <google/protobuf/arena.h> // for Arena #include <gtest/gtest-message.h> // for Message #include <gtest/gtest-test-part.h> // for SuiteApiResolver, TestPa... #include <gtest/gtest_pred_impl.h> // for Test, TestInfo, TEST @@ -41,9 +43,9 @@ using caosdb::configuration::InsecureConnectionConfiguration; using caosdb::connection::Connection; using caosdb::entity::Entity; using caosdb::exceptions::ConnectionError; -using ProtoEntity = caosdb::entity::v1alpha1::Entity; +using ProtoEntity = caosdb::entity::v1::Entity; using caosdb::entity::Role; -using caosdb::entity::v1alpha1::RetrieveResponse; +using caosdb::entity::v1::RetrieveResponse; TEST(test_transaction, create_transaction) { const auto *host = "localhost"; @@ -113,9 +115,10 @@ TEST(test_transaction, test_multi_result_set_empty) { TEST(test_transaction, test_multi_result_iterator) { std::vector<std::unique_ptr<Entity>> one_elem; - RetrieveResponse response; - response.mutable_entity_response()->mutable_entity()->set_id("100"); - one_elem.push_back(std::make_unique<Entity>(response.release_entity_response())); + Arena arena; + auto *response = Arena::CreateMessage<RetrieveResponse>(&arena); + response->mutable_entity_response()->mutable_entity()->set_id("100"); + one_elem.push_back(std::make_unique<Entity>(response->mutable_entity_response())); MultiResultSet rs(std::move(one_elem)); EXPECT_EQ(rs.size(), 1); @@ -127,9 +130,10 @@ TEST(test_transaction, test_multi_result_iterator) { TEST(test_transaction, test_multi_result_set_one) { std::vector<std::unique_ptr<Entity>> one_elem; - RetrieveResponse response; - response.mutable_entity_response()->mutable_entity()->set_id("100"); - one_elem.push_back(std::make_unique<Entity>(response.release_entity_response())); + Arena arena; + auto *response = Arena::CreateMessage<RetrieveResponse>(&arena); + response->mutable_entity_response()->mutable_entity()->set_id("100"); + one_elem.push_back(std::make_unique<Entity>(response->mutable_entity_response())); MultiResultSet rs(std::move(one_elem)); EXPECT_EQ(rs.size(), 1); @@ -139,27 +143,28 @@ TEST(test_transaction, test_multi_result_set_one) { TEST(test_transaction, test_multi_result_set_three) { std::vector<std::unique_ptr<Entity>> three_elem; - MultiTransactionResponse response; - response.add_responses() + Arena arena; + auto *response = Arena::CreateMessage<MultiTransactionResponse>(&arena); + response->add_responses() ->mutable_retrieve_response() ->mutable_entity_response() ->mutable_entity() ->set_id("100"); auto *entity_with_error = - response.add_responses()->mutable_retrieve_response()->mutable_entity_response(); + response->add_responses()->mutable_retrieve_response()->mutable_entity_response(); entity_with_error->mutable_entity()->set_id("101"); entity_with_error->add_errors()->set_code(1); - response.add_responses() + response->add_responses() ->mutable_retrieve_response() ->mutable_entity_response() ->mutable_entity() ->set_id("102"); - auto *responses = response.mutable_responses(); + auto *responses = response->mutable_responses(); std::vector<std::unique_ptr<Entity>> entities; for (auto sub_response : *responses) { three_elem.push_back(std::make_unique<Entity>( - sub_response.mutable_retrieve_response()->release_entity_response())); + sub_response.mutable_retrieve_response()->mutable_entity_response())); } MultiResultSet rs(std::move(three_elem)); diff --git a/test/test_utility.cpp b/test/test_utility.cpp index 3a9a420cee742c1001c727a6154452ee10e8d8fb..74db29afa798ccdbf9d4be45497e1a44762d630d 100644 --- a/test/test_utility.cpp +++ b/test/test_utility.cpp @@ -20,10 +20,7 @@ * */ -#include "gmock/gmock-matchers.h" // for ElementsAre, EXPECT_THAT #include "boost/beast/core/detail/base64.hpp" // for encoded_size -#include "boost/json/object.hpp" // for object -#include "boost/json/value.hpp" // for value #include "caosdb/data_type.h" // for atomicdatatype_names #include "caosdb/entity.h" // for importance_names, role... #include "caosdb/status_code.h" // for get_status_description @@ -38,7 +35,6 @@ #include <utility> // for pair namespace caosdb::utility { -using ::testing::ElementsAre; TEST(test_utility, base64_encode) { auto test_plain = std::string("admin:caosdb"); @@ -48,17 +44,6 @@ TEST(test_utility, base64_encode) { EXPECT_EQ(test_encoded, base64_encode(test_plain)); } -TEST(test_utility, test_load_json_file) { - auto json = load_json_file(TEST_DATA_DIR + "/test.json").as_object(); - - EXPECT_EQ(json["it"], "tests"); - EXPECT_EQ(json["null values"], nullptr); - EXPECT_THAT(json["this"].as_array(), ElementsAre("is", "a", "test")); - EXPECT_THAT(json["numbers"].as_array(), ElementsAre(1, 2, 3.3)); - auto sub = json["arrays and objects"].as_object(); - EXPECT_THAT(sub["see?"].as_array(), ElementsAre(true, false)); -} - TEST(test_utility, enum_names) { // All working enums for (const auto &entry : caosdb::entity::importance_names) { diff --git a/test/test_value.cpp b/test/test_value.cpp index 241f2bd0ce2a7291184a79cdaa0612f2b99fa204..8de10b9051c5ded66f8ea3b4a23581f861a75b8d 100644 --- a/test/test_value.cpp +++ b/test/test_value.cpp @@ -20,24 +20,24 @@ * */ -#include "caosdb/value.h" // for Value -#include "caosdb/entity/v1alpha1/main.pb.h" // for AtomicDataType, DataType -#include "caosdb/protobuf_helper.h" // for ProtoMessageWrapper -#include <algorithm> // for max -#include <cmath> // for isnan -#include <gtest/gtest-message.h> // for Message -#include <gtest/gtest-test-part.h> // for TestPartResult, SuiteApi... -#include <gtest/gtest_pred_impl.h> // for AssertionResult, Test -#include <initializer_list> // for initializer_list -#include <string> // for string, basic_string -#include <vector> // for vector +#include "caosdb/value.h" // for Value +#include "caosdb/entity/v1/main.pb.h" // for AtomicDataType, DataType +#include "caosdb/protobuf_helper.h" // for ProtoMessageWrapper +#include <algorithm> // for max +#include <cmath> // for isnan +#include <gtest/gtest-message.h> // for Message +#include <gtest/gtest-test-part.h> // for TestPartResult, SuiteApi... +#include <gtest/gtest_pred_impl.h> // for AssertionResult, Test +#include <initializer_list> // for initializer_list +#include <string> // for string, basic_string +#include <vector> // for vector namespace caosdb::entity { -using ProtoValue = caosdb::entity::v1alpha1::Value; -using ProtoEntity = caosdb::entity::v1alpha1::Entity; -using ProtoParent = caosdb::entity::v1alpha1::Parent; -using ProtoDataType = caosdb::entity::v1alpha1::DataType; -using ProtoAtomicDataType = caosdb::entity::v1alpha1::AtomicDataType; +using ProtoValue = caosdb::entity::v1::Value; +using ProtoEntity = caosdb::entity::v1::Entity; +using ProtoParent = caosdb::entity::v1::Parent; +using ProtoDataType = caosdb::entity::v1::DataType; +using ProtoAtomicDataType = caosdb::entity::v1::AtomicDataType; TEST(test_value, test_null) { Value value; @@ -188,9 +188,9 @@ TEST(test_value, test_value_to_string) { EXPECT_EQ(value3.ToString(), "{\n \"scalarValue\": {\n \"doubleValue\": 2.6\n }\n}\n"); Value value4(std::vector<bool>{true, false}); - EXPECT_EQ(value4.ToString(), - "{\n \"listValues\": {\n \"values\": [\n {\n \"booleanValue\": true\n },\n " - "{\n \"booleanValue\": false\n }\n ]\n }\n}\n"); + EXPECT_EQ(value4.ToString(), "{\n \"listValues\": {\n \"values\": [\n {\n " + "\"booleanValue\": true\n },\n " + "{\n \"booleanValue\": false\n }\n ]\n }\n}\n"); } } // namespace caosdb::entity diff --git a/test_package/CMakeLists.txt b/test_package/CMakeLists.txt index d11580a845a3660e22be3ade1a3cc04cb95f1dd3..6e0db0446b0d4a2e1767f1ecdf2156ffb5dbb295 100644 --- a/test_package/CMakeLists.txt +++ b/test_package/CMakeLists.txt @@ -14,7 +14,7 @@ set(test_cases # dependencies include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) -conan_basic_setup() +conan_basic_setup(KEEP_RPATHS) # supress warnings during build of gtest cmake_policy(SET CMP0054 NEW) @@ -33,6 +33,9 @@ foreach (i RANGE "${len_test_cases}") ${CONAN_LIBS_GTEST} ${CONAN_LIBS_GRPC} ${CONAN_LIBS_ABSEIL} ${CONAN_LIBS_OPENSSL} ${CONAN_LIBS_C-ARES} ${CONAN_LIBS_BZIP2} ${CONAN_LIBS_PROTOBUF} ${CONAN_LIBS_ZLIB}) + if("${CMAKE_BUILD_TYPE}" MATCHES "Debug") + target_link_libraries(${test_case_name} PRIVATE caosdb_grpc) + endif() target_include_directories(${test_case_name} PUBLIC ${CONAN_INCLUDE_DIRS}) set_target_properties(${test_case_name} PROPERTIES diff --git a/test_package/conanfile.py b/test_package/conanfile.py index a003a6b0b97b32b30632b12fb4659a086cf36ddf..541113405bfca3b1222de81124a13586fe4bbda5 100644 --- a/test_package/conanfile.py +++ b/test_package/conanfile.py @@ -6,6 +6,9 @@ from conans import ConanFile, CMake, tools class LibcaosdbTestConan(ConanFile): settings = "os", "compiler", "build_type", "arch" generators = "cmake" + build_requires = [ + ("gtest/1.11.0"), + ] def build(self): cmake = CMake(self)