From e7e073c232085d4a95c897fe471411d472e3d09a Mon Sep 17 00:00:00 2001
From: Timm Fitschen <t.fitschen@indiscale.com>
Date: Mon, 2 Aug 2021 12:06:43 +0200
Subject: [PATCH] WIP: retrieve multi

---
 include/caosdb/entity.h      | 306 +++++++++++++++++------------------
 include/caosdb/exceptions.h  |   2 +
 include/caosdb/transaction.h |  20 ++-
 src/caosdb/configuration.cpp |   2 +-
 src/caosdb/transaction.cpp   |   1 -
 test/test_transaction.cpp    |  14 +-
 6 files changed, 185 insertions(+), 160 deletions(-)

diff --git a/include/caosdb/entity.h b/include/caosdb/entity.h
index c84f044..2d098c5 100644
--- a/include/caosdb/entity.h
+++ b/include/caosdb/entity.h
@@ -64,187 +64,187 @@ private:
 };
 
 /**
-* Container for Messages.
-*/
+ * Container for Messages.
+ */
 class Messages {
 public:
-[[nodiscard]] inline auto Size() const -> int { return wrapped->size(); }
-[[nodiscard]] inline auto At(int index) const -> const Message {
-  return Message(&(wrapped->at(index)));
-}
+  [[nodiscard]] inline auto Size() const -> int { return wrapped->size(); }
+  [[nodiscard]] inline auto At(int index) const -> const Message {
+    return Message(&(wrapped->at(index)));
+  }
 
-friend class Entity;
+  friend class Entity;
 
 private:
-inline Messages() : wrapped(nullptr){};
+  inline Messages() : wrapped(nullptr){};
 
-::google::protobuf::RepeatedPtrField<caosdb::entity::v1alpha1::Message>
-  *wrapped;
+  ::google::protobuf::RepeatedPtrField<caosdb::entity::v1alpha1::Message>
+    *wrapped;
 };
 
 /**
-* Parent of an Entity.
-*
-* This implementation uses protobuf messages as storage backends. In other
-* words, this class wraps a protobuf message and provides getter and setter
-* methods.
-*/
+ * Parent of an Entity.
+ *
+ * This implementation uses protobuf messages as storage backends. In other
+ * words, this class wraps a protobuf message and provides getter and setter
+ * methods.
+ */
 class Parent {
 public:
-explicit inline Parent(caosdb::entity::v1alpha1::Parent *wrapped)
-  : wrapped(wrapped){};
-Parent();
-
-/**
- * Return the id of the parent entity.
- */
-[[nodiscard]] auto GetId() const -> const std::string &;
-/**
- * Return the name of the parent entity.
- */
-[[nodiscard]] auto GetName() const -> const std::string &;
-/**
- * Return the description of the parent entity.
- */
-[[nodiscard]] auto GetDescription() const -> const std::string &;
+  explicit inline Parent(caosdb::entity::v1alpha1::Parent *wrapped)
+    : wrapped(wrapped){};
+  Parent();
+
+  /**
+   * Return the id of the parent entity.
+   */
+  [[nodiscard]] auto GetId() const -> const std::string &;
+  /**
+   * Return the name of the parent entity.
+   */
+  [[nodiscard]] auto GetName() const -> const std::string &;
+  /**
+   * Return the description of the parent entity.
+   */
+  [[nodiscard]] auto GetDescription() const -> const std::string &;
+
+  /**
+   * Set the id of the parent.
+   */
+  auto SetId(const std::string &id) -> void;
+  /**
+   * Set the name of the parent.
+   */
+  auto SetName(const std::string &name) -> void;
 
-/**
- * Set the id of the parent.
- */
-auto SetId(const std::string &id) -> void;
-/**
- * Set the name of the parent.
- */
-auto SetName(const std::string &name) -> void;
+  /**
+   * Return a json string representing this parent.
+   *
+   * This is intended for debugging.
+   */
+  inline auto ToString() const -> const std::string {
+    google::protobuf::util::JsonOptions options;
+    std::string out;
+    google::protobuf::util::MessageToJsonString(*(this->wrapped), &out,
+                                                options);
+    return out;
+  }
 
-/**
- * Return a json string representing this parent.
- *
- * This is intended for debugging.
- */
-inline auto ToString() const -> const std::string {
-  google::protobuf::util::JsonOptions options;
-  std::string out;
-  google::protobuf::util::MessageToJsonString(*(this->wrapped), &out,
-                                              options);
-  return out;
-}
-
-// TODO(fspreck) These need implementations. See Entity::GetErrors for
-// inspiration.
-/**
- * Return the error messages of this parent.
- */
-[[nodiscard]] inline auto GetErrors() const -> const Messages &;
-/**
- * Return the warning messages of this parent.
- */
-[[nodiscard]] inline auto GetWarnings() const -> const Messages &;
-/**
- * Return the info messages of this parent.
- */
-[[nodiscard]] inline auto GetInfos() const -> const Messages &;
+  // TODO(fspreck) These need implementations. See Entity::GetErrors for
+  // inspiration.
+  /**
+   * Return the error messages of this parent.
+   */
+  [[nodiscard]] inline auto GetErrors() const -> const Messages &;
+  /**
+   * Return the warning messages of this parent.
+   */
+  [[nodiscard]] inline auto GetWarnings() const -> const Messages &;
+  /**
+   * Return the info messages of this parent.
+   */
+  [[nodiscard]] inline auto GetInfos() const -> const Messages &;
 
-friend class Entity;
-friend class Parents;
+  friend class Entity;
+  friend class Parents;
 
 private:
-/**
- * Return an empty protobuf message pointer.
- *
- * This function is called by the default constructor of the
- * caosdb::entity::Parent class and the protobuf message is used as the
- * storage-backend for the new Parent instance.
- *
- * An 'Arena' takes care of the the memory management. Don't try to delete
- * this.
- */
-static auto CreateProtoParent() -> ProtoParent *;
-
-/**
- * Message which serves as storage backend.
- */
-mutable caosdb::entity::v1alpha1::Parent *wrapped;
+  /**
+   * Return an empty protobuf message pointer.
+   *
+   * This function is called by the default constructor of the
+   * caosdb::entity::Parent class and the protobuf message is used as the
+   * storage-backend for the new Parent instance.
+   *
+   * An 'Arena' takes care of the the memory management. Don't try to delete
+   * this.
+   */
+  static auto CreateProtoParent() -> ProtoParent *;
+
+  /**
+   * Message which serves as storage backend.
+   */
+  mutable caosdb::entity::v1alpha1::Parent *wrapped;
 };
 
 /**
-* Container for parents of entities.
-*
-* Should only be instantiated and write-accessed by the owning entity.
-*/
-class Parents {
-public:
-/**
- * Return the current size of the parent container.
+ * Container for parents of entities.
  *
- * That is also the number of parents the owning entity currently has.
- */
-[[nodiscard]] inline auto Size() const -> int { return wrapped->size(); }
-/**
- * Return the parent at the given index.
+ * Should only be instantiated and write-accessed by the owning entity.
  */
-[[nodiscard]] inline auto At(int index) const -> const Parent {
-  return Parent(&(wrapped->at(index)));
-}
+class Parents {
+public:
+  /**
+   * Return the current size of the parent container.
+   *
+   * That is also the number of parents the owning entity currently has.
+   */
+  [[nodiscard]] inline auto Size() const -> int { return wrapped->size(); }
+  /**
+   * Return the parent at the given index.
+   */
+  [[nodiscard]] inline auto At(int index) const -> const Parent {
+    return Parent(&(wrapped->at(index)));
+  }
 
-friend class Entity;
+  friend class Entity;
 
 private:
-inline Parents(){};
-explicit inline Parents(
+  inline Parents(){};
+  explicit inline Parents(
+    ::google::protobuf::RepeatedPtrField<caosdb::entity::v1alpha1::Parent>
+      *wrapped)
+    : wrapped(wrapped){};
+
+  /**
+   * Append a parent.
+   *
+   * This increases the Size() by one.
+   */
+  auto Append(const Parent &parent) -> void;
+  /**
+   * The collection of parent messages which serves as a backend for this
+   * class.
+   */
   ::google::protobuf::RepeatedPtrField<caosdb::entity::v1alpha1::Parent>
-    *wrapped)
-  : wrapped(wrapped){};
+    *wrapped;
+};
 
 /**
- * Append a parent.
+ * Property of an Entity.
  *
- * This increases the Size() by one.
- */
-auto Append(const Parent &parent) -> void;
-/**
- * The collection of parent messages which serves as a backend for this
- * class.
+ * This is a property which belongs to another entity. Don't confuse it with
+ * an Entity with the "Property" role.
  */
-::google::protobuf::RepeatedPtrField<caosdb::entity::v1alpha1::Parent>
-  *wrapped;
-};
-
-/**
-* Property of an Entity.
-*
-* This is a property which belongs to another entity. Don't confuse it with
-* an Entity with the "Property" role.
-*/
 class Property {
 public:
-explicit inline Property(caosdb::entity::v1alpha1::Property *wrapped)
-  : wrapped(wrapped){};
-
-// TODO(fspreck) All of these methods need implementations.
-[[nodiscard]] auto GetId() const -> const std::string &;
-[[nodiscard]] auto GetName() const -> const std::string &;
-[[nodiscard]] auto GetDescription() const -> const std::string &;
-[[nodiscard]] auto GetImportance() const -> const std::string &;
-[[nodiscard]] auto GetValue() const -> const std::string &;
-[[nodiscard]] auto GetUnit() const -> const std::string &;
-[[nodiscard]] auto GetDatatype() const -> const std::string &;
-[[nodiscard]] auto GetErrors() const -> const Messages &;
-[[nodiscard]] auto GetWarnings() const -> const Messages &;
-[[nodiscard]] auto GetInfos() const -> const Messages &;
-
-auto SetId(const std::string &id) -> void;
-auto SetName(const std::string &name) -> void;
-auto SetImportance(const std::string &importance) -> void;
-auto SetValue(const std::string &value) -> void;
-auto SetUnit(const std::string &unit) -> void;
-auto SetDatatype(const std::string &datatype) -> void;
-
-friend class Entity;
-friend class Properties;
+  explicit inline Property(caosdb::entity::v1alpha1::Property *wrapped)
+    : wrapped(wrapped){};
+
+  // TODO(fspreck) All of these methods need implementations.
+  [[nodiscard]] auto GetId() const -> const std::string &;
+  [[nodiscard]] auto GetName() const -> const std::string &;
+  [[nodiscard]] auto GetDescription() const -> const std::string &;
+  [[nodiscard]] auto GetImportance() const -> const std::string &;
+  [[nodiscard]] auto GetValue() const -> const std::string &;
+  [[nodiscard]] auto GetUnit() const -> const std::string &;
+  [[nodiscard]] auto GetDatatype() const -> const std::string &;
+  [[nodiscard]] auto GetErrors() const -> const Messages &;
+  [[nodiscard]] auto GetWarnings() const -> const Messages &;
+  [[nodiscard]] auto GetInfos() const -> const Messages &;
+
+  auto SetId(const std::string &id) -> void;
+  auto SetName(const std::string &name) -> void;
+  auto SetImportance(const std::string &importance) -> void;
+  auto SetValue(const std::string &value) -> void;
+  auto SetUnit(const std::string &unit) -> void;
+  auto SetDatatype(const std::string &datatype) -> void;
+
+  friend class Entity;
+  friend class Properties;
 
 private:
-caosdb::entity::v1alpha1::Property *wrapped;
+  caosdb::entity::v1alpha1::Property *wrapped;
 };
 
 /**
@@ -254,12 +254,12 @@ caosdb::entity::v1alpha1::Property *wrapped;
  */
 class Properties {
 public:
-// TODO(fspreck) Implementations needed (basically everything). See Parents
-// container for inspiration.
-[[nodiscard]] auto At(int index) const -> const Property &;
-auto Append(const Property &property) -> void;
+  // TODO(fspreck) Implementations needed (basically everything). See Parents
+  // container for inspiration.
+  [[nodiscard]] auto At(int index) const -> const Property &;
+  auto Append(const Property &property) -> void;
 
-friend class Entity;
+  friend class Entity;
 
 private:
   inline Properties(){};
diff --git a/include/caosdb/exceptions.h b/include/caosdb/exceptions.h
index 4fd5192..a1e7e40 100644
--- a/include/caosdb/exceptions.h
+++ b/include/caosdb/exceptions.h
@@ -65,6 +65,8 @@ public:
  */
 class TransactionError : public Exception {
 public:
+  TransactionError(StatusCode code, const std::string &what_arg)
+    : Exception(code, what_arg) {}
   explicit TransactionError(const std::string &what_arg)
     : Exception(StatusCode::GENERIC_TRANSACTION_ERROR, what_arg) {}
 };
diff --git a/include/caosdb/transaction.h b/include/caosdb/transaction.h
index 56bd966..80d77d1 100644
--- a/include/caosdb/transaction.h
+++ b/include/caosdb/transaction.h
@@ -24,16 +24,22 @@
 /**
  * @brief Creation and execution of transactions.
  */
-#include "caosdb/entity.h" // for Entity
+#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 "caosdb/entity.h"                            // for Entity
 #include "caosdb/logging.h"
 #include "caosdb/entity/v1alpha1/main.grpc.pb.h" // for EntityTransactionSe...
 #include "caosdb/entity/v1alpha1/main.pb.h"      // for Entity, RetrieveReq...
 #include "caosdb/transaction_status.h"           // for TransactionStatus
 #include "caosdb/status_code.h"                  // for StatusCode
 #include "google/protobuf/util/json_util.h" // for MessageToJsonString, Jso...
+#include <stdexcept>
 #include <iterator>
 #include <memory> // for shared_ptr, unique_ptr
 #include <string> // for string
+#include <vector> // for vector
 
 /*
  * Do all necessary checks and assure that another retrieval (by id or by
@@ -117,6 +123,7 @@ class ResultSet {
 public:
   virtual ~ResultSet() = default;
   [[nodiscard]] virtual auto Size() const noexcept -> int = 0;
+  [[nodiscard]] virtual auto At(const int index) const -> const Entity & = 0;
 };
 
 class MultiResultSet : public ResultSet {
@@ -150,6 +157,10 @@ public:
   [[nodiscard]] inline auto Size() const noexcept -> int override {
     return this->entities.size();
   }
+  [[nodiscard]] inline auto At(const int index) const
+    -> const Entity & override {
+    return *(this->entities.at(index));
+  }
   std::vector<std::unique_ptr<Entity>> entities;
 };
 
@@ -162,6 +173,13 @@ public:
     : entity(new Entity(idResponse)){};
   [[nodiscard]] auto GetEntity() const -> const Entity &;
   [[nodiscard]] inline auto Size() const noexcept -> int override { return 1; }
+  [[nodiscard]] inline auto At(const int index) const
+    -> const Entity & override {
+    if (index != 0) {
+      throw std::out_of_range("Index out of range. Length is 1.");
+    }
+    return *(this->entity);
+  }
 
 private:
   std::unique_ptr<Entity> entity;
diff --git a/src/caosdb/configuration.cpp b/src/caosdb/configuration.cpp
index ba15dce..c6c1e9c 100644
--- a/src/caosdb/configuration.cpp
+++ b/src/caosdb/configuration.cpp
@@ -35,9 +35,9 @@
 #include "caosdb/log_level.h"                          // for CAOSDB_DEFAULT...
 #include "caosdb/status_code.h"                        // for StatusCode
 #include "caosdb/utility.h"                            // for get_home_direc...
-#include <bits/exception.h>                            // for exception
 #include <cassert>                                     // for assert
 #include <cstdlib>                                     // for getenv
+#include <exception>                                   // IWYU pragma: keep
 #include <grpcpp/security/credentials.h>               // for SslCredentials
 #include <iterator>                                    // for next
 #include <map>                                         // for map
diff --git a/src/caosdb/transaction.cpp b/src/caosdb/transaction.cpp
index 688472e..72b59e8 100644
--- a/src/caosdb/transaction.cpp
+++ b/src/caosdb/transaction.cpp
@@ -20,7 +20,6 @@
 #include "caosdb/transaction.h"
 #include "caosdb/entity/v1alpha1/main.grpc.pb.h" // for EntityTransactionS...
 #include "caosdb/entity/v1alpha1/main.pb.h"      // for SingleRetrieveRequest
-#include "caosdb/exceptions.h"                   // for TransactionError, ...
 #include "caosdb/logging.h"
 #include "caosdb/protobuf_helper.h"               // for get_arena
 #include "caosdb/status_code.h"                   // for StatusCode, AUTHEN...
diff --git a/test/test_transaction.cpp b/test/test_transaction.cpp
index a36eb4d..6f5638c 100644
--- a/test/test_transaction.cpp
+++ b/test/test_transaction.cpp
@@ -29,7 +29,10 @@
 #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 <iostream>
 #include <memory>                      // for allocator, unique_ptr
+#include <string>                      // for string, basic_string
+#include <vector>                      // for vector
 
 namespace caosdb::transaction {
 using caosdb::configuration::InsecureConnectionConfiguration;
@@ -105,6 +108,7 @@ TEST(test_transaction, test_multi_result_set_one) {
 
   MultiResultSet rs(&response);
   EXPECT_EQ(rs.Size(), 1);
+  EXPECT_EQ(rs.At(0).GetId(), "100");
 }
 
 TEST(test_transaction, test_multi_result_set_three) {
@@ -113,10 +117,10 @@ TEST(test_transaction, test_multi_result_set_three) {
     ->mutable_retrieve_response()
     ->mutable_entity()
     ->set_id("100");
-  response.add_responses()
-    ->mutable_retrieve_response()
-    ->mutable_entity()
-    ->set_id("101");
+  auto *entity_with_error =
+    response.add_responses()->mutable_retrieve_response()->mutable_entity();
+  entity_with_error->set_id("101");
+  entity_with_error->add_errors()->set_code(1);
   response.add_responses()
     ->mutable_retrieve_response()
     ->mutable_entity()
@@ -124,6 +128,8 @@ TEST(test_transaction, test_multi_result_set_three) {
 
   MultiResultSet rs(&response);
   EXPECT_EQ(rs.Size(), 3);
+  EXPECT_TRUE(rs.At(1).HasErrors());
+  std::cout << rs.At(1).ToString();
 }
 
 } // namespace caosdb::transaction
-- 
GitLab