diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8f77eea4848b735b3489d93238e3335e36cf04c5..02c895db00b140cf0014c89bb3f33988884e6c8d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -50,6 +50,7 @@ info: - echo "$CPPLIB_REGISTRY_IMAGE" - echo "$CPPINTTEST_PIPELINE" - echo "$GIT_SUBMODULE_STRATEGY" + - echo "$CI_COMMIT_REF_NAME" # Build a docker image in which tests for this repository can run build-testenv: @@ -98,16 +99,21 @@ trigger_inttest: ## Determine the cppinttest branch... # ... 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 ; fi; # ... or use main if possible... - if [[ "$CI_COMMIT_REF_NAME" == "main" ]] ; then CPPINT_REF=main ; fi + - if echo "$CI_COMMIT_REF_NAME" | grep -c "^v" ; then + CPPINT_REF=main ; + F_BRANCH=main ; + fi # ... and fall-back to dev - CPPINT_REF=${CPPINT_REF:-dev} - - F_BRANCH=$CI_COMMIT_REF_NAME - echo "Triggering caosdb-cppinttest@${CPPINT_REF} (F_BRANCH=$F_BRANCH)" - curl -w "%{stderr}HTTPCODE=%{http_code}" -X POST diff --git a/include/caosdb/transaction.h b/include/caosdb/transaction.h index 90044e1d8bf8cf99604184bff83fffb9c9b79b27..f479683e434329f6c13799c6f8a59f866e149b36 100644 --- a/include/caosdb/transaction.h +++ b/include/caosdb/transaction.h @@ -215,7 +215,7 @@ private: class MultiResultSet : public ResultSet { public: ~MultiResultSet() = default; - explicit MultiResultSet(MultiTransactionResponse *response); + explicit MultiResultSet(std::vector<std::unique_ptr<Entity>> result_set); [[nodiscard]] inline auto Size() const noexcept -> int override { return this->entities.size(); } @@ -384,6 +384,17 @@ public: return *result_set; } + /** + * Return the result of a count query + * + * Only meaningful if there was exactly one COUNT query executed in + * this transaction. In all other cases, the return value will be + * -1. + */ + [[nodiscard]] inline auto GetCountResult() const -> int { + return query_count; + } + /** * Return the number of sub-requests in this transaction. * @@ -394,6 +405,23 @@ public: return this->request->requests_size(); } + /** + * Get a JSON representation of the respone. + * + * For debugging. + */ + inline auto ResponseToString() const -> const std::string { + google::protobuf::util::JsonOptions options; + std::string out; + google::protobuf::util::MessageToJsonString(*this->response, &out, options); + return out; + } + + /** + * Get a JSON representation of the request. + * + * For debugging. + */ inline auto RequestToString() const -> const std::string { google::protobuf::util::JsonOptions options; std::string out; @@ -411,6 +439,7 @@ private: MultiTransactionRequest *request; mutable MultiTransactionResponse *response; std::string error_message; + mutable long query_count; }; template <class InputIterator> diff --git a/src/caosdb/transaction.cpp b/src/caosdb/transaction.cpp index c32d0090392e9b8c44cc8d1e0886f69747337066..5d5387c6f5d0e51cbd9dacdec6db259e140a762b 100644 --- a/src/caosdb/transaction.cpp +++ b/src/caosdb/transaction.cpp @@ -105,6 +105,8 @@ using caosdb::entity::v1alpha1::RegisterFileUploadRequest; using caosdb::entity::v1alpha1::RegisterFileUploadResponse; using WrappedResponseCase = caosdb::entity::v1alpha1::TransactionResponse::WrappedResponseCase; +using QueryResponseCase = + caosdb::entity::v1alpha1::RetrieveResponse::QueryResponseCase; using caosdb::utility::get_arena; using grpc::ClientAsyncResponseReader; using ProtoEntity = caosdb::entity::v1alpha1::Entity; @@ -140,28 +142,8 @@ auto ResultSet::end() const -> ResultSet::iterator { return ResultSet::iterator(this, Size()); } -MultiResultSet::MultiResultSet(MultiTransactionResponse *response) { - auto *responses = response->mutable_responses(); - for (auto sub_response : *responses) { - switch (sub_response.wrapped_response_case()) { - case WrappedResponseCase::kRetrieveResponse: - this->entities.push_back(std::make_unique<Entity>( - sub_response.mutable_retrieve_response()->release_entity())); - break; - case WrappedResponseCase::kInsertResponse: - this->entities.push_back( - std::make_unique<Entity>(sub_response.release_insert_response())); - break; - case WrappedResponseCase::kDeleteResponse: - this->entities.push_back( - std::make_unique<Entity>(sub_response.release_insert_response())); - break; - default: - // TODO(tf) Updates - break; - } - } -} +MultiResultSet::MultiResultSet(std::vector<std::unique_ptr<Entity>> result_set) + : entities(std::move(result_set)) {} [[nodiscard]] auto UniqueResult::GetEntity() const -> const Entity & { const Entity *result = this->entity.get(); @@ -177,9 +159,7 @@ Transaction::Transaction( get_arena())) { this->entity_service = std::move(entity_service); this->file_service = std::move(file_service); -} - -auto Transaction::RetrieveById(const std::string &id) noexcept -> StatusCode { + this->query_count = -1; ASSERT_CAN_ADD_RETRIEVAL auto *sub_request = this->request->add_requests(); @@ -317,12 +297,29 @@ auto Transaction::WaitForIt() const noexcept -> TransactionStatus { auto *responses = this->response->mutable_responses(0); switch (responses->wrapped_response_case()) { case WrappedResponseCase::kRetrieveResponse: { - auto *entity = responses->mutable_retrieve_response()->release_entity(); - if (!entity->errors().empty()) { - this->status = TransactionStatus::TRANSACTION_ERROR( - "The request returned with errors."); + auto *retrieve_response = responses->mutable_retrieve_response(); + switch (retrieve_response->query_response_case()) { + case QueryResponseCase::kEntity: { + auto *entity = retrieve_response->release_entity(); + if (!entity->errors().empty()) { + this->status = TransactionStatus::TRANSACTION_ERROR( + "The request returned with errors."); + } + this->result_set = std::make_unique<UniqueResult>(entity); + } break; + case QueryResponseCase::kSelectResult: { + // TODO(tf) Select queries + } break; + case QueryResponseCase::kCountResult: { + this->query_count = retrieve_response->count_result(); + std::vector<std::unique_ptr<Entity>> entities; + this->result_set = + std::make_unique<MultiResultSet>(std::move(entities)); + } break; + default: + // TODO(tf) Error + break; } - this->result_set = std::make_unique<UniqueResult>(entity); } break; case WrappedResponseCase::kUpdateResponse: { auto *updatedIdResponse = responses->mutable_update_response(); @@ -353,7 +350,28 @@ auto Transaction::WaitForIt() const noexcept -> TransactionStatus { break; } } else { - this->result_set = std::make_unique<MultiResultSet>(this->response); + auto *responses = this->response->mutable_responses(); + std::vector<std::unique_ptr<Entity>> entities; + for (auto sub_response : *responses) { + switch (sub_response.wrapped_response_case()) { + case WrappedResponseCase::kRetrieveResponse: + entities.push_back(std::make_unique<Entity>( + sub_response.mutable_retrieve_response()->release_entity())); + break; + case WrappedResponseCase::kInsertResponse: + entities.push_back( + std::make_unique<Entity>(sub_response.release_insert_response())); + break; + case WrappedResponseCase::kDeleteResponse: + entities.push_back( + std::make_unique<Entity>(sub_response.release_insert_response())); + break; + default: + // TODO(tf) Updates + break; + } + } + this->result_set = std::make_unique<MultiResultSet>(std::move(entities)); } return this->status; diff --git a/test/test_transaction.cpp b/test/test_transaction.cpp index 557ded7b87fe9947391bb47f6c37b49ee1824cfb..86d3294e13166867ef7a409f9ceb7513753d6bae 100644 --- a/test/test_transaction.cpp +++ b/test/test_transaction.cpp @@ -31,6 +31,7 @@ #include "gtest/gtest_pred_impl.h" // for Test, TestInfo, TEST #include <memory> // for allocator, unique_ptr #include <string> // for string, basic_string +#include <utility> // for move #include <vector> // for vector namespace caosdb::transaction { @@ -39,6 +40,7 @@ using caosdb::connection::Connection; using caosdb::exceptions::ConnectionError; using caosdb::transaction::UniqueResult; using ProtoEntity = caosdb::entity::v1alpha1::Entity; +using caosdb::entity::v1alpha1::RetrieveResponse; TEST(test_transaction, create_transaction) { const auto *host = "localhost"; @@ -92,21 +94,18 @@ TEST(test_transaction, test_retrieve_by_ids) { } TEST(test_transaction, test_multi_result_set_empty) { - MultiTransactionResponse response; - - MultiResultSet rs(&response); + std::vector<std::unique_ptr<Entity>> empty; + MultiResultSet rs(std::move(empty)); EXPECT_EQ(rs.Size(), 0); } TEST(test_transaction, test_multi_result_iterator) { - MultiTransactionResponse response; - - response.add_responses() - ->mutable_retrieve_response() - ->mutable_entity() - ->set_id("100"); + std::vector<std::unique_ptr<Entity>> one_elem; + RetrieveResponse response; + response.mutable_entity()->set_id("100"); + one_elem.push_back(std::make_unique<Entity>(response.release_entity())); - MultiResultSet rs(&response); + MultiResultSet rs(std::move(one_elem)); EXPECT_EQ(rs.Size(), 1); for (const Entity &entity : rs) { @@ -126,18 +125,19 @@ TEST(test_transaction, test_unique_result_iterator) { } TEST(test_transaction, test_multi_result_set_one) { - MultiTransactionResponse response; - response.add_responses() - ->mutable_retrieve_response() - ->mutable_entity() - ->set_id("100"); + std::vector<std::unique_ptr<Entity>> one_elem; + RetrieveResponse response; + response.mutable_entity()->set_id("100"); + one_elem.push_back(std::make_unique<Entity>(response.release_entity())); - MultiResultSet rs(&response); + MultiResultSet rs(std::move(one_elem)); EXPECT_EQ(rs.Size(), 1); EXPECT_EQ(rs.At(0).GetId(), "100"); } TEST(test_transaction, test_multi_result_set_three) { + std::vector<std::unique_ptr<Entity>> three_elem; + MultiTransactionResponse response; response.add_responses() ->mutable_retrieve_response() @@ -152,7 +152,14 @@ TEST(test_transaction, test_multi_result_set_three) { ->mutable_entity() ->set_id("102"); - MultiResultSet rs(&response); + auto *responses = response.mutable_responses(); + std::vector<std::unique_ptr<Entity>> entities; + for (auto sub_response : *responses) { + three_elem.push_back(std::make_unique<Entity>( + sub_response.mutable_retrieve_response()->release_entity())); + } + + MultiResultSet rs(std::move(three_elem)); EXPECT_EQ(rs.Size(), 3); EXPECT_TRUE(rs.At(1).HasErrors()); }