diff --git a/.clang-format b/.clang-format index 19ff63cb42294f1ce5aa49d78a74d82e6141927b..af6747eb4b062e0f6ec7d670cbb1aec40c4338bd 100644 --- a/.clang-format +++ b/.clang-format @@ -54,7 +54,7 @@ BreakConstructorInitializersBeforeComma: false BreakConstructorInitializers: BeforeColon BreakAfterJavaFieldAnnotations: false BreakStringLiterals: true -ColumnLimit: 80 +ColumnLimit: 100 CommentPragmas: '^ IWYU pragma:' CompactNamespaces: false ConstructorInitializerAllOnOneLineOrOnePerLine: false diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a54a23c5ad43ef851afeea2e31351a00ec2cadcc..d81b6e4ad2475604755798318be85371cd21484a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -24,6 +24,7 @@ variables: CPPLIB_REGISTRY_IMAGE: $CI_REGISTRY/caosdb/src/caosdb-cpplib/testenv:$CI_COMMIT_REF_NAME CPPINTTEST_PIPELINE: https://gitlab.indiscale.com/api/v4/projects/111/trigger/pipeline + CPPINTTEST_BRANCHES: https://gitlab.indiscale.com/api/v4/projects/111/repository/branches GIT_SUBMODULE_STRATEGY: normal ## FOR DEBUGGING @@ -101,8 +102,13 @@ trigger_inttest: # ... use an f-branch if posible... - F_BRANCH=dev - if echo "$CI_COMMIT_REF_NAME" | grep -c "^f-" ; then - CPPINT_REF=$CI_COMMIT_REF_NAME ; - F_BRANCH=$CI_COMMIT_REF_NAME ; + if curl -o /dev/null -s -w "%{http_code}" $CPPINTTEST_BRANCHES/$CI_COMMIT_REF_NAME | grep "404"; then + CPPINT_REF=dev ; + F_BRANCH=dev ; + else + CPPINT_REF=$CI_COMMIT_REF_NAME ; + F_BRANCH=$CI_COMMIT_REF_NAME ; + fi fi; # ... or use main if possible... - if [[ "$CI_COMMIT_REF_NAME" == "main" ]] ; then diff --git a/CHANGELOG.md b/CHANGELOG.md index 10652f17f2f515bb408d91ffc2f18564c7452f1d..03710a3d17afebc1636ed47bd870742db3be9e04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,10 +5,12 @@ 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] +## [0.0.13 - Unreleased] ### Added +- New functions getEnumNameFromValue() and getEnumValueFromName(). + ### Changed ### Deprecated diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c3603ca52409df19a008b0e1a73a4766d9be596..30a702752b32a068346694e8401bc10198c9268a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ cmake_minimum_required(VERSION 3.13) -set(libcaosdb_VERSION 0.0.11) +set(libcaosdb_VERSION 0.0.13) set(libcaosdb_COMPATIBLE_SERVER_VERSION_MAJOR 0) set(libcaosdb_COMPATIBLE_SERVER_VERSION_MINOR 5) set(libcaosdb_COMPATIBLE_SERVER_VERSION_PATCH 0) @@ -412,7 +412,7 @@ install(FILES ${PROJECT_SOURCE_DIR}/caosdbConfigVersion.cmake ### code formatting with clang-format ####################################################### option(AUTOFORMATTING "call clang-format at configure time" ON) -if(AUTOFORMATTING) +if(AUTOFORMATTING AND NOT SKIP_LINTING) file(GLOB format_test_sources test/*.cpp test/*.h test/*.h.in) execute_process(COMMAND clang-format -i --verbose ${libcaosdb_INCL} ${libcaosdb_SRC} ${libcaosdb_TEST_SRC} diff --git a/README_SETUP.md b/README_SETUP.md deleted file mode 100644 index 147745c32ad3d1460609e91942e4b7400b243560..0000000000000000000000000000000000000000 --- a/README_SETUP.md +++ /dev/null @@ -1,140 +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 "cppstd=11"` - -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. - -### 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-install` - -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 ..` -4. `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/README_SETUP.md b/README_SETUP.md new file mode 120000 index 0000000000000000000000000000000000000000..c5c7270fb583274df037848bfb735cdb48829d28 --- /dev/null +++ b/README_SETUP.md @@ -0,0 +1 @@ +doc/README_SETUP.md \ No newline at end of file diff --git a/conanfile.py b/conanfile.py index 300f652d76620d2cd6d4c698a0d651941daed5a4..7b34a061a4502c4f303517117ac77f77d622b32b 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.11" + version = "0.0.13" license = "AGPL-3.0-or-later" author = "Timm C. Fitschen <t.fitschen@indiscale.com>" url = "https://gitlab.indiscale.com/caosdb/src/caosdb-cpplib.git" diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 76d7dad56583120795d49f1828998315597e803c..4255ab7d0f5531187491de7586a8c7b6c61545f7 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -81,10 +81,20 @@ if (DOXYGEN_FOUND) -c ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR} sphinx_out - DEPENDS doc-doxygen + DEPENDS doc-doxygen + Examples.rst + README_SETUP.md WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Generating API documentation with Sphinx" - VERBATIM ) + VERBATIM + ) + # Copying files is necessary: https://stackoverflow.com/a/45808534/232888 + # TODO fix for docs + #FILE(COPY + #Examples.rst + #README_SETUP.md + # Tutorial.rst + #DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") else () message("Sphinx need to be installed to generate the sphinx documentation") endif () diff --git a/doc/Examples.rst b/doc/Examples.rst new file mode 100644 index 0000000000000000000000000000000000000000..ea65e02cd421b880d5d748c6774798ac115d0d9a --- /dev/null +++ b/doc/Examples.rst @@ -0,0 +1,237 @@ +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 + +.. code:: cpp + + const auto &connection = + caosdb::connection::ConnectionManager::GetDefaultConnection(); + +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(); + std::cout << "Server Version: " << v_info->GetMajor() << "." + << v_info->GetMinor() << "." << v_info->GetPatch() << "-" + << v_info->GetPreRelease() << "-" << v_info->GetBuild() + << std::endl; + + +Retrieve a Record +----------------- + +With libcaosdb you can create a transaction +object, fill it with sub-requests, execute it, and retrieve the +result(s) . This +is handy when you want to have several requests in the same transaction. +However, most of the time, e.g., when retrieving one or multiple +Records, this is not necessary. libcaosdb provides helper functions so +you don’t have to worry about transactions and their executions. Assume +you want to retrieve an Entity with id=123. This is done via + +.. code:: cpp + + const auto &connection = + caosdb::connection::ConnectionManager::GetDefaultConnection(); + + auto transaction(connection->CreateTransaction()); + + const auto *id = "1231"; + transaction->RetrieveById(id); + auto status = transaction->Execute(); + + const auto &result_set = transaction->GetResultSet(); + + const auto &entity = result_set.at(0) + + +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. + +Retrieving multiple entities works in the same way. Type + +.. code:: cpp + + const std::vector<std::string> ids = {"1220", "1221", "1222"}; + transaction->RetrieveById(ids.begin(), ids.end()); + +to retrieve the entities with ids 1220, 1221 and 1222. They can then be +accessed using ``result_set.at(1)`` etc. + +The same (and more) can be achieved by building and executing the +transaction manually. This is done by + +.. code:: cpp + + const auto &connection = + caosdb::connection::ConnectionManager::GetDefaultConnection(); + auto transaction(connection->CreateTransaction()); + + transaction->RetrieveById("1231"); + 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. + +Execute queries +--------------- + +Executing queries works very similar to the retrieval of entities via +ids. + +FIND and SELECT queries +~~~~~~~~~~~~~~~~~~~~~~~ + +In general, entities can be found using CaosDB’s query language like + +.. code:: cpp + + const auto &connection = + caosdb::connection::ConnectionManager::GetDefaultConnection(); + + auto query_transaction(connection->CreateTransaction()); + query_transaction->Query("FIND ENTITY WITH id = 1222"); + query_transaction->Execute(); + auto result_set = query_transaction->GetResultSet(); + std::cout << "Found " << result_set.size() + << "entity with id=" + << result_set.at(0).GetId() << std::endl; + +``result_set`` is a (possibly empty) list of entities that can be +inspected as above. + +:: + + SELECT queries haven't been implemented in the C++ client yet and + thus cannot be executed from libcaosdb right now. SELECT queries + will be added in a future release. + +COUNT queries +~~~~~~~~~~~~~ + +COUNT queries are different from FIND or SELECT queries in two ways. +Firstly, they do not return entities but a single number which is why, +secondly, they do not have a result set that could be returned. +The result of the count is +obtained using the :cpp:any:`GetCountResult<caosdb::transaction::Transaction::GetCountResult>` function: + +.. code:: cpp + + const auto &connection = + caosdb::connection::ConnectionManager::GetDefaultConnection(); + + auto query_transaction(connection->CreateTransaction()); + query_transaction->Query("COUNT RECORD person WITH NAME LIKE '*Baggins'"); + query_transaction->Execute(); + std::cout << "Found " << query_transaction->GetCountResult() + << "entities."<< std::endl; + +Insert, update, and delete entities +----------------------------------- + +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(); + + + // ######## INSERT ######## + // create the entity + Entity entity; + entity.SetRole(Role::RECORD_TYPE); + entity.SetName("RT1"); + + // create the transaction, add the task and execute the transaction + auto insert_transaction(connection->CreateTransaction()); + insert_transaction->InsertEntity(&entity); + auto insert_status = insert_transaction->Execute(); + + const auto &insert_result_set = insert_transaction->GetResultSet(); + // the result is an entity with the new id + const auto &new_entity = insert_result_set.at(0); + std::cout << "The newly inserted entity has the id " + << new_entity.GetId() << std::endl; + + + // get the inserted entity + // RETRIEVE + auto retrieve_transaction(connection->CreateTransaction()); + retrieve_transaction->RetrieveById(new_entity.GetId()); + retrieve_transaction->Execute(); + // save the entity from the result set in a new variable + auto update_entity(retrieve_transaction->GetResultSet().at(0)); + + // ######## UPDATE ######## + // and change it + update_entity.SetName("RT1-Update"); + + // create update transaction + auto update_transaction(connection->CreateTransaction()); + update_transaction->UpdateEntity(&update_entity); + auto update_status = update_transaction->Execute(); + // same as with insert transaction, the update transaction returns an entity + // with the id + const auto &updated_entity = update_transaction->GetResultSet().at(0); + std::cout << "The entity with the id " + << update_entity.GetId() << "was updated." << std::endl; + + // ######## DELETE ######## + auto delete_transaction(connection->CreateTransaction()); + delete_transaction->DeleteById(updated_entity .GetId()); + auto delete_status = delete_transaction->Execute(); + + // again, the delete transaction returns a result set with entities + // with the ids that where deleted + const auto &delete_result_set = delete_transaction->GetResultSet(); + + +Up- and Download a file +--------------- + +.. code:: cpp + + const auto &connection = + caosdb::connection::ConnectionManager::GetDefaultConnection(); + + Entity file; + file.SetRole(Role::FILE); + file.SetFilePath("test.txt"); + file.SetLocalPath(test_upload_file_1); + + // in order to upload a file, the corresponding entity simply has to be + // inserted + auto insert_transaction(connection->CreateTransaction()); + insert_transaction->InsertEntity(&file); + insert_transaction->Execute(); + + // entity in the result set contains the new id + const auto &insert_results = insert_transaction->GetResultSet(); + const auto &inserted_file = insert_results.at(0); + + // for the download you need to use the RetrieveAndDownloadFilesById task and + // supply the path where the file shall be stored + test_download_file = fs::path("test_download_file_delete_me.dat"); + auto download_transaction(connection->CreateTransaction()); + download_transaction->RetrieveAndDownloadFilesById( + inserted_file.GetId(), test_download_file.string()); + download_transaction->ExecuteAsynchronously(); + download_transaction->WaitForIt().GetCode() + + const auto &download_results = download_transaction->GetResultSet(); + const auto &downloaded_file = download_results.at(0); diff --git a/doc/README_SETUP.md b/doc/README_SETUP.md new file mode 100644 index 0000000000000000000000000000000000000000..f73190cad3386518361a9d76dac2f1825d5f3f28 --- /dev/null +++ b/doc/README_SETUP.md @@ -0,0 +1,142 @@ +# 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 "cppstd=11"` + +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. + +### 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-install` + +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 ..` +4. `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/conf.py.in b/doc/conf.py.in index f04a7a83ac79d555d819528d3ae6d92ed63580ee..c359c11e4d785a840761e50e93c2787d86312a43 100644 --- a/doc/conf.py.in +++ b/doc/conf.py.in @@ -45,7 +45,8 @@ extensions = [ 'sphinx.ext.viewcode', 'sphinx_sitemap', 'sphinx.ext.inheritance_diagram', - 'breathe' + 'breathe', + "recommonmark" # For markdown files. ] # Add any paths that contain templates here, relative to this directory. diff --git a/doc/index.rst.in b/doc/index.rst.in index e3fac2458d21571721f412adb3c120264f14dee6..47b16c95efa3da4aee32a1c6f2b559e5295377e3 100644 --- a/doc/index.rst.in +++ b/doc/index.rst.in @@ -25,13 +25,13 @@ Welcome to |PROJECT_NAME|'s documentation! ========================================== -This is work in progress. - .. toctree:: :maxdepth: 4 :caption: Contents: Welcome <self> + Getting Started <README_SETUP> + Examples.rst cppapi/index capi/index diff --git a/doc/requirements.txt b/doc/requirements.txt index 491959d5a9d70de347b8640872f9bf190af02261..1a306c69d3e8c80b51e0a0824da0d66ca378ad11 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -2,6 +2,7 @@ alabaster==0.7.12 Babel==2.9.1 breathe==4.30.0 certifi==2020.12.5 +recommonmark chardet==4.0.0 docutils==0.16 idna==2.10 diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index c0db7a2c007d13394a06bede00d1c601ad83bef2..18d9334acdac17d3b583efabb4e2eeb116cbb5a9 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -25,6 +25,7 @@ set(libcaosdb_INCL ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/configuration.h ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/connection.h ${CMAKE_CURRENT_BINARY_DIR}/caosdb/constants.h + ${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/handler_interface.h @@ -39,6 +40,7 @@ set(libcaosdb_INCL ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/transaction_status.h ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/unary_rpc_handler.h ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/utility.h + ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/value.h ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/file_transmission/register_file_upload_handler.h # TODO this file is still missing # ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/file_transmission/register_file_download_handler.h diff --git a/include/caosdb/authentication.h b/include/caosdb/authentication.h index fc2420c5dc3100682a16eefb56494a63e64e8162..070346c9366d89e7476f125b74feaea4ceb40a32 100644 --- a/include/caosdb/authentication.h +++ b/include/caosdb/authentication.h @@ -70,8 +70,7 @@ public: auto GetMetadata(string_ref service_url, string_ref method_name, const AuthContext &channel_auth_context, - std::multimap<grpc::string, grpc::string> *metadata) - -> Status override; + std::multimap<grpc::string, grpc::string> *metadata) -> Status override; }; class PlainPasswordAuthenticator : public Authenticator { @@ -79,11 +78,9 @@ private: std::string basic; public: - PlainPasswordAuthenticator(const std::string &username, - const std::string &password); + PlainPasswordAuthenticator(const std::string &username, const std::string &password); - [[nodiscard]] auto GetCallCredentials() const - -> std::shared_ptr<grpc::CallCredentials> override; + [[nodiscard]] auto GetCallCredentials() const -> std::shared_ptr<grpc::CallCredentials> override; }; } // namespace authentication } // namespace caosdb diff --git a/include/caosdb/configuration.h b/include/caosdb/configuration.h index bb6a1ff598be3df57ae24b21e5844cad6a9c0e71..2c521e7b0f36c351dabd6f7341ea3bb393fd402c 100644 --- a/include/caosdb/configuration.h +++ b/include/caosdb/configuration.h @@ -62,8 +62,7 @@ private: public: ConnectionConfiguration(const std::string &host, int port); virtual ~ConnectionConfiguration() = default; - friend auto operator<<(std::ostream &out, - const ConnectionConfiguration &configuration) + friend auto operator<<(std::ostream &out, const ConnectionConfiguration &configuration) -> std::ostream &; [[nodiscard]] auto virtual ToString() const -> std::string = 0; @@ -79,8 +78,7 @@ private: public: InsecureConnectionConfiguration(const std::string &host, int port); - [[nodiscard]] auto GetChannelCredentials() const - -> std::shared_ptr<ChannelCredentials> override; + [[nodiscard]] auto GetChannelCredentials() const -> std::shared_ptr<ChannelCredentials> override; [[nodiscard]] auto ToString() const -> std::string override; }; @@ -91,15 +89,13 @@ private: public: TlsConnectionConfiguration(const std::string &host, int port); - TlsConnectionConfiguration(const std::string &host, int port, - const Authenticator &authenticator); + TlsConnectionConfiguration(const std::string &host, int port, const Authenticator &authenticator); TlsConnectionConfiguration(const std::string &host, int port, const CertificateProvider &certificate_provider); TlsConnectionConfiguration(const std::string &host, int port, const CertificateProvider &certificate_provider, const Authenticator &authenticator); - [[nodiscard]] auto GetChannelCredentials() const - -> std::shared_ptr<ChannelCredentials> override; + [[nodiscard]] auto GetChannelCredentials() const -> std::shared_ptr<ChannelCredentials> override; [[nodiscard]] auto ToString() const -> std::string override; }; @@ -114,17 +110,13 @@ public: private: auto ConvertLogLevel(const std::string &string_level) const -> int; - auto CreateConsoleSinkConfiguration(const object &from, - const std::string &name, int level) const + 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 + 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 + 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 + 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; @@ -143,23 +135,19 @@ private: /** * @param from - a single connection configuration. */ - auto CreateCertificateProvider(const object &from) const - -> std::unique_ptr<CertificateProvider>; + 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>; + 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 + auto CreateConnectionConfiguration(const bool tls, const std::string &host, const int port, + const CertificateProvider *certificate_provider, + const Authenticator *authenticator) const -> std::unique_ptr<ConnectionConfiguration>; /** @@ -200,8 +188,7 @@ public: /** * See mLoadSingleJSONConfiguration. */ - inline static auto LoadSingleJSONConfiguration(const path &json_file) - -> void { + inline static auto LoadSingleJSONConfiguration(const path &json_file) -> void { GetInstance().mLoadSingleJSONConfiguration(json_file); } @@ -218,8 +205,7 @@ public: */ inline static auto GetDefaultConnectionConfiguration() -> std::unique_ptr<ConnectionConfiguration> { - return GetInstance().mGetConnectionConfiguration( - GetInstance().mGetDefaultConnectionName()); + return GetInstance().mGetConnectionConfiguration(GetInstance().mGetDefaultConnectionName()); } /** diff --git a/include/caosdb/connection.h b/include/caosdb/connection.h index ef9597bb06cb5454160eb02938219a8ced564d17..d3ed0945e0022f29e6097fb4ea2d9207c3258987 100644 --- a/include/caosdb/connection.h +++ b/include/caosdb/connection.h @@ -85,8 +85,7 @@ public: * RetrieveVersionInfoNoExceptions() before the version info is locally * available. Otherwise a nullptr is being returned. */ - [[nodiscard]] inline auto GetVersionInfo() const noexcept - -> const VersionInfo * { + [[nodiscard]] inline auto GetVersionInfo() const noexcept -> const VersionInfo * { return this->version_info.get(); }; @@ -128,8 +127,7 @@ private: auto mHasConnection(const std::string &name) const -> bool; - auto mGetConnection(const std::string &name) const - -> const std::shared_ptr<Connection> &; + auto mGetConnection(const std::string &name) const -> const std::shared_ptr<Connection> &; auto mGetDefaultConnection() const -> const std::shared_ptr<Connection> &; @@ -148,22 +146,18 @@ public: return ConnectionManager::GetInstance().mHasConnection(name); }; - inline static auto GetConnection(const std::string &name) - -> const std::shared_ptr<Connection> & { + inline static auto GetConnection(const std::string &name) -> const std::shared_ptr<Connection> & { return ConnectionManager::GetInstance().mGetConnection(name); }; /** * Get the connection marked by the "default" key in the configuration. */ - inline static auto GetDefaultConnection() - -> const std::shared_ptr<Connection> & { + inline static auto GetDefaultConnection() -> const std::shared_ptr<Connection> & { return ConnectionManager::GetInstance().mGetDefaultConnection(); }; - inline static auto Reset() -> void { - return ConnectionManager::GetInstance().mReset(); - }; + inline static auto Reset() -> void { return ConnectionManager::GetInstance().mReset(); }; ConnectionManager(ConnectionManager const &) = delete; void operator=(ConnectionManager const &) = delete; diff --git a/include/caosdb/data_type.h b/include/caosdb/data_type.h new file mode 100644 index 0000000000000000000000000000000000000000..22358fcda808c8ebf93c140156ba7e39c5757e8d --- /dev/null +++ b/include/caosdb/data_type.h @@ -0,0 +1,227 @@ +/* + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com> + * Copyright (C) 2021 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/>. + * + */ + +/** + * DataTypes have 2 dimensions: They may be atomic or reference typed, and they + * may be scalar or list valued. If they are atomic, they have an + * AtomicDataType. If they are reference typed, the reference name can be + * obtained with GetName(). + */ + +#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 +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 caosdb::utility::ProtoMessageWrapper; + +class Entity; +class Property; + +// Atomic data types. +enum class AtomicDataType { + // The data type is unset/unknown. + UNSPECIFIED = ProtoAtomicDataType::ATOMIC_DATA_TYPE_UNSPECIFIED, + // TEXT data type. + TEXT = ProtoAtomicDataType::ATOMIC_DATA_TYPE_TEXT, + // DOUBLE data type. + DOUBLE = ProtoAtomicDataType::ATOMIC_DATA_TYPE_DOUBLE, + // DATETIME data type. + DATETIME = ProtoAtomicDataType::ATOMIC_DATA_TYPE_DATETIME, + // INTEGER data type. + INTEGER = ProtoAtomicDataType::ATOMIC_DATA_TYPE_INTEGER, + // BOOLEAN data type. + BOOLEAN = ProtoAtomicDataType::ATOMIC_DATA_TYPE_BOOLEAN, +}; + +const std::map<AtomicDataType, std::string> atomicdatatype_names = { + {AtomicDataType::UNSPECIFIED, "UNSPECIFIED"}, {AtomicDataType::TEXT, "TEXT"}, + {AtomicDataType::DOUBLE, "DOUBLE"}, {AtomicDataType::DATETIME, "DATETIME"}, + {AtomicDataType::INTEGER, "INTEGER"}, {AtomicDataType::BOOLEAN, "BOOLEAN"}}; + +class DataType; +class ListDataType; + +class ReferenceDataType : public ProtoMessageWrapper<ProtoDataType> { +public: + [[nodiscard]] inline auto GetName() const noexcept -> const std::string & { + // is list of reference? + if (this->wrapped->data_type_case() == DataTypeCase::kListDataType) { + return this->wrapped->list_data_type().reference_data_type().name(); + } + return this->wrapped->reference_data_type().name(); + } + + friend class DataType; + friend class ListDataType; + + inline auto GetWrapped() const -> const ProtoDataType * { return wrapped; } + +protected: + static auto GetEmptyInstance() -> const ReferenceDataType & { + static ReferenceDataType instance; + return instance; + } + inline static auto Create(ProtoDataType *wrapped) -> std::unique_ptr<ReferenceDataType> { + return std::unique_ptr<ReferenceDataType>(new ReferenceDataType(wrapped)); + } + ReferenceDataType() : ProtoMessageWrapper<ProtoDataType>() {} + ReferenceDataType(ProtoDataType *wrapped) : ProtoMessageWrapper<ProtoDataType>(wrapped) {} +}; + +class ListDataType : public ProtoMessageWrapper<ProtoDataType> { +public: + [[nodiscard]] inline auto IsListOfReference() const noexcept -> bool { + return this->wrapped->list_data_type().list_data_type_case() == + ListDataTypeCase::kReferenceDataType; + } + [[nodiscard]] inline auto GetReferenceDataType() const -> const ReferenceDataType & { + if (!IsListOfReference()) { + return ReferenceDataType::GetEmptyInstance(); + } + if (reference_data_type == nullptr) { + this->reference_data_type = + std::unique_ptr<ReferenceDataType>(ReferenceDataType::Create(this->wrapped).release()); + } + return *this->reference_data_type; + } + + [[nodiscard]] inline auto IsListOfAtomic() const noexcept -> bool { + return this->wrapped->list_data_type().list_data_type_case() == + ListDataTypeCase::kAtomicDataType; + } + [[nodiscard]] inline auto GetAtomicDataType() const -> AtomicDataType { + return static_cast<AtomicDataType>(this->wrapped->list_data_type().atomic_data_type()); + } + + friend class DataType; + +protected: + static auto GetEmptyInstance() -> const ListDataType & { + static auto empty_instance = ListDataType(); + return empty_instance; + } + inline static auto Create(ProtoDataType *wrapped) -> std::unique_ptr<ListDataType> { + return std::unique_ptr<ListDataType>(new ListDataType(wrapped)); + } + ListDataType() : ProtoMessageWrapper<ProtoDataType>() {} + + ListDataType(ProtoDataType *wrapped) : ProtoMessageWrapper<ProtoDataType>(wrapped) {} + + mutable std::unique_ptr<ReferenceDataType> reference_data_type; +}; + +class DataType : public ProtoMessageWrapper<ProtoDataType> { +public: + DataType(ProtoDataType *wrapped) : ProtoMessageWrapper<ProtoDataType>(wrapped) {} + DataType() : ProtoMessageWrapper<ProtoDataType>() {} + /** + * Create an AtomicDataType typed DataType. For references, use the std::string constructor. + */ + DataType(AtomicDataType data_type, bool list_type = false) : DataType() { + if (list_type) { + this->wrapped->mutable_list_data_type()->set_atomic_data_type( + static_cast<ProtoAtomicDataType>(data_type)); + } else { + this->wrapped->set_atomic_data_type(static_cast<ProtoAtomicDataType>(data_type)); + } + } + /** + * Create a reference typed DataType. + */ + DataType(const std::string &data_type, bool list_type = false) : DataType() { + if (list_type) { + this->wrapped->mutable_list_data_type()->mutable_reference_data_type()->set_name(data_type); + } else { + this->wrapped->mutable_reference_data_type()->set_name(data_type); + } + } + + inline static auto ListOf(const AtomicDataType &atomic_data_type) -> DataType { + DataType result; + result.wrapped->mutable_list_data_type()->set_atomic_data_type( + static_cast<ProtoAtomicDataType>(atomic_data_type)); + return result; + } + inline static auto ListOf(const std::string reference_data_type) -> DataType { + DataType result; + result.wrapped->mutable_list_data_type()->mutable_reference_data_type()->set_name( + reference_data_type); + return result; + } + + [[nodiscard]] inline auto IsAtomic() const noexcept -> bool { + return this->wrapped->data_type_case() == DataTypeCase::kAtomicDataType; + } + [[nodiscard]] inline auto AsAtomic() const noexcept -> AtomicDataType { + return static_cast<AtomicDataType>(this->wrapped->atomic_data_type()); + } + + [[nodiscard]] inline auto IsReference() const noexcept -> bool { + return this->wrapped->data_type_case() == DataTypeCase::kReferenceDataType; + } + [[nodiscard]] inline auto AsReference() const noexcept -> const ReferenceDataType & { + if (!IsReference()) { + return ReferenceDataType::GetEmptyInstance(); + } else if (reference_data_type == nullptr) { + reference_data_type = + std::unique_ptr<ReferenceDataType>(ReferenceDataType::Create(this->wrapped).release()); + } + return *reference_data_type; + } + + [[nodiscard]] inline auto IsList() const noexcept -> bool { + return this->wrapped->data_type_case() == DataTypeCase::kListDataType; + } + + [[nodiscard]] inline auto AsList() const noexcept -> const ListDataType & { + if (!IsList()) { + return ListDataType::GetEmptyInstance(); + } else if (list_data_type == nullptr) { + list_data_type = std::unique_ptr<ListDataType>(ListDataType::Create(this->wrapped).release()); + } + return *list_data_type; + } + + inline auto operator==(const DataType &other) const noexcept -> bool { + // TODO(tf) Is this safe? + return this->wrapped->SerializeAsString() == other.wrapped->SerializeAsString(); + } + + friend class Entity; + friend class Property; + +protected: + mutable std::unique_ptr<ReferenceDataType> reference_data_type; + mutable std::unique_ptr<ListDataType> list_data_type; +}; + +} // namespace caosdb::entity + +#endif diff --git a/include/caosdb/entity.h b/include/caosdb/entity.h index 3917e934122453e71d782604903143ecf5625bd1..13834b71d8467c45df58e199f98fd3c6606d69b4 100644 --- a/include/caosdb/entity.h +++ b/include/caosdb/entity.h @@ -29,10 +29,12 @@ #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/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 @@ -40,14 +42,16 @@ #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 <google/protobuf/util/json_util.h> // for MessageToJson... #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 <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 <vector> // for vector namespace caosdb::entity { using boost::filesystem::exists; @@ -58,6 +62,8 @@ 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 caosdb::entity::v1alpha1::EntityRole; +using ProtoImportance = caosdb::entity::v1alpha1::Importance; using caosdb::StatusCode; using caosdb::entity::v1alpha1::EntityResponse; using caosdb::entity::v1alpha1::FileTransmissionId; @@ -66,6 +72,39 @@ using google::protobuf::RepeatedPtrField; static const std::string logger_name = "caosdb::entity"; +/** + * The property importance. + */ +enum class Importance { + UNSPECIFIED = ProtoImportance::IMPORTANCE_UNSPECIFIED, ///< Unset/None + OBLIGATORY = ProtoImportance::IMPORTANCE_OBLIGATORY, ///< Obligatory importance. + RECOMMENDED = ProtoImportance::IMPORTANCE_RECOMMENDED, ///< Recommended importance. + SUGGESTED = ProtoImportance::IMPORTANCE_SUGGESTED, ///< Suggested importance. + FIX = ProtoImportance::IMPORTANCE_FIX, ///< Fix importance. +}; +const std::map<Importance, std::string> importance_names = { + {Importance::UNSPECIFIED, "UNSPECIFIED"}, + {Importance::OBLIGATORY, "OBLIGATORY"}, + {Importance::RECOMMENDED, "RECOMMENDED"}, + {Importance::SUGGESTED, "SUGGESTED"}, + {Importance::FIX, "FIX"}}; + +/** + * The entity role. + */ +enum class Role { + UNSPECIFIED = EntityRole::ENTITY_ROLE_UNSPECIFIED, ///< Unset/None + RECORD_TYPE = EntityRole::ENTITY_ROLE_RECORD_TYPE, ///< RecordType + RECORD = EntityRole::ENTITY_ROLE_RECORD, ///< Record + PROPERTY = EntityRole::ENTITY_ROLE_PROPERTY, ///< Property + FILE = EntityRole::ENTITY_ROLE_FILE, ///< File +}; +const std::map<Role, std::string> role_names = {{Role::UNSPECIFIED, "UNSPECIFIED"}, + {Role::RECORD_TYPE, "RECORD_TYPE"}, + {Role::RECORD, "RECORD"}, + {Role::PROPERTY, "PROPERTY"}, + {Role::FILE, "FILE"}}; + struct FileDescriptor { FileTransmissionId *file_transmission_id; ProtoFileDescriptor *wrapped; @@ -88,9 +127,7 @@ public: /** * Return a const reference to the element at the given index. */ - [[nodiscard]] inline auto at(int index) const -> const T & { - return *mutable_at(index); - } + [[nodiscard]] inline auto at(int index) const -> const T & { return *mutable_at(index); } /** * Return a mutable pointer to the element at the given index. @@ -127,8 +164,7 @@ public: protected: RepeatedPtrFieldWrapper(){}; - explicit inline RepeatedPtrFieldWrapper( - ::google::protobuf::RepeatedPtrField<P> *wrapped) + explicit inline RepeatedPtrFieldWrapper(::google::protobuf::RepeatedPtrField<P> *wrapped) : wrapped(wrapped){}; /** @@ -149,7 +185,7 @@ protected: /** * Remove the element at the given index. */ - inline auto remove(int index) -> void { + inline auto Remove(int index) -> void { this->wrapped->DeleteSubrange(index, 1); if (cache.count(index) > 0) { cache.erase(index); @@ -172,8 +208,8 @@ protected: private: class iterator : public std::iterator<std::output_iterator_tag, T> { public: - explicit iterator(const RepeatedPtrFieldWrapper<T, P> *instance, - int index = 0); + explicit iterator(const RepeatedPtrFieldWrapper<T, P> *instance, int index = 0); + // TODO(henrik) add unit tests auto operator*() const -> T &; auto operator++() -> iterator &; auto operator++(int) -> iterator; @@ -186,8 +222,8 @@ private: }; template <class T, class P> -RepeatedPtrFieldWrapper<T, P>::iterator::iterator( - const RepeatedPtrFieldWrapper<T, P> *instance, int index) +RepeatedPtrFieldWrapper<T, P>::iterator::iterator(const RepeatedPtrFieldWrapper<T, P> *instance, + int index) : current_index(index), instance(instance) {} template <typename T, typename P> @@ -211,32 +247,27 @@ auto RepeatedPtrFieldWrapper<T, P>::iterator::operator++(int) } template <typename T, typename P> -auto RepeatedPtrFieldWrapper<T, P>::iterator::operator!=( - const iterator &rhs) const -> bool { +auto RepeatedPtrFieldWrapper<T, P>::iterator::operator!=(const iterator &rhs) const -> bool { return this->current_index != rhs.current_index; } template <typename T, typename P> -auto RepeatedPtrFieldWrapper<T, P>::begin() - -> RepeatedPtrFieldWrapper<T, P>::iterator { +auto RepeatedPtrFieldWrapper<T, P>::begin() -> RepeatedPtrFieldWrapper<T, P>::iterator { return RepeatedPtrFieldWrapper<T, P>::iterator(this, 0); } template <typename T, typename P> -auto RepeatedPtrFieldWrapper<T, P>::end() - -> RepeatedPtrFieldWrapper<T, P>::iterator { +auto RepeatedPtrFieldWrapper<T, P>::end() -> RepeatedPtrFieldWrapper<T, P>::iterator { return RepeatedPtrFieldWrapper<T, P>::iterator(this, size()); } template <typename T, typename P> -auto RepeatedPtrFieldWrapper<T, P>::begin() const - -> const RepeatedPtrFieldWrapper<T, P>::iterator { +auto RepeatedPtrFieldWrapper<T, P>::begin() const -> const RepeatedPtrFieldWrapper<T, P>::iterator { return RepeatedPtrFieldWrapper<T, P>::iterator(this, 0); } template <typename T, typename P> -auto RepeatedPtrFieldWrapper<T, P>::end() const - -> const RepeatedPtrFieldWrapper<T, P>::iterator { +auto RepeatedPtrFieldWrapper<T, P>::end() const -> const RepeatedPtrFieldWrapper<T, P>::iterator { return RepeatedPtrFieldWrapper<T, P>::iterator(this, size()); } @@ -264,9 +295,7 @@ public: * * The description is intended for a human reader. */ - [[nodiscard]] inline auto GetDescription() const -> std::string { - return wrapped->description(); - } + [[nodiscard]] inline auto GetDescription() const -> std::string { return wrapped->description(); } friend class Entity; // TODO(fspreck) Re-enable once we have decided how messages are @@ -340,8 +369,7 @@ public: inline auto ToString() const -> const std::string { google::protobuf::util::JsonOptions options; std::string out; - google::protobuf::util::MessageToJsonString(*(this->wrapped), &out, - options); + google::protobuf::util::MessageToJsonString(*(this->wrapped), &out, options); return out; } @@ -411,8 +439,7 @@ public: private: inline Parents() : RepeatedPtrFieldWrapper(){}; explicit inline Parents( - ::google::protobuf::RepeatedPtrField<caosdb::entity::v1alpha1::Parent> - *wrapped) + ::google::protobuf::RepeatedPtrField<caosdb::entity::v1alpha1::Parent> *wrapped) : RepeatedPtrFieldWrapper(wrapped){}; }; @@ -424,7 +451,9 @@ private: */ class Property { public: - explicit inline Property(ProtoProperty *wrapped) : wrapped(wrapped){}; + explicit inline Property(ProtoProperty *other) + : value(Value(other->mutable_value())), data_type(DataType(other->mutable_data_type())), + wrapped(other){}; Property(); /** @@ -442,11 +471,11 @@ public: /** * Return the importance of this property */ - [[nodiscard]] auto GetImportance() const -> const std::string &; + [[nodiscard]] auto GetImportance() const -> Importance; /** * Return the value of this property */ - [[nodiscard]] auto GetValue() const -> const std::string &; + [[nodiscard]] auto GetValue() const -> const Value &; /** * Return the unit of this property */ @@ -454,7 +483,7 @@ public: /** * Return the datatype of this property */ - [[nodiscard]] auto GetDatatype() const -> const std::string &; + [[nodiscard]] auto GetDataType() const -> const DataType &; // TODO(fspreck) Implement these when we have decided how to attach // messages to properties. // [[nodiscard]] auto GetErrors() const -> const Messages &; @@ -476,11 +505,22 @@ public: /** * Set the importance of this property. */ - auto SetImportance(const std::string &importance) -> void; + auto SetImportance(Importance importance) -> void; /** * Set the value of this property. */ - auto SetValue(const std::string &value) -> void; + auto SetValue(const Value &value) -> StatusCode; + auto SetValue(const std::string &value) -> StatusCode; + auto SetValue(const char *value) -> StatusCode; + auto SetValue(const double value) -> StatusCode; + auto SetValue(const std::vector<std::string> &values) -> StatusCode; + auto SetValue(const std::vector<char *> &values) -> StatusCode; + auto SetValue(const std::vector<int64_t> &values) -> StatusCode; + auto SetValue(const std::vector<double> &values) -> StatusCode; + auto SetValue(const std::vector<bool> &values) -> StatusCode; + auto SetValue(const int64_t value) -> StatusCode; + auto SetValue(const bool value) -> StatusCode; + /** * Set the unit of this property. */ @@ -488,7 +528,9 @@ public: /** * Set the datatype of this property. */ - auto SetDatatype(const std::string &datatype) -> void; + auto SetDataType(const DataType &new_data_type) -> StatusCode; + auto SetDataType(const AtomicDataType new_data_type, bool list_type = false) -> StatusCode; + auto SetDataType(const std::string &new_data_type, bool list_type = false) -> StatusCode; /** * Return a json string representing this property. @@ -498,8 +540,7 @@ public: inline auto ToString() const -> const std::string { google::protobuf::util::JsonOptions options; std::string out; - google::protobuf::util::MessageToJsonString(*(this->wrapped), &out, - options); + google::protobuf::util::MessageToJsonString(*(this->wrapped), &out, options); return out; } @@ -510,6 +551,8 @@ public: private: static auto CreateProtoProperty() -> ProtoProperty *; + Value value; + DataType data_type; mutable ProtoProperty *wrapped; }; @@ -518,10 +561,18 @@ private: * Container for Properties of Entities. * * Should only be instantiated and write-accessed by the owning entity. + * + * Note that iterating over the Property contents only works via references, + * since the Property copy constructor is deliberately disabled: + * + * \code + * // Accessing single properties as reference + * auto &property = my_properties.at(0); + * // Iterating via reference + * for (auto &property : my_properties) {...} + * \endcode */ -class Properties - : public RepeatedPtrFieldWrapper<Property, - caosdb::entity::v1alpha1::Property> { +class Properties : public RepeatedPtrFieldWrapper<Property, caosdb::entity::v1alpha1::Property> { public: ~Properties() = default; friend class Entity; @@ -529,10 +580,8 @@ public: private: inline Properties(){}; explicit inline Properties( - ::google::protobuf::RepeatedPtrField<caosdb::entity::v1alpha1::Property> - *wrapped) - : RepeatedPtrFieldWrapper<Property, caosdb::entity::v1alpha1::Property>( - wrapped){}; + ::google::protobuf::RepeatedPtrField<caosdb::entity::v1alpha1::Property> *wrapped) + : RepeatedPtrFieldWrapper<Property, caosdb::entity::v1alpha1::Property>(wrapped){}; }; /** @@ -541,65 +590,59 @@ private: class Entity { public: Entity(); - inline Entity(const Entity &original) : Entity(CreateProtoEntity()) { + inline Entity(const Entity &original) + : wrapped(original.wrapped), value(Value(original.wrapped->mutable_value())), + data_type(DataType(original.wrapped->mutable_data_type())) { this->wrapped->CopyFrom(*original.wrapped); + data_type.wrapped = this->wrapped->mutable_data_type(); + value.wrapped = this->wrapped->mutable_value(); + properties.wrapped = this->wrapped->mutable_properties(); + parents.wrapped = this->wrapped->mutable_parents(); + errors.wrapped = CreateMessagesField(); + warnings.wrapped = CreateMessagesField(); + infos.wrapped = CreateMessagesField(); }; - explicit Entity(IdResponse *idResponse); - explicit Entity(ProtoEntity *wrapped) : wrapped(wrapped) { + explicit Entity(IdResponse *id_response); + explicit Entity(ProtoEntity *other) + : wrapped(other), value(Value(other->mutable_value())), + data_type(DataType(other->mutable_data_type())) { + data_type.wrapped = this->wrapped->mutable_data_type(); + value.wrapped = this->wrapped->mutable_value(); properties.wrapped = this->wrapped->mutable_properties(); parents.wrapped = this->wrapped->mutable_parents(); errors.wrapped = CreateMessagesField(); warnings.wrapped = CreateMessagesField(); infos.wrapped = CreateMessagesField(); }; - explicit inline Entity(EntityResponse *response) - : Entity(response->release_entity()) { + explicit inline Entity(EntityResponse *response) : Entity(response->release_entity()) { errors.wrapped->Swap(response->mutable_errors()); warnings.wrapped->Swap(response->mutable_warnings()); infos.wrapped->Swap(response->mutable_infos()); }; - [[nodiscard]] inline auto GetId() const noexcept -> const std::string & { - return wrapped->id(); - }; - [[nodiscard]] inline auto HasId() const noexcept -> bool { - return !wrapped->id().empty(); - } + [[nodiscard]] inline auto GetId() const noexcept -> const std::string & { return wrapped->id(); }; + [[nodiscard]] inline auto HasId() const noexcept -> bool { return !wrapped->id().empty(); } [[nodiscard]] inline auto GetVersionId() const -> const std::string & { return wrapped->version().id(); }; - [[nodiscard]] inline auto GetRole() const -> const std::string & { - return wrapped->role(); - }; - [[nodiscard]] inline auto GetName() const -> const std::string & { - return wrapped->name(); - }; + [[nodiscard]] inline auto GetRole() const -> Role { return static_cast<Role>(wrapped->role()); }; + [[nodiscard]] inline auto GetName() const -> const std::string & { return wrapped->name(); }; [[nodiscard]] inline auto GetDescription() const -> const std::string & { return wrapped->description(); }; - [[nodiscard]] inline auto GetDatatype() const -> const std::string & { - return wrapped->datatype(); - }; - [[nodiscard]] inline auto GetUnit() const -> const std::string & { - return wrapped->unit(); - }; - [[nodiscard]] inline auto GetValue() const -> const std::string & { - return wrapped->value(); - }; + [[nodiscard]] inline auto GetDataType() const -> const DataType & { return this->data_type; }; + [[nodiscard]] inline auto GetUnit() const -> const std::string & { return wrapped->unit(); }; + [[nodiscard]] inline auto GetValue() const -> const Value & { return this->value; }; [[nodiscard]] auto GetParents() const -> const Parents &; + // TODO(henrik) const prevents properties from being changed + // what about an interface that operates on the list directly? [[nodiscard]] auto GetProperties() const -> const Properties &; - [[nodiscard]] inline auto GetErrors() const -> const Messages & { - return errors; - } - [[nodiscard]] inline auto HasErrors() const -> bool { - return this->errors.wrapped->size() > 0; - } - [[nodiscard]] auto GetWarnings() const -> const Messages & { - return warnings; - } + [[nodiscard]] inline auto GetErrors() const -> const Messages & { return errors; } + [[nodiscard]] inline auto HasErrors() const -> bool { return this->errors.wrapped->size() > 0; } + [[nodiscard]] auto GetWarnings() const -> const Messages & { return warnings; } [[nodiscard]] inline auto HasWarnings() const -> bool { return this->warnings.wrapped->size() > 0; } @@ -608,22 +651,34 @@ public: inline auto ToString() const -> const std::string { google::protobuf::util::JsonOptions options; std::string out; - google::protobuf::util::MessageToJsonString(*(this->wrapped), &out, - options); + google::protobuf::util::MessageToJsonString(*(this->wrapped), &out, options); return out; } - auto SetRole(const std::string &role) -> void; + auto SetRole(Role role) -> void; auto SetName(const std::string &name) -> void; /** * Set the description of this entity. */ auto SetDescription(const std::string &description) -> void; - auto SetValue(const std::string &value) -> void; + auto SetValue(const Value &value) -> StatusCode; + auto SetValue(const std::string &value) -> StatusCode; + auto SetValue(const char *value) -> StatusCode; + auto SetValue(const double value) -> StatusCode; + auto SetValue(const std::vector<std::string> &values) -> StatusCode; + auto SetValue(const std::vector<char *> &values) -> StatusCode; + auto SetValue(const std::vector<int64_t> &values) -> StatusCode; + auto SetValue(const std::vector<double> &values) -> StatusCode; + auto SetValue(const std::vector<bool> &values) -> StatusCode; + auto SetValue(const int64_t value) -> StatusCode; + auto SetValue(const bool value) -> StatusCode; + auto SetUnit(const std::string &unit) -> void; - // Currently no references or lists. - auto SetDatatype(const std::string &datatype) -> void; + + auto SetDataType(const DataType &new_data_type) -> StatusCode; + auto SetDataType(const AtomicDataType new_data_type, bool list_type = false) -> StatusCode; + auto SetDataType(const std::string &new_data_type, bool list_type = false) -> StatusCode; auto AppendProperty(const Property &property) -> void; auto RemoveProperty(int index) -> void; @@ -636,47 +691,36 @@ public: auto CopyTo(ProtoEntity *target) -> void; 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 { + 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 GetFileDescriptor() -> FileDescriptor & { return this->file_descriptor; } inline auto GetLocalPath() const noexcept -> const boost::filesystem::path & { return this->file_descriptor.local_path; } - inline auto SetLocalPath(const boost::filesystem::path &local_path) noexcept - -> StatusCode { - if (GetRole() != "File") { - CAOSDB_LOG_WARN(logger_name) - << "Entity::SetLocalPath failed. This is not a file entity."; + inline auto SetLocalPath(const boost::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; } if (!exists(local_path)) { CAOSDB_LOG_WARN(logger_name) - << "Entity::SetLocalPath failed. This file does not exists: " - << local_path.string(); + << "Entity::SetLocalPath failed. This file does not exists: " << local_path.string(); return StatusCode::FILE_DOES_NOT_EXIST_LOCALLY; } if (is_directory(local_path)) { CAOSDB_LOG_WARN(logger_name) - << "Entity::SetLocalPath failed. This file is a directory: " - << local_path.string(); + << "Entity::SetLocalPath failed. This file is a directory: " << local_path.string(); return StatusCode::PATH_IS_A_DIRECTORY; } - CAOSDB_LOG_TRACE(logger_name) - << "Entity::SetLocalPath(" << local_path.string() << ");"; + CAOSDB_LOG_TRACE(logger_name) << "Entity::SetLocalPath(" << local_path.string() << ");"; this->file_descriptor.local_path = local_path; return StatusCode::SUCCESS; } @@ -697,6 +741,8 @@ private: static auto CreateMessagesField() -> RepeatedPtrField<ProtoMessage> *; auto SetId(const std::string &id) -> void; auto SetVersionId(const std::string &id) -> void; + +private: FileDescriptor file_descriptor; ProtoEntity *wrapped; Properties properties; @@ -704,6 +750,8 @@ private: Messages errors; Messages warnings; Messages infos; + Value value; + DataType data_type; }; } // namespace caosdb::entity diff --git a/include/caosdb/exceptions.h b/include/caosdb/exceptions.h index 9ac46d2fd2e0a24fab08c49606b21033893c14e7..304216679200329660c5068362fa9e089f089235 100644 --- a/include/caosdb/exceptions.h +++ b/include/caosdb/exceptions.h @@ -65,8 +65,7 @@ public: */ class TransactionError : public Exception { protected: - TransactionError(StatusCode code, const std::string &what_arg) - : Exception(code, what_arg) {} + TransactionError(StatusCode code, const std::string &what_arg) : Exception(code, what_arg) {} public: explicit TransactionError(const std::string &what_arg) diff --git a/include/caosdb/file_transmission/download_request_handler.h b/include/caosdb/file_transmission/download_request_handler.h index cb2108aa3c9c091316e557c1d732297d84171db9..3af72cc5939ced7a2f6c2edf86981cc8ef62cbb0 100644 --- a/include/caosdb/file_transmission/download_request_handler.h +++ b/include/caosdb/file_transmission/download_request_handler.h @@ -74,8 +74,7 @@ using caosdb::transaction::HandlerTag; class DownloadRequestHandler final : public HandlerInterface { public: DownloadRequestHandler(HandlerTag tag, FileTransmissionService::Stub *stub, - grpc::CompletionQueue *cq, - FileDescriptor file_descriptor); + grpc::CompletionQueue *cq, FileDescriptor file_descriptor); ~DownloadRequestHandler() override = default; diff --git a/include/caosdb/file_transmission/register_file_upload_handler.h b/include/caosdb/file_transmission/register_file_upload_handler.h index 17a42c0a2a2cf1d591048abb6e4c8b329bfd008c..f4586220980b056891effb142c4d736efc809fcf 100644 --- a/include/caosdb/file_transmission/register_file_upload_handler.h +++ b/include/caosdb/file_transmission/register_file_upload_handler.h @@ -73,8 +73,7 @@ public: ~RegisterFileUploadHandler(); RegisterFileUploadHandler(const RegisterFileUploadHandler &) = delete; - RegisterFileUploadHandler & - operator=(const RegisterFileUploadHandler &) = delete; + RegisterFileUploadHandler &operator=(const RegisterFileUploadHandler &) = delete; RegisterFileUploadHandler(RegisterFileUploadHandler &&) = delete; RegisterFileUploadHandler &operator=(RegisterFileUploadHandler &&) = delete; @@ -85,8 +84,7 @@ protected: FileTransmissionService::Stub *stub_; - std::unique_ptr<grpc::ClientAsyncResponseReader<RegisterFileUploadResponse>> - rpc_; + std::unique_ptr<grpc::ClientAsyncResponseReader<RegisterFileUploadResponse>> rpc_; RegisterFileUploadRequest *request_; RegisterFileUploadResponse *response_; diff --git a/include/caosdb/file_transmission/upload_request_handler.h b/include/caosdb/file_transmission/upload_request_handler.h index 54621d12ba7d67d374037ecdb1f1259662071319..9965d54ef870c0ab0ae21b65e456859fb1ef34a3 100644 --- a/include/caosdb/file_transmission/upload_request_handler.h +++ b/include/caosdb/file_transmission/upload_request_handler.h @@ -72,8 +72,7 @@ using caosdb::transaction::HandlerTag; class UploadRequestHandler final : public HandlerInterface { public: UploadRequestHandler(HandlerTag tag, FileTransmissionService::Stub *stub, - grpc::CompletionQueue *cq, - FileDescriptor file_descriptor); + grpc::CompletionQueue *cq, FileDescriptor file_descriptor); ~UploadRequestHandler() override = default; @@ -89,13 +88,7 @@ public: void Cancel() override; protected: - enum class CallState { - NewCall, - SendingHeader, - SendingFile, - ExpectingResponse, - CallComplete - }; + enum class CallState { NewCall, SendingHeader, SendingFile, ExpectingResponse, CallComplete }; void handleNewCallState(); void handleSendingHeaderState(); diff --git a/include/caosdb/info.h b/include/caosdb/info.h index a9e94c1077f809bd5e2e28c225773e91b13a9e98..cf2c879120becd8db211e85df39d62ac9ba1434e 100644 --- a/include/caosdb/info.h +++ b/include/caosdb/info.h @@ -54,21 +54,13 @@ public: * server behind the given connection. */ explicit inline VersionInfo(ProtoVersionInfo *info) : info(info){}; - [[nodiscard]] inline auto GetMajor() const -> int32_t { - return this->info->major(); - } - [[nodiscard]] inline auto GetMinor() const -> int32_t { - return this->info->minor(); - } - [[nodiscard]] inline auto GetPatch() const -> int32_t { - return this->info->patch(); - } + [[nodiscard]] inline auto GetMajor() const -> int32_t { return this->info->major(); } + [[nodiscard]] inline auto GetMinor() const -> int32_t { return this->info->minor(); } + [[nodiscard]] inline auto GetPatch() const -> int32_t { return this->info->patch(); } [[nodiscard]] inline auto GetPreRelease() const -> const std::string & { return this->info->pre_release(); } - [[nodiscard]] inline auto GetBuild() const -> const std::string & { - return this->info->build(); - } + [[nodiscard]] inline auto GetBuild() const -> const std::string & { return this->info->build(); } private: /// This object is the owner of the Protobuf VersionInfo message. diff --git a/include/caosdb/logging.h b/include/caosdb/logging.h index 439eefd41ea0c90f263b095f1033270e3d546e7b..35c5fdfa1a72ba5f55933f3bd99aa93f313c3e33 100644 --- a/include/caosdb/logging.h +++ b/include/caosdb/logging.h @@ -38,8 +38,7 @@ namespace caosdb::logging { const std::string logger_name = "caosdb::logging"; -typedef boost::log::sources::severity_channel_logger_mt<int, std::string> - boost_logger_class; +typedef boost::log::sources::severity_channel_logger_mt<int, std::string> boost_logger_class; BOOST_LOG_GLOBAL_LOGGER(logger, boost_logger_class) @@ -67,8 +66,7 @@ public: virtual ~LoggingConfiguration() = default; LoggingConfiguration(int level); auto AddSink(const std::shared_ptr<SinkConfiguration> &sink) -> void; - auto GetSinks() const - -> const std::vector<std::shared_ptr<SinkConfiguration>> &; + auto GetSinks() const -> const std::vector<std::shared_ptr<SinkConfiguration>> &; private: std::vector<std::shared_ptr<SinkConfiguration>> sinks; @@ -102,8 +100,7 @@ public: [[nodiscard]] virtual auto GetDestination() const -> const std::string & = 0; friend auto initialize_logging_defaults() -> int; - friend auto - initialize_logging(const LoggingConfiguration &logging_configuration) -> void; + friend auto initialize_logging(const LoggingConfiguration &logging_configuration) -> void; protected: virtual auto Configure(boost::log::settings &settings) const -> void; @@ -118,8 +115,7 @@ public: ConsoleSinkConfiguration(const std::string &name, int level); [[nodiscard]] auto GetDestination() const -> const std::string & override; friend auto initialize_logging_defaults() -> int; - friend auto - initialize_logging(const LoggingConfiguration &logging_configuration) -> void; + friend auto initialize_logging(const LoggingConfiguration &logging_configuration) -> void; protected: typedef SinkConfiguration sink_configuration; @@ -139,12 +135,10 @@ class FileSinkConfiguration : public SinkConfiguration { public: virtual ~FileSinkConfiguration() = default; FileSinkConfiguration(const std::string &name, int level); - [[nodiscard]] virtual auto GetDestination() const - -> const std::string & override; + [[nodiscard]] virtual auto GetDestination() const -> const std::string & override; auto SetDirectory(const std::string &directory) -> void; friend auto initialize_logging_defaults() -> int; - friend auto - initialize_logging(const LoggingConfiguration &logging_configuration) -> void; + friend auto initialize_logging(const LoggingConfiguration &logging_configuration) -> void; protected: typedef SinkConfiguration sink_configuration; @@ -159,8 +153,7 @@ class SyslogSinkConfiguration : public SinkConfiguration { public: virtual ~SyslogSinkConfiguration() = default; SyslogSinkConfiguration(const std::string &name, int level); - [[nodiscard]] virtual auto GetDestination() const - -> const std::string & override; + [[nodiscard]] virtual auto GetDestination() const -> const std::string & override; private: const std::string destination = "Syslog"; @@ -193,29 +186,22 @@ 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) -#define CAOSDB_LOG_ERROR(Channel) \ - BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), Channel, \ - CAOSDB_LOG_LEVEL_ERROR) -#define CAOSDB_LOG_WARN(Channel) \ - BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), Channel, \ - CAOSDB_LOG_LEVEL_WARN) -#define CAOSDB_LOG_INFO(Channel) \ - BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), Channel, \ - CAOSDB_LOG_LEVEL_INFO) -#define CAOSDB_LOG_DEBUG(Channel) \ - BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), Channel, \ - CAOSDB_LOG_LEVEL_DEBUG) -#define CAOSDB_LOG_TRACE(Channel) \ - BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), Channel, \ - CAOSDB_LOG_LEVEL_TRACE) - -#define CAOSDB_LOG_ERROR_AND_RETURN_STATUS(Channel, StatusCode, Message) \ - CAOSDB_LOG_ERROR(Channel) \ - << "StatusCode (" << StatusCode << ") " \ - << caosdb::get_status_description(StatusCode) << ": " << Message; \ +#define CAOSDB_LOG_FATAL(Channel) \ + BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), Channel, CAOSDB_LOG_LEVEL_FATAL) +#define CAOSDB_LOG_ERROR(Channel) \ + BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), Channel, CAOSDB_LOG_LEVEL_ERROR) +#define CAOSDB_LOG_WARN(Channel) \ + BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), Channel, CAOSDB_LOG_LEVEL_WARN) +#define CAOSDB_LOG_INFO(Channel) \ + BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), Channel, CAOSDB_LOG_LEVEL_INFO) +#define CAOSDB_LOG_DEBUG(Channel) \ + BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), Channel, CAOSDB_LOG_LEVEL_DEBUG) +#define CAOSDB_LOG_TRACE(Channel) \ + BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), Channel, CAOSDB_LOG_LEVEL_TRACE) + +#define CAOSDB_LOG_ERROR_AND_RETURN_STATUS(Channel, StatusCode, Message) \ + CAOSDB_LOG_ERROR(Channel) << "StatusCode (" << StatusCode << ") " \ + << caosdb::get_status_description(StatusCode) << ": " << Message; \ return StatusCode; #endif diff --git a/include/caosdb/message_code.h b/include/caosdb/message_code.h index 2cc3f516f4e3356d9dfccc9e0435bfdfe2063306..367b5e9be8c43887e85436ac5491545329de9f10 100644 --- a/include/caosdb/message_code.h +++ b/include/caosdb/message_code.h @@ -41,17 +41,16 @@ namespace caosdb::entity { 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, + 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, }; [[nodiscard]] inline auto get_message_code(int code) noexcept -> MessageCode { // TODO(tf) smarter, less forgot-it-prone implementation - static MessageCode all_codes[] = { - MessageCode::UNSPECIFIED, MessageCode::UNKNOWN, - MessageCode::ENTITY_DOES_NOT_EXIST, MessageCode::ENTITY_HAS_NO_PROPERTIES}; + static MessageCode all_codes[] = {MessageCode::UNSPECIFIED, MessageCode::UNKNOWN, + MessageCode::ENTITY_DOES_NOT_EXIST, + MessageCode::ENTITY_HAS_NO_PROPERTIES}; for (MessageCode known_code : all_codes) { if (known_code == code) { diff --git a/include/caosdb/protobuf_helper.h b/include/caosdb/protobuf_helper.h index bd3395f4de7e8cd586a613869e84b1d5ffeb729b..3cfa3d433d540c545fd3d96789e9cec9166022ee 100644 --- a/include/caosdb/protobuf_helper.h +++ b/include/caosdb/protobuf_helper.h @@ -22,14 +22,15 @@ #ifndef CAOSDB_PROTOBUF_HELPER_H #define CAOSDB_PROTOBUF_HELPER_H +#include "caosdb/status_code.h" #include <google/protobuf/arena.h> // for Arena #include <google/protobuf/extension_set.h> // for Arena -#define CAOSDB_DEBUG_MESSAGE_STRING(message, out) \ - std::string out; \ - { \ - google::protobuf::util::JsonOptions options; \ - google::protobuf::util::MessageToJsonString(message, &out, options); \ +#define CAOSDB_DEBUG_MESSAGE_STRING(message, out) \ + std::string out; \ + { \ + google::protobuf::util::JsonOptions options; \ + google::protobuf::util::MessageToJsonString(message, &out, options); \ } namespace caosdb::utility { @@ -38,5 +39,19 @@ using google::protobuf::Arena; auto get_arena() -> Arena *; +template <typename P> class ProtoMessageWrapper { +public: + ProtoMessageWrapper(const ProtoMessageWrapper &other) = default; + inline auto CopyFrom(const ProtoMessageWrapper &other) noexcept -> StatusCode { + this->wrapped->CopyFrom(*other.wrapped); + return StatusCode::SUCCESS; + } + +protected: + ProtoMessageWrapper() : ProtoMessageWrapper(Arena::CreateMessage<P>(get_arena())) {} + ProtoMessageWrapper(P *wrapped) : wrapped(wrapped) {} + P *wrapped; +}; + } // namespace caosdb::utility #endif diff --git a/include/caosdb/status_code.h b/include/caosdb/status_code.h index f996901581f10d3fdadc0137b3b0a3db74348036..573b126fa94435c4669ace37ea00cbdbbbde6545 100644 --- a/include/caosdb/status_code.h +++ b/include/caosdb/status_code.h @@ -54,11 +54,13 @@ enum StatusCode { UNSUPPORTED_FEATURE = 27, ORIGINAL_ENTITY_MISSING_ID = 28, EXTERN_C_ASSIGNMENT_ERROR = 29, - PATH_IS_A_DIRECTORY = 30, - FILE_DOES_NOT_EXIST_LOCALLY = 31, - FILE_UPLOAD_ERROR = 32, - FILE_DOWNLOAD_ERROR = 33, - NOT_A_FILE_ENTITY = 34, + ENTITY_CANNOT_HAVE_A_DATA_TYPE = 30, + ENTITY_CANNOT_HAVE_A_VALUE = 31, + NOT_A_FILE_ENTITY = 32, + PATH_IS_A_DIRECTORY = 33, + FILE_DOES_NOT_EXIST_LOCALLY = 34, + FILE_UPLOAD_ERROR = 35, + FILE_DOWNLOAD_ERROR = 36, OTHER_CLIENT_ERROR = 9999, }; diff --git a/include/caosdb/transaction.h b/include/caosdb/transaction.h index bda5bb355b5dc317e6727c8bcea5ac10450e582f..c994ed65131f4236d872fdf1b0af862128d6c284 100644 --- a/include/caosdb/transaction.h +++ b/include/caosdb/transaction.h @@ -21,20 +21,21 @@ #ifndef CAOSDB_TRANSACTION_H #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/handler_interface.h" // for HandlerInterface -#include "caosdb/transaction_handler.h" // for EntityTransactionHandler -#include "caosdb/logging.h" // for CAOSDB_LOG_ERR... -#include "caosdb/protobuf_helper.h" // for get_arena -#include "caosdb/status_code.h" // for StatusCode -#include "caosdb/transaction_status.h" // for StatusCode -#include <boost/log/core/record.hpp> // for record -#include <boost/log/sources/record_ostream.hpp> // for basic_record_o... +#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/handler_interface.h" // for HandlerInterface +#include "caosdb/transaction_handler.h" // for EntityTransactionHandler +#include "caosdb/logging.h" // for CAOSDB_LOG_ERR... +#include "caosdb/protobuf_helper.h" // for get_arena +#include "caosdb/status_code.h" // for StatusCode +#include "caosdb/transaction_status.h" // for StatusCode +#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 <google/protobuf/arena.h> // for Arena +#include <google/protobuf/generated_message_util.h> // for CreateMessage... #include <google/protobuf/util/json_util.h> // for MessageToJsonS... #include <grpcpp/impl/codegen/completion_queue.h> // for CompletionQueue #include <iterator> // for iterator, next @@ -49,113 +50,109 @@ * Do all necessary checks and assure that another retrieval (by id or by * query) can be added as a sub-request to a transaction. */ -#define ASSERT_CAN_ADD_RETRIEVAL \ - if (!IsStatus(TransactionStatus::INITIAL()) && \ - !IsStatus(TransactionStatus::GO_ON())) { \ - return StatusCode::TRANSACTION_STATUS_ERROR; \ - } \ - switch (this->transaction_type) { \ - case NONE: \ - this->transaction_type = TransactionType::READ_ONLY; \ - break; \ - case READ_ONLY: \ - break; \ - case MIXED_READ_AND_WRITE: \ - break; \ - default: \ - CAOSDB_LOG_ERROR_AND_RETURN_STATUS( \ - logger_name, StatusCode::TRANSACTION_TYPE_ERROR, \ - "You cannot add a retrieval to this transaction because it has the " \ - "wrong TransactionType.") \ +#define ASSERT_CAN_ADD_RETRIEVAL \ + if (!IsStatus(TransactionStatus::INITIAL()) && !IsStatus(TransactionStatus::GO_ON())) { \ + return StatusCode::TRANSACTION_STATUS_ERROR; \ + } \ + switch (this->transaction_type) { \ + case NONE: \ + this->transaction_type = TransactionType::READ_ONLY; \ + break; \ + case READ_ONLY: \ + break; \ + case MIXED_READ_AND_WRITE: \ + break; \ + default: \ + CAOSDB_LOG_ERROR_AND_RETURN_STATUS( \ + logger_name, StatusCode::TRANSACTION_TYPE_ERROR, \ + "You cannot add a retrieval to this transaction because it has the " \ + "wrong TransactionType.") \ } /** * Do all necessary checks and assure that another retrieval (by id or by * query) can be added as a sub-request to a transaction. */ -#define ASSERT_CAN_ADD_QUERY \ - ASSERT_CAN_ADD_RETRIEVAL \ - if (this->has_query) { \ - CAOSDB_LOG_ERROR_AND_RETURN_STATUS( \ - logger_name, StatusCode::UNSUPPORTED_FEATURE, \ - "Currently the number of queries which can be processed in a single " \ - "transaction is limitted to one."); \ +#define ASSERT_CAN_ADD_QUERY \ + ASSERT_CAN_ADD_RETRIEVAL \ + if (this->has_query) { \ + CAOSDB_LOG_ERROR_AND_RETURN_STATUS( \ + logger_name, StatusCode::UNSUPPORTED_FEATURE, \ + "Currently the number of queries which can be processed in a single " \ + "transaction is limitted to one."); \ } /** * Do all necessary checks and assure that another deletion can be added as a * sub-request to a transaction. */ -#define ASSERT_CAN_ADD_DELETION \ - if (!IsStatus(TransactionStatus::INITIAL()) && \ - !IsStatus(TransactionStatus::GO_ON())) { \ - return StatusCode::TRANSACTION_STATUS_ERROR; \ - } \ - switch (this->transaction_type) { \ - case NONE: \ - this->transaction_type = TransactionType::DELETE; \ - case DELETE: \ - case MIXED_WRITE: \ - case MIXED_READ_AND_WRITE: \ - break; \ - default: \ - CAOSDB_LOG_ERROR_AND_RETURN_STATUS( \ - logger_name, StatusCode::TRANSACTION_TYPE_ERROR, \ - "You cannot add a deletion to this transaction because it has the " \ - "wrong TransactionType.") \ +#define ASSERT_CAN_ADD_DELETION \ + if (!IsStatus(TransactionStatus::INITIAL()) && !IsStatus(TransactionStatus::GO_ON())) { \ + return StatusCode::TRANSACTION_STATUS_ERROR; \ + } \ + switch (this->transaction_type) { \ + case NONE: \ + this->transaction_type = TransactionType::DELETE; \ + case DELETE: \ + case MIXED_WRITE: \ + case MIXED_READ_AND_WRITE: \ + break; \ + default: \ + CAOSDB_LOG_ERROR_AND_RETURN_STATUS( \ + logger_name, StatusCode::TRANSACTION_TYPE_ERROR, \ + "You cannot add a deletion to this transaction because it has the " \ + "wrong TransactionType.") \ } /** * Do all necessary checks and assure that another insertion can be added as a * sub-request to a transaction. */ -#define ASSERT_CAN_ADD_INSERTION \ - if (!IsStatus(TransactionStatus::INITIAL()) && \ - !IsStatus(TransactionStatus::GO_ON())) { \ - return StatusCode::TRANSACTION_STATUS_ERROR; \ - } \ - switch (this->transaction_type) { \ - case NONE: \ - this->transaction_type = TransactionType::INSERT; \ - case INSERT: \ - case MIXED_WRITE: \ - case MIXED_READ_AND_WRITE: \ - break; \ - default: \ - CAOSDB_LOG_ERROR_AND_RETURN_STATUS( \ - logger_name, StatusCode::TRANSACTION_TYPE_ERROR, \ - "You cannot add an insertion to this transaction because it has the " \ - "wrong TransactionType.") \ +#define ASSERT_CAN_ADD_INSERTION \ + if (!IsStatus(TransactionStatus::INITIAL()) && !IsStatus(TransactionStatus::GO_ON())) { \ + return StatusCode::TRANSACTION_STATUS_ERROR; \ + } \ + switch (this->transaction_type) { \ + case NONE: \ + this->transaction_type = TransactionType::INSERT; \ + case INSERT: \ + case MIXED_WRITE: \ + case MIXED_READ_AND_WRITE: \ + break; \ + default: \ + CAOSDB_LOG_ERROR_AND_RETURN_STATUS( \ + logger_name, StatusCode::TRANSACTION_TYPE_ERROR, \ + "You cannot add an insertion to this transaction because it has the " \ + "wrong TransactionType.") \ } /** * Do all necessary checks and assure that another update can be added as a * sub-request to a transaction. */ -#define ASSERT_CAN_ADD_UPDATE \ - if (!IsStatus(TransactionStatus::INITIAL()) && \ - !IsStatus(TransactionStatus::GO_ON())) { \ - return StatusCode::TRANSACTION_STATUS_ERROR; \ - } \ - switch (this->transaction_type) { \ - case NONE: \ - this->transaction_type = TransactionType::INSERT; \ - case INSERT: \ - case MIXED_WRITE: \ - case MIXED_READ_AND_WRITE: \ - break; \ - default: \ - CAOSDB_LOG_ERROR_AND_RETURN_STATUS( \ - logger_name, StatusCode::TRANSACTION_TYPE_ERROR, \ - "You cannot add an update to this transaction because it has the " \ - "wrong TransactionType.") \ - } \ - if (!entity->HasId()) { \ - CAOSDB_LOG_ERROR_AND_RETURN_STATUS( \ - logger_name, StatusCode::ORIGINAL_ENTITY_MISSING_ID, \ - "You cannot update this entity without any id. Probably you did not " \ - "retrieve it first? Entity updates should always start with the " \ - "retrieval of the existing entity which may then be changed.") \ +#define ASSERT_CAN_ADD_UPDATE \ + if (!IsStatus(TransactionStatus::INITIAL()) && !IsStatus(TransactionStatus::GO_ON())) { \ + return StatusCode::TRANSACTION_STATUS_ERROR; \ + } \ + switch (this->transaction_type) { \ + case NONE: \ + this->transaction_type = TransactionType::INSERT; \ + case INSERT: \ + case MIXED_WRITE: \ + case MIXED_READ_AND_WRITE: \ + break; \ + default: \ + CAOSDB_LOG_ERROR_AND_RETURN_STATUS( \ + logger_name, StatusCode::TRANSACTION_TYPE_ERROR, \ + "You cannot add an update to this transaction because it has the " \ + "wrong TransactionType.") \ + } \ + if (!entity->HasId()) { \ + CAOSDB_LOG_ERROR_AND_RETURN_STATUS( \ + logger_name, StatusCode::ORIGINAL_ENTITY_MISSING_ID, \ + "You cannot update this entity without any id. Probably you did not " \ + "retrieve it first? Entity updates should always start with the " \ + "retrieval of the existing entity which may then be changed.") \ } /** @@ -219,14 +216,10 @@ private: class AbstractMultiResultSet : public ResultSet { public: virtual ~AbstractMultiResultSet() = default; - inline explicit AbstractMultiResultSet( - std::vector<std::unique_ptr<Entity>> result_set) + inline explicit AbstractMultiResultSet(std::vector<std::unique_ptr<Entity>> result_set) : items(std::move(result_set)) {} - [[nodiscard]] inline auto size() const noexcept -> int override { - return this->items.size(); - } - [[nodiscard]] inline auto at(const int index) const - -> const Entity & override { + [[nodiscard]] inline auto size() const noexcept -> int override { return this->items.size(); } + [[nodiscard]] inline auto at(const int index) const -> const Entity & override { return *(this->items.at(index)); } [[nodiscard]] inline auto mutable_at(int index) const -> Entity * override { @@ -286,8 +279,7 @@ public: * If the file cannot be downloaded due to unsufficient permissions an error * is appended. */ - auto RetrieveAndDownloadFilesById(const std::string &id, - const std::string &local_path) noexcept + auto RetrieveAndDownloadFilesById(const std::string &id, const std::string &local_path) noexcept -> StatusCode; /** @@ -302,8 +294,7 @@ public: * Add all entity ids to this transaction for retrieval. */ template <class InputIterator> - inline auto RetrieveById(InputIterator begin, InputIterator end) noexcept - -> StatusCode; + inline auto RetrieveById(InputIterator begin, InputIterator end) noexcept -> StatusCode; /** * Add a query to this transaction. @@ -369,9 +360,7 @@ public: /** * Return the current status of the transaction. */ - [[nodiscard]] inline auto GetStatus() const noexcept -> TransactionStatus { - return this->status; - } + [[nodiscard]] inline auto GetStatus() const noexcept -> TransactionStatus { return this->status; } [[nodiscard]] inline auto GetResultSet() const noexcept -> const ResultSet & { return *(this->result_set.get()); @@ -384,9 +373,7 @@ public: * this transaction. In all other cases, the return value will be * -1. */ - [[nodiscard]] inline auto GetCountResult() const noexcept -> long { - return query_count; - } + [[nodiscard]] inline auto GetCountResult() const noexcept -> long { return query_count; } /** * Return the number of sub-requests in this transaction. @@ -425,9 +412,7 @@ public: /** * Return the vector which holds all the files which are to be uploaded. */ - inline auto GetUploadFiles() const -> const std::vector<FileDescriptor> & { - return upload_files; - } + inline auto GetUploadFiles() const -> const std::vector<FileDescriptor> & { return upload_files; } protected: /** @@ -463,11 +448,10 @@ private: std::map<std::string, FileDescriptor> download_files; // auto RegisterUploadFile(RegisterFileUploadResponse *response) -> void; - auto UploadFile(FileUploadResponse *response, - const FileDescriptor &file_descriptor, + auto UploadFile(FileUploadResponse *response, const FileDescriptor &file_descriptor, const std::string ®istration_id) -> void; - auto DownloadFile(FileDownloadResponse *response, - const FileTransmissionId &file_transmission_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; @@ -481,8 +465,7 @@ private: }; template <class InputIterator> -inline auto Transaction::RetrieveById(InputIterator begin, - InputIterator end) noexcept +inline auto Transaction::RetrieveById(InputIterator begin, InputIterator end) noexcept -> StatusCode { ASSERT_CAN_ADD_RETRIEVAL diff --git a/include/caosdb/transaction_handler.h b/include/caosdb/transaction_handler.h index 0a7154d03dfbde19284807d1e1f40998c89e1de0..18cb5fcfcaa87a924ff0f36b0c5356d10fc9f70b 100644 --- a/include/caosdb/transaction_handler.h +++ b/include/caosdb/transaction_handler.h @@ -17,14 +17,12 @@ class EntityTransactionHandler final : public UnaryRpcHandler { public: EntityTransactionHandler(HandlerTag tag, EntityTransactionService::Stub *stub, grpc::CompletionQueue *completion_queue, - MultiTransactionRequest *request, - MultiTransactionResponse *response); + MultiTransactionRequest *request, MultiTransactionResponse *response); ~EntityTransactionHandler() override = default; EntityTransactionHandler(const EntityTransactionHandler &) = delete; - EntityTransactionHandler & - operator=(const EntityTransactionHandler &) = delete; + EntityTransactionHandler &operator=(const EntityTransactionHandler &) = delete; EntityTransactionHandler(EntityTransactionHandler &&) = delete; EntityTransactionHandler &operator=(EntityTransactionHandler &&) = delete; @@ -35,8 +33,7 @@ protected: EntityTransactionService::Stub *stub_; - std::unique_ptr<grpc::ClientAsyncResponseReader<MultiTransactionResponse>> - rpc_; + std::unique_ptr<grpc::ClientAsyncResponseReader<MultiTransactionResponse>> rpc_; MultiTransactionRequest *request_; MultiTransactionResponse *response_; diff --git a/include/caosdb/transaction_status.h b/include/caosdb/transaction_status.h index ca40c578bc1c3dd2555ccda97c06b4da726e9c7b..218ac8614ca73ed16d7d15d9793c698a8446c5b9 100644 --- a/include/caosdb/transaction_status.h +++ b/include/caosdb/transaction_status.h @@ -39,11 +39,11 @@ using caosdb::exceptions::TransactionTypeError; /** * Define static factory method in the TransactionStatus class. */ -#define CAOSDB_TRANSACTION_STATUS_DEFAULT_FACTORY(_StatusName, _StatusCode) \ - inline static auto _StatusName()->const TransactionStatus & { \ - static const TransactionStatus instance( \ - _StatusCode, caosdb::get_status_description(_StatusCode)); \ - return instance; \ +#define CAOSDB_TRANSACTION_STATUS_DEFAULT_FACTORY(_StatusName, _StatusCode) \ + inline static auto _StatusName()->const TransactionStatus & { \ + static const TransactionStatus instance(_StatusCode, \ + caosdb::get_status_description(_StatusCode)); \ + return instance; \ } /** @@ -99,25 +99,21 @@ public: * possibly due to misconfiguration of the client, errors in the network or * because the server is down. */ - CAOSDB_TRANSACTION_STATUS_DEFAULT_FACTORY(CONNECTION_ERROR, - StatusCode::CONNECTION_ERROR) + CAOSDB_TRANSACTION_STATUS_DEFAULT_FACTORY(CONNECTION_ERROR, StatusCode::CONNECTION_ERROR) /** * Factory for an AUTHENTICATION_ERROR status. * * This status means that the RPC layer reported an authentication error. */ - CAOSDB_TRANSACTION_STATUS_DEFAULT_FACTORY(AUTHENTICATION_ERROR, - StatusCode::AUTHENTICATION_ERROR) + CAOSDB_TRANSACTION_STATUS_DEFAULT_FACTORY(AUTHENTICATION_ERROR, StatusCode::AUTHENTICATION_ERROR) /** * Another factory for an TRANSACTION_ERROR Status with a detailed * description. */ - inline static auto AUTHENTICATION_ERROR(const std::string &details) - -> const TransactionStatus { - return TransactionStatus( - StatusCode::AUTHENTICATION_ERROR, - caosdb::get_status_description(StatusCode::AUTHENTICATION_ERROR) + - " Original error: " + details); + inline static auto AUTHENTICATION_ERROR(const std::string &details) -> const TransactionStatus { + return TransactionStatus(StatusCode::AUTHENTICATION_ERROR, + caosdb::get_status_description(StatusCode::AUTHENTICATION_ERROR) + + " Original error: " + details); } /** * Factory for a FILE_UPLOAD_ERROR status. @@ -125,49 +121,43 @@ public: * This status means that the transaction failed during the upload of the * file blobs of file entities. */ - CAOSDB_TRANSACTION_STATUS_DEFAULT_FACTORY(FILE_UPLOAD_ERROR, - StatusCode::FILE_UPLOAD_ERROR); + CAOSDB_TRANSACTION_STATUS_DEFAULT_FACTORY(FILE_UPLOAD_ERROR, StatusCode::FILE_UPLOAD_ERROR); /** * Factory for a FILE_DOWN_ERROR status. * * This status means that the transaction failed during the download of the * file blobs of file entities. */ - CAOSDB_TRANSACTION_STATUS_DEFAULT_FACTORY(FILE_DOWNLOAD_ERROR, - StatusCode::FILE_DOWNLOAD_ERROR); + CAOSDB_TRANSACTION_STATUS_DEFAULT_FACTORY(FILE_DOWNLOAD_ERROR, StatusCode::FILE_DOWNLOAD_ERROR); /** * Factory for a TRANSACTION_ERROR status. * * This status means that the transaction failed due to errors thrown by the * server. */ - CAOSDB_TRANSACTION_STATUS_DEFAULT_FACTORY( - TRANSACTION_ERROR, StatusCode::GENERIC_TRANSACTION_ERROR) + CAOSDB_TRANSACTION_STATUS_DEFAULT_FACTORY(TRANSACTION_ERROR, + StatusCode::GENERIC_TRANSACTION_ERROR) /** * Another factory for a TRANSACTION_ERROR status with a detailed * description. */ - inline static auto TRANSACTION_ERROR(const std::string &details) - -> const TransactionStatus { - return TransactionStatus( - StatusCode::GENERIC_TRANSACTION_ERROR, - caosdb::get_status_description(StatusCode::GENERIC_TRANSACTION_ERROR) + - " Original error: " + details); + inline static auto TRANSACTION_ERROR(const std::string &details) -> const TransactionStatus { + return TransactionStatus(StatusCode::GENERIC_TRANSACTION_ERROR, + caosdb::get_status_description(StatusCode::GENERIC_TRANSACTION_ERROR) + + " Original error: " + details); } /** * Factory for a RPC_ERROR with a detailed description. * * This status is used for any error on the RPC layer. */ - inline static auto RPC_ERROR(const std::string &details) - -> const TransactionStatus { + inline static auto RPC_ERROR(const std::string &details) -> const TransactionStatus { // We use the GENERIC_RPC_ERROR here because we might want to add further // RPC_ERROR states with different error codes (which stem from GRPC) here // in the future. - return TransactionStatus( - StatusCode::GENERIC_RPC_ERROR, - caosdb::get_status_description(StatusCode::GENERIC_RPC_ERROR) + - " Original error: " + details); + return TransactionStatus(StatusCode::GENERIC_RPC_ERROR, + caosdb::get_status_description(StatusCode::GENERIC_RPC_ERROR) + + " Original error: " + details); } /** @@ -177,18 +167,16 @@ public: * supposedly do not have a special handling. */ inline static auto GENERIC_ERROR(const std::string &details) { - return TransactionStatus( - StatusCode::GENERIC_ERROR, - caosdb::get_status_description(StatusCode::GENERIC_ERROR) + - "Original error: " + details); + return TransactionStatus(StatusCode::GENERIC_ERROR, + caosdb::get_status_description(StatusCode::GENERIC_ERROR) + + "Original error: " + details); } inline auto ThrowExceptionIfError() const -> void { TransactionStatus::ThrowExceptionIfError(this->code, this->description); } - inline static auto ThrowExceptionIfError(StatusCode code, - const std::string &description) + inline static auto ThrowExceptionIfError(StatusCode code, const std::string &description) -> void { if (!IsError(code)) { return; @@ -222,18 +210,14 @@ public: /** * Return true if this TransactionStatus represents an erroneous state. */ - inline auto IsError() const -> bool { - return TransactionStatus::IsError(this->code); - }; + inline auto IsError() const -> bool { return TransactionStatus::IsError(this->code); }; /** * Return a description of the erroneous state. * * No description yields an empty string. */ - inline auto GetDescription() const -> const std::string & { - return this->description; - } + inline auto GetDescription() const -> const std::string & { return this->description; } /** * Return the status code of the state. diff --git a/include/caosdb/unary_rpc_handler.h b/include/caosdb/unary_rpc_handler.h index 6955504a2baea38cb0bd8075bdca2d20c9f8a52a..0d35eec0f03d546b70ae5c1c59aa057896bb575b 100644 --- a/include/caosdb/unary_rpc_handler.h +++ b/include/caosdb/unary_rpc_handler.h @@ -60,8 +60,7 @@ namespace caosdb::transaction { class UnaryRpcHandler : public HandlerInterface { public: inline UnaryRpcHandler(grpc::CompletionQueue *completion_queue) - : HandlerInterface(), state_(CallState::NewCall), - completion_queue(completion_queue) {} + : HandlerInterface(), state_(CallState::NewCall), completion_queue(completion_queue) {} void Start() override { transaction_status = TransactionStatus::EXECUTING(); diff --git a/include/caosdb/utility.h b/include/caosdb/utility.h index dd53ff952b9737fe76222d998b6813e744b0ad3d..0cadf664346b31f7de19134eed02d13ff148269d 100644 --- a/include/caosdb/utility.h +++ b/include/caosdb/utility.h @@ -21,20 +21,25 @@ #ifndef CAOSDB_UTILS_H #define CAOSDB_UTILS_H +#include "caosdb/entity.h" +#include "caosdb/data_type.h" #include <boost/beast/core/detail/base64.hpp> #include <boost/filesystem.hpp> #include <boost/filesystem/fstream.hpp> #include <boost/filesystem/string_file.hpp> +#include <boost/lexical_cast.hpp> // for lexical_cast #include <boost/json.hpp> #include <cassert> #include <cstdlib> +#include <exception> // for logic_error #include <fstream> #include <iostream> +#include <map> #include <memory> -#include <string> -#include <string_view> #include <mutex> #include <shared_mutex> +#include <string> +#include <string_view> namespace caosdb::utility { using boost::filesystem::exists; @@ -43,6 +48,43 @@ using boost::filesystem::path; using boost::json::stream_parser; using boost::json::value; +/** + * @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."); +} + +// Forward declaration of specializations +template <> +auto getEnumNameFromValue<caosdb::entity::AtomicDataType>(caosdb::entity::AtomicDataType v) + -> std::string; +template <> +auto getEnumNameFromValue<caosdb::entity::Importance>(caosdb::entity::Importance v) -> std::string; +template <> auto getEnumNameFromValue<caosdb::entity::Role>(caosdb::entity::Role v) -> std::string; + +/** + * @brief Get the enum value from a string. + * + * @detail May be useful for higher-order CaosDB clients and only makes sense if specialized. + */ +template <typename Enum> auto getEnumValueFromName(const std::string &name) -> Enum { + throw std::logic_error(std::string("Enum type ") + typeid(Enum).name() + " not implemented."); +} + +// Forward declaration of specializations +template <> +auto getEnumValueFromName<caosdb::entity::AtomicDataType>(const std::string &name) + -> caosdb::entity::AtomicDataType; +template <> +auto getEnumValueFromName<caosdb::entity::Importance>(const std::string &name) + -> caosdb::entity::Importance; +template <> +auto getEnumValueFromName<caosdb::entity::Role>(const std::string &name) -> caosdb::entity::Role; + /** * @brief Read a text file into a string and return the file's content. */ @@ -68,8 +110,7 @@ inline auto get_env_var(const char *key, const char *fallback) -> const char * { * @brief Return the value of an environment variable or - if undefined - the * fallback value. */ -inline auto get_env_var(const std::string &key, const std::string &fallback) - -> const std::string { +inline auto get_env_var(const std::string &key, const std::string &fallback) -> const std::string { const char *val = get_env_var(key.c_str(), fallback.c_str()); auto const result = std::string(val); @@ -84,8 +125,7 @@ inline auto base64_encode(const std::string &plain) -> std::string { 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); + 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); diff --git a/include/caosdb/value.h b/include/caosdb/value.h new file mode 100644 index 0000000000000000000000000000000000000000..989f780ed25a535fb34a97281f55e29c005a6c53 --- /dev/null +++ b/include/caosdb/value.h @@ -0,0 +1,213 @@ +/* + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com> + * Copyright (C) 2021 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/>. + * + */ + +#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 "caosdb/logging.h" +#include <google/protobuf/util/json_util.h> // for MessageToJson... +#include <memory> // for unique_ptr +#include <string> // for string +#include <vector> // for vector + +#define LIST_VALUE_CONSTRUCTOR(TYPE, SETTER) \ + explicit inline Value(const std::vector<TYPE> &values) : ProtoMessageWrapper<ProtoValue>() { \ + for (const auto &value : values) { \ + this->wrapped->mutable_list_values()->add_values()->SETTER(value); \ + } \ + } + +namespace caosdb::entity { +using caosdb::utility::ProtoMessageWrapper; +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; + +class Entity; +class Property; + +// Represents special values which are otherwise hard to tranfer via protobuf. +enum SpecialValue { + // Represent the NULL value. + NULL_VALUE = ProtoSpecialValue::SPECIAL_VALUE_UNSPECIFIED, + // The empty string. + EMPTY_STRING = ProtoSpecialValue::SPECIAL_VALUE_EMPTY_STRING, +}; + +class ScalarValue : public ProtoMessageWrapper<ProtoScalarValue> { +public: + inline ScalarValue(ProtoScalarValue *wrapped) : ProtoMessageWrapper<ProtoScalarValue>(wrapped) {} + + [[nodiscard]] inline auto IsString() const noexcept -> bool { + return (this->wrapped->scalar_value_case() == ScalarValueCase::kStringValue) || + (this->wrapped->scalar_value_case() == ScalarValueCase::kSpecialValue && + this->wrapped->special_value() == ProtoSpecialValue::SPECIAL_VALUE_EMPTY_STRING); + return false; + } + [[nodiscard]] inline auto AsString() const noexcept -> const std::string & { + return this->wrapped->string_value(); + ; + } + + [[nodiscard]] inline auto IsDouble() const noexcept -> bool { + return (this->wrapped->scalar_value_case() == ScalarValueCase::kDoubleValue); + } + [[nodiscard]] inline auto AsDouble() const noexcept -> double { + return this->wrapped->double_value(); + } + + [[nodiscard]] inline auto IsInteger() const noexcept -> bool { + return (this->wrapped->scalar_value_case() == ScalarValueCase::kIntegerValue); + } + [[nodiscard]] inline auto AsInteger() const noexcept -> int64_t { + return this->wrapped->integer_value(); + } + + [[nodiscard]] inline auto IsBool() const noexcept -> bool { + return (this->wrapped->scalar_value_case() == ScalarValueCase::kBooleanValue); + } + [[nodiscard]] inline auto AsBool() const noexcept -> bool { + return this->wrapped->boolean_value(); + } +}; + +class Value : public ProtoMessageWrapper<ProtoValue> { +public: + inline Value() : ProtoMessageWrapper<ProtoValue>() { + // has NULL_VALUE now + } + explicit inline Value(ProtoValue *wrapped) : ProtoMessageWrapper<ProtoValue>(wrapped) {} + explicit inline Value(const std::string &value) : ProtoMessageWrapper<ProtoValue>() { + this->wrapped->mutable_scalar_value()->set_string_value(value); + } + explicit inline Value(const char *value) : ProtoMessageWrapper<ProtoValue>() { + this->wrapped->mutable_scalar_value()->set_string_value(std::string(value)); + } + explicit inline Value(double value) : ProtoMessageWrapper<ProtoValue>() { + this->wrapped->mutable_scalar_value()->set_double_value(value); + } + explicit inline Value(int64_t value) : ProtoMessageWrapper<ProtoValue>() { + this->wrapped->mutable_scalar_value()->set_integer_value(value); + } + explicit inline Value(int value) : Value((int64_t)value) {} + explicit inline Value(bool value) : ProtoMessageWrapper<ProtoValue>() { + this->wrapped->mutable_scalar_value()->set_boolean_value(value); + } + + LIST_VALUE_CONSTRUCTOR(int, set_integer_value) + LIST_VALUE_CONSTRUCTOR(int64_t, set_integer_value) + LIST_VALUE_CONSTRUCTOR(double, set_double_value) + LIST_VALUE_CONSTRUCTOR(std::string, set_string_value) + LIST_VALUE_CONSTRUCTOR(char *, set_string_value) + LIST_VALUE_CONSTRUCTOR(bool, set_boolean_value) + + [[nodiscard]] inline auto IsNull() const noexcept -> bool { + return this->wrapped->value_case() == ValueCase::VALUE_NOT_SET; + } + + [[nodiscard]] inline auto IsString() const noexcept -> bool { + if (this->wrapped->value_case() == ValueCase::kScalarValue) { + + return (this->wrapped->scalar_value().scalar_value_case() == ScalarValueCase::kStringValue) || + (this->wrapped->scalar_value().scalar_value_case() == ScalarValueCase::kSpecialValue && + this->wrapped->scalar_value().special_value() == + ProtoSpecialValue::SPECIAL_VALUE_EMPTY_STRING); + } + return false; + } + [[nodiscard]] inline auto AsString() const noexcept -> const std::string & { + return this->wrapped->scalar_value().string_value(); + ; + } + + [[nodiscard]] inline auto IsDouble() const noexcept -> bool { + if (this->wrapped->value_case() == ValueCase::kScalarValue) { + + return (this->wrapped->scalar_value().scalar_value_case() == ScalarValueCase::kDoubleValue); + } + return false; + } + [[nodiscard]] inline auto AsDouble() const noexcept -> double { + return this->wrapped->scalar_value().double_value(); + } + + [[nodiscard]] inline auto IsInteger() const noexcept -> bool { + if (this->wrapped->value_case() == ValueCase::kScalarValue) { + + return (this->wrapped->scalar_value().scalar_value_case() == ScalarValueCase::kIntegerValue); + } + return false; + } + [[nodiscard]] inline auto AsInteger() const noexcept -> int64_t { + return this->wrapped->scalar_value().integer_value(); + } + + [[nodiscard]] inline auto IsBool() const noexcept -> bool { + if (this->wrapped->value_case() == ValueCase::kScalarValue) { + + return (this->wrapped->scalar_value().scalar_value_case() == ScalarValueCase::kBooleanValue); + } + return false; + } + [[nodiscard]] inline auto AsBool() const noexcept -> bool { + return this->wrapped->scalar_value().boolean_value(); + } + + [[nodiscard]] inline auto IsList() const noexcept -> bool { + return this->wrapped->value_case() == ValueCase::kListValues; + } + [[nodiscard]] inline auto AsList() const noexcept -> const std::vector<ScalarValue> & { + if (!IsList()) { + // create empty list + this->list_values = std::make_unique<std::vector<ScalarValue>>(); + } + if (this->list_values == nullptr) { + this->list_values = std::make_unique<std::vector<ScalarValue>>(); + for (auto &scalar : *(this->wrapped->mutable_list_values()->mutable_values())) { + this->list_values->push_back(ScalarValue(&scalar)); + } + } + return *(this->list_values); + } + + inline auto operator==(const Value &other) const noexcept -> bool { + return this->wrapped->SerializeAsString() == other.wrapped->SerializeAsString(); + } + + inline auto ToString() const noexcept -> const std::string { + CAOSDB_DEBUG_MESSAGE_STRING(*wrapped, out) + CAOSDB_LOG_DEBUG("caosdb::entity") << "HERE 1 [" << wrapped << "] " << out; + return out; + } + + friend class Entity; + friend class Property; + +private: + mutable std::unique_ptr<std::vector<ScalarValue>> list_values; +}; + +} // namespace caosdb::entity + +#endif diff --git a/include/ccaosdb.h b/include/ccaosdb.h index 4597690ee2f77e18b086df702b97642b18d19744..d2f899fd7657fa4c3867f2e008ff9fb270ca8490 100644 --- a/include/ccaosdb.h +++ b/include/ccaosdb.h @@ -137,8 +137,7 @@ int caosdb_connection_create_pem_file_certificate_provider( * * EXPERT USE ONLY. Only use it when you know what you are doing. */ -int caosdb_connection_delete_certificate_provider( - caosdb_connection_certificate_provider *provider); +int caosdb_connection_delete_certificate_provider(caosdb_connection_certificate_provider *provider); /** * Create a tls-secured connection configuration. @@ -153,8 +152,8 @@ int caosdb_connection_delete_certificate_provider( * Only use it when you know what you are doing. */ int caosdb_connection_create_tls_connection_configuration( - caosdb_connection_connection_configuration *out, const char *host, - const int port, caosdb_authentication_authenticator *authenticator, + caosdb_connection_connection_configuration *out, const char *host, const int port, + caosdb_authentication_authenticator *authenticator, caosdb_connection_certificate_provider *provider); /** @@ -173,8 +172,7 @@ int caosdb_connection_create_tls_connection_configuration( * Only use it when you know what you are doing. */ int caosdb_connection_create_insecure_connection_configuration( - caosdb_connection_connection_configuration *out, const char *host, - const int port); + caosdb_connection_connection_configuration *out, const char *host, const int port); /** * Destructor function for the caosdb_connection_connection_configuration @@ -192,8 +190,7 @@ int caosdb_connection_delete_connection_configuration( * @param cacert path to a pem-file. */ int caosdb_connection_configuration_add_cacert( - caosdb_connection_connection_configuration *configuration, - const char *cacert); + caosdb_connection_connection_configuration *configuration, const char *cacert); /** * Create a plain password authenticator. @@ -206,16 +203,14 @@ int caosdb_connection_configuration_add_cacert( * Only use it when you know what you are doing. */ int caosdb_authentication_create_plain_password_authenticator( - caosdb_authentication_authenticator *out, const char *username, - const char *password); + caosdb_authentication_authenticator *out, const char *username, const char *password); /** * Destructor function for the caosdb_authentication_authenticator struct. * * EXPERT USE ONLY. Only use it when you know what you are doing. */ -int caosdb_authentication_delete_authenticator( - caosdb_authentication_authenticator *authenticator); +int caosdb_authentication_delete_authenticator(caosdb_authentication_authenticator *authenticator); /** * Create a connection instance. @@ -239,31 +234,28 @@ int caosdb_connection_create_connection( * * EXPERT USE ONLY. Only use it when you know what you are doing. */ -int caosdb_connection_delete_connection( - caosdb_connection_connection *connection); +int caosdb_connection_delete_connection(caosdb_connection_connection *connection); /** * Request the version of the server. */ -int caosdb_connection_get_version_info( - caosdb_info_version_info *out, - const caosdb_connection_connection *connection); +int caosdb_connection_get_version_info(caosdb_info_version_info *out, + const caosdb_connection_connection *connection); /** * Get the default connection from the ConnectionManager. * * The default connection is to be specified in a configuration file. */ -int caosdb_connection_connection_manager_get_default_connection( - caosdb_connection_connection *out); +int caosdb_connection_connection_manager_get_default_connection(caosdb_connection_connection *out); /** * Get a named connection from the ConnectionManager. * * The named connection is to be specified in a configuration file. */ -int caosdb_connection_connection_manager_get_connection( - caosdb_connection_connection *out, const char *name); +int caosdb_connection_connection_manager_get_connection(caosdb_connection_connection *out, + const char *name); /**************************************************************************** * ENTITY STUFF AND TRANSACTIONS @@ -282,19 +274,16 @@ typedef struct { * This transaction has to be deleted manually by * caosdb_transaction_delete_transaction() later on. */ -int caosdb_connection_connection_create_transaction( - caosdb_connection_connection *connection, - caosdb_transaction_transaction *out); -int caosdb_transaction_delete_transaction( - caosdb_transaction_transaction *transaction); -int caosdb_transaction_transaction_retrieve_by_id( - caosdb_transaction_transaction *transaction, const char *id); -int caosdb_transaction_transaction_retrieve_by_ids( - caosdb_transaction_transaction *transaction, const char *ids[], int length); -int caosdb_transaction_transaction_query( - caosdb_transaction_transaction *transaction, const char *query); -int caosdb_transaction_transaction_execute( - caosdb_transaction_transaction *transaction); +int caosdb_connection_connection_create_transaction(caosdb_connection_connection *connection, + caosdb_transaction_transaction *out); +int caosdb_transaction_delete_transaction(caosdb_transaction_transaction *transaction); +int caosdb_transaction_transaction_retrieve_by_id(caosdb_transaction_transaction *transaction, + const char *id); +int caosdb_transaction_transaction_retrieve_by_ids(caosdb_transaction_transaction *transaction, + const char *ids[], int length); +int caosdb_transaction_transaction_query(caosdb_transaction_transaction *transaction, + const char *query); +int caosdb_transaction_transaction_execute(caosdb_transaction_transaction *transaction); // TODO(fspreck) execute_asynchronously may be added as a separate // function once we actually support asynchronous execution. @@ -303,12 +292,11 @@ typedef struct { bool _deletable = false; } caosdb_transaction_result_set; -int caosdb_transaction_transaction_get_result_set( - caosdb_transaction_transaction *transaction, - caosdb_transaction_result_set *out); +int caosdb_transaction_transaction_get_result_set(caosdb_transaction_transaction *transaction, + caosdb_transaction_result_set *out); -int caosdb_transaction_transaction_get_count_result( - caosdb_transaction_transaction *transaction, long *out); +int caosdb_transaction_transaction_get_count_result(caosdb_transaction_transaction *transaction, + long *out); typedef struct { void *wrapped_entity; @@ -317,8 +305,7 @@ typedef struct { int caosdb_transaction_result_set_at(caosdb_transaction_result_set *result_set, caosdb_entity_entity *entity, int index); -int caosdb_transaction_result_set_size( - caosdb_transaction_result_set *result_set, int *out); +int caosdb_transaction_result_set_size(caosdb_transaction_result_set *result_set, int *out); typedef struct { void *wrapped_property; @@ -337,55 +324,41 @@ typedef struct { int caosdb_entity_entity_get_id(caosdb_entity_entity *entity, char *out); int caosdb_entity_entity_get_role(caosdb_entity_entity *entity, char *out); int caosdb_entity_entity_get_name(caosdb_entity_entity *entity, char *out); -int caosdb_entity_entity_get_description(caosdb_entity_entity *entity, - char *out); +int caosdb_entity_entity_get_description(caosdb_entity_entity *entity, char *out); int caosdb_entity_entity_get_datatype(caosdb_entity_entity *entity, char *out); int caosdb_entity_entity_get_unit(caosdb_entity_entity *entity, char *out); int caosdb_entity_entity_get_value(caosdb_entity_entity *entity, char *out); -int caosdb_entity_entity_get_version_id(caosdb_entity_entity *entity, - char *out); -int caosdb_entity_entity_get_errors_size(caosdb_entity_entity *entity, - int *out); -int caosdb_entity_entity_get_error(caosdb_entity_entity *entity, - caosdb_entity_message *out, int index); -int caosdb_entity_entity_get_warnings_size(caosdb_entity_entity *entity, - int *out); -int caosdb_entity_entity_get_warning(caosdb_entity_entity *entity, - caosdb_entity_message *out, int index); +int caosdb_entity_entity_get_version_id(caosdb_entity_entity *entity, char *out); +int caosdb_entity_entity_get_errors_size(caosdb_entity_entity *entity, int *out); +int caosdb_entity_entity_get_error(caosdb_entity_entity *entity, caosdb_entity_message *out, + int index); +int caosdb_entity_entity_get_warnings_size(caosdb_entity_entity *entity, int *out); +int caosdb_entity_entity_get_warning(caosdb_entity_entity *entity, caosdb_entity_message *out, + int index); int caosdb_entity_entity_get_infos_size(caosdb_entity_entity *entity, int *out); -int caosdb_entity_entity_get_info(caosdb_entity_entity *entity, - caosdb_entity_message *out, int index); -int caosdb_entity_entity_get_properties_size(caosdb_entity_entity *entity, - int *out); -int caosdb_entity_entity_get_property(caosdb_entity_entity *entity, - caosdb_entity_property *out, int index); -int caosdb_entity_entity_get_parents_size(caosdb_entity_entity *entity, - int *out); -int caosdb_entity_entity_get_parent(caosdb_entity_entity *entity, - caosdb_entity_parent *out, int index); +int caosdb_entity_entity_get_info(caosdb_entity_entity *entity, caosdb_entity_message *out, + int index); +int caosdb_entity_entity_get_properties_size(caosdb_entity_entity *entity, int *out); +int caosdb_entity_entity_get_property(caosdb_entity_entity *entity, caosdb_entity_property *out, + int index); +int caosdb_entity_entity_get_parents_size(caosdb_entity_entity *entity, int *out); +int caosdb_entity_entity_get_parent(caosdb_entity_entity *entity, caosdb_entity_parent *out, + int index); int caosdb_entity_property_get_id(caosdb_entity_property *property, char *out); -int caosdb_entity_property_get_name(caosdb_entity_property *property, - char *out); -int caosdb_entity_property_get_description(caosdb_entity_property *property, - char *out); -int caosdb_entity_property_get_importance(caosdb_entity_property *property, - char *out); -int caosdb_entity_property_get_datatype(caosdb_entity_property *property, - char *out); -int caosdb_entity_property_get_unit(caosdb_entity_property *property, - char *out); -int caosdb_entity_property_get_value(caosdb_entity_property *property, - char *out); +int caosdb_entity_property_get_name(caosdb_entity_property *property, char *out); +int caosdb_entity_property_get_description(caosdb_entity_property *property, char *out); +int caosdb_entity_property_get_importance(caosdb_entity_property *property, char *out); +int caosdb_entity_property_get_datatype(caosdb_entity_property *property, char *out); +int caosdb_entity_property_get_unit(caosdb_entity_property *property, char *out); +int caosdb_entity_property_get_value(caosdb_entity_property *property, char *out); int caosdb_entity_parent_get_id(caosdb_entity_parent *parent, char *out); int caosdb_entity_parent_get_name(caosdb_entity_parent *parent, char *out); -int caosdb_entity_parent_get_description(caosdb_entity_parent *parent, - char *out); +int caosdb_entity_parent_get_description(caosdb_entity_parent *parent, char *out); int caosdb_entity_message_get_code(caosdb_entity_message *message, int *out); -int caosdb_entity_message_get_description(caosdb_entity_message *message, - char *out); +int caosdb_entity_message_get_description(caosdb_entity_message *message, char *out); // CONSTRUCTORS AND DESTRUCTORS int caosdb_entity_create_entity(caosdb_entity_entity *out); @@ -396,42 +369,27 @@ int caosdb_entity_create_parent(caosdb_entity_parent *out); int caosdb_entity_delete_parent(caosdb_entity_parent *out); // SETTERS FOR EVERYTHING THAT MAY BE SET -int caosdb_entity_entity_set_role(caosdb_entity_entity *entity, - const char *role); -int caosdb_entity_entity_set_name(caosdb_entity_entity *entity, - const char *name); -int caosdb_entity_entity_set_description(caosdb_entity_entity *entity, - const char *description); -int caosdb_entity_entity_set_datatype(caosdb_entity_entity *entity, - const char *datatype); -int caosdb_entity_entity_set_unit(caosdb_entity_entity *entity, - const char *unit); -int caosdb_entity_entity_set_value(caosdb_entity_entity *entity, - const char *value); -int caosdb_entity_entity_append_parent(caosdb_entity_entity *entity, - caosdb_entity_parent *parent); +int caosdb_entity_entity_set_role(caosdb_entity_entity *entity, const char *role); +int caosdb_entity_entity_set_name(caosdb_entity_entity *entity, const char *name); +int caosdb_entity_entity_set_description(caosdb_entity_entity *entity, const char *description); +int caosdb_entity_entity_set_datatype(caosdb_entity_entity *entity, const char *datatype); +int caosdb_entity_entity_set_unit(caosdb_entity_entity *entity, const char *unit); +int caosdb_entity_entity_set_value(caosdb_entity_entity *entity, const char *value); +int caosdb_entity_entity_append_parent(caosdb_entity_entity *entity, caosdb_entity_parent *parent); int caosdb_entity_entity_remove_parent(caosdb_entity_entity *entity, int index); int caosdb_entity_entity_append_property(caosdb_entity_entity *entity, caosdb_entity_property *property); -int caosdb_entity_entity_remove_property(caosdb_entity_entity *entity, - int index); - -int caosdb_entity_property_set_id(caosdb_entity_property *property, - const char *id); -int caosdb_entity_property_set_name(caosdb_entity_property *property, - const char *name); -int caosdb_entity_property_set_datatype(caosdb_entity_property *property, - const char *datatype); -int caosdb_entity_property_set_importance(caosdb_entity_property *property, - const char *importance); -int caosdb_entity_property_set_unit(caosdb_entity_property *property, - const char *unit); -int caosdb_entity_property_set_value(caosdb_entity_property *property, - const char *value); +int caosdb_entity_entity_remove_property(caosdb_entity_entity *entity, int index); + +int caosdb_entity_property_set_id(caosdb_entity_property *property, const char *id); +int caosdb_entity_property_set_name(caosdb_entity_property *property, const char *name); +int caosdb_entity_property_set_datatype(caosdb_entity_property *property, const char *datatype); +int caosdb_entity_property_set_importance(caosdb_entity_property *property, const char *importance); +int caosdb_entity_property_set_unit(caosdb_entity_property *property, const char *unit); +int caosdb_entity_property_set_value(caosdb_entity_property *property, const char *value); int caosdb_entity_parent_set_id(caosdb_entity_parent *parent, const char *id); -int caosdb_entity_parent_set_name(caosdb_entity_parent *parent, - const char *name); +int caosdb_entity_parent_set_name(caosdb_entity_parent *parent, const char *name); #ifdef __cplusplus } diff --git a/proto b/proto index 485173a714d9ff7c2388945b0a4cad35980cda69..6f81c44a02b9258293bfb83b4de7831ef8d7c4e9 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 485173a714d9ff7c2388945b0a4cad35980cda69 +Subproject commit 6f81c44a02b9258293bfb83b4de7831ef8d7c4e9 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 89180ee81fc6b07d4f081c90fd1200530a2d60b6..cb00898b70776b99c197556c435398d254578cbf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -29,6 +29,7 @@ set(libcaosdb_SRC ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/protobuf_helper.cpp ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/transaction.cpp ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/transaction_handler.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/utility.cpp ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/unary_rpc_handler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/file_transmission/register_file_upload_handler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/file_transmission/upload_request_handler.cpp diff --git a/src/caosdb/authentication.cpp b/src/caosdb/authentication.cpp index a1c84e5b5b04ebc5e0e6909ad4d274f5389117bb..50ff24455ac87227f475775974abae1228fc50d3 100644 --- a/src/caosdb/authentication.cpp +++ b/src/caosdb/authentication.cpp @@ -34,28 +34,28 @@ using grpc::MetadataCredentialsPlugin; using grpc::Status; using grpc::string_ref; -MetadataCredentialsPluginImpl::MetadataCredentialsPluginImpl(std::string key, - std::string value) +MetadataCredentialsPluginImpl::MetadataCredentialsPluginImpl(std::string key, std::string value) : key(std::move(key)), value(std::move(value)) {} -auto MetadataCredentialsPluginImpl::GetMetadata( - string_ref /*service_url*/, string_ref /*method_name*/, - const AuthContext & /*channel_auth_context*/, - std::multimap<grpc::string, grpc::string> *metadata) -> Status { +auto MetadataCredentialsPluginImpl::GetMetadata(string_ref /*service_url*/, + string_ref /*method_name*/, + const AuthContext & /*channel_auth_context*/, + std::multimap<grpc::string, grpc::string> *metadata) + -> Status { metadata->insert(std::make_pair(this->key, this->value)); return Status::OK; } -PlainPasswordAuthenticator::PlainPasswordAuthenticator( - const std::string &username, const std::string &password) { +PlainPasswordAuthenticator::PlainPasswordAuthenticator(const std::string &username, + const std::string &password) { this->basic = "Basic " + base64_encode(username + ":" + password); } auto PlainPasswordAuthenticator::GetCallCredentials() const -> std::shared_ptr<grpc::CallCredentials> { - auto call_creds = grpc::MetadataCredentialsFromPlugin( - std::unique_ptr<grpc::MetadataCredentialsPlugin>( + auto call_creds = + grpc::MetadataCredentialsFromPlugin(std::unique_ptr<grpc::MetadataCredentialsPlugin>( new MetadataCredentialsPluginImpl("authentication", this->basic))); return call_creds; } diff --git a/src/caosdb/configuration.cpp b/src/caosdb/configuration.cpp index 5ebda79ff7e8f8cc59a72f19a8ec4970ace5c1b4..edce302e00bcb5645d734e2ff577be23d0a8bd67 100644 --- a/src/caosdb/configuration.cpp +++ b/src/caosdb/configuration.cpp @@ -75,8 +75,7 @@ auto PemFileCertificateProvider::GetCertificatePem() const -> std::string { return this->certificate_provider; } -PemCertificateProvider::PemCertificateProvider( - const std::string &certificate_provider) { +PemCertificateProvider::PemCertificateProvider(const std::string &certificate_provider) { this->certificate_provider = certificate_provider; } @@ -84,26 +83,21 @@ auto PemCertificateProvider::GetCertificatePem() const -> std::string { return this->certificate_provider; } -ConnectionConfiguration::ConnectionConfiguration(const std::string &host, - int port) { +ConnectionConfiguration::ConnectionConfiguration(const std::string &host, int port) { this->host = host; this->port = port; } -auto ConnectionConfiguration::GetHost() const -> std::string { - return this->host; -} +auto ConnectionConfiguration::GetHost() const -> std::string { return this->host; } auto ConnectionConfiguration::GetPort() const -> int { return this->port; } -auto operator<<(std::ostream &out, const ConnectionConfiguration &configuration) - -> std::ostream & { +auto operator<<(std::ostream &out, const ConnectionConfiguration &configuration) -> std::ostream & { out << configuration.ToString(); return out; } -InsecureConnectionConfiguration::InsecureConnectionConfiguration( - const std::string &host, int port) +InsecureConnectionConfiguration::InsecureConnectionConfiguration(const std::string &host, int port) : ConnectionConfiguration(host, port) { this->credentials = InsecureChannelCredentials(); } @@ -118,41 +112,38 @@ auto InsecureConnectionConfiguration::ToString() const -> std::string { std::to_string(this->GetPort()) + ")"; } -TlsConnectionConfiguration::TlsConnectionConfiguration(const std::string &host, - int port) +TlsConnectionConfiguration::TlsConnectionConfiguration(const std::string &host, int port) : ConnectionConfiguration(host, port) { SslCredentialsOptions options; this->credentials = SslCredentials(options); } TlsConnectionConfiguration::TlsConnectionConfiguration( - const std::string &host, int port, - const CertificateProvider &certificate_provider) + const std::string &host, int port, const CertificateProvider &certificate_provider) : ConnectionConfiguration(host, port) { SslCredentialsOptions options; options.pem_root_certs = certificate_provider.GetCertificatePem(); this->credentials = SslCredentials(options); } -TlsConnectionConfiguration::TlsConnectionConfiguration( - const std::string &host, int port, const Authenticator &authenticator) +TlsConnectionConfiguration::TlsConnectionConfiguration(const std::string &host, int port, + const Authenticator &authenticator) : ConnectionConfiguration(host, port) { SslCredentialsOptions options; - this->credentials = grpc::CompositeChannelCredentials( - SslCredentials(options), authenticator.GetCallCredentials()); + this->credentials = + grpc::CompositeChannelCredentials(SslCredentials(options), authenticator.GetCallCredentials()); } TlsConnectionConfiguration::TlsConnectionConfiguration( - const std::string &host, int port, - const CertificateProvider &certificate_provider, + const std::string &host, int port, const CertificateProvider &certificate_provider, const Authenticator &authenticator) : ConnectionConfiguration(host, port) { SslCredentialsOptions options; options.pem_root_certs = certificate_provider.GetCertificatePem(); - this->credentials = grpc::CompositeChannelCredentials( - SslCredentials(options), authenticator.GetCallCredentials()); + this->credentials = + grpc::CompositeChannelCredentials(SslCredentials(options), authenticator.GetCallCredentials()); } auto TlsConnectionConfiguration::GetChannelCredentials() const @@ -161,31 +152,29 @@ auto TlsConnectionConfiguration::GetChannelCredentials() const } auto TlsConnectionConfiguration::ToString() const -> std::string { - return "TlsConnectionConfiguration(" + this->GetHost() + "," + - std::to_string(this->GetPort()) + "," + this->certificate_provider + - ")"; + return "TlsConnectionConfiguration(" + this->GetHost() + "," + std::to_string(this->GetPort()) + + "," + this->certificate_provider + ")"; } -auto ConnectionConfigurationHelper::CreateCertificateProvider( - const object &from) const -> std::unique_ptr<CertificateProvider> { +auto ConnectionConfigurationHelper::CreateCertificateProvider(const object &from) const + -> 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"); assert(path_str.is_string() == true); const path certificate_file = path(path_str.as_string().c_str()); if (!exists(certificate_file)) { - throw ConfigurationError( - "File does not exist (server_certificate_path): " + - certificate_file.string()); + throw ConfigurationError("File does not exist (server_certificate_path): " + + certificate_file.string()); } - certificate_provider = std::make_unique<PemFileCertificateProvider>( - path(path_str.as_string().c_str())); + certificate_provider = + std::make_unique<PemFileCertificateProvider>(path(path_str.as_string().c_str())); } return certificate_provider; } -auto ConnectionConfigurationHelper::CreateAuthenticator( - const object &from) const -> std::unique_ptr<Authenticator> { +auto ConnectionConfigurationHelper::CreateAuthenticator(const object &from) const + -> std::unique_ptr<Authenticator> { std::unique_ptr<Authenticator> authenticator; if (from.contains("authentication")) { assert(from.at("authentication").is_object()); @@ -205,8 +194,7 @@ auto ConnectionConfigurationHelper::CreateAuthenticator( assert(password.is_string()); authenticator = std::make_unique<PlainPasswordAuthenticator>( - std::string(username.as_string().c_str()), - std::string(password.as_string().c_str())); + std::string(username.as_string().c_str()), std::string(password.as_string().c_str())); } else { throw ConfigurationError("Unknow authentication type: '" + type + "'."); } @@ -216,22 +204,19 @@ auto ConnectionConfigurationHelper::CreateAuthenticator( auto ConnectionConfigurationHelper::CreateConnectionConfiguration( const bool tls, const std::string &host, const int port, - const CertificateProvider *certificate_provider, - const Authenticator *authenticator) const + const CertificateProvider *certificate_provider, const Authenticator *authenticator) const -> std::unique_ptr<ConnectionConfiguration> { if (tls) { if (certificate_provider != nullptr && authenticator != nullptr) { // authenticated and special certificate - return std::make_unique<TlsConnectionConfiguration>( - host, port, *certificate_provider, *authenticator); + return std::make_unique<TlsConnectionConfiguration>(host, port, *certificate_provider, + *authenticator); } else if (certificate_provider != nullptr) { // unauthenticated, special certificate - return std::make_unique<TlsConnectionConfiguration>( - host, port, *certificate_provider); + return std::make_unique<TlsConnectionConfiguration>(host, port, *certificate_provider); } else if (authenticator != nullptr) { // authenticated, no special certificate - return std::make_unique<TlsConnectionConfiguration>(host, port, - *authenticator); + return std::make_unique<TlsConnectionConfiguration>(host, port, *authenticator); } // unauthenticated, no special certificate return std::make_unique<TlsConnectionConfiguration>(host, port); @@ -250,8 +235,8 @@ auto ConnectionConfigurationHelper::IsTls(const object &from) const -> bool { return tls; } -auto ConnectionConfigurationHelper::CreateConnectionConfiguration( - const object &from) const -> std::unique_ptr<ConnectionConfiguration> { +auto ConnectionConfigurationHelper::CreateConnectionConfiguration(const object &from) const + -> std::unique_ptr<ConnectionConfiguration> { assert(from.contains("host")); const auto &host = from.at("host"); assert(host.is_string()); @@ -266,28 +251,30 @@ auto ConnectionConfigurationHelper::CreateConnectionConfiguration( auto authenticator = CreateAuthenticator(from); - return CreateConnectionConfiguration( - tls, std::string(host.as_string().c_str()), - static_cast<int>(port.as_int64()), certificate_provider.get(), - authenticator.get()); + return CreateConnectionConfiguration(tls, std::string(host.as_string().c_str()), + static_cast<int>(port.as_int64()), + certificate_provider.get(), authenticator.get()); } -auto LoggingConfigurationHelper::CreateConsoleSinkConfiguration( - const object & /*from*/, const std::string &name, int level) const +auto LoggingConfigurationHelper::CreateConsoleSinkConfiguration(const object & /*from*/, + const std::string &name, + int level) const -> 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 LoggingConfigurationHelper::CreateSyslogSinkConfiguration(const object & /*from*/, + const std::string &name, + int level) const -> 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 LoggingConfigurationHelper::CreateFileSinkConfiguration(const object &from, + const std::string &name, + int level) const -> std::shared_ptr<caosdb::logging::SinkConfiguration> { auto result = std::make_shared<FileSinkConfiguration>(name, level); if (from.contains("directory")) { @@ -296,16 +283,15 @@ auto LoggingConfigurationHelper::CreateFileSinkConfiguration( return result; } -auto LoggingConfigurationHelper::CreateSinkConfiguration( - const object &from, const std::string &name, int default_level) const +auto LoggingConfigurationHelper::CreateSinkConfiguration(const object &from, + const std::string &name, + int default_level) const -> std::shared_ptr<caosdb::logging::SinkConfiguration> { assert(from.contains("destination")); - const auto &destination = - std::string(from.at("destination").as_string().c_str()); + const auto &destination = std::string(from.at("destination").as_string().c_str()); - int level = from.contains("level") - ? ConvertLogLevel(from.at("level").as_string().c_str()) - : default_level; + int level = + from.contains("level") ? ConvertLogLevel(from.at("level").as_string().c_str()) : default_level; if (destination == "file") { return CreateFileSinkConfiguration(from, name, level); @@ -318,8 +304,7 @@ auto LoggingConfigurationHelper::CreateSinkConfiguration( } } -auto LoggingConfigurationHelper::ConvertLogLevel( - const std::string &string_level) const -> int { +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}, @@ -333,11 +318,10 @@ auto LoggingConfigurationHelper::ConvertLogLevel( } } -auto LoggingConfigurationHelper::CreateLoggingConfiguration( - const object &from) const -> LoggingConfiguration { - auto default_level_str = from.contains("level") - ? std::string(from.at("level").as_string().c_str()) - : ""; +auto LoggingConfigurationHelper::CreateLoggingConfiguration(const object &from) const + -> LoggingConfiguration { + auto default_level_str = + from.contains("level") ? std::string(from.at("level").as_string().c_str()) : ""; int default_level = ConvertLogLevel(default_level_str); auto result = LoggingConfiguration(default_level); @@ -351,8 +335,8 @@ auto LoggingConfigurationHelper::CreateLoggingConfiguration( const auto *elem = sinks.begin(); while (elem != sinks.end()) { - result.AddSink(CreateSinkConfiguration( - elem->value().as_object(), elem->key().to_string(), default_level)); + result.AddSink(CreateSinkConfiguration(elem->value().as_object(), elem->key().to_string(), + default_level)); elem = std::next(elem); } } @@ -369,9 +353,8 @@ auto ConfigurationManager::mReset() noexcept -> int { } catch (const caosdb::exceptions::Exception &exc) { return exc.GetCode(); } catch (const std::exception &exc) { - CAOSDB_LOG_ERROR(logger_name) - << "Unknown error during the reset of the ConfigurationManager: " - << exc.what(); + CAOSDB_LOG_ERROR(logger_name) << "Unknown error during the reset of the ConfigurationManager: " + << exc.what(); return StatusCode::CONFIGURATION_ERROR; } } @@ -384,15 +367,13 @@ auto ConfigurationManager::mClear() noexcept -> int { } catch (const caosdb::exceptions::Exception &exc) { return exc.GetCode(); } catch (const std::exception &exc) { - CAOSDB_LOG_ERROR(logger_name) - << "Unknown error during the reset of the ConfigurationManager: " - << exc.what(); + CAOSDB_LOG_ERROR(logger_name) << "Unknown error during the reset of the ConfigurationManager: " + << exc.what(); return StatusCode::CONFIGURATION_ERROR; } } -auto ConfigurationManager::mLoadSingleJSONConfiguration(const path &json_file) - -> void { +auto ConfigurationManager::mLoadSingleJSONConfiguration(const path &json_file) -> void { if (!json_configuration.is_null()) { throw ConfigurationError("This CaosDB client has already been configured."); } @@ -403,11 +384,10 @@ auto ConfigurationManager::mLoadSingleJSONConfiguration(const path &json_file) json_configuration = load_json_file(json_file); } -auto ConfigurationManager::mGetConnectionConfiguration( - const std::string &name) const -> std::unique_ptr<ConnectionConfiguration> { +auto ConfigurationManager::mGetConnectionConfiguration(const std::string &name) const + -> std::unique_ptr<ConnectionConfiguration> { auto connection_json = GetConnection(name); - return connection_configuration_helper.CreateConnectionConfiguration( - connection_json); + return connection_configuration_helper.CreateConnectionConfiguration(connection_json); } auto ConfigurationManager::mGetDefaultConnectionName() const -> std::string { @@ -442,33 +422,28 @@ auto ConfigurationManager::GetConfiguration() const -> const 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."); + 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."); + 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."); + throw ConfigurationError("This CaosDB client hasn't any configured connections."); } return connections_object; } -auto ConfigurationManager::GetConnection(const std::string &name) const - -> const 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."); + throw ConfigurationError("The connection '" + name + "' has not been defined."); } // TODO(tf) This has apparently a cognitive complexity of 34>25 (threshold). @@ -476,13 +451,11 @@ auto ConfigurationManager::InitializeDefaults() -> int { // NOLINT // find the configuration file... std::unique_ptr<path> configuration_file_path; - for (const char *const &configuration_file : - caosdb::LIBCAOSDB_CONFIGURATION_FILES_PRECEDENCE) { + for (const char *const &configuration_file : caosdb::LIBCAOSDB_CONFIGURATION_FILES_PRECEDENCE) { if (strcmp(configuration_file, "$CAOSDB_CLIENT_CONFIGURATION") == 0) { // user specified a file via the environment variable // TODO(tf) make this thread-secure (concurrency-mt-unsafe) - const auto *from_env_var = - getenv("CAOSDB_CLIENT_CONFIGURATION"); // NOLINT + const auto *from_env_var = getenv("CAOSDB_CLIENT_CONFIGURATION"); // NOLINT if (from_env_var != nullptr) { configuration_file_path = std::make_unique<path>(from_env_var); if (exists(*configuration_file_path)) { @@ -532,10 +505,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.is_object()) { + CAOSDB_LOG_INFO(logger_name) << "Loaded configuration from " << *(configuration_file_path.get()) + << "."; } return 0; diff --git a/src/caosdb/connection.cpp b/src/caosdb/connection.cpp index b43444ce085d262a0ed8e960001e31c8da1a0124..d6782f8ffa42238888998bdff65dc666fbf55c18 100644 --- a/src/caosdb/connection.cpp +++ b/src/caosdb/connection.cpp @@ -48,17 +48,14 @@ using caosdb::transaction::TransactionStatus; Connection::Connection(const ConnectionConfiguration &configuration) { const std::string target = configuration.GetHost() + ":" + std::to_string(configuration.GetPort()); - this->channel = - grpc::CreateChannel(target, configuration.GetChannelCredentials()); + this->channel = grpc::CreateChannel(target, configuration.GetChannelCredentials()); this->general_info_service = GeneralInfoService::NewStub(this->channel); this->entity_transaction_service = std::make_shared<EntityTransactionService::Stub>(this->channel); - this->file_transmission_service = - std::make_shared<FileTransmissionService::Stub>(this->channel); + this->file_transmission_service = std::make_shared<FileTransmissionService::Stub>(this->channel); } -auto Connection::RetrieveVersionInfoNoExceptions() const noexcept - -> TransactionStatus { +auto Connection::RetrieveVersionInfoNoExceptions() const noexcept -> TransactionStatus { const GetVersionInfoRequest request; GetVersionInfoResponse response; @@ -70,20 +67,18 @@ auto Connection::RetrieveVersionInfoNoExceptions() const noexcept if (!grpc_status.ok()) { switch (grpc_status.error_code()) { case grpc::StatusCode::UNAUTHENTICATED: - status = - TransactionStatus::AUTHENTICATION_ERROR(grpc_status.error_message()); + status = TransactionStatus::AUTHENTICATION_ERROR(grpc_status.error_message()); break; case grpc::StatusCode::UNAVAILABLE: status = TransactionStatus::CONNECTION_ERROR(); break; default: auto error_message = grpc_status.error_message(); - status = TransactionStatus::RPC_ERROR( - std::to_string(grpc_status.error_code()) + " - " + error_message); + status = TransactionStatus::RPC_ERROR(std::to_string(grpc_status.error_code()) + " - " + + error_message); } } else { - this->version_info = - std::make_unique<VersionInfo>(response.release_version_info()); + this->version_info = std::make_unique<VersionInfo>(response.release_version_info()); } return status; @@ -96,8 +91,7 @@ auto Connection::RetrieveVersionInfo() const -> const VersionInfo & { return *GetVersionInfo(); } -[[nodiscard]] auto Connection::CreateTransaction() const - -> std::unique_ptr<Transaction> { +[[nodiscard]] auto Connection::CreateTransaction() const -> std::unique_ptr<Transaction> { auto entity_service = this->entity_transaction_service; auto file_service = this->file_transmission_service; return std::make_unique<Transaction>(entity_service, file_service); @@ -115,19 +109,17 @@ 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::UnknownConnectionError("No connection named '" + name + + "' present."); } } return this->connections.at(name); } -auto ConnectionManager::mGetDefaultConnection() const - -> const std::shared_ptr<Connection> & { +auto ConnectionManager::mGetDefaultConnection() const -> const std::shared_ptr<Connection> & { if (!HasConnection(default_connection_name)) { default_connection_name = ConfigurationManager::GetDefaultConnectionName(); - auto default_connection = - ConfigurationManager::GetDefaultConnectionConfiguration(); + auto default_connection = ConfigurationManager::GetDefaultConnectionConfiguration(); connections[default_connection_name] = std::make_shared<Connection>(*default_connection.release()); } diff --git a/src/caosdb/entity.cpp b/src/caosdb/entity.cpp index 8f410a3c6c454375fe827ba8058e20423ef9ccce..16ea5dbfc99b173efdac9bdbbfe0d87a2e289fee 100644 --- a/src/caosdb/entity.cpp +++ b/src/caosdb/entity.cpp @@ -20,16 +20,21 @@ * */ #include "caosdb/entity.h" -#include "caosdb/entity/v1alpha1/main.pb.h" // for RepeatedPtrField, Property -#include "caosdb/protobuf_helper.h" // for get_arena -#include <google/protobuf/arena.h> // for Arena -#include <new> // for operator new +#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 <google/protobuf/generated_message_util.h> // for Arena::Create... +#include <new> // for operator new namespace caosdb::entity { using caosdb::entity::v1alpha1::IdResponse; 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 caosdb::utility::get_arena; @@ -49,33 +54,25 @@ auto Parent::CreateProtoParent() -> ProtoParent * { return Arena::CreateMessage<ProtoParent>(get_arena()); } -auto Parent::SetName(const std::string &name) -> void { - this->wrapped->set_name(name); -} +auto Parent::SetName(const std::string &name) -> void { this->wrapped->set_name(name); } auto Parent::SetId(const std::string &id) -> void { this->wrapped->set_id(id); } -[[nodiscard]] auto Parent::GetId() const -> const std::string & { - return this->wrapped->id(); -} +[[nodiscard]] auto Parent::GetId() const -> const std::string & { return this->wrapped->id(); } -[[nodiscard]] auto Parent::GetName() const -> const std::string & { - return this->wrapped->name(); -} +[[nodiscard]] auto Parent::GetName() const -> const std::string & { return this->wrapped->name(); } [[nodiscard]] auto Parent::GetDescription() const -> const std::string & { return this->wrapped->description(); } -Property::Property() : wrapped(Property::CreateProtoProperty()) {} +Property::Property() : Property(Property::CreateProtoProperty()) {} auto Property::CreateProtoProperty() -> ProtoProperty * { return Arena::CreateMessage<ProtoProperty>(get_arena()); } -[[nodiscard]] auto Property::GetId() const -> const std::string & { - return this->wrapped->id(); -} +[[nodiscard]] auto Property::GetId() const -> const std::string & { return this->wrapped->id(); } [[nodiscard]] auto Property::GetName() const -> const std::string & { return this->wrapped->name(); @@ -85,87 +82,104 @@ auto Property::CreateProtoProperty() -> ProtoProperty * { return this->wrapped->description(); } -[[nodiscard]] auto Property::GetImportance() const -> const std::string & { - return this->wrapped->importance(); +[[nodiscard]] auto Property::GetImportance() const -> Importance { + return static_cast<Importance>(this->wrapped->importance()); } -[[nodiscard]] auto Property::GetValue() const -> const std::string & { - return this->wrapped->value(); -} +[[nodiscard]] auto Property::GetValue() const -> const Value & { return this->value; } [[nodiscard]] auto Property::GetUnit() const -> const std::string & { return this->wrapped->unit(); } -[[nodiscard]] auto Property::GetDatatype() const -> const std::string & { - return this->wrapped->datatype(); -} +[[nodiscard]] auto Property::GetDataType() const -> const DataType & { return this->data_type; } -auto Property::SetId(const std::string &id) -> void { - this->wrapped->set_id(id); -} +auto Property::SetId(const std::string &id) -> void { this->wrapped->set_id(id); } -auto Property::SetName(const std::string &name) -> void { - this->wrapped->set_name(name); -} +auto Property::SetName(const std::string &name) -> void { this->wrapped->set_name(name); } auto Property::SetDescription(const std::string &description) -> void { this->wrapped->set_description(description); } -auto Property::SetImportance(const std::string &importance) -> void { - this->wrapped->set_importance(importance); +auto Property::SetImportance(Importance importance) -> void { + this->wrapped->set_importance(static_cast<ProtoImportance>(importance)); } -auto Property::SetValue(const std::string &value) -> void { - this->wrapped->set_value(value); +auto Property::SetValue(const Value &value) -> StatusCode { return this->value.CopyFrom(value); } + +auto Property::SetValue(const std::string &value) -> StatusCode { return SetValue(Value(value)); } + +auto Property::SetValue(const char *value) -> StatusCode { return SetValue(Value(value)); } + +auto Property::SetValue(double value) -> StatusCode { return SetValue(Value(value)); } + +auto Property::SetValue(const std::vector<std::string> &values) -> StatusCode { + return SetValue(Value(values)); } -auto Property::SetUnit(const std::string &unit) -> void { - this->wrapped->set_unit(unit); +auto Property::SetValue(const std::vector<char *> &values) -> StatusCode { + return SetValue(Value(values)); } -auto Property::SetDatatype(const std::string &datatype) -> void { - this->wrapped->set_datatype(datatype); +auto Property::SetValue(const std::vector<int64_t> &values) -> StatusCode { + return SetValue(Value(values)); } -[[nodiscard]] auto Entity::GetParents() const -> const Parents & { - return parents; +auto Property::SetValue(const std::vector<double> &values) -> StatusCode { + return SetValue(Value(values)); } -auto Entity::AppendParent(const Parent &parent) -> void { - this->parents.Append(parent); +auto Property::SetValue(const std::vector<bool> &values) -> StatusCode { + return SetValue(Value(values)); } -auto Entity::RemoveParent(int index) -> void { this->parents.remove(index); } +auto Property::SetValue(const int64_t value) -> StatusCode { return SetValue(Value(value)); } + +auto Property::SetValue(const bool value) -> StatusCode { return SetValue(Value(value)); } -[[nodiscard]] auto Entity::GetProperties() const -> const Properties & { - return properties; +auto Property::SetUnit(const std::string &unit) -> void { this->wrapped->set_unit(unit); } + +auto Property::SetDataType(const DataType &new_data_type) -> StatusCode { + return this->data_type.CopyFrom(new_data_type); } -auto Entity::AppendProperty(const Property &property) -> void { - this->properties.Append(property); +auto Property::SetDataType(const AtomicDataType new_data_type, bool list_type) -> StatusCode { + return SetDataType(DataType(new_data_type, list_type)); } -auto Entity::RemoveProperty(int index) -> void { - this->properties.remove(index); +auto Property::SetDataType(const std::string &new_data_type, bool list_type) -> StatusCode { + return SetDataType(DataType(new_data_type, list_type)); } +[[nodiscard]] auto Entity::GetParents() const -> const Parents & { return parents; } + +auto Entity::AppendParent(const Parent &parent) -> void { this->parents.Append(parent); } + +auto Entity::RemoveParent(int index) -> void { this->parents.Remove(index); } + +[[nodiscard]] auto Entity::GetProperties() const -> const Properties & { return properties; } + +auto Entity::AppendProperty(const Property &property) -> void { this->properties.Append(property); } + +auto Entity::RemoveProperty(int index) -> void { this->properties.Remove(index); } + auto Entity::CreateProtoEntity() -> ProtoEntity * { return Arena::CreateMessage<ProtoEntity>(get_arena()); } -auto Entity::CreateMessagesField() -> RepeatedPtrField<ProtoMessage> * { - return Arena::CreateMessage<RepeatedPtrField<ProtoMessage>>(get_arena()); +Entity::Entity(IdResponse *id_response) : Entity() { + this->wrapped->set_id(id_response->id()); + this->wrapped->mutable_version()->Swap(id_response->mutable_version()); + this->errors.wrapped->Swap(id_response->mutable_errors()); + this->warnings.wrapped->Swap(id_response->mutable_warnings()); + this->infos.wrapped->Swap(id_response->mutable_infos()); } Entity::Entity() : Entity(Entity::CreateProtoEntity()) {} -Entity::Entity(IdResponse *idResponse) : Entity() { - this->wrapped->set_id(idResponse->id()); - this->errors.wrapped->Swap(idResponse->mutable_errors()); - this->warnings.wrapped->Swap(idResponse->mutable_warnings()); - this->infos.wrapped->Swap(idResponse->mutable_infos()); +auto Entity::CreateMessagesField() -> RepeatedPtrField<ProtoMessage> * { + return Arena::CreateMessage<RepeatedPtrField<ProtoMessage>>(get_arena()); } auto Entity::SetId(const std::string &id) -> void { this->wrapped->set_id(id); } @@ -174,32 +188,68 @@ auto Entity::SetVersionId(const std::string &id) -> void { this->wrapped->mutable_version()->set_id(id); } -auto Entity::CopyTo(ProtoEntity *target) -> void { - target->CopyFrom(*(this->wrapped)); +auto Entity::CopyTo(ProtoEntity *target) -> void { target->CopyFrom(*(this->wrapped)); } + +auto Entity::SetRole(Role role) -> void { this->wrapped->set_role(static_cast<EntityRole>(role)); } + +auto Entity::SetName(const std::string &name) -> void { this->wrapped->set_name(name); } + +auto Entity::SetDescription(const std::string &description) -> void { + this->wrapped->set_description(description); +} + +auto Entity::SetValue(const Value &value) -> StatusCode { + if (GetRole() != Role::PROPERTY) { + return StatusCode::ENTITY_CANNOT_HAVE_A_VALUE; + } + return this->value.CopyFrom(value); +} + +auto Entity::SetValue(const std::string &value) -> StatusCode { return SetValue(Value(value)); } + +auto Entity::SetValue(const char *value) -> StatusCode { return SetValue(Value(value)); } + +auto Entity::SetValue(double value) -> StatusCode { return SetValue(Value(value)); } + +auto Entity::SetValue(const std::vector<std::string> &values) -> StatusCode { + return SetValue(Value(values)); } -auto Entity::SetRole(const std::string &role) -> void { - this->wrapped->set_role(role); +auto Entity::SetValue(const std::vector<char *> &values) -> StatusCode { + return SetValue(Value(values)); } -auto Entity::SetName(const std::string &name) -> void { - this->wrapped->set_name(name); +auto Entity::SetValue(const std::vector<int64_t> &values) -> StatusCode { + return SetValue(Value(values)); } -auto Entity::SetDescription(const std::string &description) -> void { - this->wrapped->set_description(description); +auto Entity::SetValue(const std::vector<double> &values) -> StatusCode { + return SetValue(Value(values)); } -auto Entity::SetValue(const std::string &value) -> void { - this->wrapped->set_value(value); +auto Entity::SetValue(const std::vector<bool> &values) -> StatusCode { + return SetValue(Value(values)); +} + +auto Entity::SetValue(const int64_t value) -> StatusCode { return SetValue(Value(value)); } + +auto Entity::SetValue(const bool value) -> StatusCode { return SetValue(Value(value)); } + +auto Entity::SetUnit(const std::string &unit) -> void { this->wrapped->set_unit(unit); } + +auto Entity::SetDataType(const DataType &new_data_type) -> StatusCode { + if (GetRole() != Role::PROPERTY) { + return StatusCode::ENTITY_CANNOT_HAVE_A_DATA_TYPE; + } + return this->data_type.CopyFrom(new_data_type); } -auto Entity::SetUnit(const std::string &unit) -> void { - this->wrapped->set_unit(unit); +auto Entity::SetDataType(const AtomicDataType new_data_type, bool list_type) -> StatusCode { + return SetDataType(DataType(new_data_type, list_type)); } -auto Entity::SetDatatype(const std::string &datatype) -> void { - this->wrapped->set_datatype(datatype); +auto Entity::SetDataType(const std::string &new_data_type, bool list_type) -> StatusCode { + return SetDataType(DataType(new_data_type, list_type)); } auto Entity::SetFilePath(const std::string &path) -> void { diff --git a/src/caosdb/file_transmission/download_request_handler.cpp b/src/caosdb/file_transmission/download_request_handler.cpp index fb36ca5b46cbf2c4f08c2c06bc9faf6b00e038be..a157754b337e798fc4c144cb44abea153053ed79 100644 --- a/src/caosdb/file_transmission/download_request_handler.cpp +++ b/src/caosdb/file_transmission/download_request_handler.cpp @@ -59,30 +59,30 @@ #include <boost/preprocessor/seq/limits/size_256.hpp> // for BOOST_PP_SEQ_... #include <exception> // IWYU pragma: keep // IWYU pragma: no_include <bits/exception.h> -#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 +#include <google/protobuf/arena.h> // for Arena +#include <google/protobuf/generated_message_util.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 namespace caosdb::transaction { using caosdb::StatusCode; using caosdb::utility::get_arena; using google::protobuf::Arena; -DownloadRequestHandler::DownloadRequestHandler( - HandlerTag tag, FileTransmissionService::Stub *stub, - grpc::CompletionQueue *cq, FileDescriptor file_descriptor) +DownloadRequestHandler::DownloadRequestHandler(HandlerTag tag, FileTransmissionService::Stub *stub, + grpc::CompletionQueue *cq, + FileDescriptor file_descriptor) : tag_(tag), stub_(stub), cq_(cq), request_(Arena::CreateMessage<FileDownloadRequest>(get_arena())), - response_(Arena::CreateMessage<FileDownloadResponse>(get_arena())), - state_(CallState::NewCall), file_descriptor_(std::move(file_descriptor)), - bytesReceived_(0) {} + response_(Arena::CreateMessage<FileDownloadResponse>(get_arena())), state_(CallState::NewCall), + file_descriptor_(std::move(file_descriptor)), bytesReceived_(0) {} bool DownloadRequestHandler::OnNext(bool ok) { try { @@ -104,15 +104,13 @@ bool DownloadRequestHandler::OnNext(bool ok) { return true; } catch (std::exception &e) { - CAOSDB_LOG_ERROR(logger_name) - << "DownloadRequestHandler caught an exception: " << e.what(); + CAOSDB_LOG_ERROR(logger_name) << "DownloadRequestHandler caught an exception: " << e.what(); transaction_status = TransactionStatus::GENERIC_ERROR(e.what()); state_ = CallState::CallComplete; } catch (...) { - CAOSDB_LOG_ERROR(logger_name) - << "Transaction error: unknown exception caught"; - transaction_status = TransactionStatus::GENERIC_ERROR( - "DownloadRequestHandler caught an unknown exception"); + CAOSDB_LOG_ERROR(logger_name) << "Transaction error: unknown exception caught"; + transaction_status = + TransactionStatus::GENERIC_ERROR("DownloadRequestHandler caught an unknown exception"); state_ = CallState::CallComplete; } @@ -128,36 +126,30 @@ bool DownloadRequestHandler::OnNext(bool ok) { void DownloadRequestHandler::Cancel() { ctx_.TryCancel(); } void DownloadRequestHandler::handleNewCallState() { - CAOSDB_LOG_TRACE(logger_name) - << "Enter DownloadRequestHandler::handleNewCallState. local_path = " - << file_descriptor_.local_path - << ", download_id = " << file_descriptor_.file_transmission_id; + CAOSDB_LOG_TRACE(logger_name) << "Enter DownloadRequestHandler::handleNewCallState. local_path = " + << file_descriptor_.local_path + << ", 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)); + request_->mutable_file_transmission_id()->CopyFrom(*(file_descriptor_.file_transmission_id)); rpc_ = stub_->PrepareAsyncFileDownload(&ctx_, *request_, cq_); transaction_status = TransactionStatus::EXECUTING(); state_ = CallState::SendingRequest; rpc_->StartCall(tag_); - CAOSDB_LOG_TRACE(logger_name) - << "Leave DownloadRequestHandler::handleNewCallState"; + CAOSDB_LOG_TRACE(logger_name) << "Leave DownloadRequestHandler::handleNewCallState"; } void DownloadRequestHandler::handleSendingRequestState() { - CAOSDB_LOG_TRACE(logger_name) - << "Enter DownloadRequestHandler::handleSendingRequestState"; + CAOSDB_LOG_TRACE(logger_name) << "Enter DownloadRequestHandler::handleSendingRequestState"; state_ = CallState::ReceivingFile; rpc_->Read(response_, tag_); - CAOSDB_LOG_TRACE(logger_name) - << "Leave DownloadRequestHandler::handleSendingRequestState"; + CAOSDB_LOG_TRACE(logger_name) << "Leave DownloadRequestHandler::handleSendingRequestState"; } void DownloadRequestHandler::handleReceivingFileState() { - CAOSDB_LOG_TRACE(logger_name) - << "Enter DownloadRequestHandler::handleReceivingFileState"; + CAOSDB_LOG_TRACE(logger_name) << "Enter DownloadRequestHandler::handleReceivingFileState"; if (response_->has_chunk()) { const auto &chunkData = response_->chunk().data(); if (chunkData.empty()) { @@ -173,35 +165,30 @@ void DownloadRequestHandler::handleReceivingFileState() { } else { throw std::runtime_error("File chunk expected"); } - CAOSDB_LOG_TRACE(logger_name) - << "Leave DownloadRequestHandler::handleReceivingFileState"; + CAOSDB_LOG_TRACE(logger_name) << "Leave DownloadRequestHandler::handleReceivingFileState"; } void DownloadRequestHandler::handleCallCompleteState() { - CAOSDB_LOG_TRACE(logger_name) - << "Enter DownloadRequestHandler::handleCallCompleteState"; + CAOSDB_LOG_TRACE(logger_name) << "Enter DownloadRequestHandler::handleCallCompleteState"; switch (status_.error_code()) { case grpc::OK: { - CAOSDB_LOG_INFO(logger_name) - << "DownloadRequestHandler finished successfully (" - << file_descriptor_.local_path << "): Download complete, " - << bytesReceived_ << " bytes received."; + CAOSDB_LOG_INFO(logger_name) << "DownloadRequestHandler finished successfully (" + << file_descriptor_.local_path << "): Download complete, " + << bytesReceived_ << " bytes received."; } break; default: { auto code(static_cast<StatusCode>(status_.error_code())); std::string description(get_status_description(code) + " Original message: " + status_.error_message()); transaction_status = TransactionStatus(code, description); - CAOSDB_LOG_ERROR(logger_name) - << "DownloadRequestHandler finished with an error (" - << file_descriptor_.local_path << "): Download aborted with code " << code - << " - " << description; + CAOSDB_LOG_ERROR(logger_name) << "DownloadRequestHandler finished with an error (" + << file_descriptor_.local_path << "): Download aborted with code " + << code << " - " << description; } break; } - CAOSDB_LOG_TRACE(logger_name) - << "Leave DownloadRequestHandler::handleCallCompleteState"; + CAOSDB_LOG_TRACE(logger_name) << "Leave DownloadRequestHandler::handleCallCompleteState"; } } // namespace caosdb::transaction diff --git a/src/caosdb/file_transmission/file_writer.cpp b/src/caosdb/file_transmission/file_writer.cpp index 90c816fa8c6d3d43ecad3e4e0dbf575d7016d15e..5cf7d3a798942fc2ab9a3fe4a278b0e29d362f6e 100644 --- a/src/caosdb/file_transmission/file_writer.cpp +++ b/src/caosdb/file_transmission/file_writer.cpp @@ -53,8 +53,7 @@ namespace caosdb::transaction { -FileWriter::FileWriter(boost::filesystem::path filename) - : filename_(std::move(filename)) { +FileWriter::FileWriter(boost::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 b2020223f1c79f69e77b1e0950bac1c8f1220986..7b5c18c83729060768d882132067c5c8dd496d67 100644 --- a/src/caosdb/file_transmission/register_file_upload_handler.cpp +++ b/src/caosdb/file_transmission/register_file_upload_handler.cpp @@ -59,26 +59,24 @@ namespace caosdb::transaction { RegisterFileUploadHandler::~RegisterFileUploadHandler() = default; -RegisterFileUploadHandler::RegisterFileUploadHandler( - HandlerTag tag, FileTransmissionService::Stub *stub, - grpc::CompletionQueue *completion_queue, RegisterFileUploadRequest *request, - RegisterFileUploadResponse *response) - : UnaryRpcHandler(completion_queue), tag_(tag), stub_(stub), - request_(request), response_(response) {} +RegisterFileUploadHandler::RegisterFileUploadHandler(HandlerTag tag, + FileTransmissionService::Stub *stub, + grpc::CompletionQueue *completion_queue, + RegisterFileUploadRequest *request, + RegisterFileUploadResponse *response) + : UnaryRpcHandler(completion_queue), tag_(tag), stub_(stub), request_(request), + response_(response) {} void RegisterFileUploadHandler::handleNewCallState() { - CAOSDB_LOG_TRACE(logger_name) - << "Enter RegisterFileUploadHandler::handleNewCallState."; + CAOSDB_LOG_TRACE(logger_name) << "Enter RegisterFileUploadHandler::handleNewCallState."; - rpc_ = stub_->PrepareAsyncRegisterFileUpload(&call_context, *request_, - completion_queue); + rpc_ = stub_->PrepareAsyncRegisterFileUpload(&call_context, *request_, completion_queue); state_ = CallState::CallComplete; rpc_->StartCall(); rpc_->Finish(response_, &status_, tag_); - CAOSDB_LOG_TRACE(logger_name) - << "Leave RegisterFileUploadHandler::handleNewCallState"; + CAOSDB_LOG_TRACE(logger_name) << "Leave RegisterFileUploadHandler::handleNewCallState"; } } // namespace caosdb::transaction diff --git a/src/caosdb/file_transmission/upload_request_handler.cpp b/src/caosdb/file_transmission/upload_request_handler.cpp index 27926bfaabe4dd18feca80f191ff496573196e52..cc8170249b932fb8bfa572fd345746bbbacc16af 100644 --- a/src/caosdb/file_transmission/upload_request_handler.cpp +++ b/src/caosdb/file_transmission/upload_request_handler.cpp @@ -61,31 +61,29 @@ #include <cstdint> // for uint64_t #include <exception> // IWYU pragma: keep // IWYU pragma: no_include <bits/exception.h> -#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 -#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 endl, streamsize -#include <string> // for basic_string -#include <utility> // for move +#include <google/protobuf/arena.h> // for Arena +#include <google/protobuf/generated_message_util.h> // for CreateMessage... +#include <grpcpp/impl/codegen/async_stream.h> // for ClientAsyncWr... +#include <grpcpp/impl/codegen/call_op_set.h> // for WriteOptions +#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 endl, streamsize +#include <string> // for basic_string +#include <utility> // for move namespace caosdb::transaction { using caosdb::StatusCode; using caosdb::utility::get_arena; using google::protobuf::Arena; -UploadRequestHandler::UploadRequestHandler(HandlerTag tag, - FileTransmissionService::Stub *stub, +UploadRequestHandler::UploadRequestHandler(HandlerTag tag, FileTransmissionService::Stub *stub, grpc::CompletionQueue *cq, FileDescriptor file_descriptor) - : tag_(tag), stub_(stub), cq_(cq), - request_(Arena::CreateMessage<FileUploadRequest>(get_arena())), - response_(Arena::CreateMessage<FileUploadResponse>(get_arena())), - state_(CallState::NewCall), file_descriptor_(std::move(file_descriptor)), - bytesToSend_(0) {} + : tag_(tag), stub_(stub), cq_(cq), request_(Arena::CreateMessage<FileUploadRequest>(get_arena())), + response_(Arena::CreateMessage<FileUploadResponse>(get_arena())), state_(CallState::NewCall), + file_descriptor_(std::move(file_descriptor)), bytesToSend_(0) {} bool UploadRequestHandler::OnNext(bool ok) { try { @@ -109,15 +107,13 @@ bool UploadRequestHandler::OnNext(bool ok) { return true; } catch (std::exception &e) { - CAOSDB_LOG_ERROR(logger_name) - << "UploadRequestHandler caught an exception: " << e.what(); + CAOSDB_LOG_ERROR(logger_name) << "UploadRequestHandler caught an exception: " << e.what(); transaction_status = TransactionStatus::GENERIC_ERROR(e.what()); state_ = CallState::CallComplete; } catch (...) { - CAOSDB_LOG_ERROR(logger_name) - << "Transaction error: unknown exception caught"; - transaction_status = TransactionStatus::GENERIC_ERROR( - "UploadRequestHandler caught an unknown exception"); + CAOSDB_LOG_ERROR(logger_name) << "Transaction error: unknown exception caught"; + transaction_status = + TransactionStatus::GENERIC_ERROR("UploadRequestHandler caught an unknown exception"); state_ = CallState::CallComplete; } @@ -187,31 +183,27 @@ void UploadRequestHandler::handleExpectingResponseState() { } void UploadRequestHandler::handleCallCompleteState() { - CAOSDB_LOG_TRACE(logger_name) - << "Enter UploadRequestHandler::handleCallCompleteState"; + CAOSDB_LOG_TRACE(logger_name) << "Enter UploadRequestHandler::handleCallCompleteState"; switch (status_.error_code()) { case grpc::OK: { auto bytesSent = fileReader_ != nullptr ? fileReader_->fileSize() : 0; - CAOSDB_LOG_INFO(logger_name) - << "UploadRequestHandler finished successfully (" - << file_descriptor_.local_path << "): upload complete, " << bytesSent - << " bytes sent"; + CAOSDB_LOG_INFO(logger_name) << "UploadRequestHandler finished successfully (" + << file_descriptor_.local_path << "): upload complete, " + << bytesSent << " bytes sent"; } break; default: { auto code(static_cast<StatusCode>(status_.error_code())); std::string description(get_status_description(code) + " Original message: " + status_.error_message()); transaction_status = TransactionStatus(code, description); - CAOSDB_LOG_ERROR(logger_name) - << "UploadRequestHandler finished with an error (" - << file_descriptor_.local_path << "): Upload aborted with code " << code - << " - " << description; + CAOSDB_LOG_ERROR(logger_name) << "UploadRequestHandler finished with an error (" + << file_descriptor_.local_path << "): Upload aborted with code " + << code << " - " << description; } break; } - CAOSDB_LOG_TRACE(logger_name) - << "Leave UploadRequestHandler::handleCallCompleteState"; + CAOSDB_LOG_TRACE(logger_name) << "Leave UploadRequestHandler::handleCallCompleteState"; } } // namespace caosdb::transaction diff --git a/src/caosdb/logging.cpp b/src/caosdb/logging.cpp index 5e6cd4e3577b57ec7491a26ae71982667a096609..4070786b2bb4073da5800f4a57b9c0dfcff5d6ac 100644 --- a/src/caosdb/logging.cpp +++ b/src/caosdb/logging.cpp @@ -48,11 +48,9 @@ BOOST_LOG_GLOBAL_LOGGER_INIT(logger, boost_logger_class) { boost_logger_class lg; return lg; } -LoggingConfiguration::LoggingConfiguration(int level) - : LevelConfiguration(level) {} +LoggingConfiguration::LoggingConfiguration(int level) : LevelConfiguration(level) {} -auto LoggingConfiguration::AddSink( - const std::shared_ptr<SinkConfiguration> &sink) -> void { +auto LoggingConfiguration::AddSink(const std::shared_ptr<SinkConfiguration> &sink) -> void { this->sinks.push_back(sink); } @@ -64,14 +62,10 @@ auto LoggingConfiguration::GetSinks() const SinkConfiguration::SinkConfiguration(std::string name, int level) : LevelConfiguration(level), name(std::move(name)) {} -[[nodiscard]] auto SinkConfiguration::GetName() const -> const std::string & { - return this->name; -} +[[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(boost::log::settings &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()); @@ -79,31 +73,24 @@ auto SinkConfiguration::Configure(boost::log::settings &settings) const settings[sink]["Format"] = "[%TimeStamp%][%Severity%] %Channel% - %Message%"; } -ConsoleSinkConfiguration::ConsoleSinkConfiguration(const std::string &name, - int level) +ConsoleSinkConfiguration::ConsoleSinkConfiguration(const std::string &name, int level) : SinkConfiguration(name, level) {} -[[nodiscard]] auto ConsoleSinkConfiguration::GetDestination() const - -> const std::string & { - CAOSDB_LOG_TRACE(logger_name) - << "Enter ConsoleSinkConfiguration::GetDestination()"; +[[nodiscard]] auto ConsoleSinkConfiguration::GetDestination() const -> const std::string & { + CAOSDB_LOG_TRACE(logger_name) << "Enter ConsoleSinkConfiguration::GetDestination()"; return this->destination; } -auto ConsoleSinkConfiguration::Configure(boost::log::settings &settings) const - -> void { - CAOSDB_LOG_TRACE(logger_name) - << "Enter ConsoleSinkConfiguration::Configure(&settings)"; +auto ConsoleSinkConfiguration::Configure(boost::log::settings &settings) const -> void { + CAOSDB_LOG_TRACE(logger_name) << "Enter ConsoleSinkConfiguration::Configure(&settings)"; sink_configuration::Configure(settings); } FileSinkConfiguration::FileSinkConfiguration(const std::string &name, int level) : SinkConfiguration(name, level) {} -[[nodiscard]] auto FileSinkConfiguration::GetDestination() const - -> const std::string & { - CAOSDB_LOG_TRACE(logger_name) - << "Enter FileSinkConfiguration::GetDestination()"; +[[nodiscard]] auto FileSinkConfiguration::GetDestination() const -> const std::string & { + CAOSDB_LOG_TRACE(logger_name) << "Enter FileSinkConfiguration::GetDestination()"; return this->destination; } @@ -111,20 +98,16 @@ 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(boost::log::settings &settings) const -> void { + CAOSDB_LOG_TRACE(logger_name) << "Enter FileSinkConfiguration::Configure(&settings)"; sink_configuration::Configure(settings); settings["Sink." + GetName() + ".Target"] = this->directory; } -SyslogSinkConfiguration::SyslogSinkConfiguration(const std::string &name, - int level) +SyslogSinkConfiguration::SyslogSinkConfiguration(const std::string &name, int level) : SinkConfiguration(name, level) {} -[[nodiscard]] auto SyslogSinkConfiguration::GetDestination() const - -> const std::string & { +[[nodiscard]] auto SyslogSinkConfiguration::GetDestination() const -> const std::string & { return this->destination; } @@ -137,8 +120,7 @@ auto initialize_logging_defaults() -> int { // now set everything up const static std::vector<std::shared_ptr<SinkConfiguration>> default_sinks = { - std::make_shared<ConsoleSinkConfiguration>("DEFAULT_SINK_1", - CAOSDB_DEFAULT_LOG_LEVEL)}; + std::make_shared<ConsoleSinkConfiguration>("DEFAULT_SINK_1", CAOSDB_DEFAULT_LOG_LEVEL)}; boost::log::settings default_settings; @@ -150,8 +132,7 @@ auto initialize_logging_defaults() -> int { boost::log::init_from_settings(default_settings); auto core = boost::log::core::get(); - core->add_global_attribute("TimeStamp", - boost::log::attributes::local_clock()); + core->add_global_attribute("TimeStamp", boost::log::attributes::local_clock()); CAOSDB_LOG_DEBUG(logger_name) << "Initialized default settings."; @@ -185,39 +166,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; + BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::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; + BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::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; + BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::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; + BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::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; + BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::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; + BOOST_LOG_CHANNEL_SEV(caosdb::logging::logger::get(), channel, CAOSDB_LOG_LEVEL_TRACE) << msg; } } // namespace caosdb::logging diff --git a/src/caosdb/transaction.cpp b/src/caosdb/transaction.cpp index a46019f3a5b83cc0bb058aa6446100bceac87242..75350b2680b55976d9a7a96b58962540216d4eae 100644 --- a/src/caosdb/transaction.cpp +++ b/src/caosdb/transaction.cpp @@ -18,32 +18,33 @@ * */ #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/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" -#include "caosdb/file_transmission/upload_request_handler.h" // Upload... -#include "caosdb/logging.h" // for CAOSDB_LOG_FATAL -#include "caosdb/status_code.h" // for StatusCode -#include "caosdb/transaction_handler.h" -#include <algorithm> // for max -#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 "caosdb/entity/v1alpha1/main.grpc.pb.h" // for EntityTransac... +#include "caosdb/entity/v1alpha1/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 +#include "caosdb/file_transmission/upload_request_handler.h" // Upload... +#include "caosdb/logging.h" // for CAOSDB_LOG_FATAL +#include "caosdb/status_code.h" // for StatusCode +#include "caosdb/transaction_handler.h" // for EntityTransactionHandler +#include <algorithm> // for max +#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 <bits/exception.h> -#include <exception> // IWYU pragma: keep -#include <google/protobuf/arena.h> // for Arena -#include <grpc/impl/codegen/gpr_types.h> -#include <grpcpp/impl/codegen/completion_queue.h> // for CompletionQueue -#include <iosfwd> // for streamsize -#include <map> // for map, operator!= -#include <memory> // for unique_ptr -#include <stdexcept> // for out_of_range -#include <utility> // for move, pair +#include <exception> // IWYU pragma: keep +#include <google/protobuf/arena.h> // for Arena +#include <google/protobuf/generated_message_util.h> // for CreateMessage... +#include <grpc/impl/codegen/gpr_types.h> // for gpr_timespec +#include <grpcpp/impl/codegen/completion_queue.h> // for CompletionQueue +#include <iosfwd> // for streamsize +#include <map> // for map, operator!= +#include <memory> // for unique_ptr +#include <stdexcept> // for out_of_range +#include <utility> // for move, pair namespace caosdb { @@ -51,14 +52,11 @@ namespace caosdb { auto get_status_description(int code) -> const std::string & { static const std::string MISSING_DESCRIPTION = "MISSING DESCRIPTION"; static const std::map<int, std::string> descriptions = { - {StatusCode::INITIAL, - "The transaction has just been intialized. It has not been executed yet " - "and clients can still change it and add sub-transactions."}, - {StatusCode::GO_ON, - "The transaction has a transaction_type yet and clients may add matching " - "sub-transaction or execute it right-away."}, - {StatusCode::READY, - "The transaction is ready for execution and cannot be changed anymore."}, + {StatusCode::INITIAL, "The transaction has just been intialized. It has not been executed yet " + "and clients can still change it and add sub-transactions."}, + {StatusCode::GO_ON, "The transaction has a transaction_type yet and clients may add matching " + "sub-transaction or execute it right-away."}, + {StatusCode::READY, "The transaction is ready for execution and cannot be changed anymore."}, {StatusCode::EXECUTING, "The transaction is currently being executed."}, {StatusCode::SUCCESS, "The action was successful"}, {StatusCode::CONNECTION_ERROR, @@ -70,8 +68,7 @@ auto get_status_description(int code) -> const std::string & { {StatusCode::GENERIC_RPC_ERROR, "The attempt to execute this transaction was not successful because an " "error occured in the transport or RPC protocol layer."}, - {StatusCode::GENERIC_ERROR, - "An error occured. Please review the logs for more information."}, + {StatusCode::GENERIC_ERROR, "An error occured. Please review the logs for more information."}, {StatusCode::GENERIC_TRANSACTION_ERROR, "The transaction terminated unsuccessfully with transaction errors."}, {StatusCode::CONFIGURATION_ERROR, @@ -92,10 +89,8 @@ auto get_status_description(int code) -> const std::string & { {StatusCode::PATH_IS_A_DIRECTORY, "The given path is a directory."}, {StatusCode::FILE_DOES_NOT_EXIST_LOCALLY, "The file does not not exist in the local file system."}, - {StatusCode::FILE_DOWNLOAD_ERROR, - "The transaction failed during the download of the files"}, - {StatusCode::FILE_UPLOAD_ERROR, - "The transaction failed during the upload of the files"}, + {StatusCode::FILE_DOWNLOAD_ERROR, "The transaction failed during the download of the files"}, + {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, @@ -121,8 +116,7 @@ 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 RetrieveResponseCase = caosdb::entity::v1alpha1::RetrieveResponse::RetrieveResponseCase; using ProtoEntity = caosdb::entity::v1alpha1::Entity; using google::protobuf::Arena; using NextStatus = grpc::CompletionQueue::NextStatus; @@ -150,20 +144,15 @@ auto ResultSet::iterator::operator!=(const iterator &rhs) const -> bool { return this->current_index != rhs.current_index; } -auto ResultSet::begin() const -> ResultSet::iterator { - return ResultSet::iterator(this, 0); -} +auto ResultSet::begin() const -> ResultSet::iterator { return ResultSet::iterator(this, 0); } -auto ResultSet::end() const -> ResultSet::iterator { - return ResultSet::iterator(this, size()); -} +auto ResultSet::end() const -> ResultSet::iterator { return ResultSet::iterator(this, size()); } MultiResultSet::MultiResultSet(std::vector<std::unique_ptr<Entity>> result_set) : AbstractMultiResultSet(std::move(result_set)) {} -Transaction::Transaction( - std::shared_ptr<EntityTransactionService::Stub> entity_service, - std::shared_ptr<FileTransmissionService::Stub> file_service) +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); @@ -181,12 +170,12 @@ auto Transaction::RetrieveById(const std::string &id) noexcept -> StatusCode { return this->status.GetCode(); } -auto Transaction::RetrieveAndDownloadFilesById( - const std::string &id, const std::string &local_path) noexcept -> StatusCode { +auto Transaction::RetrieveAndDownloadFilesById(const std::string &id, + const std::string &local_path) noexcept + -> StatusCode { ASSERT_CAN_ADD_RETRIEVAL - auto *retrieve_request = - this->request->add_requests()->mutable_retrieve_request(); + auto *retrieve_request = this->request->add_requests()->mutable_retrieve_request(); retrieve_request->set_id(id); retrieve_request->set_register_file_download(true); @@ -222,9 +211,8 @@ auto Transaction::DeleteById(const std::string &id) noexcept -> StatusCode { auto Transaction::InsertEntity(Entity *entity) noexcept -> StatusCode { ASSERT_CAN_ADD_INSERTION - auto *entity_request = this->request->add_requests() - ->mutable_insert_request() - ->mutable_entity_request(); + auto *entity_request = + this->request->add_requests()->mutable_insert_request()->mutable_entity_request(); auto *proto_entity = entity_request->mutable_entity(); // copy the original entity for the transaction @@ -241,9 +229,8 @@ auto Transaction::InsertEntity(Entity *entity) noexcept -> StatusCode { auto Transaction::UpdateEntity(Entity *entity) noexcept -> StatusCode { ASSERT_CAN_ADD_UPDATE - auto *entity_request = this->request->add_requests() - ->mutable_update_request() - ->mutable_entity_request(); + auto *entity_request = + this->request->add_requests()->mutable_update_request()->mutable_entity_request(); auto *proto_entity = entity_request->mutable_entity(); entity->CopyTo(proto_entity); @@ -258,8 +245,8 @@ auto Transaction::UpdateEntity(Entity *entity) noexcept -> StatusCode { auto Transaction::Execute() -> TransactionStatus { auto status_code = ExecuteAsynchronously(); - TransactionStatus::ThrowExceptionIfError( - status_code, caosdb::get_status_description(status_code)); + TransactionStatus::ThrowExceptionIfError(status_code, + caosdb::get_status_description(status_code)); auto status = WaitForIt(); status.ThrowExceptionIfError(); return status; @@ -267,8 +254,7 @@ auto Transaction::Execute() -> TransactionStatus { // TODO(tf) This has apparently a cognitive complexity of 39>25 (threshold). auto Transaction::ExecuteAsynchronously() noexcept -> StatusCode { // NOLINT - if (!IsStatus(TransactionStatus::READY()) && - !IsStatus(TransactionStatus::GO_ON())) { + if (!IsStatus(TransactionStatus::READY()) && !IsStatus(TransactionStatus::GO_ON())) { return StatusCode::TRANSACTION_STATUS_ERROR; } switch (this->transaction_type) { @@ -291,21 +277,17 @@ auto Transaction::ExecuteAsynchronously() noexcept -> StatusCode { // NOLINT // upload files first if (!upload_files.empty()) { - CAOSDB_LOG_INFO(logger_name) - << "Number of files to be uploaded: " << upload_files.size(); + CAOSDB_LOG_INFO(logger_name) << "Number of files to be uploaded: " << upload_files.size(); - auto *registration_request = - Arena::CreateMessage<RegisterFileUploadRequest>(GetArena()); - auto *registration_response = - Arena::CreateMessage<RegisterFileUploadResponse>(GetArena()); + auto *registration_request = Arena::CreateMessage<RegisterFileUploadRequest>(GetArena()); + auto *registration_response = Arena::CreateMessage<RegisterFileUploadResponse>(GetArena()); - handler_ = std::make_unique<RegisterFileUploadHandler>( - &handler_, file_service.get(), &completion_queue, registration_request, - registration_response); + handler_ = + std::make_unique<RegisterFileUploadHandler>(&handler_, file_service.get(), &completion_queue, + registration_request, registration_response); this->status = ProcessCalls(); - if (registration_response->status() != - RegistrationStatus::REGISTRATION_STATUS_ACCEPTED) { + if (registration_response->status() != RegistrationStatus::REGISTRATION_STATUS_ACCEPTED) { this->status = TransactionStatus::FILE_UPLOAD_ERROR(); return StatusCode::EXECUTING; } @@ -313,10 +295,9 @@ auto Transaction::ExecuteAsynchronously() noexcept -> StatusCode { // NOLINT for (auto &file_descriptor : upload_files) { file_descriptor.file_transmission_id->set_registration_id( registration_response->registration_id()); - CAOSDB_LOG_INFO(logger_name) - << "Uploading " << file_descriptor.local_path; - handler_ = std::make_unique<UploadRequestHandler>( - &handler_, file_service.get(), &completion_queue, file_descriptor); + CAOSDB_LOG_INFO(logger_name) << "Uploading " << file_descriptor.local_path; + handler_ = std::make_unique<UploadRequestHandler>(&handler_, file_service.get(), + &completion_queue, file_descriptor); this->status = ProcessCalls(); if (this->status.GetCode() != StatusCode::EXECUTING) { return StatusCode::EXECUTING; @@ -324,8 +305,9 @@ auto Transaction::ExecuteAsynchronously() noexcept -> StatusCode { // NOLINT } } - handler_ = std::make_unique<EntityTransactionHandler>( - &handler_, entity_service.get(), &completion_queue, request, response); + CAOSDB_LOG_DEBUG(logger_name) << "RPC Request: " << RequestToString(); + handler_ = std::make_unique<EntityTransactionHandler>(&handler_, entity_service.get(), + &completion_queue, request, response); this->status = ProcessCalls(); if (this->status.GetCode() != StatusCode::EXECUTING) { return StatusCode::EXECUTING; @@ -335,16 +317,12 @@ auto Transaction::ExecuteAsynchronously() noexcept -> StatusCode { // NOLINT if (status.GetCode() == StatusCode::EXECUTING && !download_files.empty()) { // run over all retrieved entities and get the download_id for (auto sub_response : *(response->mutable_responses())) { - if (sub_response.transaction_response_case() == - TransactionResponseCase::kRetrieveResponse) { - if (sub_response.retrieve_response() - .entity_response() - .has_download_id()) { + if (sub_response.transaction_response_case() == TransactionResponseCase::kRetrieveResponse) { + if (sub_response.retrieve_response().entity_response().has_download_id()) { 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(); + download_files[entity_id].file_transmission_id = entity_response->release_download_id(); // TODO(tf) handle error } } @@ -352,11 +330,10 @@ auto Transaction::ExecuteAsynchronously() noexcept -> StatusCode { // NOLINT for (const auto &item : download_files) { auto file_descriptor(item.second); - CAOSDB_LOG_INFO(logger_name) - << "Downloading " << file_descriptor.local_path; + CAOSDB_LOG_INFO(logger_name) << "Downloading " << file_descriptor.local_path; - handler_ = std::make_unique<DownloadRequestHandler>( - &handler_, file_service.get(), &completion_queue, file_descriptor); + handler_ = std::make_unique<DownloadRequestHandler>(&handler_, file_service.get(), + &completion_queue, file_descriptor); this->status = ProcessCalls(); if (this->status.GetCode() != StatusCode::EXECUTING) { return StatusCode::EXECUTING; @@ -384,8 +361,7 @@ auto Transaction::WaitForIt() const noexcept -> TransactionStatus { // NOLINT switch (retrieve_response->retrieve_response_case()) { case RetrieveResponseCase::kEntityResponse: { - auto *retrieve_entity_response = - retrieve_response->release_entity_response(); + auto *retrieve_entity_response = retrieve_response->release_entity_response(); result = std::make_unique<Entity>(retrieve_entity_response); } break; case RetrieveResponseCase::kSelectResult: { @@ -416,26 +392,22 @@ auto Transaction::WaitForIt() const noexcept -> TransactionStatus { // NOLINT } case TransactionResponseCase::kInsertResponse: { - auto *inserted_id_response = - sub_response.mutable_insert_response()->release_id_response(); + auto *inserted_id_response = sub_response.mutable_insert_response()->release_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()->release_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()->release_id_response(); result = std::make_unique<Entity>(updated_id_response); break; } default: - CAOSDB_LOG_FATAL(logger_name) - << "Received invalid TransactionResponseCase."; + CAOSDB_LOG_FATAL(logger_name) << "Received invalid TransactionResponseCase."; break; } if (result != nullptr) { @@ -457,8 +429,7 @@ auto Transaction::WaitForIt() const noexcept -> TransactionStatus { // NOLINT this->result_set = std::make_unique<MultiResultSet>(std::move(entities)); if (set_error) { - this->status = TransactionStatus::TRANSACTION_ERROR( - "The request terminated with errors."); + this->status = TransactionStatus::TRANSACTION_ERROR("The request terminated with errors."); } return this->status; @@ -493,8 +464,7 @@ auto Transaction::ProcessCalls() -> TransactionStatus { } } break; case NextStatus::SHUTDOWN: { - CAOSDB_LOG_ERROR(logger_name) - << "Notification queue has been shut down unexpectedly."; + CAOSDB_LOG_ERROR(logger_name) << "Notification queue has been shut down unexpectedly."; result = handler_->GetStatus(); handler_.reset(); return result; @@ -503,8 +473,7 @@ auto Transaction::ProcessCalls() -> TransactionStatus { CAOSDB_LOG_DEBUG(logger_name) << "Timeout, waiting..."; } break; default: - CAOSDB_LOG_FATAL(logger_name) - << "Got an invalid NextStatus from CompletionQueue."; + CAOSDB_LOG_FATAL(logger_name) << "Got an invalid NextStatus from CompletionQueue."; result = handler_->GetStatus(); handler_.reset(); return result; diff --git a/src/caosdb/transaction_handler.cpp b/src/caosdb/transaction_handler.cpp index cf020af35bf56b2e68da11a92b0961995397f2fd..e97e626139dd967353491310627f96acefbdb8eb 100644 --- a/src/caosdb/transaction_handler.cpp +++ b/src/caosdb/transaction_handler.cpp @@ -13,28 +13,26 @@ namespace caosdb::transaction { -EntityTransactionHandler::EntityTransactionHandler( - HandlerTag tag, EntityTransactionService::Stub *stub, - grpc::CompletionQueue *completion_queue, MultiTransactionRequest *request, - MultiTransactionResponse *response) - : UnaryRpcHandler(completion_queue), tag_(tag), stub_(stub), - request_(request), response_(response) {} +EntityTransactionHandler::EntityTransactionHandler(HandlerTag tag, + EntityTransactionService::Stub *stub, + grpc::CompletionQueue *completion_queue, + MultiTransactionRequest *request, + MultiTransactionResponse *response) + : UnaryRpcHandler(completion_queue), tag_(tag), stub_(stub), request_(request), + response_(response) {} void EntityTransactionHandler::handleNewCallState() { - CAOSDB_LOG_TRACE(logger_name) - << "Enter EntityTransactionHandler::handleNewCallState with " - "CompletionQueue " - << completion_queue; + CAOSDB_LOG_TRACE(logger_name) << "Enter EntityTransactionHandler::handleNewCallState with " + "CompletionQueue " + << completion_queue; - rpc_ = stub_->PrepareAsyncMultiTransaction(&call_context, *request_, - completion_queue); + rpc_ = stub_->PrepareAsyncMultiTransaction(&call_context, *request_, completion_queue); state_ = CallState::CallComplete; rpc_->StartCall(); rpc_->Finish(response_, &status_, tag_); - CAOSDB_LOG_TRACE(logger_name) - << "Leave EntityTransactionHandler::handleNewCallState"; + CAOSDB_LOG_TRACE(logger_name) << "Leave EntityTransactionHandler::handleNewCallState"; } } // namespace caosdb::transaction diff --git a/src/caosdb/unary_rpc_handler.cpp b/src/caosdb/unary_rpc_handler.cpp index 4d1e1cf618ef119278b02fdc3657d17482a87601..f2307549f575f3311a5c096007a1c98b12db1722 100644 --- a/src/caosdb/unary_rpc_handler.cpp +++ b/src/caosdb/unary_rpc_handler.cpp @@ -74,8 +74,7 @@ bool UnaryRpcHandler::OnNext(bool ok) { return false; } } else { - CAOSDB_LOG_ERROR(logger_name) - << "UnaryRpcHandler::OnNext(false)!. This should not happen."; + CAOSDB_LOG_ERROR(logger_name) << "UnaryRpcHandler::OnNext(false)!. This should not happen."; // TODO(tf) Handle this error: // in CallComplete state: "Client-side Finish: ok should always be true" // in ReceivingFile state: "ok indicates that the RPC is going to go to @@ -88,15 +87,13 @@ bool UnaryRpcHandler::OnNext(bool ok) { return true; } catch (std::exception &e) { - CAOSDB_LOG_ERROR(logger_name) - << "UnaryRpcHandler caught an exception: " << e.what(); + CAOSDB_LOG_ERROR(logger_name) << "UnaryRpcHandler caught an exception: " << e.what(); transaction_status = TransactionStatus::GENERIC_ERROR(e.what()); state_ = CallState::CallComplete; } catch (...) { - CAOSDB_LOG_ERROR(logger_name) - << "Transaction error: unknown exception caught"; - transaction_status = TransactionStatus::GENERIC_ERROR( - "UnaryRpcHandler caught an unknown exception"); + CAOSDB_LOG_ERROR(logger_name) << "Transaction error: unknown exception caught"; + transaction_status = + TransactionStatus::GENERIC_ERROR("UnaryRpcHandler caught an unknown exception"); state_ = CallState::CallComplete; } @@ -110,8 +107,7 @@ bool UnaryRpcHandler::OnNext(bool ok) { void UnaryRpcHandler::Cancel() { call_context.TryCancel(); } void UnaryRpcHandler::handleCallCompleteState() { - CAOSDB_LOG_TRACE(logger_name) - << "Enter UnaryRpcHandler::handleCallCompleteState"; + CAOSDB_LOG_TRACE(logger_name) << "Enter UnaryRpcHandler::handleCallCompleteState"; switch (status_.error_code()) { case grpc::OK: @@ -122,14 +118,12 @@ void UnaryRpcHandler::handleCallCompleteState() { std::string description(get_status_description(code) + " Original message: " + status_.error_message()); transaction_status = TransactionStatus(code, description); - CAOSDB_LOG_ERROR(logger_name) - << "UnaryRpcHandler finished with an error (Code " << code - << "): " << description; + CAOSDB_LOG_ERROR(logger_name) << "UnaryRpcHandler finished with an error (Code " << code + << "): " << description; break; } - CAOSDB_LOG_TRACE(logger_name) - << "Leave UnaryRpcHandler::handleCallCompleteState"; + CAOSDB_LOG_TRACE(logger_name) << "Leave UnaryRpcHandler::handleCallCompleteState"; } } // namespace caosdb::transaction diff --git a/src/caosdb/utility.cpp b/src/caosdb/utility.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d049b91c4ce06337de57f24715df983e80ba88e3 --- /dev/null +++ b/src/caosdb/utility.cpp @@ -0,0 +1,89 @@ +/* + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2021 Daniel Hornung <d.hornung@indiscale.com> + * Copyright (C) 2021 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/>. + * + */ +#include "caosdb/data_type.h" +#include "caosdb/entity.h" +#include "caosdb/utility.h" +#include <algorithm> + +namespace caosdb::utility { + +using caosdb::entity::AtomicDataType; +using caosdb::entity::Importance; +using caosdb::entity::Role; + +// using emap = std::map<int, std::string>; // enum mapping + +// Enum helper template specializations ////////////////////////////////////// +template <> auto getEnumNameFromValue<Importance>(Importance v) -> std::string { + auto result = caosdb::entity::importance_names.at(v); + return result; +} + +template <> auto getEnumNameFromValue<Role>(Role v) -> std::string { + auto result = caosdb::entity::role_names.at(v); + return result; +} + +template <> auto getEnumNameFromValue<AtomicDataType>(AtomicDataType v) -> std::string { + auto result = caosdb::entity::atomicdatatype_names.at(v); + return result; +} + +template <> auto getEnumValueFromName<Importance>(const std::string &name) -> Importance { + // TODO (dh): Why does this compile? + // if (caosdb::entity::importance_names.begin()->second == name) {} + // std::for_each(caosdb::entity::importance_names.begin(), + // caosdb::entity::importance_names.end(), + // [](const auto &entry){}); + // TODO (dh): Whereas this does not? + // auto result = std::find(caosdb::entity::importance_names.cbegin(), + // caosdb::entity::importance_names.cend(), + // [name](const auto& entry){ return entry.second == name; }); + // Workaround: plaint old iteration: + for (auto const &entry : caosdb::entity::importance_names) { + if (entry.second == name) { + return entry.first; + } + } + throw std::out_of_range(std::string("Could not find enum value for string '") + name + "'."); +} + +template <> auto getEnumValueFromName<AtomicDataType>(const std::string &name) -> AtomicDataType { + for (auto const &entry : caosdb::entity::atomicdatatype_names) { + if (entry.second == name) { + return entry.first; + } + } + throw std::out_of_range(std::string("Could not find enum value for string '") + name + "'."); +} + +template <> auto getEnumValueFromName<Role>(const std::string &name) -> Role { + for (auto const &entry : caosdb::entity::role_names) { + if (entry.second == name) { + return entry.first; + } + } + throw std::out_of_range(std::string("Could not find enum value for string '") + name + "'."); +} + +// End of template specialization ///////////////////////////////////////////// + +} // namespace caosdb::utility diff --git a/src/ccaosdb.cpp b/src/ccaosdb.cpp index d962c5bae38d655b90ce4e208bac9f042aabc7fa..dce0970bf21343eb12ffac6098450d507de70e59 100644 --- a/src/ccaosdb.cpp +++ b/src/ccaosdb.cpp @@ -41,112 +41,91 @@ extern "C" { * Macro for wrapping every function into a try-catch clause. If an exception * occurs, the given StatusCode is being returned. */ -#define ERROR_RETURN_CODE(code, fun, body) \ - fun { \ - CAOSDB_LOG_TRACE(CCAOSDB_LOGGER_NAME) << "Enter " << #fun; \ - try { \ - body \ - } catch (const std::exception &exc) { \ - caosdb::logging::caosdb_log_fatal(CCAOSDB_LOGGER_NAME, exc.what()); \ - return caosdb::StatusCode::code; \ - } \ +#define ERROR_RETURN_CODE(code, fun, body) \ + fun { \ + CAOSDB_LOG_TRACE(CCAOSDB_LOGGER_NAME) << "Enter " << #fun; \ + try { \ + body \ + } catch (const std::exception &exc) { \ + caosdb::logging::caosdb_log_fatal(CCAOSDB_LOGGER_NAME, exc.what()); \ + return caosdb::StatusCode::code; \ + } \ } /** * Macro for entity getters */ -#define CAOSDB_ENTITY_GET(element, body_part) \ - ERROR_RETURN_CODE( \ - GENERIC_ERROR, \ - int caosdb_entity_entity_get_##element(caosdb_entity_entity *entity, \ - char *out), \ - { \ - auto *wrapped_entity = \ - static_cast<caosdb::entity::Entity *>(entity->wrapped_entity); \ - body_part return 0; \ +#define CAOSDB_ENTITY_GET(element, body_part) \ + ERROR_RETURN_CODE( \ + GENERIC_ERROR, \ + int caosdb_entity_entity_get_##element(caosdb_entity_entity *entity, char *out), { \ + auto *wrapped_entity = static_cast<caosdb::entity::Entity *>(entity->wrapped_entity); \ + body_part return 0; \ }) /** * Macro for entity setters */ -#define CAOSDB_ENTITY_SET(element, value, body_part) \ - ERROR_RETURN_CODE( \ - GENERIC_ERROR, \ - int caosdb_entity_entity_set_##element(caosdb_entity_entity *entity, \ - const char *value), \ - { \ - auto *wrapped_entity = \ - static_cast<caosdb::entity::Entity *>(entity->wrapped_entity); \ - body_part return 0; \ +#define CAOSDB_ENTITY_SET(element, value, body_part) \ + ERROR_RETURN_CODE( \ + GENERIC_ERROR, \ + int caosdb_entity_entity_set_##element(caosdb_entity_entity *entity, const char *value), { \ + auto *wrapped_entity = static_cast<caosdb::entity::Entity *>(entity->wrapped_entity); \ + body_part return 0; \ }) /** * Macro for property getters */ -#define CAOSDB_PROPERTY_GET(element, body_part) \ - ERROR_RETURN_CODE( \ - GENERIC_ERROR, \ - int caosdb_entity_property_get_##element(caosdb_entity_property *property, \ - char *out), \ - { \ - auto *wrapped_property = \ - static_cast<caosdb::entity::Property *>(property->wrapped_property); \ - body_part return 0; \ +#define CAOSDB_PROPERTY_GET(element, body_part) \ + ERROR_RETURN_CODE( \ + GENERIC_ERROR, \ + int caosdb_entity_property_get_##element(caosdb_entity_property *property, char *out), { \ + auto *wrapped_property = \ + static_cast<caosdb::entity::Property *>(property->wrapped_property); \ + body_part return 0; \ }) /** * Macro for property setters */ -#define CAOSDB_PROPERTY_SET(element, value, body_part) \ - ERROR_RETURN_CODE( \ - GENERIC_ERROR, \ - int caosdb_entity_property_set_##element(caosdb_entity_property *property, \ - const char *value), \ - { \ - auto *wrapped_property = \ - static_cast<caosdb::entity::Property *>(property->wrapped_property); \ - body_part return 0; \ +#define CAOSDB_PROPERTY_SET(element, value, body_part) \ + ERROR_RETURN_CODE( \ + GENERIC_ERROR, \ + int caosdb_entity_property_set_##element(caosdb_entity_property *property, const char *value), \ + { \ + auto *wrapped_property = \ + static_cast<caosdb::entity::Property *>(property->wrapped_property); \ + body_part return 0; \ }) /** * Macro for parent getters */ -#define CAOSDB_PARENT_GET(element, body_part) \ - ERROR_RETURN_CODE( \ - GENERIC_ERROR, \ - int caosdb_entity_parent_get_##element(caosdb_entity_parent *parent, \ - char *out), \ - { \ - auto *wrapped_parent = \ - static_cast<caosdb::entity::Parent *>(parent->wrapped_parent); \ - body_part return 0; \ +#define CAOSDB_PARENT_GET(element, body_part) \ + ERROR_RETURN_CODE( \ + GENERIC_ERROR, \ + int caosdb_entity_parent_get_##element(caosdb_entity_parent *parent, char *out), { \ + auto *wrapped_parent = static_cast<caosdb::entity::Parent *>(parent->wrapped_parent); \ + body_part return 0; \ }) /** * Macro for parent setters */ -#define CAOSDB_PARENT_SET(element, value, body_part) \ - ERROR_RETURN_CODE( \ - GENERIC_ERROR, \ - int caosdb_entity_parent_set_##element(caosdb_entity_parent *parent, \ - const char *value), \ - { \ - auto *wrapped_parent = \ - static_cast<caosdb::entity::Parent *>(parent->wrapped_parent); \ - body_part return 0; \ +#define CAOSDB_PARENT_SET(element, value, body_part) \ + ERROR_RETURN_CODE( \ + GENERIC_ERROR, \ + int caosdb_entity_parent_set_##element(caosdb_entity_parent *parent, const char *value), { \ + auto *wrapped_parent = static_cast<caosdb::entity::Parent *>(parent->wrapped_parent); \ + body_part return 0; \ }) -int caosdb_constants_LIBCAOSDB_VERSION_MAJOR() { - return caosdb::LIBCAOSDB_VERSION_MAJOR; -} +int caosdb_constants_LIBCAOSDB_VERSION_MAJOR() { return caosdb::LIBCAOSDB_VERSION_MAJOR; } -int caosdb_constants_LIBCAOSDB_VERSION_MINOR() { - return caosdb::LIBCAOSDB_VERSION_MINOR; -} +int caosdb_constants_LIBCAOSDB_VERSION_MINOR() { return caosdb::LIBCAOSDB_VERSION_MINOR; } -int caosdb_constants_LIBCAOSDB_VERSION_PATCH() { - return caosdb::LIBCAOSDB_VERSION_PATCH; -} +int caosdb_constants_LIBCAOSDB_VERSION_PATCH() { return caosdb::LIBCAOSDB_VERSION_PATCH; } int caosdb_constants_COMPATIBLE_SERVER_VERSION_MAJOR() { return caosdb::COMPATIBLE_SERVER_VERSION_MAJOR; @@ -164,9 +143,7 @@ const char *caosdb_constants_COMPATIBLE_SERVER_VERSION_PRE_RELEASE() { return caosdb::COMPATIBLE_SERVER_VERSION_PRE_RELEASE; } -int caosdb_status_code_OTHER_CLIENT_ERROR() { - return caosdb::StatusCode::OTHER_CLIENT_ERROR; -} +int caosdb_status_code_OTHER_CLIENT_ERROR() { return caosdb::StatusCode::OTHER_CLIENT_ERROR; } const char *caosdb_utility_get_env_var(const char *name, const char *fallback) { return caosdb::utility::get_env_var(name, fallback); @@ -178,65 +155,61 @@ const char *caosdb_get_status_description(int code) { ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_connection_create_pem_file_certificate_provider( - caosdb_connection_certificate_provider *out, - const char *path), + 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)); + new caosdb::configuration::PemFileCertificateProvider(std::string(path)); out->_deletable = true; return 0; }) -ERROR_RETURN_CODE( - GENERIC_ERROR, - int caosdb_connection_delete_certificate_provider( - caosdb_connection_certificate_provider *provider), - { - if (provider->_deletable) { - delete static_cast<caosdb::configuration::CertificateProvider *>( - provider->wrapped_certificate_provider); - } - provider->_deletable = false; - return 0; - }) +ERROR_RETURN_CODE(GENERIC_ERROR, + int caosdb_connection_delete_certificate_provider( + caosdb_connection_certificate_provider *provider), + { + if (provider->_deletable) { + delete static_cast<caosdb::configuration::CertificateProvider *>( + provider->wrapped_certificate_provider); + } + provider->_deletable = false; + return 0; + }) ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_authentication_create_plain_password_authenticator( - caosdb_authentication_authenticator *out, - const char *username, const char *password), + 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)); + new caosdb::authentication::PlainPasswordAuthenticator(std::string(username), + std::string(password)); out->_deletable = true; return 0; }) -ERROR_RETURN_CODE( - GENERIC_ERROR, - int caosdb_authentication_delete_authenticator( - caosdb_authentication_authenticator *authenticator), - { - if (authenticator->_deletable) { - delete static_cast<caosdb::authentication::Authenticator *>( - authenticator->wrapped_authenticator); - } - authenticator->_deletable = false; - return 0; - }) +ERROR_RETURN_CODE(GENERIC_ERROR, + int caosdb_authentication_delete_authenticator( + caosdb_authentication_authenticator *authenticator), + { + if (authenticator->_deletable) { + delete static_cast<caosdb::authentication::Authenticator *>( + authenticator->wrapped_authenticator); + } + authenticator->_deletable = false; + return 0; + }) ERROR_RETURN_CODE( GENERIC_ERROR, int caosdb_connection_create_tls_connection_configuration( - caosdb_connection_connection_configuration *out, const char *host, - const int port, caosdb_authentication_authenticator *authenticator, + caosdb_connection_connection_configuration *out, const char *host, const int port, + caosdb_authentication_authenticator *authenticator, caosdb_connection_certificate_provider *provider), { if (out->_deletable) { @@ -244,29 +217,22 @@ ERROR_RETURN_CODE( } auto host_str = std::string(host); if (authenticator != nullptr && provider != nullptr) { - auto wrapped_provider = - static_cast<caosdb::configuration::CertificateProvider *>( - provider->wrapped_certificate_provider); + auto wrapped_provider = static_cast<caosdb::configuration::CertificateProvider *>( + provider->wrapped_certificate_provider); auto wrapped_authenticator = - static_cast<caosdb::authentication::Authenticator *>( - authenticator->wrapped_authenticator); - out->wrapped_connection_configuration = - new caosdb::configuration::TlsConnectionConfiguration( - host_str, port, *wrapped_provider, *wrapped_authenticator); + static_cast<caosdb::authentication::Authenticator *>(authenticator->wrapped_authenticator); + out->wrapped_connection_configuration = new caosdb::configuration::TlsConnectionConfiguration( + host_str, port, *wrapped_provider, *wrapped_authenticator); } else if (authenticator != nullptr) { auto wrapped_authenticator = - static_cast<caosdb::authentication::Authenticator *>( - authenticator->wrapped_authenticator); - out->wrapped_connection_configuration = - new caosdb::configuration::TlsConnectionConfiguration( - host_str, port, *wrapped_authenticator); + static_cast<caosdb::authentication::Authenticator *>(authenticator->wrapped_authenticator); + out->wrapped_connection_configuration = new caosdb::configuration::TlsConnectionConfiguration( + host_str, port, *wrapped_authenticator); } else if (provider != nullptr) { - auto wrapped_provider = - static_cast<caosdb::configuration::CertificateProvider *>( - provider->wrapped_certificate_provider); + auto wrapped_provider = static_cast<caosdb::configuration::CertificateProvider *>( + provider->wrapped_certificate_provider); out->wrapped_connection_configuration = - new caosdb::configuration::TlsConnectionConfiguration( - host_str, port, *wrapped_provider); + new caosdb::configuration::TlsConnectionConfiguration(host_str, port, *wrapped_provider); } else { out->wrapped_connection_configuration = new caosdb::configuration::TlsConnectionConfiguration(host_str, port); @@ -275,54 +241,50 @@ ERROR_RETURN_CODE( return 0; }) -ERROR_RETURN_CODE( - GENERIC_ERROR, - int caosdb_connection_create_insecure_connection_configuration( - 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; - return 0; - }) +ERROR_RETURN_CODE(GENERIC_ERROR, + int caosdb_connection_create_insecure_connection_configuration( + 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; + return 0; + }) -ERROR_RETURN_CODE( - GENERIC_ERROR, - int caosdb_connection_delete_connection_configuration( - caosdb_connection_connection_configuration *configuration), - { - if (configuration->_deletable) { - delete static_cast<caosdb::configuration::ConnectionConfiguration *>( - configuration->wrapped_connection_configuration); - } - configuration->_deletable = false; - return 0; - }) +ERROR_RETURN_CODE(GENERIC_ERROR, + int caosdb_connection_delete_connection_configuration( + caosdb_connection_connection_configuration *configuration), + { + if (configuration->_deletable) { + delete static_cast<caosdb::configuration::ConnectionConfiguration *>( + configuration->wrapped_connection_configuration); + } + configuration->_deletable = false; + return 0; + }) -ERROR_RETURN_CODE( - GENERIC_ERROR, - int caosdb_connection_create_connection( - 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); - out->wrapped_connection = new caosdb::connection::Connection(*config); - out->_deletable = true; - return 0; - }) +ERROR_RETURN_CODE(GENERIC_ERROR, + int caosdb_connection_create_connection( + 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); + out->wrapped_connection = new caosdb::connection::Connection(*config); + out->_deletable = true; + return 0; + }) ERROR_RETURN_CODE(GENERIC_ERROR, - int caosdb_connection_delete_connection( - caosdb_connection_connection *connection), + int caosdb_connection_delete_connection(caosdb_connection_connection *connection), { if (connection->_deletable) { delete static_cast<caosdb::connection::Connection *>( @@ -334,12 +296,11 @@ ERROR_RETURN_CODE(GENERIC_ERROR, ERROR_RETURN_CODE( GENERIC_ERROR, - int caosdb_connection_get_version_info( - caosdb_info_version_info *out, - const caosdb_connection_connection *connection), + int caosdb_connection_get_version_info(caosdb_info_version_info *out, + const caosdb_connection_connection *connection), { - auto *wrapped_connection = static_cast<caosdb::connection::Connection *>( - connection->wrapped_connection); + auto *wrapped_connection = + static_cast<caosdb::connection::Connection *>(connection->wrapped_connection); auto status = wrapped_connection->RetrieveVersionInfoNoExceptions(); if (status.IsError()) { @@ -352,33 +313,30 @@ ERROR_RETURN_CODE( out->patch = (int)version_info->GetPatch(); // copy pre_release, needs local variable because out->pre_release is const - char *pre_release = (char *)malloc( - sizeof(char) * (version_info->GetPreRelease().length() + 1)); + char *pre_release = (char *)malloc(sizeof(char) * (version_info->GetPreRelease().length() + 1)); strcpy(pre_release, version_info->GetPreRelease().c_str()); out->pre_release = pre_release; // copy build, needs local variable because out->build is const - char *build = - (char *)malloc(sizeof(char) * (version_info->GetBuild().length() + 1)); + char *build = (char *)malloc(sizeof(char) * (version_info->GetBuild().length() + 1)); strcpy(build, version_info->GetBuild().c_str()); out->build = build; return 0; }) -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; - return 0; - }) +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; + return 0; + }) ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_connection_connection_manager_get_connection( @@ -388,9 +346,7 @@ ERROR_RETURN_CODE(GENERIC_ERROR, return caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR; } out->wrapped_connection = - caosdb::connection::ConnectionManager::GetConnection( - std::string(name)) - .get(); + caosdb::connection::ConnectionManager::GetConnection(std::string(name)).get(); // managed by the connection manager now, so not // to be deleted manually out->_deletable = false; @@ -402,436 +358,393 @@ ERROR_RETURN_CODE(GENERIC_ERROR, ****************************************************************************/ ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_connection_connection_create_transaction( - caosdb_connection_connection *connection, - caosdb_transaction_transaction *out), + 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(); + static_cast<caosdb::connection::Connection *>(connection->wrapped_connection); + out->wrapped_transaction = wrapped_connection->CreateTransaction().release(); out->_deletable = true; return 0; }) -ERROR_RETURN_CODE(GENERIC_ERROR, - int caosdb_transaction_delete_transaction( - caosdb_transaction_transaction *transaction), - { - if (transaction->_deletable) { - delete static_cast<caosdb::transaction::Transaction *>( - transaction->wrapped_transaction); - } - return 0; - }) +ERROR_RETURN_CODE( + GENERIC_ERROR, + int caosdb_transaction_delete_transaction(caosdb_transaction_transaction *transaction), { + if (transaction->_deletable) { + delete static_cast<caosdb::transaction::Transaction *>(transaction->wrapped_transaction); + } + return 0; + }) ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_transaction_transaction_retrieve_by_id( - caosdb_transaction_transaction *transaction, - const char *id), + caosdb_transaction_transaction *transaction, const char *id), { - auto *wrapped_transaction = - static_cast<caosdb::transaction::Transaction *>( - transaction->wrapped_transaction); + auto *wrapped_transaction = static_cast<caosdb::transaction::Transaction *>( + transaction->wrapped_transaction); return wrapped_transaction->RetrieveById(std::string(id)); }) ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_transaction_transaction_retrieve_by_ids( - caosdb_transaction_transaction *transaction, - const char *ids[], int length), + caosdb_transaction_transaction *transaction, const char *ids[], int length), { - auto *wrapped_transaction = - static_cast<caosdb::transaction::Transaction *>( - transaction->wrapped_transaction); + auto *wrapped_transaction = static_cast<caosdb::transaction::Transaction *>( + transaction->wrapped_transaction); return wrapped_transaction->RetrieveById(ids, ids + length); }) ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_transaction_transaction_query( - caosdb_transaction_transaction *transaction, - const char *query), + caosdb_transaction_transaction *transaction, const char *query), { - auto *wrapped_transaction = - static_cast<caosdb::transaction::Transaction *>( - transaction->wrapped_transaction); + auto *wrapped_transaction = static_cast<caosdb::transaction::Transaction *>( + transaction->wrapped_transaction); return wrapped_transaction->Query(std::string(query)); }) -ERROR_RETURN_CODE(GENERIC_ERROR, - int caosdb_transaction_transaction_execute( - caosdb_transaction_transaction *transaction), - { - auto *wrapped_transaction = - static_cast<caosdb::transaction::Transaction *>( - transaction->wrapped_transaction); - wrapped_transaction->ExecuteAsynchronously(); - auto status = wrapped_transaction->WaitForIt(); - return status.GetCode(); - }) +ERROR_RETURN_CODE( + GENERIC_ERROR, + int caosdb_transaction_transaction_execute(caosdb_transaction_transaction *transaction), { + auto *wrapped_transaction = + static_cast<caosdb::transaction::Transaction *>(transaction->wrapped_transaction); + wrapped_transaction->ExecuteAsynchronously(); + auto status = wrapped_transaction->WaitForIt(); + return status.GetCode(); + }) -ERROR_RETURN_CODE(GENERIC_ERROR, - 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())); - out->_deletable = false; - return 0; - }) +ERROR_RETURN_CODE( + GENERIC_ERROR, + 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())); + out->_deletable = false; + return 0; + }) ERROR_RETURN_CODE(GENERIC_ERROR, int caosdb_transaction_transaction_get_count_result( caosdb_transaction_transaction *transaction, long *out), { - auto *wrapped_transaction = - static_cast<caosdb::transaction::Transaction *>( - transaction->wrapped_transaction); + auto *wrapped_transaction = static_cast<caosdb::transaction::Transaction *>( + transaction->wrapped_transaction); long cr(wrapped_transaction->GetCountResult()); *out = cr; return 0; }) ERROR_RETURN_CODE(GENERIC_ERROR, - int caosdb_transaction_result_set_at( - caosdb_transaction_result_set *result_set, - caosdb_entity_entity *entity, int index), + int caosdb_transaction_result_set_at(caosdb_transaction_result_set *result_set, + caosdb_entity_entity *entity, int index), { - auto *wrapped_result_set = - static_cast<caosdb::transaction::MultiResultSet *>( - result_set->wrapped_result_set); - entity->wrapped_entity = - wrapped_result_set->mutable_at(index); + auto *wrapped_result_set = static_cast<caosdb::transaction::MultiResultSet *>( + result_set->wrapped_result_set); + entity->wrapped_entity = wrapped_result_set->mutable_at(index); return 0; }) ERROR_RETURN_CODE(GENERIC_ERROR, - int caosdb_transaction_result_set_size( - caosdb_transaction_result_set *result_set, int *out), + int caosdb_transaction_result_set_size(caosdb_transaction_result_set *result_set, + int *out), { - auto *wrapped_result_set = - static_cast<caosdb::transaction::MultiResultSet *>( - result_set->wrapped_result_set); + auto *wrapped_result_set = static_cast<caosdb::transaction::MultiResultSet *>( + result_set->wrapped_result_set); int size(wrapped_result_set->size()); *out = size; return 0; }) +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) { + delete static_cast<caosdb::entity::Entity *>(out->wrapped_entity); + } + 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) { + delete static_cast<caosdb::entity::Property *>(out->wrapped_property); + } + 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) { + delete static_cast<caosdb::entity::Parent *>(out->wrapped_parent); + } + out->_deletable = false; + return 0; +}) + +CAOSDB_ENTITY_GET(id, strcpy(out, wrapped_entity->GetId().c_str());) +// TODO(fspreck) +// CAOSDB_ENTITY_GET(role, strcpy(out, wrapped_entity->GetRole().c_str());) +CAOSDB_ENTITY_GET(name, strcpy(out, wrapped_entity->GetName().c_str());) +CAOSDB_ENTITY_GET(description, strcpy(out, wrapped_entity->GetDescription().c_str());) +// TODO(fspreck) +// CAOSDB_ENTITY_GET(datatype, strcpy(out, +// wrapped_entity->GetDatatype().c_str());) +// TODO(fspreck) +// CAOSDB_ENTITY_GET(value, strcpy(out, wrapped_entity->GetValue().c_str());) +CAOSDB_ENTITY_GET(unit, strcpy(out, wrapped_entity->GetUnit().c_str());) +CAOSDB_ENTITY_GET(version_id, strcpy(out, wrapped_entity->GetVersionId().c_str());) + ERROR_RETURN_CODE(GENERIC_ERROR, - int caosdb_entity_create_entity(caosdb_entity_entity *out), { + int caosdb_entity_entity_get_errors_size(caosdb_entity_entity *entity, int *out), + { + auto *wrapped_entity = + static_cast<caosdb::entity::Entity *>(entity->wrapped_entity); + *out = wrapped_entity->GetErrors().size(); + return 0; + }) + +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; } - out->wrapped_entity = new caosdb::entity::Entity(); - out->_deletable = true; + auto *wrapped_entity = + static_cast<caosdb::entity::Entity *>(entity->wrapped_entity); + out->wrapped_message = wrapped_entity->GetErrors().mutable_at(index); + out->_deletable = false; + return 0; + }) + +ERROR_RETURN_CODE(GENERIC_ERROR, + int caosdb_entity_entity_get_warnings_size(caosdb_entity_entity *entity, + int *out), + { + auto *wrapped_entity = + static_cast<caosdb::entity::Entity *>(entity->wrapped_entity); + *out = wrapped_entity->GetWarnings().size(); return 0; }) ERROR_RETURN_CODE(GENERIC_ERROR, - int caosdb_entity_delete_entity(caosdb_entity_entity *out), { + int caosdb_entity_entity_get_warning(caosdb_entity_entity *entity, + caosdb_entity_message *out, int index), + { if (out->_deletable) { - delete static_cast<caosdb::entity::Entity *>( - out->wrapped_entity); + 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); 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) { - delete static_cast<caosdb::entity::Property *>(out->wrapped_property); - } - out->_deletable = false; - return 0; - }) +ERROR_RETURN_CODE(GENERIC_ERROR, + int caosdb_entity_entity_get_infos_size(caosdb_entity_entity *entity, int *out), { + auto *wrapped_entity = + static_cast<caosdb::entity::Entity *>(entity->wrapped_entity); + *out = wrapped_entity->GetInfos().size(); + return 0; + }) ERROR_RETURN_CODE(GENERIC_ERROR, - int caosdb_entity_create_parent(caosdb_entity_parent *out), { + 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; } - out->wrapped_parent = new caosdb::entity::Parent(); - out->_deletable = true; + auto *wrapped_entity = + static_cast<caosdb::entity::Entity *>(entity->wrapped_entity); + out->wrapped_message = wrapped_entity->GetInfos().mutable_at(index); + out->_deletable = false; + return 0; + }) + +ERROR_RETURN_CODE(GENERIC_ERROR, + int caosdb_entity_entity_get_properties_size(caosdb_entity_entity *entity, + int *out), + { + auto *wrapped_entity = + static_cast<caosdb::entity::Entity *>(entity->wrapped_entity); + *out = wrapped_entity->GetProperties().size(); return 0; }) ERROR_RETURN_CODE(GENERIC_ERROR, - int caosdb_entity_delete_parent(caosdb_entity_parent *out), { + int caosdb_entity_entity_get_property(caosdb_entity_entity *entity, + caosdb_entity_property *out, int index), + { if (out->_deletable) { - delete static_cast<caosdb::entity::Parent *>( - out->wrapped_parent); + 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); out->_deletable = false; return 0; }) -CAOSDB_ENTITY_GET(id, strcpy(out, wrapped_entity->GetId().c_str());) -CAOSDB_ENTITY_GET(role, strcpy(out, wrapped_entity->GetRole().c_str());) -CAOSDB_ENTITY_GET(name, strcpy(out, wrapped_entity->GetName().c_str());) -CAOSDB_ENTITY_GET(description, - strcpy(out, wrapped_entity->GetDescription().c_str());) -CAOSDB_ENTITY_GET(datatype, strcpy(out, wrapped_entity->GetDatatype().c_str());) -CAOSDB_ENTITY_GET(value, strcpy(out, wrapped_entity->GetValue().c_str());) -CAOSDB_ENTITY_GET(unit, strcpy(out, wrapped_entity->GetUnit().c_str());) -CAOSDB_ENTITY_GET(version_id, - strcpy(out, wrapped_entity->GetVersionId().c_str());) - -ERROR_RETURN_CODE( - GENERIC_ERROR, - int caosdb_entity_entity_get_errors_size(caosdb_entity_entity *entity, - int *out), - { - auto *wrapped_entity = - static_cast<caosdb::entity::Entity *>(entity->wrapped_entity); - *out = wrapped_entity->GetErrors().size(); - return 0; - }) - -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); - out->_deletable = false; - return 0; - }) - -ERROR_RETURN_CODE( - GENERIC_ERROR, - int caosdb_entity_entity_get_warnings_size(caosdb_entity_entity *entity, - int *out), - { - auto *wrapped_entity = - static_cast<caosdb::entity::Entity *>(entity->wrapped_entity); - *out = wrapped_entity->GetWarnings().size(); - return 0; - }) - -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); - out->_deletable = false; - return 0; - }) - -ERROR_RETURN_CODE( - GENERIC_ERROR, - int caosdb_entity_entity_get_infos_size(caosdb_entity_entity *entity, - int *out), - { - auto *wrapped_entity = - static_cast<caosdb::entity::Entity *>(entity->wrapped_entity); - *out = wrapped_entity->GetInfos().size(); - return 0; - }) - -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); - out->_deletable = false; - return 0; - }) - -ERROR_RETURN_CODE( - GENERIC_ERROR, - int caosdb_entity_entity_get_properties_size(caosdb_entity_entity *entity, - int *out), - { - auto *wrapped_entity = - static_cast<caosdb::entity::Entity *>(entity->wrapped_entity); - *out = wrapped_entity->GetProperties().size(); - return 0; - }) - -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); - out->_deletable = false; - return 0; - }) - -ERROR_RETURN_CODE( - GENERIC_ERROR, - int caosdb_entity_entity_get_parents_size(caosdb_entity_entity *entity, - int *out), - { - auto *wrapped_entity = - static_cast<caosdb::entity::Entity *>(entity->wrapped_entity); - *out = wrapped_entity->GetParents().size(); - return 0; - }) +ERROR_RETURN_CODE(GENERIC_ERROR, + int caosdb_entity_entity_get_parents_size(caosdb_entity_entity *entity, int *out), + { + auto *wrapped_entity = + static_cast<caosdb::entity::Entity *>(entity->wrapped_entity); + *out = wrapped_entity->GetParents().size(); + return 0; + }) -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); - out->_deletable = false; - return 0; - }) +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); + out->_deletable = false; + return 0; + }) CAOSDB_PARENT_GET(id, strcpy(out, wrapped_parent->GetId().c_str());) CAOSDB_PARENT_GET(name, strcpy(out, wrapped_parent->GetName().c_str());) -CAOSDB_PARENT_GET(description, - strcpy(out, wrapped_parent->GetDescription().c_str());) +CAOSDB_PARENT_GET(description, strcpy(out, wrapped_parent->GetDescription().c_str());) CAOSDB_PROPERTY_GET(id, strcpy(out, wrapped_property->GetId().c_str());) CAOSDB_PROPERTY_GET(name, strcpy(out, wrapped_property->GetName().c_str());) -CAOSDB_PROPERTY_GET(description, - strcpy(out, wrapped_property->GetDescription().c_str());) -CAOSDB_PROPERTY_GET(importance, - strcpy(out, wrapped_property->GetImportance().c_str());) -CAOSDB_PROPERTY_GET(datatype, - strcpy(out, wrapped_property->GetDatatype().c_str());) +CAOSDB_PROPERTY_GET(description, strcpy(out, wrapped_property->GetDescription().c_str());) +// TODO(fspreck) +// CAOSDB_PROPERTY_GET(importance, +// strcpy(out, wrapped_property->GetImportance().c_str());) +// TODO(fspreck) +// CAOSDB_PROPERTY_GET(datatype, +// strcpy(out, wrapped_property->GetDatatype().c_str());) CAOSDB_PROPERTY_GET(unit, strcpy(out, wrapped_property->GetUnit().c_str());) -CAOSDB_PROPERTY_GET(value, strcpy(out, wrapped_property->GetValue().c_str());) +// TODO(fspreck) +// CAOSDB_PROPERTY_GET(value, strcpy(out, +// wrapped_property->GetValue().c_str());) -ERROR_RETURN_CODE( - GENERIC_ERROR, - int caosdb_entity_message_get_code(caosdb_entity_message *message, int *out), - { - auto *wrapped_message = - static_cast<caosdb::entity::Message *>(message->wrapped_message); - *out = wrapped_message->GetCode(); - return 0; - }) +ERROR_RETURN_CODE(GENERIC_ERROR, + int caosdb_entity_message_get_code(caosdb_entity_message *message, int *out), { + auto *wrapped_message = + static_cast<caosdb::entity::Message *>(message->wrapped_message); + *out = wrapped_message->GetCode(); + return 0; + }) -ERROR_RETURN_CODE( - GENERIC_ERROR, - int caosdb_entity_message_get_description(caosdb_entity_message *message, - char *out), - { - auto *wrapped_message = - static_cast<caosdb::entity::Message *>(message->wrapped_message); - strcpy(out, wrapped_message->GetDescription().c_str()); - return 0; - }) +ERROR_RETURN_CODE(GENERIC_ERROR, + int caosdb_entity_message_get_description(caosdb_entity_message *message, + char *out), + { + auto *wrapped_message = + static_cast<caosdb::entity::Message *>(message->wrapped_message); + strcpy(out, wrapped_message->GetDescription().c_str()); + return 0; + }) -CAOSDB_ENTITY_SET(role, role, wrapped_entity->SetRole(std::string(role));) +// TODO(fspreck) +// CAOSDB_ENTITY_SET(role, role, wrapped_entity->SetRole(std::string(role));) CAOSDB_ENTITY_SET(name, name, wrapped_entity->SetName(std::string(name));) CAOSDB_ENTITY_SET(description, description, wrapped_entity->SetDescription(std::string(description));) -CAOSDB_ENTITY_SET(datatype, datatype, - wrapped_entity->SetDatatype(std::string(datatype));) +// TODO(fspreck) +// CAOSDB_ENTITY_SET(datatype, datatype, +// wrapped_entity->SetDataType(std::string(datatype));) CAOSDB_ENTITY_SET(unit, unit, wrapped_entity->SetUnit(std::string(unit));) -CAOSDB_ENTITY_SET(value, value, wrapped_entity->SetValue(std::string(value));) +// TODO(fspreck) +// CAOSDB_ENTITY_SET(value, value, +// wrapped_entity->SetValue(std::string(value));) -ERROR_RETURN_CODE( - GENERIC_ERROR, - int caosdb_entity_entity_append_parent(caosdb_entity_entity *entity, - caosdb_entity_parent *parent), - { - auto *wrapped_entity = - static_cast<caosdb::entity::Entity *>(entity->wrapped_entity); - auto *wrapped_parent = - static_cast<caosdb::entity::Parent *>(parent->wrapped_parent); - wrapped_entity->AppendParent(*wrapped_parent); - return 0; - }) +ERROR_RETURN_CODE(GENERIC_ERROR, + int caosdb_entity_entity_append_parent(caosdb_entity_entity *entity, + caosdb_entity_parent *parent), + { + auto *wrapped_entity = + static_cast<caosdb::entity::Entity *>(entity->wrapped_entity); + auto *wrapped_parent = + static_cast<caosdb::entity::Parent *>(parent->wrapped_parent); + wrapped_entity->AppendParent(*wrapped_parent); + return 0; + }) -ERROR_RETURN_CODE( - GENERIC_ERROR, - int caosdb_entity_entity_remove_parent(caosdb_entity_entity *entity, - int index), - { - auto *wrapped_entity = - static_cast<caosdb::entity::Entity *>(entity->wrapped_entity); - wrapped_entity->RemoveParent(index); - return 0; - }) +ERROR_RETURN_CODE(GENERIC_ERROR, + int caosdb_entity_entity_remove_parent(caosdb_entity_entity *entity, int index), { + auto *wrapped_entity = + static_cast<caosdb::entity::Entity *>(entity->wrapped_entity); + wrapped_entity->RemoveParent(index); + return 0; + }) -ERROR_RETURN_CODE( - GENERIC_ERROR, - int caosdb_entity_entity_append_property(caosdb_entity_entity *entity, - caosdb_entity_property *property), - { - auto *wrapped_entity = - static_cast<caosdb::entity::Entity *>(entity->wrapped_entity); - auto *wrapped_property = - static_cast<caosdb::entity::Property *>(property->wrapped_property); - wrapped_entity->AppendProperty(*wrapped_property); - return 0; - }) -ERROR_RETURN_CODE( - GENERIC_ERROR, - int caosdb_entity_entity_remove_property(caosdb_entity_entity *entity, - int index), - { - auto *wrapped_entity = - static_cast<caosdb::entity::Entity *>(entity->wrapped_entity); - wrapped_entity->RemoveProperty(index); - return 0; - }) +ERROR_RETURN_CODE(GENERIC_ERROR, + int caosdb_entity_entity_append_property(caosdb_entity_entity *entity, + caosdb_entity_property *property), + { + auto *wrapped_entity = + static_cast<caosdb::entity::Entity *>(entity->wrapped_entity); + auto *wrapped_property = + static_cast<caosdb::entity::Property *>(property->wrapped_property); + wrapped_entity->AppendProperty(*wrapped_property); + return 0; + }) +ERROR_RETURN_CODE(GENERIC_ERROR, + int caosdb_entity_entity_remove_property(caosdb_entity_entity *entity, int index), + { + auto *wrapped_entity = + static_cast<caosdb::entity::Entity *>(entity->wrapped_entity); + wrapped_entity->RemoveProperty(index); + return 0; + }) CAOSDB_PARENT_SET(id, id, wrapped_parent->SetId(std::string(id));) CAOSDB_PARENT_SET(name, name, wrapped_parent->SetName(std::string(name));) CAOSDB_PROPERTY_SET(name, name, wrapped_property->SetName(std::string(name));) CAOSDB_PROPERTY_SET(id, id, wrapped_property->SetId(std::string(id));) -CAOSDB_PROPERTY_SET(datatype, datatype, - wrapped_property->SetDatatype(std::string(datatype));) -CAOSDB_PROPERTY_SET(importance, importance, - wrapped_property->SetImportance(std::string(importance));) +// TODO(fspreck) +// CAOSDB_PROPERTY_SET(datatype, datatype, +// wrapped_property->SetDataType(std::string(datatype));) +// TODO(fspreck) +// CAOSDB_PROPERTY_SET(importance, importance, +// wrapped_property->SetImportance(std::string(importance));) CAOSDB_PROPERTY_SET(unit, unit, wrapped_property->SetUnit(std::string(unit));) -CAOSDB_PROPERTY_SET(value, value, - wrapped_property->SetValue(std::string(value));) +// TODO(fspreck) +// CAOSDB_PROPERTY_SET(value, value, +// wrapped_property->SetValue(std::string(value));) } diff --git a/src/ccaosdbcli.c b/src/ccaosdbcli.c index e06dff51bcc62fcc8ae2bc4e2db53647d6c3de06..e3ce7dea431441b5ef6f827f02f8741681f631c2 100644 --- a/src/ccaosdbcli.c +++ b/src/ccaosdbcli.c @@ -4,30 +4,25 @@ int main(void) { int status = 0; // last function return value - printf( - "CaosDB C client (libcaosdb %d.%d.%d)\nWe don't miss the H of caos.\n\n", - LIBCAOSDB_VERSION_MAJOR, LIBCAOSDB_VERSION_MINOR, LIBCAOSDB_VERSION_PATCH); + printf("CaosDB C client (libcaosdb %d.%d.%d)\nWe don't miss the H of caos.\n\n", + LIBCAOSDB_VERSION_MAJOR, LIBCAOSDB_VERSION_MINOR, LIBCAOSDB_VERSION_PATCH); caosdb_connection_connection connection; - status = - caosdb_connection_connection_manager_get_default_connection(&connection); + status = caosdb_connection_connection_manager_get_default_connection(&connection); if (status != 0) { - printf("An error occured: ERROR %d - %s\n", status, - caosdb_get_status_description(status)); + printf("An error occured: ERROR %d - %s\n", status, caosdb_get_status_description(status)); return status; } caosdb_info_version_info version_info; status = caosdb_connection_get_version_info(&version_info, &connection); if (status != 0) { - printf("An error occured: ERROR %d - %s\n", status, - caosdb_get_status_description(status)); + printf("An error occured: ERROR %d - %s\n", status, caosdb_get_status_description(status)); return status; } - printf("Server version: %d.%d.%d-%s-%s\n", version_info.major, - version_info.minor, version_info.patch, version_info.pre_release, - version_info.build); + printf("Server version: %d.%d.%d-%s-%s\n", version_info.major, version_info.minor, + version_info.patch, version_info.pre_release, version_info.build); return 0; } diff --git a/src/cxxcaosdbcli.cpp b/src/cxxcaosdbcli.cpp index f94144923b79fc4f2a511b6248f158067085b222..1760975460281614051c1ac9790be840d7c36c4f 100644 --- a/src/cxxcaosdbcli.cpp +++ b/src/cxxcaosdbcli.cpp @@ -33,23 +33,19 @@ auto main() -> int { - std::cout << "CaosDB C++ client (libcaosdb " - << caosdb::LIBCAOSDB_VERSION_MINOR << "." - << caosdb::LIBCAOSDB_VERSION_MINOR << "." - << caosdb::LIBCAOSDB_VERSION_PATCH << ")\n" + std::cout << "CaosDB C++ client (libcaosdb " << caosdb::LIBCAOSDB_VERSION_MINOR << "." + << caosdb::LIBCAOSDB_VERSION_MINOR << "." << caosdb::LIBCAOSDB_VERSION_PATCH << ")\n" << "We don't miss the H of caos.\n" << std::endl; try { - const auto &connection = - caosdb::connection::ConnectionManager::GetDefaultConnection(); + const auto &connection = caosdb::connection::ConnectionManager::GetDefaultConnection(); connection->RetrieveVersionInfoNoExceptions(); // get version info of the server const auto &v_info = connection->GetVersionInfo(); - std::cout << "Server Version: " << v_info->GetMajor() << "." - << v_info->GetMinor() << "." << v_info->GetPatch() << "-" - << v_info->GetPreRelease() << "-" << v_info->GetBuild() + std::cout << "Server Version: " << v_info->GetMajor() << "." << v_info->GetMinor() << "." + << v_info->GetPatch() << "-" << v_info->GetPreRelease() << "-" << v_info->GetBuild() << std::endl; // retrieve an entity @@ -57,12 +53,10 @@ auto main() -> int { transaction->RetrieveById("20"); transaction->Execute(); const auto &result_set = - dynamic_cast<const caosdb::transaction::UniqueResult &>( - transaction->GetResultSet()); + dynamic_cast<const caosdb::transaction::UniqueResult &>(transaction->GetResultSet()); // print description - std::cout << "Entity Description: " - << result_set.GetEntity().GetDescription() << std::endl; + std::cout << "Entity Description: " << result_set.GetEntity().GetDescription() << std::endl; return 0; } catch (const caosdb::exceptions::ConfigurationError &exc) { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0ecb50169e94b5f758a429054c80c80e9d420c4d..6edff54857aca64b64c99a47ea8344ebf9eee265 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -20,14 +20,17 @@ # append all the test cases here (file name without the ".cpp" suffix) set(test_cases + test_data_type test_configuration test_connection test_entity test_file_transmission test_info + test_list_properties test_protobuf test_transaction test_utility + test_value test_ccaosdb ) @@ -57,15 +60,16 @@ foreach (i RANGE "${len_test_cases}") target_include_directories(${test_case_name} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) if(_LINTING) - set_target_properties(${test_case_name} - PROPERTIES - CXX_CLANG_TIDY "${_CMAKE_CXX_CLANG_TIDY};${_CMAKE_CXX_CLANG_TIDY_TEST_CHECKS}" - CXX_INCLUDE_WHAT_YOU_USE "${_CMAKE_CXX_INCLUDE_WHAT_YOU_USE}") + set_target_properties(${test_case_name} + PROPERTIES + CXX_CLANG_TIDY "${_CMAKE_CXX_CLANG_TIDY};${_CMAKE_CXX_CLANG_TIDY_TEST_CHECKS}" + CXX_INCLUDE_WHAT_YOU_USE "${_CMAKE_CXX_INCLUDE_WHAT_YOU_USE}") endif() gtest_discover_tests(${test_case_name} WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" PROPERTIES - LABELS "caosdb-cpplib-unit-tests") + LABELS "caosdb-cpplib-unit-tests" + ) endforeach () # copy test data to build dir diff --git a/test/caosdb_test_utility.h.in b/test/caosdb_test_utility.h.in index baac638f5668a05c6464fef99410bb345ba8b3c3..8c3761e9f57432c8345f56bd4734fe633247228a 100644 --- a/test/caosdb_test_utility.h.in +++ b/test/caosdb_test_utility.h.in @@ -29,31 +29,47 @@ * @author Timm Fitschen * @date 2021-07-07 */ -#define EXPECT_THROW_MESSAGE(statement, exeption_type, message) \ - EXPECT_THROW( \ - try { statement; } catch (const exeption_type &e) { \ - EXPECT_EQ(std::string(e.what()), message); \ - throw; \ - }, \ - exeption_type) -#define ASSERT_THROW_MESSAGE(statement, exeption_type, message) \ - ASSERT_THROW( \ - try { statement; } catch (const exeption_type &e) { \ - ASSERT_EQ(std::string(e.what()), message); \ - throw; \ - }, \ - exeption_type) -#define EXPECT_NULL(statement) \ - if (statement != nullptr) { \ - FAIL() << "Should be a nullptr"; \ - } else { \ - SUCCEED(); \ +#define EXPECT_THROW_MESSAGE(statement, exception_type, message) \ + EXPECT_THROW( \ + try { statement; } catch (const exception_type &e) { \ + EXPECT_EQ(std::string(e.what()), message); \ + throw; \ + }, \ + exception_type) +#define ASSERT_THROW_MESSAGE(statement, exception_type, message) \ + ASSERT_THROW( \ + try { statement; } catch (const exception_type &e) { \ + ASSERT_EQ(std::string(e.what()), message); \ + throw; \ + }, \ + exception_type) +#define EXPECT_THROW_STARTS_WITH(statement, exception_type, pattern) \ + EXPECT_THROW( \ + try { statement; } catch (const exception_type &e) { \ + auto pat_s = std::string(pattern); \ + EXPECT_EQ(std::string(e.what()).substr(0, pat_s.size()), pat_s); \ + throw; \ + }, \ + exception_type) +#define ASSERT_THROW_STARTS_WITH(statement, exception_type, message) \ + ASSERT_THROW( \ + try { statement; } catch (const exception_type &e) { \ + auto pat_s = std::string(pattern); \ + ASSERT_EQ(std::string(e.what()).substr(0, pat_s.size()), pat_s); \ + throw; \ + }, \ + exception_type) +#define EXPECT_NULL(statement) \ + if (statement != nullptr) { \ + FAIL() << "Should be a nullptr"; \ + } else { \ + SUCCEED(); \ } -#define ASSERT_NULL(statement) \ - if (statement != nullptr) { \ - ADD_FAIL() << "Should be a nullptr"; \ - } else { \ - SUCCEED(); \ +#define ASSERT_NULL(statement) \ + if (statement != nullptr) { \ + ADD_FAIL() << "Should be a nullptr"; \ + } else { \ + SUCCEED(); \ } #endif diff --git a/test/test_ccaosdb.cpp b/test/test_ccaosdb.cpp index 1009cc5962c6a309052509e36d39c3f6ee97ea98..2c45ef7bf3986c8461a9ffe0943e8d1ba1112621 100644 --- a/test/test_ccaosdb.cpp +++ b/test/test_ccaosdb.cpp @@ -39,20 +39,16 @@ protected: TEST_DATA_DIR + "/test_caosdb_client.json"); } - void TearDown() override { - caosdb::configuration::ConfigurationManager::Clear(); - } + void TearDown() override { caosdb::configuration::ConfigurationManager::Clear(); } }; TEST_F(test_ccaosdb, test_get_env_var) { - const char *const some_var = - caosdb_utility_get_env_var("SOME_ENV_VAR", "fall-back"); + const char *const some_var = caosdb_utility_get_env_var("SOME_ENV_VAR", "fall-back"); EXPECT_EQ("fall-back", some_var); } TEST_F(test_ccaosdb, test_other_client_error) { - EXPECT_EQ(caosdb_status_code_OTHER_CLIENT_ERROR(), - caosdb::StatusCode::OTHER_CLIENT_ERROR); + EXPECT_EQ(caosdb_status_code_OTHER_CLIENT_ERROR(), caosdb::StatusCode::OTHER_CLIENT_ERROR); } TEST_F(test_ccaosdb, test_get_default_connection) { @@ -65,23 +61,20 @@ TEST_F(test_ccaosdb, test_get_default_connection) { TEST_F(test_ccaosdb, test_get_connection) { caosdb_connection_connection out; - caosdb_connection_connection_manager_get_connection(&out, - "local-caosdb-admin"); + caosdb_connection_connection_manager_get_connection(&out, "local-caosdb-admin"); EXPECT_TRUE(out.wrapped_connection); } TEST_F(test_ccaosdb, test_execute_transaction) { caosdb_connection_connection connection; - caosdb_connection_connection_manager_get_connection(&connection, - "local-caosdb-admin"); + caosdb_connection_connection_manager_get_connection(&connection, "local-caosdb-admin"); caosdb_transaction_transaction transaction; caosdb_connection_connection_create_transaction(&connection, &transaction); EXPECT_TRUE(transaction.wrapped_transaction); - int return_code( - caosdb_transaction_transaction_retrieve_by_id(&transaction, "some_id")); + int return_code(caosdb_transaction_transaction_retrieve_by_id(&transaction, "some_id")); EXPECT_EQ(return_code, caosdb::StatusCode::GO_ON); return_code = caosdb_transaction_transaction_execute(&transaction); @@ -91,14 +84,12 @@ TEST_F(test_ccaosdb, test_execute_transaction) { EXPECT_EQ(return_code, 0); caosdb_transaction_transaction multi_transaction; - caosdb_connection_connection_create_transaction(&connection, - &multi_transaction); + caosdb_connection_connection_create_transaction(&connection, &multi_transaction); // We explicitely want to define a C-style array here, so we disable // linting const char *ids[] = {"id1", "id2", "id3"}; // NOLINT - return_code = - caosdb_transaction_transaction_retrieve_by_ids(&multi_transaction, ids, 3); + return_code = caosdb_transaction_transaction_retrieve_by_ids(&multi_transaction, ids, 3); EXPECT_EQ(return_code, caosdb::StatusCode::GO_ON); return_code = caosdb_transaction_delete_transaction(&multi_transaction); @@ -108,20 +99,17 @@ TEST_F(test_ccaosdb, test_execute_transaction) { TEST_F(test_ccaosdb, test_multi_retrieve) { std::cout << "Entering test_multi_retrieve ..." << std::endl; caosdb_connection_connection connection; - caosdb_connection_connection_manager_get_connection(&connection, - "local-caosdb-admin"); + caosdb_connection_connection_manager_get_connection(&connection, "local-caosdb-admin"); std::cout << "Creating transaction" << std::endl; caosdb_transaction_transaction multi_transaction; - caosdb_connection_connection_create_transaction(&connection, - &multi_transaction); + caosdb_connection_connection_create_transaction(&connection, &multi_transaction); // We explicitely want to define a C-style array here, so we disable // linting const char *ids[] = {"id1", "id2", "id3"}; // NOLINT std::cout << "Adding mutli retrieval ..." << std::endl; - int return_code( - caosdb_transaction_transaction_retrieve_by_ids(&multi_transaction, ids, 3)); + int return_code(caosdb_transaction_transaction_retrieve_by_ids(&multi_transaction, ids, 3)); EXPECT_EQ(return_code, caosdb::StatusCode::GO_ON); std::cout << "Deleting transaction ..." << std::endl; @@ -131,14 +119,12 @@ TEST_F(test_ccaosdb, test_multi_retrieve) { TEST_F(test_ccaosdb, test_query) { caosdb_connection_connection connection; - caosdb_connection_connection_manager_get_connection(&connection, - "local-caosdb-admin"); + caosdb_connection_connection_manager_get_connection(&connection, "local-caosdb-admin"); caosdb_transaction_transaction transaction; caosdb_connection_connection_create_transaction(&connection, &transaction); - int return_code(caosdb_transaction_transaction_query( - &transaction, "FIND ENTITY WITH id=123")); + int return_code(caosdb_transaction_transaction_query(&transaction, "FIND ENTITY WITH id=123")); EXPECT_EQ(return_code, caosdb::StatusCode::GO_ON); return_code = caosdb_transaction_delete_transaction(&transaction); @@ -170,25 +156,28 @@ TEST_F(test_ccaosdb, test_entity) { EXPECT_EQ(return_code, 0); EXPECT_EQ(strcmp(out, "length"), 0); - caosdb_entity_entity_set_role(&entity, "Property"); - caosdb_entity_entity_get_role(&entity, out); - EXPECT_EQ(strcmp(out, "Property"), 0); + // TODO(fspreck) + // caosdb_entity_entity_set_role(&entity, "Property"); + // caosdb_entity_entity_get_role(&entity, out); + // EXPECT_EQ(strcmp(out, "Property"), 0); caosdb_entity_entity_set_description(&entity, "The length of an object"); caosdb_entity_entity_get_description(&entity, out); EXPECT_EQ(strcmp(out, "The length of an object"), 0); - caosdb_entity_entity_set_datatype(&entity, "DOUBLE"); - caosdb_entity_entity_get_datatype(&entity, out); - EXPECT_EQ(strcmp(out, "DOUBLE"), 0); + // TODO(fspreck) + // caosdb_entity_entity_set_datatype(&entity, "DOUBLE"); + // caosdb_entity_entity_get_datatype(&entity, out); + // EXPECT_EQ(strcmp(out, "DOUBLE"), 0); caosdb_entity_entity_set_unit(&entity, "m"); caosdb_entity_entity_get_unit(&entity, out); EXPECT_EQ(strcmp(out, "m"), 0); - caosdb_entity_entity_set_value(&entity, "5.0"); - caosdb_entity_entity_get_value(&entity, out); - EXPECT_EQ(strcmp(out, "5.0"), 0); + // TODO(fspreck) + // caosdb_entity_entity_set_value(&entity, "5.0"); + // caosdb_entity_entity_get_value(&entity, out); + // EXPECT_EQ(strcmp(out, "5.0"), 0); return_code = caosdb_entity_delete_entity(&entity); EXPECT_EQ(return_code, 0); @@ -222,10 +211,13 @@ TEST_F(test_ccaosdb, test_property) { caosdb_entity_property_set_id(&property, "some_id"); caosdb_entity_property_set_name(&property, "some_name"); - caosdb_entity_property_set_datatype(&property, "some_datatype"); - caosdb_entity_property_set_importance(&property, "some_importance"); + // TODO(fspreck) + // caosdb_entity_property_set_datatype(&property, "some_datatype"); + // TODO(fspreck) + // caosdb_entity_property_set_importance(&property, "some_importance"); caosdb_entity_property_set_unit(&property, "some_unit"); - caosdb_entity_property_set_value(&property, "some_value"); + // TODO(fspreck) + // caosdb_entity_property_set_value(&property, "some_value"); char out[255] = {"a"}; // NOLINT caosdb_entity_property_get_id(&property, out); @@ -234,17 +226,20 @@ TEST_F(test_ccaosdb, test_property) { caosdb_entity_property_get_name(&property, out); EXPECT_EQ(strcmp(out, "some_name"), 0); - caosdb_entity_property_get_datatype(&property, out); - EXPECT_EQ(strcmp(out, "some_datatype"), 0); + // TODO(fspreck) + // caosdb_entity_property_get_datatype(&property, out); + // EXPECT_EQ(strcmp(out, "some_datatype"), 0); - caosdb_entity_property_get_importance(&property, out); - EXPECT_EQ(strcmp(out, "some_importance"), 0); + // TODO(fspreck) + // caosdb_entity_property_get_importance(&property, out); + // EXPECT_EQ(strcmp(out, "some_importance"), 0); caosdb_entity_property_get_unit(&property, out); EXPECT_EQ(strcmp(out, "some_unit"), 0); - caosdb_entity_property_get_value(&property, out); - EXPECT_EQ(strcmp(out, "some_value"), 0); + // TODO(fspreck) + // caosdb_entity_property_get_value(&property, out); + // EXPECT_EQ(strcmp(out, "some_value"), 0); return_code = caosdb_entity_delete_property(&property); EXPECT_EQ(return_code, 0); @@ -265,8 +260,10 @@ TEST_F(test_ccaosdb, test_entity_with_parent_and_property) { caosdb_entity_property_set_id(&input_property, "property_id"); caosdb_entity_property_set_name(&input_property, "property_name"); - caosdb_entity_property_set_datatype(&input_property, "property_datatype"); - caosdb_entity_property_set_value(&input_property, "property_value"); + // TODO(fspreck) + // caosdb_entity_property_set_datatype(&input_property, "property_datatype"); + // TODO(fspreck) + // caosdb_entity_property_set_value(&input_property, "property_value"); caosdb_entity_entity entity; return_code = caosdb_entity_create_entity(&entity); @@ -311,13 +308,15 @@ TEST_F(test_ccaosdb, test_entity_with_parent_and_property) { caosdb_entity_property_get_name(&output_property, out); EXPECT_EQ(strcmp(in, out), 0); - caosdb_entity_property_get_datatype(&input_property, in); - caosdb_entity_property_get_datatype(&output_property, out); - EXPECT_EQ(strcmp(in, out), 0); + // TODO(fspreck) + // caosdb_entity_property_get_datatype(&input_property, in); + // caosdb_entity_property_get_datatype(&output_property, out); + // EXPECT_EQ(strcmp(in, out), 0); - caosdb_entity_property_get_value(&input_property, in); - caosdb_entity_property_get_value(&output_property, out); - EXPECT_EQ(strcmp(in, out), 0); + // TODO(fspreck) + // caosdb_entity_property_get_value(&input_property, in); + // caosdb_entity_property_get_value(&output_property, out); + // EXPECT_EQ(strcmp(in, out), 0); std::cout << "Comparing parent..." << std::endl; caosdb_entity_parent output_parent; diff --git a/test/test_configuration.cpp b/test/test_configuration.cpp index abc797fbe97fb408e0ff05ea5deab2a8581f194a..6d5f2e9449e5be21452fdcca6a04f4e02f531d13 100644 --- a/test/test_configuration.cpp +++ b/test/test_configuration.cpp @@ -39,52 +39,43 @@ protected: }; TEST_F(test_configuration, load_json) { - ConfigurationManager::LoadSingleJSONConfiguration(TEST_DATA_DIR + - "/test_caosdb_client.json"); - EXPECT_THROW_MESSAGE( - ConfigurationManager::LoadSingleJSONConfiguration("anything"), - ConfigurationError, "This CaosDB client has already been configured."); + ConfigurationManager::LoadSingleJSONConfiguration(TEST_DATA_DIR + "/test_caosdb_client.json"); + EXPECT_THROW_MESSAGE(ConfigurationManager::LoadSingleJSONConfiguration("anything"), + ConfigurationError, "This CaosDB client has already been configured."); ConfigurationManager::Clear(); - EXPECT_THROW_MESSAGE( - ConfigurationManager::LoadSingleJSONConfiguration("anything"), - ConfigurationError, "Configuration file does not exist."); + EXPECT_THROW_MESSAGE(ConfigurationManager::LoadSingleJSONConfiguration("anything"), + ConfigurationError, "Configuration file does not exist."); ConfigurationManager::Clear(); } TEST_F(test_configuration, get_default_connection_configuration_error) { - EXPECT_THROW_MESSAGE(ConfigurationManager::GetDefaultConnectionName(), - ConfigurationError, + EXPECT_THROW_MESSAGE(ConfigurationManager::GetDefaultConnectionName(), ConfigurationError, "This CaosDB client has not been configured."); ConfigurationManager::LoadSingleJSONConfiguration( TEST_DATA_DIR + "/test_broken_caosdb_client_no_connections1.json"); - EXPECT_THROW_MESSAGE(ConfigurationManager::GetDefaultConnectionName(), - ConfigurationError, + EXPECT_THROW_MESSAGE(ConfigurationManager::GetDefaultConnectionName(), ConfigurationError, "This CaosDB client hasn't any configured connections."); ConfigurationManager::Clear(); ConfigurationManager::LoadSingleJSONConfiguration( TEST_DATA_DIR + "/test_broken_caosdb_client_no_connections2.json"); - EXPECT_THROW_MESSAGE(ConfigurationManager::GetDefaultConnectionName(), - ConfigurationError, + EXPECT_THROW_MESSAGE(ConfigurationManager::GetDefaultConnectionName(), ConfigurationError, "This CaosDB client hasn't any configured connections."); ConfigurationManager::Clear(); ConfigurationManager::LoadSingleJSONConfiguration( TEST_DATA_DIR + "/test_broken_caosdb_client_no_connections3.json"); - EXPECT_THROW_MESSAGE(ConfigurationManager::GetDefaultConnectionName(), - ConfigurationError, + EXPECT_THROW_MESSAGE(ConfigurationManager::GetDefaultConnectionName(), ConfigurationError, "This CaosDB client hasn't any configured connections."); ConfigurationManager::Clear(); } TEST_F(test_configuration, initialize_logging) { - auto logging_configuration = - caosdb::logging::LoggingConfiguration(CAOSDB_LOG_LEVEL_ALL); - auto console_sink = - std::make_shared<caosdb::logging::ConsoleSinkConfiguration>( - "console", CAOSDB_DEFAULT_LOG_LEVEL); + auto logging_configuration = caosdb::logging::LoggingConfiguration(CAOSDB_LOG_LEVEL_ALL); + auto console_sink = std::make_shared<caosdb::logging::ConsoleSinkConfiguration>( + "console", CAOSDB_DEFAULT_LOG_LEVEL); logging_configuration.AddSink(console_sink); initialize_logging(logging_configuration); diff --git a/test/test_connection.cpp b/test/test_connection.cpp index 7c2efab9566d58c709c060e4206fc0d193ac75df..99391536edf031fbe4a326f56e24f68e5a50b5d3 100644 --- a/test/test_connection.cpp +++ b/test/test_connection.cpp @@ -40,8 +40,7 @@ class test_connection : public ::testing::Test { protected: void SetUp() override { ConfigurationManager::Clear(); - ConfigurationManager::LoadSingleJSONConfiguration( - TEST_DATA_DIR + "/test_caosdb_client.json"); + ConfigurationManager::LoadSingleJSONConfiguration(TEST_DATA_DIR + "/test_caosdb_client.json"); }; void TearDown() override { ConfigurationManager::Clear(); }; }; diff --git a/test/test_data_type.cpp b/test/test_data_type.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9200a68356695b5bde9bbd1e2125e604ea2c078c --- /dev/null +++ b/test/test_data_type.cpp @@ -0,0 +1,116 @@ +/* + * + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com> + * Copyright (C) 2021 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/>. + * + */ + +#include "caosdb/data_type.h" // for DataType, AtomicDataType +#include "caosdb/entity.h" // for Entity +#include "caosdb/logging.h" // for CAOSDB_LOG_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 <string> // for allocator + +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; + +TEST(test_data_type, test_atomic) { + ProtoDataType proto_data_type; + + for (const auto &map_el : atomicdatatype_names) { + Entity entity; + entity.SetRole(Role::PROPERTY); + // the different AtomicDataType are associated with integers + entity.SetDataType(map_el.first); + EXPECT_TRUE(entity.GetDataType().IsAtomic()); + EXPECT_EQ(entity.GetDataType().AsAtomic(), map_el.first); + + proto_data_type.set_atomic_data_type(static_cast<ProtoAtomicDataType>(map_el.first)); + DataType data_type(&proto_data_type); + entity.SetDataType(data_type); + + EXPECT_FALSE(data_type.IsReference()); + EXPECT_EQ(data_type.AsReference().GetName(), std::basic_string<char>("")); + EXPECT_FALSE(data_type.IsList()); + EXPECT_TRUE(data_type.IsAtomic()); + EXPECT_EQ(data_type.AsAtomic(), map_el.first); + } +} + +TEST(test_data_type, test_reference) { + ProtoDataType proto_data_type; + + Entity entity; + entity.SetRole(Role::PROPERTY); + entity.SetDataType("Person"); + EXPECT_TRUE(entity.GetDataType().IsReference()); + EXPECT_EQ(entity.GetDataType().AsReference().GetName(), "Person"); + + proto_data_type.mutable_reference_data_type()->set_name("Person"); + DataType data_type(&proto_data_type); + entity.SetDataType(data_type); + + EXPECT_TRUE(data_type.IsReference()); + EXPECT_FALSE(data_type.IsList()); + EXPECT_FALSE(data_type.IsAtomic()); + EXPECT_EQ(data_type.AsReference().GetName(), "Person"); +} + +TEST(test_data_type, test_list_of_atomic) { + for (const auto &map_el : atomicdatatype_names) { + DataType data_type(map_el.first, true); + + EXPECT_FALSE(data_type.IsReference()); + EXPECT_FALSE(data_type.IsAtomic()); + EXPECT_TRUE(data_type.IsList()); + const auto &list_data_type = data_type.AsList(); + EXPECT_EQ(list_data_type.GetReferenceDataType().GetName(), std::basic_string<char>("")); + EXPECT_TRUE(list_data_type.IsListOfAtomic()); + EXPECT_FALSE(list_data_type.IsListOfReference()); + EXPECT_EQ(list_data_type.GetAtomicDataType(), map_el.first); + } +} + +TEST(test_data_type, test_list_of_reference) { + auto data_type = DataType("person", true); + + EXPECT_FALSE(data_type.IsReference()); + EXPECT_FALSE(data_type.IsAtomic()); + EXPECT_TRUE(data_type.IsList()); + + const auto &list_data_type = data_type.AsList(); + EXPECT_TRUE(list_data_type.IsListOfReference()); + EXPECT_FALSE(list_data_type.IsListOfAtomic()); + const auto *wrapped = list_data_type.GetReferenceDataType().GetWrapped(); + CAOSDB_DEBUG_MESSAGE_STRING(*wrapped, out) + CAOSDB_LOG_DEBUG("caosdb::entity") << "wrapped " + out; + EXPECT_EQ(list_data_type.GetReferenceDataType().GetName(), "person"); +} + +} // namespace caosdb::entity diff --git a/test/test_entity.cpp b/test/test_entity.cpp index 3d2343bbb17e3fb484ebebb8c5db471ab336e3c2..95c451d8d83154352731f1947d3972586e5b6a79 100644 --- a/test/test_entity.cpp +++ b/test/test_entity.cpp @@ -21,6 +21,7 @@ * */ #include "caosdb_test_utility.h" +#include "caosdb/data_type.h" // for DataType, AtomicDat... #include "caosdb/entity.h" // for Entity, Parent, Par... #include "caosdb/entity/v1alpha1/main.grpc.pb.h" // for EntityTransactionSe... #include "caosdb/entity/v1alpha1/main.pb.h" // for IdResponse, Message @@ -28,12 +29,15 @@ #include "caosdb/protobuf_helper.h" // for get_arena #include "caosdb/status_code.h" // for StatusCode, FILE_DO... #include "caosdb/transaction.h" // for Transaction -#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 "caosdb/value.h" // for Value +#include <exception> +#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> #include <memory> // for allocator, shared_ptr +#include <stdexcept> #include <string> // for operator+, string namespace caosdb::entity { @@ -68,17 +72,42 @@ TEST(test_entity, test_property_setters) { auto prop = Property(); prop.SetName("prop_name"); prop.SetId("prop_id"); - prop.SetImportance("prop_importance"); + prop.SetImportance(Importance::OBLIGATORY); prop.SetValue("prop_value"); prop.SetUnit("prop_unit"); - prop.SetDatatype("prop_dtype"); + prop.SetDataType("prop_dtype"); EXPECT_EQ(prop.GetName(), "prop_name"); EXPECT_EQ(prop.GetId(), "prop_id"); - EXPECT_EQ(prop.GetImportance(), "prop_importance"); - EXPECT_EQ(prop.GetValue(), "prop_value"); + EXPECT_EQ(prop.GetImportance(), Importance::OBLIGATORY); + EXPECT_TRUE(prop.GetValue().IsString()); + EXPECT_EQ(prop.GetValue().AsString(), "prop_value"); EXPECT_EQ(prop.GetUnit(), "prop_unit"); - EXPECT_EQ(prop.GetDatatype(), "prop_dtype"); + EXPECT_TRUE(prop.GetDataType().IsReference()); + EXPECT_EQ(prop.GetDataType().AsReference().GetName(), "prop_dtype"); + EXPECT_FALSE(prop.GetDataType().IsList()); + + prop.SetDataType(AtomicDataType::DATETIME); + EXPECT_TRUE(prop.GetDataType().IsAtomic()); + EXPECT_EQ(prop.GetDataType().AsAtomic(), AtomicDataType::DATETIME); + EXPECT_FALSE(prop.GetDataType().IsList()); +} + +TEST(test_entity, test_list_property_setters) { + auto prop = Property(); + + prop.SetDataType(AtomicDataType::DATETIME); // Set as atomic first. + EXPECT_TRUE(prop.GetDataType().IsAtomic()); + EXPECT_EQ(prop.GetDataType().AsAtomic(), AtomicDataType::DATETIME); + + prop.SetDataType(AtomicDataType::DOUBLE, true); + auto const &dtype = prop.GetDataType(); + EXPECT_FALSE(dtype.IsAtomic()); // Should not be true anymore. + EXPECT_FALSE(dtype.IsReference()); + EXPECT_TRUE(dtype.IsList()); + EXPECT_NE(dtype.AsAtomic(), AtomicDataType::DATETIME); // Should be overwritten. + EXPECT_TRUE(dtype.AsList().IsListOfAtomic()); + EXPECT_EQ(dtype.AsList().GetAtomicDataType(), AtomicDataType::DOUBLE); } TEST(test_entity, test_append_property) { @@ -87,28 +116,31 @@ TEST(test_entity, test_append_property) { auto prop = Property(); prop.SetName("prop_name"); prop.SetId("prop_id"); - prop.SetImportance("prop_importance"); + prop.SetImportance(Importance::RECOMMENDED); prop.SetValue("prop_value"); prop.SetUnit("prop_unit"); - prop.SetDatatype("prop_dtype"); + prop.SetDataType("prop_dtype"); EXPECT_EQ(entity.GetProperties().size(), 0); entity.AppendProperty(prop); EXPECT_EQ(entity.GetProperties().size(), 1); - auto same_prop = entity.GetProperties().at(0); + // also test RepeatedPtrFieldWrapper.at() + const auto &same_prop = entity.GetProperties().at(0); + EXPECT_THROW((void)entity.GetProperties().at(2), std::out_of_range); + EXPECT_THROW((void)entity.GetProperties().at(-1), std::out_of_range); EXPECT_EQ(prop.GetName(), same_prop.GetName()); EXPECT_EQ(prop.GetId(), same_prop.GetId()); EXPECT_EQ(prop.GetImportance(), same_prop.GetImportance()); EXPECT_EQ(prop.GetValue(), same_prop.GetValue()); EXPECT_EQ(prop.GetUnit(), same_prop.GetUnit()); - EXPECT_EQ(prop.GetDatatype(), same_prop.GetDatatype()); + EXPECT_EQ(prop.GetDataType(), same_prop.GetDataType()); } TEST(test_entity, test_copy_to) { auto entity = Entity(); - entity.SetRole("original_role"); + entity.SetRole(Role::RECORD); entity.SetName("orignial_name"); auto parent = Parent(); @@ -123,8 +155,7 @@ TEST(test_entity, test_copy_to) { // create protobuf entity to which all fields ae copied and then a // CaoosDB entity from that protobuf entity. - auto *proto_copy = - google::protobuf::Arena::CreateMessage<ProtoEntity>(get_arena()); + auto *proto_copy = google::protobuf::Arena::CreateMessage<ProtoEntity>(get_arena()); entity.CopyTo(proto_copy); auto copied = Entity(proto_copy); @@ -142,15 +173,15 @@ TEST(test_entity, test_insert_entity) { std::shared_ptr<transaction::FileTransmissionService::Stub>(nullptr)); auto entity = Entity(); - entity.SetRole("entity_role"); + entity.SetRole(Role::RECORD_TYPE); entity.SetName("entity_name"); - EXPECT_EQ(entity.GetRole(), "entity_role"); + EXPECT_EQ(entity.GetRole(), Role::RECORD_TYPE); EXPECT_EQ(entity.GetName(), "entity_name"); transaction.InsertEntity(&entity); - EXPECT_EQ(entity.GetRole(), "entity_role"); + EXPECT_EQ(entity.GetRole(), Role::RECORD_TYPE); EXPECT_EQ(entity.GetName(), "entity_name"); } @@ -160,19 +191,21 @@ TEST(test_entity, test_insert_with_role) { std::shared_ptr<transaction::FileTransmissionService::Stub>(nullptr)); auto entity = Entity(); - entity.SetRole("Property"); - entity.SetDatatype("DOUBLE"); + entity.SetRole(Role::PROPERTY); + entity.SetDataType(AtomicDataType::DOUBLE); entity.SetName("Length"); entity.SetUnit("m"); - entity.SetValue("5.5"); + entity.SetValue(5.5); transaction.InsertEntity(&entity); - EXPECT_EQ(entity.GetRole(), "Property"); - EXPECT_EQ(entity.GetDatatype(), "DOUBLE"); + EXPECT_EQ(entity.GetRole(), Role::PROPERTY); + EXPECT_TRUE(entity.GetDataType().IsAtomic()); + EXPECT_EQ(entity.GetDataType().AsAtomic(), AtomicDataType::DOUBLE); EXPECT_EQ(entity.GetName(), "Length"); EXPECT_EQ(entity.GetUnit(), "m"); - EXPECT_EQ(entity.GetValue(), "5.5"); + EXPECT_TRUE(entity.GetValue().IsDouble()); + EXPECT_DOUBLE_EQ(entity.GetValue().AsDouble(), 5.5); } TEST(test_entity, test_insert_with_parent) { @@ -211,10 +244,10 @@ TEST(test_entity, test_insert_with_property) { auto prop = Property(); prop.SetName("prop_name"); prop.SetId("prop_id"); - prop.SetImportance("prop_importance"); - prop.SetValue("prop_value"); + prop.SetImportance(Importance::FIX); + prop.SetValue(Value("prop_value")); prop.SetUnit("prop_unit"); - prop.SetDatatype("prop_dtype"); + prop.SetDataType("prop_dtype"); entity.AppendProperty(prop); @@ -222,14 +255,15 @@ TEST(test_entity, test_insert_with_property) { EXPECT_EQ(entity.GetProperties().size(), 1); - auto inserted_prop = entity.GetProperties().at(0); + const auto &inserted_prop = entity.GetProperties().at(0); EXPECT_EQ(prop.GetName(), inserted_prop.GetName()); EXPECT_EQ(prop.GetId(), inserted_prop.GetId()); EXPECT_EQ(prop.GetImportance(), inserted_prop.GetImportance()); + EXPECT_EQ(prop.GetValue().ToString(), inserted_prop.GetValue().ToString()); EXPECT_EQ(prop.GetValue(), inserted_prop.GetValue()); EXPECT_EQ(prop.GetUnit(), inserted_prop.GetUnit()); - EXPECT_EQ(prop.GetDatatype(), inserted_prop.GetDatatype()); + EXPECT_EQ(prop.GetDataType(), inserted_prop.GetDataType()); } TEST(test_entity, test_from_id_response) { @@ -245,8 +279,7 @@ TEST(test_entity, test_from_id_response) { EXPECT_TRUE(entity.HasErrors()); EXPECT_EQ(entity.GetErrors().size(), 1); EXPECT_EQ(entity.GetErrors().at(0).GetDescription(), "error_desc"); - EXPECT_EQ(entity.GetErrors().at(0).GetCode(), - MessageCode::ENTITY_DOES_NOT_EXIST); + EXPECT_EQ(entity.GetErrors().at(0).GetCode(), MessageCode::ENTITY_DOES_NOT_EXIST); IdResponse idr_warnings_and_infos; idr_warnings_and_infos.set_id("other_entity_id"); @@ -263,8 +296,7 @@ TEST(test_entity, test_from_id_response) { EXPECT_EQ(other_ent.GetWarnings().size(), 1); EXPECT_TRUE(other_ent.HasWarnings()); EXPECT_EQ(other_ent.GetWarnings().at(0).GetDescription(), "warning_desc"); - EXPECT_EQ(other_ent.GetWarnings().at(0).GetCode(), - MessageCode::ENTITY_HAS_NO_PROPERTIES); + EXPECT_EQ(other_ent.GetWarnings().at(0).GetCode(), MessageCode::ENTITY_HAS_NO_PROPERTIES); EXPECT_EQ(other_ent.GetInfos().size(), 1); EXPECT_EQ(other_ent.GetInfos().at(0).GetDescription(), "info_desc"); EXPECT_EQ(other_ent.GetInfos().at(0).GetCode(), MessageCode::UNSPECIFIED); @@ -277,14 +309,13 @@ TEST(test_entity, test_add_file_to_non_file_entity) { TEST(test_entity, test_add_non_existing_file) { Entity entity; - entity.SetRole("File"); - EXPECT_EQ(entity.SetLocalPath("non-existing/path"), - StatusCode::FILE_DOES_NOT_EXIST_LOCALLY); + entity.SetRole(Role::FILE); + EXPECT_EQ(entity.SetLocalPath("non-existing/path"), StatusCode::FILE_DOES_NOT_EXIST_LOCALLY); } TEST(test_entity, test_add_directory_path) { Entity entity; - entity.SetRole("File"); + entity.SetRole(Role::FILE); EXPECT_EQ(entity.SetLocalPath("./"), StatusCode::PATH_IS_A_DIRECTORY); } @@ -386,8 +417,11 @@ TEST(test_entity, test_property_iterator) { ASSERT_EQ(entity.GetProperties().size(), 5); int counter = 0; for (auto &property : entity.GetProperties()) { + // TODO(tf) Copy constructor was deleted + // auto nonref_property = entity.GetProperties().at(counter); auto name = "PROPERTY-" + std::to_string(counter); EXPECT_EQ(property.GetName(), name); + // EXPECT_EQ(nonref_property.GetName(), name); counter++; } EXPECT_EQ(counter, 5); @@ -414,10 +448,17 @@ TEST(test_entity, test_description) { EXPECT_EQ(parent.GetDescription(), "desc parent"); } +TEST(test_entity, test_role) { + Entity entity; + entity.SetRole(Role::RECORD_TYPE); + + EXPECT_EQ(entity.GetRole(), Role::RECORD_TYPE); +} + TEST(test_entity, test_add_file) { Entity entity; - entity.SetRole("File"); - EXPECT_EQ(entity.SetLocalPath(TEST_DATA_DIR + "/test.json"), - StatusCode::SUCCESS); + entity.SetRole(Role::FILE); + EXPECT_EQ(entity.SetLocalPath(TEST_DATA_DIR + "/test.json"), StatusCode::SUCCESS); } + } // namespace caosdb::entity diff --git a/test/test_file_transmission.cpp b/test/test_file_transmission.cpp index 801b89db3a07f5b96e530cfbdfc8335c892a1331..7c5eb745e8f451b0282fa844510dc71ad402ed18 100644 --- a/test/test_file_transmission.cpp +++ b/test/test_file_transmission.cpp @@ -23,9 +23,9 @@ #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 +#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; @@ -35,9 +35,7 @@ class test_file_transmission : public ::testing::Test { protected: fs::path test_file_name; - void SetUp() override { - test_file_name = fs::path("this_is_a_test_file_remove_me.dat"); - } + void SetUp() override { test_file_name = fs::path("this_is_a_test_file_remove_me.dat"); } void TearDown() override { fs::remove(test_file_name); } }; diff --git a/test/test_list_properties.cpp b/test/test_list_properties.cpp new file mode 100644 index 0000000000000000000000000000000000000000..34895dfa15eabc207c2a485f4a22fcb33428a791 --- /dev/null +++ b/test/test_list_properties.cpp @@ -0,0 +1,64 @@ +/* + * + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com> + * Copyright (C) 2021 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/>. + * + */ + +#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 <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; + +TEST(test_list_property, test_list_of_text) { + Property list_property; + list_property.SetDataType(DataType::ListOf(AtomicDataType::TEXT)); + std::vector<std::string> in_value{"item1", "item2", "item3"}; + list_property.SetValue(in_value); + + Entity entity; + entity.SetRole(Role::RECORD_TYPE); + entity.SetName("TestRT"); + entity.AppendProperty(list_property); + + const auto &data_type = entity.GetProperties().at(0).GetDataType(); + const auto &value = entity.GetProperties().at(0).GetValue(); + + EXPECT_TRUE(data_type.IsList()); + EXPECT_TRUE(data_type.AsList().IsListOfAtomic()); + EXPECT_EQ(data_type.AsList().GetAtomicDataType(), AtomicDataType::TEXT); + + EXPECT_TRUE(value.IsList()); + EXPECT_EQ(value.AsList().size(), 3); + EXPECT_TRUE(value.AsList().at(1).IsString()); + EXPECT_EQ(value.AsList().at(1).AsString(), "item2"); +} + +} // namespace caosdb::entity diff --git a/test/test_protobuf.cpp b/test/test_protobuf.cpp index 9dc957a2f85cd95ce3ead5f59ab8c10868582003..43ab6883b42f1dca1c2785103f6a274eb2b2f1bc 100644 --- a/test/test_protobuf.cpp +++ b/test/test_protobuf.cpp @@ -19,14 +19,17 @@ * 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 <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 caosdb::entity::v1alpha1::Entity; +using ProtoEntity = caosdb::entity::v1alpha1::Entity; +using caosdb::entity::Entity; using caosdb::entity::v1alpha1::Message; TEST(test_protobuf, test_swap_trivial) { @@ -50,12 +53,12 @@ TEST(test_protobuf, test_swap_trivial) { } TEST(test_protobuf, test_swap_nested) { - Entity entity_source; + ProtoEntity entity_source; entity_source.set_id("entity_id"); auto *version_source = entity_source.mutable_version(); version_source->set_id("version_id"); - Entity entity_destination; + ProtoEntity entity_destination; auto *version_destination = entity_destination.mutable_version(); EXPECT_EQ(entity_source.id(), "entity_id"); @@ -81,4 +84,28 @@ TEST(test_protobuf, test_swap_nested) { 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(); + data_type_source->mutable_reference_data_type()->set_name("src_per"); + + ProtoEntity entity_destination; + 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"); + + 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"); + + Entity entity(&entity_destination); + EXPECT_EQ(entity.GetDataType().AsReference().GetName(), "src_per"); + + const Entity ©_entity(entity); + EXPECT_EQ(copy_entity.GetDataType().AsReference().GetName(), "src_per"); +} + } // namespace caosdb diff --git a/test/test_transaction.cpp b/test/test_transaction.cpp index 70ba13a78b10db3af421411ae7f9ba631a49ff03..21c00f86b20758e03dc6f1d78e4aad11b469479e 100644 --- a/test/test_transaction.cpp +++ b/test/test_transaction.cpp @@ -42,6 +42,7 @@ using caosdb::connection::Connection; using caosdb::entity::Entity; using caosdb::exceptions::ConnectionError; using ProtoEntity = caosdb::entity::v1alpha1::Entity; +using caosdb::entity::Role; using caosdb::entity::v1alpha1::RetrieveResponse; TEST(test_transaction, create_transaction) { @@ -51,11 +52,10 @@ TEST(test_transaction, create_transaction) { auto transaction = connection.CreateTransaction(); ASSERT_EQ(StatusCode::GO_ON, transaction->RetrieveById("100")); - EXPECT_THROW_MESSAGE( - transaction->Execute(), ConnectionError, - "The attempt to execute this transaction was not successful because the " - "connection to the server could not be established. " - "Original message: failed to connect to all addresses"); + EXPECT_THROW_MESSAGE(transaction->Execute(), ConnectionError, + "The attempt to execute this transaction was not successful because the " + "connection to the server could not be established. " + "Original message: failed to connect to all addresses"); } TEST(test_transaction, test_multi_result_set) { @@ -115,8 +115,7 @@ 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())); + one_elem.push_back(std::make_unique<Entity>(response.release_entity_response())); MultiResultSet rs(std::move(one_elem)); EXPECT_EQ(rs.size(), 1); @@ -130,8 +129,7 @@ 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())); + one_elem.push_back(std::make_unique<Entity>(response.release_entity_response())); MultiResultSet rs(std::move(one_elem)); EXPECT_EQ(rs.size(), 1); @@ -147,9 +145,8 @@ TEST(test_transaction, test_multi_result_set_three) { ->mutable_entity_response() ->mutable_entity() ->set_id("100"); - auto *entity_with_error = response.add_responses() - ->mutable_retrieve_response() - ->mutable_entity_response(); + auto *entity_with_error = + 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() @@ -177,7 +174,7 @@ TEST(test_transaction, test_update_entity) { auto transaction = connection.CreateTransaction(); caosdb::entity::Entity update_entity; - update_entity.SetRole("New role"); + update_entity.SetName("New Name"); auto error = transaction->UpdateEntity(&update_entity); EXPECT_EQ(error, StatusCode::ORIGINAL_ENTITY_MISSING_ID); @@ -216,7 +213,7 @@ TEST(test_transaction, test_insert_with_file) { Connection connection(configuration); auto transaction = connection.CreateTransaction(); Entity entity; - entity.SetRole("File"); + entity.SetRole(Role::FILE); entity.SetLocalPath(TEST_DATA_DIR + "/test.json"); EXPECT_TRUE(transaction->GetUploadFiles().empty()); diff --git a/test/test_utility.cpp b/test/test_utility.cpp index cb6021dc631c90b49ab8c3538f2b09fcc47723a3..a64fcee8c94fa527692bbd96ca0b54f94bd6f524 100644 --- a/test/test_utility.cpp +++ b/test/test_utility.cpp @@ -24,6 +24,8 @@ #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/utility.h" // for base64_encode, load_js... #include "caosdb_test_utility.h" // for TEST_DATA_DIR #include <gtest/gtest-message.h> // for Message @@ -53,4 +55,27 @@ TEST(test_utility, test_load_json_file) { 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) { + EXPECT_EQ(getEnumNameFromValue<caosdb::entity::Importance>(entry.first), entry.second); + EXPECT_EQ(getEnumValueFromName<caosdb::entity::Importance>(entry.second), entry.first); + } + for (const auto &entry : caosdb::entity::role_names) { + EXPECT_EQ(getEnumNameFromValue<caosdb::entity::Role>(entry.first), entry.second); + EXPECT_EQ(getEnumValueFromName<caosdb::entity::Role>(entry.second), entry.first); + } + for (const auto &entry : caosdb::entity::atomicdatatype_names) { + EXPECT_EQ(getEnumNameFromValue<caosdb::entity::AtomicDataType>(entry.first), entry.second); + EXPECT_EQ(getEnumValueFromName<caosdb::entity::AtomicDataType>(entry.second), entry.first); + } + + // Some non-working examples + EXPECT_THROW_MESSAGE(getEnumValueFromName<caosdb::entity::Importance>("Invalid name"), + std::out_of_range, "Could not find enum value for string 'Invalid name'."); + enum e1 { a }; + EXPECT_THROW_STARTS_WITH(getEnumNameFromValue<e1>(a), std::logic_error, "Enum type "); + EXPECT_THROW_STARTS_WITH(getEnumValueFromName<e1>("Hello!"), std::logic_error, "Enum type "); +} + } // namespace caosdb::utility diff --git a/test/test_value.cpp b/test/test_value.cpp new file mode 100644 index 0000000000000000000000000000000000000000..74d30f04b621a0e118bc7591a07aab052786c790 --- /dev/null +++ b/test/test_value.cpp @@ -0,0 +1,138 @@ +/* + * + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com> + * Copyright (C) 2021 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/>. + * + */ + +#include "caosdb/value.h" // for Value +#include "caosdb/entity/v1alpha1/main.pb.h" // for AtomicDataType, DataType +#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 ProtoEntity = caosdb::entity::v1alpha1::Entity; +using ProtoParent = caosdb::entity::v1alpha1::Parent; +using ProtoDataType = caosdb::entity::v1alpha1::DataType; +using ProtoAtomicDataType = caosdb::entity::v1alpha1::AtomicDataType; + +TEST(test_value, test_null) { + Value value; + EXPECT_TRUE(value.IsNull()); + EXPECT_FALSE(value.IsDouble()); + EXPECT_FALSE(value.IsBool()); + EXPECT_FALSE(value.IsInteger()); + EXPECT_FALSE(value.IsString()); + EXPECT_FALSE(value.IsList()); +} + +TEST(test_value, test_string) { + Value value(std::string("test")); + EXPECT_FALSE(value.IsNull()); + EXPECT_TRUE(value.IsString()); + EXPECT_FALSE(value.IsDouble()); + EXPECT_FALSE(value.IsBool()); + EXPECT_FALSE(value.IsInteger()); + + EXPECT_EQ(value.AsString(), "test"); + + Value empty_string(std::string("")); + EXPECT_FALSE(empty_string.IsNull()); + EXPECT_TRUE(empty_string.IsString()); + EXPECT_FALSE(empty_string.IsDouble()); + EXPECT_FALSE(empty_string.IsBool()); + EXPECT_FALSE(empty_string.IsInteger()); + + EXPECT_EQ(empty_string.AsString(), ""); + + // Test inequality + Value string1("1"); + Value int1(1); + EXPECT_FALSE(string1 == int1); +} + +TEST(test_value, test_double) { + Value value(2.26); + EXPECT_FALSE(value.IsNull()); + EXPECT_FALSE(value.IsString()); + EXPECT_TRUE(value.IsDouble()); + EXPECT_FALSE(value.IsBool()); + EXPECT_FALSE(value.IsInteger()); + + EXPECT_EQ(value.AsDouble(), 2.26); + + Value nan(std::sqrt(-1.0)); + EXPECT_FALSE(nan.IsNull()); + EXPECT_FALSE(nan.IsString()); + EXPECT_TRUE(nan.IsDouble()); + EXPECT_FALSE(nan.IsBool()); + EXPECT_FALSE(nan.IsInteger()); + + EXPECT_TRUE(std::isnan(nan.AsDouble())); +} + +TEST(test_value, test_integer) { + Value value(1337); + EXPECT_FALSE(value.IsNull()); + EXPECT_FALSE(value.IsString()); + EXPECT_FALSE(value.IsDouble()); + EXPECT_FALSE(value.IsBool()); + EXPECT_TRUE(value.IsInteger()); + + EXPECT_EQ(value.AsInteger(), 1337); +} + +TEST(test_value, test_boolean) { + Value value(true); + EXPECT_FALSE(value.IsNull()); + EXPECT_FALSE(value.IsString()); + EXPECT_FALSE(value.IsDouble()); + EXPECT_TRUE(value.IsBool()); + EXPECT_FALSE(value.IsInteger()); + + EXPECT_EQ(value.AsBool(), true); +} + +TEST(test_value, test_list) { + std::vector<std::string> ids; + for (std::string id : {"id0", "id1", "id2"}) { + ids.push_back(id); + } + Value value(ids); + + EXPECT_FALSE(value.IsNull()); + EXPECT_TRUE(value.IsList()); + EXPECT_FALSE(value.IsString()); + EXPECT_FALSE(value.IsDouble()); + EXPECT_FALSE(value.IsBool()); + EXPECT_FALSE(value.IsInteger()); + + auto list_value = value.AsList(); + int counter = 0; + for (auto item : list_value) { + EXPECT_EQ(item.IsString(), true); + EXPECT_EQ(item.AsString(), "id" + std::to_string(counter++)); + } +} +} // namespace caosdb::entity