Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • caosdb/src/caosdb-cpplib
1 result
Show changes
Commits on Source (33)
......@@ -48,7 +48,7 @@ as compiler. We use [cmake](https://cmake.org/download/) as build tool.
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 Build ##
### Creating a local Conan package ##
Building and installing libcaosdb with Conan is just a single command:
`conan create . -s "compiler.libcxx=libstdc++11"`
......
......@@ -24,6 +24,21 @@
C API
=====
.. note::
When working with libcaosdb's C API keep the following in
mind. Delete all objects (transactions, entities, properties,
parents, ...) that you created using a `caosdb_..._create_...`
function and only those.
The underlying reason is that all C++ objects are realized in the
Extern C interface as mutable structs containing a void pointer to
the actuall C++ object which is not filled when initializing the
struct but after calling a create function instead. If the C++
object wasn't created using a create function, e.g., the parent
object when getting a parent of an entity, it is owned by another
object and deleted together with that object.
.. toctree::
:glob:
......
......@@ -29,10 +29,14 @@
#ifndef CAOSDB_ENTITY_H
#define CAOSDB_ENTITY_H
#include <string> // for string
#include "caosdb/entity/v1alpha1/main.pb.h" // for RepeatedPtrField, Message
#include "caosdb/entity/v1alpha1/main.pb.h" // for ProtoEntity, ProtoParent...
#include "caosdb/message_code.h" // for get_message_code, Messag...
#include "google/protobuf/util/json_util.h" // for MessageToJsonString, Jso...
#include <google/protobuf/util/json_util.h> // for MessageToJsonString, Jso...
#include <google/protobuf/message.h> // for RepeatedPtrField, Message
#include <iterator> // for iterator, output_iterato...
#include <map> // for map
#include <stdexcept> // for out_of_range
#include <string> // for string
namespace caosdb::entity {
using caosdb::entity::v1alpha1::IdResponse;
......@@ -40,18 +44,202 @@ using ProtoParent = caosdb::entity::v1alpha1::Parent;
using ProtoProperty = caosdb::entity::v1alpha1::Property;
using ProtoEntity = caosdb::entity::v1alpha1::Entity;
using ProtoMessage = caosdb::entity::v1alpha1::Message;
using ::google::protobuf::RepeatedPtrField;
static const std::string logger_name = "caosdb::entity";
/**
* Messages convey information about the state and result of transactions.
* 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));
}
}
}
::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);
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();
}
......@@ -62,6 +250,7 @@ public:
// friend class Parent;
// friend class Property;
friend class Messages;
friend class RepeatedPtrFieldWrapper<Message, ProtoMessage>;
private:
explicit inline Message(ProtoMessage *wrapped) : wrapped(wrapped){};
......@@ -72,12 +261,9 @@ private:
/**
* Container for Messages.
*/
class Messages {
class Messages : public RepeatedPtrFieldWrapper<Message, ProtoMessage> {
public:
[[nodiscard]] inline auto Size() const -> int { return wrapped->size(); }
[[nodiscard]] inline auto At(int index) const -> const Message {
return Message(&(wrapped->at(index)));
}
~Messages();
friend class Entity;
// TODO(fspreck) Same here.
......@@ -85,9 +271,7 @@ public:
// friend class Property;
private:
inline Messages() : wrapped(nullptr){};
::google::protobuf::RepeatedPtrField<ProtoMessage> *wrapped;
inline Messages() : RepeatedPtrFieldWrapper(){};
};
/**
......@@ -166,6 +350,7 @@ public:
friend class Entity;
friend class Parents;
friend class RepeatedPtrFieldWrapper<Parent, ProtoParent>;
private:
/**
......@@ -194,40 +379,17 @@ private:
*
* Should only be instantiated and write-accessed by the owning entity.
*/
class Parents {
class Parents : public RepeatedPtrFieldWrapper<Parent, ProtoParent> {
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)));
}
~Parents() = default;
friend class Entity;
private:
inline Parents(){};
inline Parents() : RepeatedPtrFieldWrapper(){};
explicit inline Parents(
::google::protobuf::RepeatedPtrField<ProtoParent> *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<ProtoParent> *wrapped;
::google::protobuf::RepeatedPtrField<caosdb::entity::v1alpha1::Parent>
*wrapped)
: RepeatedPtrFieldWrapper(wrapped){};
};
/**
......@@ -320,6 +482,7 @@ public:
friend class Entity;
friend class Properties;
friend class RepeatedPtrFieldWrapper<Property, ProtoProperty>;
private:
static auto CreateProtoProperty() -> ProtoProperty *;
......@@ -332,37 +495,20 @@ private:
*
* Should only be instantiated and write-accessed by the owning entity.
*/
class Properties {
class Properties
: public RepeatedPtrFieldWrapper<Property,
caosdb::entity::v1alpha1::Property> {
public:
/**
* Return the current size of the properties container.
*
* This is also the number of properties the owningn entity currently has.
*/
[[nodiscard]] inline auto Size() const -> int { return wrapped->size(); }
/**
* Return the property at the given index.
*/
[[nodiscard]] auto At(int index) const -> const Property {
return Property(&(wrapped->at(index)));
}
~Properties() = default;
friend class Entity;
private:
inline Properties(){};
explicit inline Properties(
::google::protobuf::RepeatedPtrField<ProtoProperty> *wrapped)
: wrapped(wrapped){};
/**
* Append a property
*
* This increases the Size() by one.
*/
auto Append(const Property &property) -> void;
::google::protobuf::RepeatedPtrField<ProtoProperty> *wrapped;
::google::protobuf::RepeatedPtrField<caosdb::entity::v1alpha1::Property>
*wrapped)
: RepeatedPtrFieldWrapper<Property, caosdb::entity::v1alpha1::Property>(
wrapped){};
};
/**
......@@ -448,9 +594,12 @@ public:
auto SetUnit(const std::string &unit) -> void;
// Currently no references or lists.
auto SetDatatype(const std::string &datatype) -> void;
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.
*/
......
......@@ -52,6 +52,7 @@ enum StatusCode {
TRANSACTION_TYPE_ERROR = 26,
UNSUPPORTED_FEATURE = 27,
ORIGINAL_ENTITY_MISSING_ID = 28,
EXTERN_C_ASSIGNMENT_ERROR = 29,
};
auto get_status_description(int code) -> const std::string &;
......
/*
* 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/>.
*
*/
#ifdef __cplusplus
extern "C" {
#endif
......@@ -40,6 +61,7 @@ const char *caosdb_constants_COMPATIBLE_SERVER_VERSION_PRE_RELEASE();
*/
typedef struct {
void *wrapped_connection;
bool _deletable = false;
} caosdb_connection_connection;
/**
......@@ -51,6 +73,7 @@ typedef struct {
*/
typedef struct {
void *wrapped_connection_configuration;
bool _deletable = false;
} caosdb_connection_connection_configuration;
/**
......@@ -70,10 +93,12 @@ typedef struct {
typedef struct {
void *wrapped_certificate_provider;
bool _deletable = false;
} caosdb_connection_certificate_provider;
typedef struct {
void *wrapped_authenticator;
bool _deletable = false;
} caosdb_authentication_authenticator;
/**
......@@ -242,62 +267,77 @@ int caosdb_connection_connection_manager_get_connection(
// not sufficient yet.
typedef struct {
void *wrapped_transaction;
bool _deletable = false;
} caosdb_transaction_transaction;
/**
* Create a transaction on an existing connection.
*
* 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);
// TODO(fspreck) execute_asynchronously may be added as a separate
// function once we actually support asynchronous execution.
typedef struct {
void *wrapped_result_set;
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_count_result(
caosdb_transaction_transaction *transaction, long *out);
typedef struct {
void *wrapped_entity;
char **id;
char **role;
char **name;
char **description;
char **datatype;
char **unit;
char **value;
char **version_id;
bool _deletable = false;
} caosdb_entity_entity;
int caosdb_transaction_result_set_get_entity(
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);
int caosdb_transaction_result_set_size(
caosdb_transaction_result_set *result_set, int *out);
typedef struct {
void *wrapped_property;
char **id;
char **name;
char **description;
char **datatype;
char **unit;
char **value;
bool _deletable = false;
} caosdb_entity_property;
typedef struct {
void *wrapped_parent;
char **id;
char **name;
char **description;
bool _deletable = false;
} caosdb_entity_parent;
typedef struct {
void *wrapped_message;
int *code;
char **description;
bool _deletable = false;
} caosdb_entity_message;
// GETTERS FOR COMPLEX OBJECTS
// GETTERS FOR EVERYTHING
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_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,
......@@ -318,6 +358,29 @@ int caosdb_entity_entity_get_parents_size(caosdb_entity_entity *entity,
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_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_message_get_code(caosdb_entity_message *message, int *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);
int caosdb_entity_delete_entity(caosdb_entity_entity *out);
......@@ -326,11 +389,43 @@ int caosdb_entity_delete_property(caosdb_entity_property *out);
int caosdb_entity_create_parent(caosdb_entity_parent *out);
int caosdb_entity_delete_parent(caosdb_entity_parent *out);
// SETTERS FOR COMPLEX OBJECTS
// 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_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_parent_set_id(caosdb_entity_parent *parent, const char *id);
int caosdb_entity_parent_set_name(caosdb_entity_parent *parent,
const char *name);
#ifdef __cplusplus
}
......
......@@ -31,6 +31,8 @@ using ProtoProperty = caosdb::entity::v1alpha1::Property;
using ProtoEntity = caosdb::entity::v1alpha1::Entity;
using caosdb::utility::get_arena;
Messages::~Messages() = default;
Parent::Parent() : wrapped(Parent::CreateProtoParent()) {
// TODO(fspreck) Re-enable once we have decided how to attach
// messages to parents.
......@@ -47,10 +49,6 @@ auto Parent::SetName(const std::string &name) -> void {
this->wrapped->set_name(name);
}
auto Parent::GetDescription() const -> const std::string & {
return this->wrapped->description();
}
auto Parent::SetId(const std::string &id) -> void { this->wrapped->set_id(id); }
[[nodiscard]] auto Parent::GetId() const -> const std::string & {
......@@ -61,15 +59,8 @@ auto Parent::SetId(const std::string &id) -> void { this->wrapped->set_id(id); }
return this->wrapped->name();
}
auto Parents::Append(const Parent &parent) -> void {
auto *destination = this->wrapped->Add();
destination->Swap(parent.wrapped);
// Clear the originally wrapped object and return it to the Arena
parent.wrapped->Clear();
// set the pointer to the new object which is owned by the RepeatedPtrField
parent.wrapped = destination;
[[nodiscard]] auto Parent::GetDescription() const -> const std::string & {
return this->wrapped->description();
}
Property::Property() : wrapped(Property::CreateProtoProperty()) {}
......@@ -134,15 +125,6 @@ auto Property::SetDatatype(const std::string &datatype) -> void {
this->wrapped->set_datatype(datatype);
}
auto Properties::Append(const Property &property) -> void {
auto *destination = this->wrapped->Add();
destination->Swap(property.wrapped);
property.wrapped->Clear();
property.wrapped = destination;
}
[[nodiscard]] auto Entity::GetParents() const -> const Parents & {
return parents;
}
......@@ -151,6 +133,8 @@ 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;
}
......@@ -159,6 +143,10 @@ 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 google::protobuf::Arena::CreateMessage<ProtoEntity>(get_arena());
}
......
......@@ -80,7 +80,10 @@ auto get_status_description(int code) -> const std::string & {
"an id. This is the case when you did not retrieve it before applying any "
"changes and instantiated the Entity class explicitely."},
{StatusCode::UNSUPPORTED_FEATURE,
"This feature is not available in the this client implementation."}};
"This feature is not available in the this client implementation."},
{StatusCode::EXTERN_C_ASSIGNMENT_ERROR,
"You tried to assign a new object to the wrapped void pointer. You have "
"to delete the old pointee first."}};
try {
return descriptions.at(code);
} catch (const std::out_of_range &exc) {
......
This diff is collapsed.
......@@ -21,12 +21,15 @@
*/
#include "caosdb/configuration.h"
#include "caosdb/status_code.h" // for StatusCode
#include "caosdb_test_utility.h" // for EXPECT_THROW_MESSAGE, TEST_DATA_DIR
#include "ccaosdb.h" // for caosdb_utility_get_env_var
#include <cstring> // for strcmp
#include <gtest/gtest-message.h> // for Message
#include <gtest/gtest-test-part.h> // for SuiteApiResolver, TestFactoryImpl
#include <gtest/gtest_pred_impl.h> // for Test, TestInfo, EXPECT_EQ, TEST
#include <string> // for allocator
#include <iostream>
#include <string> // for allocator
class test_ccaosdb : public ::testing::Test {
protected:
......@@ -61,3 +64,349 @@ TEST_F(test_ccaosdb, test_get_connection) {
"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_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"));
EXPECT_EQ(return_code, caosdb::StatusCode::GO_ON);
return_code = caosdb_transaction_transaction_execute(&transaction);
EXPECT_EQ(return_code, caosdb::StatusCode::CONNECTION_ERROR);
return_code = caosdb_transaction_delete_transaction(&transaction);
EXPECT_EQ(return_code, 0);
caosdb_transaction_transaction 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);
EXPECT_EQ(return_code, caosdb::StatusCode::GO_ON);
return_code = caosdb_transaction_delete_transaction(&multi_transaction);
EXPECT_EQ(return_code, 0);
}
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");
std::cout << "Creating transaction" << std::endl;
caosdb_transaction_transaction 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));
EXPECT_EQ(return_code, caosdb::StatusCode::GO_ON);
std::cout << "Deleting transaction ..." << std::endl;
return_code = caosdb_transaction_delete_transaction(&multi_transaction);
EXPECT_EQ(return_code, 0);
}
TEST_F(test_ccaosdb, test_query) {
caosdb_connection_connection connection;
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"));
EXPECT_EQ(return_code, caosdb::StatusCode::GO_ON);
return_code = caosdb_transaction_delete_transaction(&transaction);
EXPECT_EQ(return_code, 0);
}
TEST_F(test_ccaosdb, test_entity) {
caosdb_entity_entity entity;
int return_code(caosdb_entity_create_entity(&entity));
EXPECT_EQ(return_code, 0);
// cannot be created again without deletion
return_code = caosdb_entity_create_entity(&entity);
EXPECT_EQ(return_code, caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR);
// deletion and re-creation is ok
return_code = caosdb_entity_delete_entity(&entity);
EXPECT_EQ(return_code, 0);
return_code = caosdb_entity_create_entity(&entity);
EXPECT_EQ(return_code, 0);
// In-depth check for one pair of setter and getter, just compare
// the strings for the rest
return_code = caosdb_entity_entity_set_name(&entity, "length");
EXPECT_EQ(return_code, 0);
char out[255] = {"a"}; // NOLINT
return_code = caosdb_entity_entity_get_name(&entity, out);
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);
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);
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);
return_code = caosdb_entity_delete_entity(&entity);
EXPECT_EQ(return_code, 0);
}
TEST_F(test_ccaosdb, test_parent) {
caosdb_entity_parent parent;
int return_code(caosdb_entity_create_parent(&parent));
EXPECT_EQ(return_code, 0);
caosdb_entity_parent_set_id(&parent, "some_id");
caosdb_entity_parent_set_name(&parent, "some_name");
char out[255] = {"a"}; // NOLINT
caosdb_entity_parent_get_id(&parent, out);
EXPECT_EQ(strcmp(out, "some_id"), 0);
caosdb_entity_parent_get_name(&parent, out);
EXPECT_EQ(strcmp(out, "some_name"), 0);
return_code = caosdb_entity_delete_parent(&parent);
EXPECT_EQ(return_code, 0);
}
TEST_F(test_ccaosdb, test_property) {
caosdb_entity_property property;
int return_code(caosdb_entity_create_property(&property));
EXPECT_EQ(return_code, 0);
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");
caosdb_entity_property_set_unit(&property, "some_unit");
caosdb_entity_property_set_value(&property, "some_value");
char out[255] = {"a"}; // NOLINT
caosdb_entity_property_get_id(&property, out);
EXPECT_EQ(strcmp(out, "some_id"), 0);
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);
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);
return_code = caosdb_entity_delete_property(&property);
EXPECT_EQ(return_code, 0);
}
TEST_F(test_ccaosdb, test_entity_with_parent_and_property) {
std::cout << "Creating objects ... " << std::endl;
caosdb_entity_parent input_parent;
int return_code(caosdb_entity_create_parent(&input_parent));
EXPECT_EQ(return_code, 0);
caosdb_entity_parent_set_id(&input_parent, "parent_id");
caosdb_entity_parent_set_name(&input_parent, "parent_name");
caosdb_entity_property input_property;
return_code = caosdb_entity_create_property(&input_property);
EXPECT_EQ(return_code, 0);
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");
caosdb_entity_entity entity;
return_code = caosdb_entity_create_entity(&entity);
EXPECT_EQ(return_code, 0);
std::cout << "Appending parent and property ..." << std::endl;
return_code = caosdb_entity_entity_append_parent(&entity, &input_parent);
EXPECT_EQ(return_code, 0);
return_code = caosdb_entity_entity_append_property(&entity, &input_property);
EXPECT_EQ(return_code, 0);
std::cout << "Counting parents and properties ..." << std::endl;
int count[] = {0}; // NOLINT
return_code = caosdb_entity_entity_get_parents_size(&entity, count);
EXPECT_EQ(return_code, 0);
EXPECT_EQ(*count, 1);
return_code = caosdb_entity_entity_get_properties_size(&entity, count);
EXPECT_EQ(return_code, 0);
EXPECT_EQ(*count, 1);
char in[255] = {"a"}; // NOLINT
char out[255] = {"b"}; // NOLINT
std::cout << "Comparing ..." << std::endl;
// cannot assign an already assigned property
return_code = caosdb_entity_entity_get_property(&entity, &input_property, 0);
EXPECT_EQ(return_code, caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR);
caosdb_entity_property output_property;
return_code = caosdb_entity_entity_get_property(&entity, &output_property, 0);
std::cout << "Got output property." << std::endl;
EXPECT_EQ(return_code, 0);
caosdb_entity_property_get_id(&input_property, in);
std::cout << "Got input id." << std::endl;
caosdb_entity_property_get_id(&output_property, out);
std::cout << "Got output id." << std::endl;
EXPECT_EQ(strcmp(in, out), 0);
caosdb_entity_property_get_name(&input_property, in);
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);
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;
return_code = caosdb_entity_entity_get_parent(&entity, &output_parent, 0);
std::cout << "Got output parent." << std::endl;
EXPECT_EQ(return_code, 0);
caosdb_entity_parent_get_id(&input_parent, in);
caosdb_entity_parent_get_id(&output_parent, out);
EXPECT_EQ(strcmp(in, out), 0);
caosdb_entity_parent_get_name(&input_parent, in);
caosdb_entity_parent_get_name(&output_parent, out);
EXPECT_EQ(strcmp(in, out), 0);
// Delete everything
std::cout << "Deleting ..." << std::endl;
return_code = caosdb_entity_delete_parent(&input_parent);
EXPECT_EQ(return_code, 0);
return_code = caosdb_entity_delete_property(&input_property);
EXPECT_EQ(return_code, 0);
return_code = caosdb_entity_delete_entity(&entity);
EXPECT_EQ(return_code, 0);
// This tests the `_deletable` flag. The wrapped cpp objects of
// `output_parent` and `output_property` are owned by the entity, so
// they have been deleted together with the entity. With a wrong
// `_deletable` flag, the following would cause segfaults.
//
return_code = caosdb_entity_delete_parent(&output_parent);
EXPECT_EQ(return_code, 0);
return_code = caosdb_entity_delete_property(&output_property);
EXPECT_EQ(return_code, 0);
}
TEST_F(test_ccaosdb, test_remove_property) {
caosdb_entity_entity entity;
int return_code(caosdb_entity_create_entity(&entity));
EXPECT_EQ(return_code, 0);
// Create two properties with names
caosdb_entity_property in_prop_1;
return_code = caosdb_entity_create_property(&in_prop_1);
EXPECT_EQ(return_code, 0);
return_code = caosdb_entity_property_set_name(&in_prop_1, "Property 1");
EXPECT_EQ(return_code, 0);
caosdb_entity_property in_prop_2;
return_code = caosdb_entity_create_property(&in_prop_2);
EXPECT_EQ(return_code, 0);
return_code = caosdb_entity_property_set_name(&in_prop_2, "Property 2");
EXPECT_EQ(return_code, 0);
// Append them
return_code = caosdb_entity_entity_append_property(&entity, &in_prop_1);
EXPECT_EQ(return_code, 0);
return_code = caosdb_entity_entity_append_property(&entity, &in_prop_2);
EXPECT_EQ(return_code, 0);
// Delete one and see that the number of properties decreases by one
int count[] = {0}; // NOLINT
return_code = caosdb_entity_entity_get_properties_size(&entity, count);
EXPECT_EQ(return_code, 0);
EXPECT_EQ(*count, 2);
return_code = caosdb_entity_entity_remove_property(&entity, 0);
EXPECT_EQ(return_code, 0);
return_code = caosdb_entity_entity_get_properties_size(&entity, count);
EXPECT_EQ(return_code, 0);
EXPECT_EQ(*count, 1);
caosdb_entity_property out_prop;
return_code = caosdb_entity_entity_get_property(&entity, &out_prop, 0);
EXPECT_EQ(return_code, 0);
char in[255] = {"a"}; // NOLINT
char out[255] = {"b"}; // NOLINT
// Deleted the first property, so the second one should remain.
return_code = caosdb_entity_property_get_name(&in_prop_2, in);
EXPECT_EQ(return_code, 0);
return_code = caosdb_entity_property_get_name(&out_prop, out);
EXPECT_EQ(return_code, 0);
EXPECT_EQ(strcmp(in, out), 0);
// Delete everything we have created
return_code = caosdb_entity_delete_property(&in_prop_2);
EXPECT_EQ(return_code, 0);
return_code = caosdb_entity_delete_property(&in_prop_1);
EXPECT_EQ(return_code, 0);
return_code = caosdb_entity_delete_entity(&entity);
EXPECT_EQ(return_code, 0);
}
......@@ -30,7 +30,9 @@
#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 <memory> // for allocator, shared_ptr
#include <iostream>
#include <memory> // for allocator, shared_ptr
#include <string>
namespace caosdb::entity {
using caosdb::entity::v1alpha1::IdResponse;
......@@ -262,6 +264,111 @@ TEST(test_entity, test_from_id_response) {
EXPECT_EQ(other_ent.GetInfos().At(0).GetCode(), MessageCode::UNSPECIFIED);
}
TEST(test_entity, test_remove_property) {
Entity entity;
for (int i = 0; i < 5; i++) {
auto name = "PROPERTY-" + std::to_string(i);
Property property;
property.SetName(name);
EXPECT_EQ(property.GetName(), name);
entity.AppendProperty(property);
EXPECT_EQ(property.GetName(), name);
// not initializing the cache
}
ASSERT_EQ(entity.GetProperties().Size(), 5);
for (int i = 5; i < 10; i++) {
auto name = "PROPERTY-" + std::to_string(i);
Property property;
property.SetName(name);
EXPECT_EQ(property.GetName(), name);
entity.AppendProperty(property);
EXPECT_EQ(property.GetName(), name);
// initializing the cache
const auto &property_2 = entity.GetProperties().At(i);
EXPECT_EQ(property_2.GetName(), name);
}
ASSERT_EQ(entity.GetProperties().Size(), 10);
for (int i = 5; i < 10; i++) {
// double checking the cache
auto name = "PROPERTY-" + std::to_string(i);
const auto &property = entity.GetProperties().At(i);
EXPECT_EQ(property.GetName(), name);
}
// Remove at index 3
// P0,P1,P2,P3,P4,P5,P6,P7,P8,P9
// ^
// P0,P1,P2, P4,P5,P6,P7,P8,P9
entity.RemoveProperty(3);
// Remove at index 6
// P0,P1,P2, P4,P5,P6,P7,P8,P9
// ^
// P0,P1,P2, P4,P5,P6, P8,P9
entity.RemoveProperty(6);
ASSERT_EQ(entity.GetProperties().Size(), 8);
// AppendProperty another property
// P0,P1,P2, P4,P5,P6, P8,P9
// ^
// P0,P1,P2, P4,P5,P6, P8,P9,P10
Property property10;
property10.SetName("PROPERTY-10");
entity.AppendProperty(property10);
ASSERT_EQ(entity.GetProperties().Size(), 9);
std::cout << "[" << std::endl;
for (int i = 0; i < 9; i++) {
std::cout << " " << entity.GetProperties().At(i).GetName() << ",\n";
}
std::cout << "]" << std::endl;
for (int i = 0; i < 3; i++) {
auto name = "PROPERTY-" + std::to_string(i);
const auto &property = entity.GetProperties().At(i);
EXPECT_EQ(property.GetName(), name);
}
for (int i = 3; i < 6; i++) {
auto name = "PROPERTY-" + std::to_string(i + 1);
const auto &property = entity.GetProperties().At(i);
EXPECT_EQ(property.GetName(), name);
}
for (int i = 6; i < 9; i++) {
auto name = "PROPERTY-" + std::to_string(i + 2);
const auto &property = entity.GetProperties().At(i);
EXPECT_EQ(property.GetName(), name);
}
}
TEST(test_entity, test_property_iterator) {
Entity entity;
for (int i = 0; i < 5; i++) {
auto name = "PROPERTY-" + std::to_string(i);
Property property;
property.SetName(name);
EXPECT_EQ(property.GetName(), name);
entity.AppendProperty(property);
}
ASSERT_EQ(entity.GetProperties().Size(), 5);
int counter = 0;
for (auto &property : entity.GetProperties()) {
auto name = "PROPERTY-" + std::to_string(counter);
EXPECT_EQ(property.GetName(), name);
counter++;
}
EXPECT_EQ(counter, 5);
}
TEST(test_entity, test_description) {
Entity entity;
Property property;
......