diff --git a/include/caosdb/data_type.h b/include/caosdb/data_type.h index d11f2efd4a1619929ed3a9a602e403d4d642c240..38e6e4de53af4bd24b346de06566bde7433a3156 100644 --- a/include/caosdb/data_type.h +++ b/include/caosdb/data_type.h @@ -40,7 +40,7 @@ using ProtoReferenceDataType = caosdb::entity::v1alpha1::ReferenceDataType; using DataTypeCase = caosdb::entity::v1alpha1::DataType::DataTypeCase; using ListDataTypeCase = caosdb::entity::v1alpha1::ListDataType::ListDataTypeCase; using caosdb::utility::ProtoMessageWrapper; -using caosdb::utility::ScalarFieldWrapper; +using caosdb::utility::ScalarProtoMessageWrapper; class Entity; class Property; @@ -69,7 +69,7 @@ const std::map<AtomicDataType, std::string> atomicdatatype_names = { class DataType; class ListDataType; -class ReferenceDataType : public ScalarFieldWrapper<ProtoDataType> { +class ReferenceDataType : public ScalarProtoMessageWrapper<ProtoDataType> { public: [[nodiscard]] inline auto GetName() const noexcept -> const std::string & { // is list of reference? @@ -92,11 +92,11 @@ protected: inline static auto Create(ProtoDataType *wrapped) -> std::unique_ptr<ReferenceDataType> { return std::unique_ptr<ReferenceDataType>(new ReferenceDataType(wrapped)); } - ReferenceDataType() : ScalarFieldWrapper<ProtoDataType>() {} - ReferenceDataType(ProtoDataType *wrapped) : ScalarFieldWrapper<ProtoDataType>(wrapped) {} + ReferenceDataType() : ScalarProtoMessageWrapper<ProtoDataType>() {} + ReferenceDataType(ProtoDataType *wrapped) : ScalarProtoMessageWrapper<ProtoDataType>(wrapped) {} }; -class ListDataType : public ScalarFieldWrapper<ProtoDataType> { +class ListDataType : public ScalarProtoMessageWrapper<ProtoDataType> { public: [[nodiscard]] inline auto IsListOfReference() const noexcept -> bool { return this->wrapped->list_data_type().list_data_type_case() == @@ -131,17 +131,17 @@ protected: inline static auto Create(ProtoDataType *wrapped) -> std::unique_ptr<ListDataType> { return std::unique_ptr<ListDataType>(new ListDataType(wrapped)); } - ListDataType() : ScalarFieldWrapper<ProtoDataType>() {} + ListDataType() : ScalarProtoMessageWrapper<ProtoDataType>() {} - ListDataType(ProtoDataType *wrapped) : ScalarFieldWrapper<ProtoDataType>(wrapped) {} + ListDataType(ProtoDataType *wrapped) : ScalarProtoMessageWrapper<ProtoDataType>(wrapped) {} mutable std::unique_ptr<ReferenceDataType> reference_data_type; }; -class DataType : public ScalarFieldWrapper<ProtoDataType> { +class DataType : public ScalarProtoMessageWrapper<ProtoDataType> { public: - DataType(ProtoDataType *wrapped) : ScalarFieldWrapper<ProtoDataType>(wrapped) {} - DataType() : ScalarFieldWrapper<ProtoDataType>() {} + DataType(ProtoDataType *wrapped) : ScalarProtoMessageWrapper<ProtoDataType>(wrapped) {} + DataType() : ScalarProtoMessageWrapper<ProtoDataType>() {} /** * Create an AtomicDataType typed DataType. For references, use the std::string constructor. */ diff --git a/include/caosdb/entity.h b/include/caosdb/entity.h index b2cd0a2a6968967e1b3c4c642b5b98223e3e2e9c..02151d16bdf84af396d5eca1d3a20cd25dbc6aee 100644 --- a/include/caosdb/entity.h +++ b/include/caosdb/entity.h @@ -45,7 +45,6 @@ #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 @@ -64,6 +63,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 ProtoValue = caosdb::entity::v1alpha1::Value; +using ProtoDataType = caosdb::entity::v1alpha1::DataType; using caosdb::entity::v1alpha1::EntityRole; using ProtoImportance = caosdb::entity::v1alpha1::Importance; using caosdb::StatusCode; @@ -119,6 +120,8 @@ struct FileDescriptor { * Abstract base class for Messages, Properties and Parents container classes. * * This is a list-like class. + * + * This class wraps a RepeatedPtrField. */ template <typename T, typename P> class RepeatedPtrFieldWrapper : public ProtoMessageWrapper<RepeatedPtrField<P>> { @@ -297,7 +300,7 @@ auto RepeatedPtrFieldWrapper<T, P>::end() const -> const RepeatedPtrFieldWrapper * A Message object can be thought of as kinf of a generalized error object in * other frameworks. Please have a look at MessageCodes for more details. */ -class Message : public ScalarFieldWrapper<ProtoMessage> { +class Message : public ScalarProtoMessageWrapper<ProtoMessage> { public: // inline Message() {}; /** @@ -326,7 +329,8 @@ public: friend class RepeatedPtrFieldWrapper<Message, ProtoMessage>; private: - explicit inline Message(ProtoMessage *wrapped) : ScalarFieldWrapper<ProtoMessage>(wrapped){}; + explicit inline Message(ProtoMessage *wrapped) + : ScalarProtoMessageWrapper<ProtoMessage>(wrapped){}; }; /** @@ -352,10 +356,10 @@ private: * words, this class wraps a protobuf message and provides getter and setter * methods. */ -class Parent : public ScalarFieldWrapper<ProtoParent> { +class Parent : public ScalarProtoMessageWrapper<ProtoParent> { public: - explicit inline Parent(ProtoParent *wrapped) : ScalarFieldWrapper<ProtoParent>(wrapped){}; - Parent() : ScalarFieldWrapper<ProtoParent>(){}; + explicit inline Parent(ProtoParent *wrapped) : ScalarProtoMessageWrapper<ProtoParent>(wrapped){}; + Parent() : ScalarProtoMessageWrapper<ProtoParent>(){}; /** * Return the id of the parent entity. @@ -439,7 +443,7 @@ private: * This is a property which belongs to another entity. Don't confuse it with * an Entity with the "Property" role. */ -class Property : public ScalarFieldWrapper<ProtoProperty> { +class Property : public ScalarProtoMessageWrapper<ProtoProperty> { public: /** * Copy constructor. @@ -465,10 +469,10 @@ public: } explicit inline Property(ProtoProperty *other) - : ScalarFieldWrapper<ProtoProperty>(other), value(this->wrapped->mutable_value()), + : ScalarProtoMessageWrapper<ProtoProperty>(other), value(this->wrapped->mutable_value()), data_type(this->wrapped->mutable_data_type()){}; inline Property() - : ScalarFieldWrapper<ProtoProperty>(), value(this->wrapped->mutable_value()), + : ScalarProtoMessageWrapper<ProtoProperty>(), value(this->wrapped->mutable_value()), data_type(this->wrapped->mutable_data_type()){}; /** @@ -627,23 +631,22 @@ private: * response. calls Entity(), then moves the data to the wrapped ProtoEntity. * */ -class Entity { +class Entity : public ScalarProtoMessageWrapper<ProtoEntity> { public: - inline Entity(const Entity &original) : Entity(Copy(*original.wrapped)) { + inline Entity(const Entity &original) + : Entity(ProtoMessageWrapper::CopyProtoMessage(original.wrapped)) { this->errors.wrapped->CopyFrom(*original.errors.wrapped); this->warnings.wrapped->CopyFrom(*original.warnings.wrapped); this->infos.wrapped->CopyFrom(*original.infos.wrapped); }; 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(); + : ScalarProtoMessageWrapper<ProtoEntity>(other), + value(this->wrapped->has_value() ? this->wrapped->mutable_value() + : static_cast<ProtoValue *>(nullptr)), + data_type(this->wrapped->has_data_type() ? this->wrapped->mutable_data_type() + : static_cast<ProtoDataType *>(nullptr)) { 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()) { this->errors.wrapped->Swap(response->mutable_errors()); @@ -659,22 +662,35 @@ public: this->infos.wrapped->Swap(id_response->mutable_infos()); }; - explicit inline Entity() : Entity(Entity::CreateProtoEntity()){}; + explicit inline Entity() + : ScalarProtoMessageWrapper<ProtoEntity>(), value(static_cast<ProtoValue *>(nullptr)), + data_type(static_cast<ProtoDataType *>(nullptr)) { + properties.wrapped = this->wrapped->mutable_properties(); + parents.wrapped = this->wrapped->mutable_parents(); + }; - [[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 this->wrapped->id(); + }; + [[nodiscard]] inline auto HasId() const noexcept -> bool { return !this->wrapped->id().empty(); } [[nodiscard]] inline auto GetVersionId() const -> const std::string & { - return wrapped->version().id(); + return this->wrapped->version().id(); }; - [[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 GetRole() const -> Role { + return static_cast<Role>(this->wrapped->role()); + }; + [[nodiscard]] inline auto GetName() const -> const std::string & { + return this->wrapped->name(); + }; [[nodiscard]] inline auto GetDescription() const -> const std::string & { - return wrapped->description(); + return this->wrapped->description(); }; [[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 GetUnit() const -> const std::string & { + return this->wrapped->unit(); + }; [[nodiscard]] inline auto GetValue() const -> const Value & { return this->value; }; [[nodiscard]] auto GetParents() const -> const Parents &; @@ -690,14 +706,6 @@ public: [[nodiscard]] auto GetInfos() const -> const Messages & { return infos; } [[nodiscard]] inline auto HasInfos() const -> bool { return this->infos.wrapped->size() > 0; } - inline auto ToString() const -> const std::string { - google::protobuf::util::JsonPrintOptions options; - options.add_whitespace = true; - std::string out; - google::protobuf::util::MessageToJsonString(*(this->wrapped), &out, options); - return out; - } - auto SetRole(Role role) -> void; auto SetName(const std::string &name) -> void; /** @@ -778,11 +786,6 @@ public: } private: - static inline auto Copy(const ProtoEntity &from) -> ProtoEntity * { - auto to = from.New(); - to->CopyFrom(from); - return to; - } inline auto GetNextFileId() -> std::string { std::string str = "0123456789abcdef"; std::mt19937 generator(std::random_device{}()); @@ -794,14 +797,12 @@ private: } return result; } - static auto CreateProtoEntity() -> ProtoEntity *; 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; Parents parents; Messages errors; diff --git a/include/caosdb/protobuf_helper.h b/include/caosdb/protobuf_helper.h index 18e54003aa04bc09b334557fd69bb30e5ecfeccb..546bcbd8f5ee6700a442a54b85b9f7bc7f380eb1 100644 --- a/include/caosdb/protobuf_helper.h +++ b/include/caosdb/protobuf_helper.h @@ -22,7 +22,6 @@ #ifndef CAOSDB_PROTOBUF_HELPER_H #define CAOSDB_PROTOBUF_HELPER_H -#include "caosdb/status_code.h" // for StatusCode, SUCCESS #include <google/protobuf/arena.h> // for Arena #include <google/protobuf/generated_message_util.h> // for Arena #include <google/protobuf/util/json_util.h> // for JsonOptions, MessageToJs... @@ -42,6 +41,9 @@ using google::protobuf::Arena; auto get_arena() -> Arena *; +/** + * Abstract wrapper class for Protobuf messages. + */ template <typename P> class ProtoMessageWrapper { public: virtual ~ProtoMessageWrapper() = 0; @@ -49,10 +51,6 @@ public: * Return a json representation of this object. */ virtual inline auto ToString() const noexcept -> const std::string = 0; - //{ - // CAOSDB_DEBUG_MESSAGE_STRING(*wrapped, out) - // return out; - //} /** * Return true if the underlying Protobuf messages have the same @@ -83,11 +81,17 @@ protected: template <typename P> ProtoMessageWrapper<P>::~ProtoMessageWrapper() = default; -template <typename P> class ScalarFieldWrapper : public ProtoMessageWrapper<P> { +/** + * Wrapper class for scalar Protobuf messages. + * + * Scalar means in this context, any message but classes derived from + * RepeatedPtrField. + */ +template <typename P> class ScalarProtoMessageWrapper : public ProtoMessageWrapper<P> { public: - inline virtual ~ScalarFieldWrapper() = default; - inline ScalarFieldWrapper() = default; - inline ScalarFieldWrapper(P *wrapped) : ProtoMessageWrapper<P>(wrapped) {} + inline virtual ~ScalarProtoMessageWrapper() = default; + inline ScalarProtoMessageWrapper() = default; + inline ScalarProtoMessageWrapper(P *wrapped) : ProtoMessageWrapper<P>(wrapped) {} /** * Return a json representation of this object. */ diff --git a/include/caosdb/value.h b/include/caosdb/value.h index 2937f1802fa5bbcacc6227201843c5d251887220..106f378173becf6f40f940be7ada3f9b40899d78 100644 --- a/include/caosdb/value.h +++ b/include/caosdb/value.h @@ -31,7 +31,8 @@ #include <vector> // for vector #define LIST_VALUE_CONSTRUCTOR(TYPE, SETTER) \ - explicit inline Value(const std::vector<TYPE> &values) : ScalarFieldWrapper<ProtoValue>() { \ + explicit inline Value(const std::vector<TYPE> &values) \ + : ScalarProtoMessageWrapper<ProtoValue>() { \ for (const auto &value : values) { \ this->wrapped->mutable_list_values()->add_values()->SETTER(value); \ } \ @@ -40,7 +41,7 @@ namespace caosdb::entity { using caosdb::utility::get_arena; using caosdb::utility::ProtoMessageWrapper; -using caosdb::utility::ScalarFieldWrapper; +using caosdb::utility::ScalarProtoMessageWrapper; using google::protobuf::Arena; using ProtoSpecialValue = caosdb::entity::v1alpha1::SpecialValue; using ProtoValue = caosdb::entity::v1alpha1::Value; @@ -168,7 +169,7 @@ protected: inline AbstractValue::~AbstractValue() {} -class ScalarValue : public AbstractValue, public ScalarFieldWrapper<ProtoScalarValue> { +class ScalarValue : public AbstractValue, public ScalarProtoMessageWrapper<ProtoScalarValue> { public: /** * Destructor. @@ -204,7 +205,7 @@ public: } inline ScalarValue(ProtoScalarValue *wrapped) - : ScalarFieldWrapper<ProtoScalarValue>(wrapped), proto_value(nullptr) {} + : ScalarProtoMessageWrapper<ProtoScalarValue>(wrapped), proto_value(nullptr) {} [[nodiscard]] inline auto IsNull() const noexcept -> bool { return (this->wrapped->scalar_value_case() == ScalarValueCase::kSpecialValue && @@ -249,7 +250,7 @@ public: return empty_collection; } [[nodiscard]] inline auto ToString() const noexcept -> const std::string { - return ScalarFieldWrapper::ToString(); + return ScalarProtoMessageWrapper::ToString(); } friend class Value; @@ -262,13 +263,13 @@ protected: } return this->proto_value; }; - inline ScalarValue() : ScalarFieldWrapper<ProtoScalarValue>(), proto_value(nullptr) {} + inline ScalarValue() : ScalarProtoMessageWrapper<ProtoScalarValue>(), proto_value(nullptr) {} private: mutable ProtoValue *proto_value; }; -class Value : public AbstractValue, public ScalarFieldWrapper<ProtoValue> { +class Value : public AbstractValue, public ScalarProtoMessageWrapper<ProtoValue> { public: /** * Copy constructor. @@ -282,7 +283,7 @@ public: * Destructor. */ inline ~Value() {} - inline Value() : ScalarFieldWrapper<ProtoValue>() { + inline Value() : ScalarProtoMessageWrapper<ProtoValue>() { // has NULL_VALUE now } explicit inline Value(const ScalarValue &value) : Value() { @@ -291,21 +292,21 @@ public: explicit inline Value(const AbstractValue &value) : Value() { this->wrapped->CopyFrom(*value.GetProtoValue()); } - explicit inline Value(ProtoValue *wrapped) : ScalarFieldWrapper<ProtoValue>(wrapped) {} - explicit inline Value(const std::string &value) : ScalarFieldWrapper<ProtoValue>() { + explicit inline Value(ProtoValue *wrapped) : ScalarProtoMessageWrapper<ProtoValue>(wrapped) {} + explicit inline Value(const std::string &value) : ScalarProtoMessageWrapper<ProtoValue>() { this->wrapped->mutable_scalar_value()->set_string_value(value); } - explicit inline Value(const char *value) : ScalarFieldWrapper<ProtoValue>() { + explicit inline Value(const char *value) : ScalarProtoMessageWrapper<ProtoValue>() { this->wrapped->mutable_scalar_value()->set_string_value(std::string(value)); } - explicit inline Value(double value) : ScalarFieldWrapper<ProtoValue>() { + explicit inline Value(double value) : ScalarProtoMessageWrapper<ProtoValue>() { this->wrapped->mutable_scalar_value()->set_double_value(value); } - explicit inline Value(int64_t value) : ScalarFieldWrapper<ProtoValue>() { + explicit inline Value(int64_t value) : ScalarProtoMessageWrapper<ProtoValue>() { this->wrapped->mutable_scalar_value()->set_integer_value(value); } explicit inline Value(int value) : Value(static_cast<int64_t>(value)) {} - explicit inline Value(bool value) : ScalarFieldWrapper<ProtoValue>() { + explicit inline Value(bool value) : ScalarProtoMessageWrapper<ProtoValue>() { this->wrapped->mutable_scalar_value()->set_boolean_value(value); } @@ -411,7 +412,7 @@ public: } [[nodiscard]] inline auto ToString() const noexcept -> const std::string { - return ScalarFieldWrapper::ToString(); + return ScalarProtoMessageWrapper::ToString(); } friend class Entity; diff --git a/src/caosdb/entity.cpp b/src/caosdb/entity.cpp index 050a9bd0fe3b9a2c0dcf213d17a47aa204ce8240..8a2e788a7e039cca9d9c6b036efad3656c3f72b0 100644 --- a/src/caosdb/entity.cpp +++ b/src/caosdb/entity.cpp @@ -163,10 +163,6 @@ auto Entity::AppendProperty(const Property &property) -> void { this->properties 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()); } diff --git a/test/test_data_type.cpp b/test/test_data_type.cpp index 51624a7e0513f4654f2eaa9fdf3519399726199d..78e5100f3ce984ece46918df4aca9ffb8f1d2522 100644 --- a/test/test_data_type.cpp +++ b/test/test_data_type.cpp @@ -117,4 +117,16 @@ TEST(test_data_type, test_list_of_reference) { EXPECT_EQ(list_data_type.GetReferenceDataType().GetName(), "person"); } +TEST(test_data_type, test_data_type_to_string) { + DataType data_type1; + EXPECT_EQ(data_type1.ToString(), "{}\n"); + + ProtoDataType proto_data_type; + DataType data_type2(&proto_data_type); + EXPECT_EQ(data_type2.ToString(), "{}\n"); + + DataType data_type3(AtomicDataType::INTEGER); + EXPECT_EQ(data_type3.ToString(), "{\n \"atomicDataType\": \"ATOMIC_DATA_TYPE_INTEGER\"\n}\n"); +} + } // namespace caosdb::entity diff --git a/test/test_entity.cpp b/test/test_entity.cpp index ad74ef6677947fcdf8c310a272584a0e54e69e88..0987f6b07d25edfa6607800f6864640bda535596 100644 --- a/test/test_entity.cpp +++ b/test/test_entity.cpp @@ -565,4 +565,9 @@ TEST(test_entity, test_add_file) { EXPECT_EQ(entity.SetLocalPath(TEST_DATA_DIR + "/test.json"), StatusCode::SUCCESS); } +TEST(test_entity, test_entity_to_string) { + Entity entity; + EXPECT_EQ(entity.ToString(), "{}\n"); +} + } // namespace caosdb::entity diff --git a/test/test_value.cpp b/test/test_value.cpp index 4e24d9258b287ed9a84538ca04c553e130c73409..241f2bd0ce2a7291184a79cdaa0612f2b99fa204 100644 --- a/test/test_value.cpp +++ b/test/test_value.cpp @@ -33,6 +33,7 @@ #include <vector> // for vector namespace caosdb::entity { +using ProtoValue = caosdb::entity::v1alpha1::Value; using ProtoEntity = caosdb::entity::v1alpha1::Entity; using ProtoParent = caosdb::entity::v1alpha1::Parent; using ProtoDataType = caosdb::entity::v1alpha1::DataType; @@ -175,4 +176,21 @@ TEST(test_value, test_abstract_value) { EXPECT_EQ(scalar_value2.GetAsDouble(), 27.5); } +TEST(test_value, test_value_to_string) { + Value value1; + EXPECT_EQ(value1.ToString(), "{}\n"); + + ProtoValue proto_value; + Value value2(&proto_value); + EXPECT_EQ(value2.ToString(), "{}\n"); + + Value value3(2.6); + EXPECT_EQ(value3.ToString(), "{\n \"scalarValue\": {\n \"doubleValue\": 2.6\n }\n}\n"); + + Value value4(std::vector<bool>{true, false}); + EXPECT_EQ(value4.ToString(), + "{\n \"listValues\": {\n \"values\": [\n {\n \"booleanValue\": true\n },\n " + "{\n \"booleanValue\": false\n }\n ]\n }\n}\n"); +} + } // namespace caosdb::entity