Select Git revision
-
Timm Fitschen authoredTimm Fitschen authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
entity.h 27.78 KiB
/*
* This file is a part of the CaosDB Project.
*
* Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
* Copyright (C) 2021 Florian Spreckelsen <f.spreckelsen@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/>.
*
*/
/**
* @brief Anything entity-related.
* @file caosdb/entity.h
* @author Timm Fitchen
* @date 2021-07-07
*/
#ifndef CAOSDB_ENTITY_H
#define CAOSDB_ENTITY_H
#include "caosdb/data_type.h" // for DataType
#include "caosdb/entity/v1alpha1/main.pb.h" // for RepeatedPtrField
#include "caosdb/logging.h" // for CAOSDB_LOG_WARN
#include "caosdb/message_code.h" // for get_message_code
#include "caosdb/protobuf_helper.h" // for get_arena
#include "caosdb/status_code.h" // for StatusCode
#include "caosdb/value.h" // for Value
#include <boost/filesystem/operations.hpp> // for exists, is_di...
#include <boost/filesystem/path.hpp> // for path
#include <boost/log/core/record.hpp> // for record
#include <boost/log/detail/attachable_sstream_buf.hpp> // for basic_ostring...
#include <boost/log/sources/record_ostream.hpp> // for basic_record_...
#include <boost/preprocessor/seq/limits/enum_256.hpp> // for BOOST_PP_SEQ_...
#include <boost/preprocessor/seq/limits/size_256.hpp> // for BOOST_PP_SEQ_...
#include <cstdint> // for int64_t
#include <google/protobuf/message.h> // for RepeatedPtrField
#include <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 <vector> // for vector
namespace caosdb::entity {
using boost::filesystem::exists;
using boost::filesystem::is_directory;
using caosdb::entity::v1alpha1::IdResponse;
using ProtoParent = caosdb::entity::v1alpha1::Parent;
using ProtoProperty = caosdb::entity::v1alpha1::Property;
using ProtoEntity = caosdb::entity::v1alpha1::Entity;
using ProtoFileDescriptor = caosdb::entity::v1alpha1::FileDescriptor;
using ProtoMessage = caosdb::entity::v1alpha1::Message;
using caosdb::entity::v1alpha1::EntityRole;
using ProtoImportance = caosdb::entity::v1alpha1::Importance;
using caosdb::StatusCode;
using caosdb::entity::v1alpha1::EntityResponse;
using caosdb::entity::v1alpha1::FileTransmissionId;
using caosdb::utility::get_arena;
using ::google::protobuf::RepeatedPtrField;
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;
boost::filesystem::path local_path;
};
/**
* Abstract base class for Messages, Properties and Parents container classes.
*
* This is a list-like class.
*/
template <typename T, typename P> class RepeatedPtrFieldWrapper {
class iterator;
public:
/**
* Return the current size of the container.
*/
[[nodiscard]] inline auto size() const -> int { return wrapped->size(); }
/**
* Return a const reference to the element at the given 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.
*/
[[nodiscard]] inline auto mutable_at(int index) const -> T * {
if (index >= size() || index < 0) {
throw std::out_of_range("Container has size " + std::to_string(size()));
}
if (cache.count(index) == 0) {
cache.emplace(index, T(&(wrapped->at(index))));
}
return &(cache.at(index));
}
/**
* Return iterator positioned at the beginning of the list.
*/
auto begin() -> iterator;
/**
* Return iterator positioned at the end of the list.
*/
auto end() -> iterator;
/**
* Return constant iterator positioned at the beginning of the list.
*/
auto begin() const -> const iterator;
/**
* Return constant iterator positioned at the end of the list.
*/
auto end() const -> const iterator;
friend class Entity;
virtual ~RepeatedPtrFieldWrapper(){};
protected:
RepeatedPtrFieldWrapper(){};
explicit inline RepeatedPtrFieldWrapper(::google::protobuf::RepeatedPtrField<P> *wrapped)
: wrapped(wrapped){};
/**
* Append an element. This adds the element to the end of the wrapped list
* and increases the size by one.
*/
inline auto Append(const T &element) -> void {
auto *destination = this->wrapped->Add();
destination->Swap(element.wrapped);
// Clear the originally wrapped object and return it to the Arena
element.wrapped->Clear();
// set the pointer to the new object which is owned by the RepeatedPtrField
element.wrapped = destination;
}
/**
* Remove the element at the given index.
*/
inline auto Remove(int index) -> void {
this->wrapped->DeleteSubrange(index, 1);
if (cache.count(index) > 0) {
cache.erase(index);
}
// shift all indices in the cache above index (such that the values do not
// get deleted/copied because this could destroy pointers (c-interface).
for (int i = index + 1; i < size(); i++) {
if (cache.count(i) > 0) {
auto handle = cache.extract(i);
handle.key()--;
cache.insert(std::move(handle));
}
}
}
inline auto Clear() noexcept -> void { this->wrapped->Clear(); }
::google::protobuf::RepeatedPtrField<P> *wrapped;
mutable std::map<int, T> cache;
private:
class iterator : public std::iterator<std::output_iterator_tag, T> {
public:
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;
auto operator!=(const iterator &rhs) const -> bool;
private:
int current_index = 0;
const RepeatedPtrFieldWrapper<T, P> *instance;
};
};
template <class T, class P>
RepeatedPtrFieldWrapper<T, P>::iterator::iterator(const RepeatedPtrFieldWrapper<T, P> *instance,
int index)
: current_index(index), instance(instance) {}
template <typename T, typename P>
auto RepeatedPtrFieldWrapper<T, P>::iterator::operator*() const -> T & {
return *(this->instance->mutable_at(current_index));
}
template <typename T, typename P>
auto RepeatedPtrFieldWrapper<T, P>::iterator::operator++()
-> RepeatedPtrFieldWrapper<T, P>::iterator & {
current_index++;
return *this;
}
template <typename T, typename P>
auto RepeatedPtrFieldWrapper<T, P>::iterator::operator++(int)
-> RepeatedPtrFieldWrapper<T, P>::iterator {
iterator tmp(*this);
operator++();
return tmp;
}
template <typename T, typename P>
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 {
return RepeatedPtrFieldWrapper<T, P>::iterator(this, 0);
}
template <typename T, typename P>
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 {
return RepeatedPtrFieldWrapper<T, P>::iterator(this, 0);
}
template <typename T, typename P>
auto RepeatedPtrFieldWrapper<T, P>::end() const -> const RepeatedPtrFieldWrapper<T, P>::iterator {
return RepeatedPtrFieldWrapper<T, P>::iterator(this, size());
}
/**
* Messages convey information about the state of entities and result of
* transactions.
*
* 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:
/**
* Get the code of this message.
*
* The message code is a unique identifier of the type of message and is
* intended to make it easiert to identify messages in a machine-readable
* way.
*/
[[nodiscard]] inline auto GetCode() const -> MessageCode {
return get_message_code(wrapped->code());
}
/**
* Get the description of this message.
*
* The description is intended for a human reader.
*/
[[nodiscard]] inline auto GetDescription() const -> std::string { return wrapped->description(); }
friend class Entity;
// TODO(fspreck) Re-enable once we have decided how messages are
// appended to parents and properties
// friend class Parent;
// friend class Property;
friend class Messages;
friend class RepeatedPtrFieldWrapper<Message, ProtoMessage>;
private:
explicit inline Message(ProtoMessage *wrapped) : wrapped(wrapped){};
ProtoMessage *wrapped;
};
/**
* Container for Messages.
*/
class Messages : public RepeatedPtrFieldWrapper<Message, ProtoMessage> {
public:
~Messages();
friend class Entity;
// TODO(fspreck) Same here.
// friend class Parent;
// friend class Property;
private:
inline Messages() : RepeatedPtrFieldWrapper(){};
};
/**
* 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(ProtoParent *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;
/**
* Return a json string representing this parent.
*
* This is intended for debugging.
*/
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;
}
// TODO(fspreck) Finish the following implementations once we have
// decided how to attach messages to parents.
// /**
// * Return the error messages of this parent.
// */
// [[nodiscard]] inline auto GetErrors() const -> const Messages & {
// return errors;
// }
// [[nodiscard]] inline auto HasErrors() const -> bool {
// return this->errors.wrapped->size() > 0;
// }
// /**
// * Return the warning messages of this parent.
// */
// [[nodiscard]] inline auto GetWarnings() const -> const Messages & {
// return warnings;
// }
// [[nodiscard]] inline auto HasWarnings() const -> bool {
// return this->warnings.wrapped->size() > 0;
// }
// /**
// * Return the info messages of this parent.
// */
// [[nodiscard]] inline auto GetInfos() const -> const Messages & {
// return infos;
// }
friend class Entity;
friend class Parents;
friend class RepeatedPtrFieldWrapper<Parent, ProtoParent>;
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 ProtoParent *wrapped;
// Messages errors;
// Messages warnings;
// Messages infos;
};
/**
* Container for parents of entities.
*
* Should only be instantiated and write-accessed by the owning entity.
*/
class Parents : public RepeatedPtrFieldWrapper<Parent, ProtoParent> {
public:
~Parents() = default;
friend class Entity;
private:
inline Parents() : RepeatedPtrFieldWrapper(){};
explicit inline Parents(
::google::protobuf::RepeatedPtrField<caosdb::entity::v1alpha1::Parent> *wrapped)
: RepeatedPtrFieldWrapper(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(ProtoProperty *other)
: value(Value(other->mutable_value())), data_type(DataType(other->mutable_data_type())),
wrapped(other){};
Property();
/**
* Return the id of this property
*/
[[nodiscard]] auto GetId() const -> const std::string &;
/**
* Return the name of this property
*/
[[nodiscard]] auto GetName() const -> const std::string &;
/**
* Return the description of this property
*/
[[nodiscard]] auto GetDescription() const -> const std::string &;
/**
* Return the importance of this property
*/
[[nodiscard]] auto GetImportance() const -> Importance;
/**
* Return the value of this property
*/
[[nodiscard]] auto GetValue() const -> const Value &;
/**
* Return the unit of this property
*/
[[nodiscard]] auto GetUnit() const -> const std::string &;
/**
* Return the datatype of this property
*/
[[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 &;
// [[nodiscard]] auto GetWarnings() const -> const Messages &;
// [[nodiscard]] auto GetInfos() const -> const Messages &;
/**
* Set the id of this property.
*/
auto SetId(const std::string &id) -> void;
/**
* Set the name of this property.
*/
auto SetName(const std::string &name) -> void;
/**
* Set the description of this property.
*/
auto SetDescription(const std::string &description) -> void;
/**
* Set the importance of this property.
*/
auto SetImportance(Importance importance) -> void;
/**
* Set the value of this property.
*/
auto SetValue(const Value &value) -> StatusCode;
// auto SetValue(const AbstractValue &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<int> &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 int value) -> StatusCode;
auto SetValue(const bool value) -> StatusCode;
/**
* Set the unit of this property.
*/
auto SetUnit(const std::string &unit) -> void;
/**
* Set the datatype of this property.
*/
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.
*
* This is intended for debugging
*/
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;
}
friend class Entity;
friend class Properties;
friend class RepeatedPtrFieldWrapper<Property, ProtoProperty>;
private:
static auto CreateProtoProperty() -> ProtoProperty *;
Value value;
DataType data_type;
mutable ProtoProperty *wrapped;
};
/**
* 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> {
public:
~Properties() = default;
friend class Entity;
private:
inline Properties(){};
explicit inline Properties(
::google::protobuf::RepeatedPtrField<caosdb::entity::v1alpha1::Property> *wrapped)
: RepeatedPtrFieldWrapper<Property, caosdb::entity::v1alpha1::Property>(wrapped){};
};
/**
* Entity is the central and basic data object of CaosDB.
*
* This class is a wrapper of the Entity class auto-generated by protobuf
* (henceforth "ProtoEntity").
*
* Overview of the Constructors:
*
* <li> Entity() - Calls Entity(ProtoEntity *) with a fresh ProtoEntity
* <li> Entity(Entity) - Copy constructor, calls Entity(ProtoEntity *) after copying wrapped
* ProtoEntity of the original, then also copies all Messages. <li> Entity(ProtoEntity *) - The
* workhorse of the constructors. Initializes everything and does not call other Entity
* constructors. <li> Entity(EntityResponse *) - Constructor which is used by the Transaction class
* to create an Entity from the server's response, calls Entity(ProtoEntity). <li> Entity(IdResponse
* *) - Constructor which is used by the Transaction class to create an Entity from the servers's
* response. calls Entity(), then moves the data to the wrapped ProtoEntity.
*
*/
class Entity {
public:
inline Entity(const Entity &original) : Entity(Copy(*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();
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());
this->warnings.wrapped->Swap(response->mutable_warnings());
this->infos.wrapped->Swap(response->mutable_infos());
};
explicit inline 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());
};
explicit inline Entity() : Entity(Entity::CreateProtoEntity()){};
[[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 -> 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 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 HasWarnings() const -> bool {
return this->warnings.wrapped->size() > 0;
}
[[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;
/**
* Set the description of this entity.
*/
auto SetDescription(const std::string &description) -> void;
// auto SetValue(const AbstractValue &value) -> StatusCode;
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<int> &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 int value) -> StatusCode;
auto SetValue(const bool value) -> StatusCode;
auto SetUnit(const std::string &unit) -> 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;
auto AppendParent(const Parent &parent) -> void;
auto RemoveParent(int index) -> void;
/**
* Copy all of this entity's features to the target ProtoEntity.
*/
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 {
file_transmission_id->set_file_id(GetNextFileId());
file_descriptor.file_transmission_id = file_transmission_id;
}
inline auto GetFileDescriptor() -> FileDescriptor & { return this->file_descriptor; }
inline auto GetLocalPath() const noexcept -> const boost::filesystem::path & {
return this->file_descriptor.local_path;
}
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();
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();
return StatusCode::PATH_IS_A_DIRECTORY;
}
CAOSDB_LOG_TRACE(logger_name) << "Entity::SetLocalPath(" << local_path.string() << ");";
this->file_descriptor.local_path = local_path;
return StatusCode::SUCCESS;
}
inline auto ClearMessages() noexcept -> void {
errors.Clear();
warnings.Clear();
infos.Clear();
}
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{}());
std::uniform_int_distribution<int> distribution(0, str.size() - 1);
std::string result(10, '\0');
for (auto &dis : result) {
dis = str[distribution(generator)];
}
return result;
}
static auto 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;
Messages warnings;
Messages infos;
Value value;
DataType data_type;
};
} // namespace caosdb::entity
#endif