finalize entity functions

Signed-off-by: Folling <mail@folling.io>
This commit is contained in:
folling 2025-01-02 09:39:08 +01:00 committed by Folling
parent f0e6dec7de
commit c489e9e8ae
Signed by: folling
SSH key fingerprint: SHA256:S9qEx5WCFFLK49tE/LKnKuJYM5sw+++Dn6qJbbyxnCY
18 changed files with 523 additions and 181 deletions

View file

@ -64,7 +64,7 @@ BreakBeforeInlineASMColon: OnlyMultiline
BreakBeforeTernaryOperators: false
BreakConstructorInitializers: AfterColon
BreakInheritanceList: AfterColon
BreakStringLiterals: true
BreakStringLiterals: false
ColumnLimit: 80
CommentPragmas: '^\\.+'

View file

@ -181,8 +181,6 @@ IKA_API void ikarus_entity_link_blueprint(
enum IkarusEntityUnlinkBlueprintFlags {
/// \brief No flags.
IkarusEntityUnlinkBlueprintFlags_None = 0,
/// \brief Keep the values associated with the blueprint, transforming them into entity values.
IkarusEntityUnlinkBlueprintFlags_KeepValues = 1,
};
/// \brief Unlinks an entity from a blueprint.
@ -203,17 +201,27 @@ IKA_API void ikarus_entity_unlink_blueprint(
IkarusErrorData * error_out
);
/// \brief Struct for an entity value.
struct IkarusEntityValue {
/// \brief The name of the value.
char const * name;
/// \brief The value in json format. \see value.h
char const * value;
};
/// \brief Gets the values of an entity.
/// \param entity The entity to get the values of.
/// \pre \li Must not be null.
/// \pre \li Must exist.
/// \param size_out An out parameter for the number of values in the returned array
/// or undefined if an error occurs.
/// \param error_out \see errors.h
/// \return The values, in json format of or null if an error occurs.
/// The json representation is an array of objects with the following keys:
/// - `name`: The name of the value.
/// - `value`: The value itself. \see value.h
IKA_API char const *
ikarus_entity_get_values(IkarusEntity * entity, IkarusErrorData * error_out);
/// \return The values or null if an error occurs.
IKA_API IkarusEntityValue * ikarus_entity_get_values(
IkarusEntity * entity,
size_t * size_out,
IkarusErrorData * error_out
);
/// \brief Gets a value of an entity.
/// \param entity The entity to get the value of.
@ -279,16 +287,25 @@ IKA_API void ikarus_entity_delete_value(
IkarusErrorData * error_out
);
/// \brief Struct for an entity property value.
struct IkarusEntityPropertyValue {
/// \brief The property.
struct IkarusProperty * property;
/// \brief The value in json format. \see value.h
char const * value;
};
/// \brief Gets the property values of an entity.
/// \param entity The entity to get the property values of.
/// \pre \li Must not be null.
/// \pre \li Must exist.
/// \param size_out An out parameter for the number of property values in the
/// returned array or undefined if an error occurs.
/// \param error_out \see errors.h
/// \return The property values, in msgpack format of or null if an error occurs.
/// The format is a map of property pointers (as integers) to values. \see
/// value.h
IKA_API char const * ikarus_entity_get_property_values(
/// \return The property values, or null if an error occurs.
IKA_API IkarusEntityPropertyValue * ikarus_entity_get_property_values(
IkarusEntity * entity,
size_t * size_out,
IkarusErrorData * error_out
);

View file

@ -11,6 +11,8 @@ void safe_strcpy(
size_t const dest_size
);
#define IKARUS_VOID_RETURN
#define IKARUS_SET_ERROR(msg, err_info) \
if (error_out != nullptr) { \
safe_strcpy( \
@ -140,9 +142,9 @@ void safe_strcpy(
IkarusErrorInfo_Client_InvalidInput \
);
#define IKARUS_FAIL_IF_NOT_EXIST(object, ret) \
#define IKARUS_FAIL_IF_NOT_EXIST_IMPL(exists_name, object, ret) \
IKARUS_VTRYRV_OR_FAIL( \
auto exists, \
auto exists_name, \
ret, \
fmt::format( \
"failed to check if {} exists", \
@ -159,7 +161,7 @@ void safe_strcpy(
); \
\
IKARUS_FAIL_IF( \
!exists, \
!exists_name, \
ret, \
fmt::format( \
"{} doesn't exist", \
@ -167,3 +169,6 @@ void safe_strcpy(
), \
IkarusErrorInfo_Client_NonExistent \
)
#define IKARUS_FAIL_IF_NOT_EXIST(object, ret) \
IKARUS_FAIL_IF_NOT_EXIST_IMPL(CPPBASE_UNIQUE_NAME(exists), object, ret)

View file

@ -3,3 +3,7 @@
#include <ikarus/errors.hpp>
#include <ikarus/objects/blueprint.hpp>
#include <ikarus/persistence/project.hpp>
IkarusBlueprint::IkarusBlueprint(struct IkarusProject * project, int64_t id):
project{project},
id{id} {}

View file

@ -3,21 +3,11 @@
#include <string>
struct IkarusBlueprint {
consteval static inline auto OBJECT_NAME() -> std::string_view {
return "blueprint";
}
constinit static inline auto object_name = "blueprint";
constinit static inline auto table_name = "blueprints";
consteval static inline auto TABLE_NAME() -> std::string_view {
return "blueprints";
}
IkarusBlueprint(
struct IkarusProject * project,
int64_t id,
std::string_view name
);
IkarusBlueprint(struct IkarusProject * project, int64_t id);
struct IkarusProject * project;
int64_t id;
std::string name;
};

View file

@ -1,18 +1,15 @@
#include "entity.hpp"
#include <algorithm>
#include <ikarus/errors.h>
#include <ikarus/errors.hpp>
#include <ikarus/objects/entity.h>
#include <ikarus/persistence/project.hpp>
IkarusEntity::IkarusEntity(
struct IkarusProject * project,
int64_t id,
std::string_view name
):
IkarusEntity::IkarusEntity(struct IkarusProject * project, int64_t id):
project{project},
id{id},
name{name} {}
id{id} {}
IkarusEntity * ikarus_entity_create(
struct IkarusProject * project,
@ -31,7 +28,7 @@ IkarusEntity * ikarus_entity_create(
);
auto const id = project->db->last_insert_rowid();
return new IkarusEntity{project, id, name};
return new IkarusEntity{project, id};
}
void ikarus_entity_delete(
@ -39,12 +36,11 @@ void ikarus_entity_delete(
IkarusEntityDeleteFlags flags,
IkarusErrorData * error_out
) {
IKARUS_FAIL_IF_NULL(entity, );
IKARUS_FAIL_IF_NOT_EXIST(entity, );
IKARUS_FAIL_IF_NULL(entity->project, );
IKARUS_FAIL_IF_NULL(entity, IKARUS_VOID_RETURN);
IKARUS_FAIL_IF_NOT_EXIST(entity, IKARUS_VOID_RETURN);
IKARUS_TRYRV_OR_FAIL(
,
IKARUS_VOID_RETURN,
"failed to delete entity: {}",
IkarusErrorInfo_Database_QueryFailed,
entity->project->db
@ -61,7 +57,6 @@ IkarusEntity * ikarus_entity_copy(
) {
IKARUS_FAIL_IF_NULL(entity, nullptr);
IKARUS_FAIL_IF_NOT_EXIST(entity, nullptr);
IKARUS_FAIL_IF_NULL(entity->project, nullptr);
IKARUS_VTRYRV_OR_FAIL(
auto id,
@ -72,34 +67,28 @@ IkarusEntity * ikarus_entity_copy(
[entity](auto * db)
-> cppbase::Result<int64_t, sqlitecpp::TransactionError> {
TRY(entity->project->db->execute(
"INSERT INTO `entities`(`name`) VALUES(?)",
entity->name.data()
"INSERT INTO `entities`(`name`) "
"SELECT `name` FROM `entities` WHERE `id` = ?",
entity->id
));
TRY(entity->project->db->execute(
"INSERT INTO `entity_values`(`entity`, `name`, `value`)"
" SELECT ?1, `name`, `value` FROM `entity_values` WHERE "
"INSERT INTO `entity_values`(`entity`, `name`, `value`) "
"SELECT ?1, `name`, `value` FROM `entity_values` WHERE "
"`entity` = ?1",
entity->id
))
TRY(entity->project->db->execute(
"INSERT INTO `entity_property_values`("
" `entity`, "
" `property`,"
" `value`"
") "
"SELECT ?1, `property`, `value` FROM "
"`entity_property_values` "
"INSERT INTO `entity_property_values`(`entity`, `property`, `value`) "
"SELECT ?1, `property`, `value` FROM `entity_property_values` "
"WHERE `entity` = ?1",
entity->id
))
TRY(entity->project->db->execute(
"INSERT INTO `entity_blueprint_links`(`entity`, "
"`blueprint`)"
"SELECT ?1, `property`, `value` FROM "
"`entity_property_values` "
"INSERT INTO `entity_blueprint_links`(`entity`, `blueprint`) "
"SELECT ?1, `property`, `value` FROM `entity_property_values` "
"WHERE `entity` = ?1",
entity->id
))
@ -109,13 +98,13 @@ IkarusEntity * ikarus_entity_copy(
)
);
return new IkarusEntity{entity->project, id, entity->name};
return new IkarusEntity{entity->project, id};
}
IkarusProject *
ikarus_entity_get_project(IkarusEntity * entity, IkarusErrorData * error_out) {
IKARUS_FAIL_IF_NULL(entity, nullptr);
IKARUS_FAIL_IF_NULL(entity->project, nullptr);
IKARUS_FAIL_IF_NOT_EXIST(entity, nullptr);
return entity->project;
}
@ -123,8 +112,20 @@ ikarus_entity_get_project(IkarusEntity * entity, IkarusErrorData * error_out) {
char const *
ikarus_entity_get_name(IkarusEntity * entity, IkarusErrorData * error_out) {
IKARUS_FAIL_IF_NULL(entity, nullptr);
IKARUS_FAIL_IF_NOT_EXIST(entity, nullptr);
return entity->name.data();
IKARUS_VTRYRV_OR_FAIL(
auto name,
nullptr,
"failed to get name for entity: {}",
IkarusErrorInfo_Database_QueryFailed,
entity->project->db->query_one<char const *>(
"SELECT `name` FROM `entities` WHERE `id` = ?",
entity->id
)
);
return name;
}
void ikarus_entity_set_name(
@ -133,11 +134,12 @@ void ikarus_entity_set_name(
IkarusEntitySetNameFlags flags,
IkarusErrorData * error_out
) {
IKARUS_FAIL_IF_NULL(entity, );
IKARUS_FAIL_IF_NAME_INVALID(name, );
IKARUS_FAIL_IF_NULL(entity, IKARUS_VOID_RETURN);
IKARUS_FAIL_IF_NOT_EXIST(entity, IKARUS_VOID_RETURN);
IKARUS_FAIL_IF_NAME_INVALID(name, IKARUS_VOID_RETURN);
IKARUS_TRYRV_OR_FAIL(
,
IKARUS_VOID_RETURN,
"failed to set name for entity: {}",
IkarusErrorInfo_Database_QueryFailed,
entity->project->db->execute(
@ -146,8 +148,152 @@ void ikarus_entity_set_name(
entity->id
)
);
}
entity->name = name;
struct IkarusBlueprint ** ikarus_entity_get_linked_blueprints(
IkarusEntity * entity,
size_t * size_out,
IkarusErrorData * error_out
) {
IKARUS_FAIL_IF_NULL(entity, nullptr);
IKARUS_FAIL_IF_NOT_EXIST(entity, nullptr);
IKARUS_FAIL_IF_NULL(size_out, nullptr);
auto count = ikarus_entity_get_linked_blueprints_count(entity, error_out);
IKARUS_FAIL_IF_ERROR(nullptr);
std::int64_t ids[count];
IKARUS_TRYRV_OR_FAIL(
nullptr,
"failed to get linked blueprints for entity: {}",
IkarusErrorInfo_Database_QueryFailed,
entity->project->db->query_many_buffered<std::int64_t>(
"SELECT `blueprint` FROM `entity_blueprint_links` WHERE `entity` = ?",
ids,
count,
entity->id
)
);
auto blueprints = new IkarusBlueprint *[count];
std::transform(ids, ids + count, blueprints, [entity](auto id) {
return new IkarusBlueprint{entity->project, id};
});
if (size_out) {
*size_out = count;
}
return blueprints;
}
size_t ikarus_entity_get_linked_blueprints_count(
IkarusEntity * entity,
IkarusErrorData * error_out
) {
IKARUS_FAIL_IF_NULL(entity, 0);
IKARUS_FAIL_IF_NOT_EXIST(entity, 0);
IKARUS_VTRYRV_OR_FAIL(
auto count,
0,
"failed to get linked blueprints count for entity: {}",
IkarusErrorInfo_Database_QueryFailed,
entity->project->db->query_one<std::int64_t>(
"SELECT COUNT(*) FROM `entity_blueprint_links` WHERE `entity` = ?",
entity->id
)
);
return count;
}
void ikarus_entity_link_blueprint(
IkarusEntity * entity,
struct IkarusBlueprint * blueprint,
IkarusEntityLinkBlueprintFlags flags,
IkarusErrorData * error_out
) {
IKARUS_FAIL_IF_NULL(entity, IKARUS_VOID_RETURN);
IKARUS_FAIL_IF_NOT_EXIST(entity, IKARUS_VOID_RETURN);
IKARUS_FAIL_IF_NULL(blueprint, IKARUS_VOID_RETURN);
IKARUS_FAIL_IF_NOT_EXIST(blueprint, IKARUS_VOID_RETURN);
IKARUS_TRYRV_OR_FAIL(
IKARUS_VOID_RETURN,
"failed to link blueprint to entity: {}",
IkarusErrorInfo_Database_QueryFailed,
entity->project->db->execute(
"INSERT INTO `entity_blueprint_links`(`entity`, `blueprint`) VALUES(?, ?)",
entity->id,
blueprint->id
)
);
}
void ikarus_entity_unlink_blueprint(
IkarusEntity * entity,
struct IkarusBlueprint * blueprint,
IkarusEntityUnlinkBlueprintFlags flags,
IkarusErrorData * error_out
) {
IKARUS_FAIL_IF_NULL(entity, IKARUS_VOID_RETURN);
IKARUS_FAIL_IF_NOT_EXIST(entity, IKARUS_VOID_RETURN);
IKARUS_FAIL_IF_NULL(blueprint, IKARUS_VOID_RETURN);
IKARUS_FAIL_IF_NOT_EXIST(blueprint, IKARUS_VOID_RETURN);
IKARUS_TRYRV_OR_FAIL(
IKARUS_VOID_RETURN,
"failed to unlink blueprint from entity: {}",
IkarusErrorInfo_Database_QueryFailed,
entity->project->db->execute(
"DELETE FROM `entity_blueprint_links` WHERE `entity` = ? AND `blueprint` = ?",
entity->id,
blueprint->id
)
);
}
IkarusEntityValue * ikarus_entity_get_values(
IkarusEntity * entity,
size_t * size_out,
IkarusErrorData * error_out
) {
IKARUS_FAIL_IF_NULL(entity, nullptr);
IKARUS_FAIL_IF_NOT_EXIST(entity, nullptr);
IKARUS_VTRYRV_OR_FAIL(
auto values_plain,
nullptr,
"failed to get values for entity: {}",
IkarusErrorInfo_Database_QueryFailed,
entity->project->db->query_many<char const *, char const *>(
"SELECT `name`, `value` FROM `entity_values` WHERE `entity` = ?",
entity->id
)
);
IkarusEntityValue * values = new IkarusEntityValue[values_plain.size()];
std::transform(
std::cbegin(values_plain),
std::cend(values_plain),
values,
[](auto const & tuple) {
return IkarusEntityValue{
tuple.template get<0>(),
tuple.template get<1>()
};
}
);
if (size_out) {
*size_out = values_plain.size();
}
return values;
}
char const * ikarus_entity_get_value(
@ -156,7 +302,22 @@ char const * ikarus_entity_get_value(
IkarusErrorData * error_out
) {
IKARUS_FAIL_IF_NULL(entity, nullptr);
IKARUS_FAIL_IF_NOT_EXIST(entity, nullptr);
IKARUS_FAIL_IF_NULL(name, nullptr);
IKARUS_VTRYRV_OR_FAIL(
auto value,
nullptr,
"failed to get value for entity: {}",
IkarusErrorInfo_Database_QueryFailed,
entity->project->db->query_one<char const *>(
"SELECT `value` FROM `entity_values` WHERE `entity` = ? AND `name` = ?",
entity->id,
name
)
);
return value;
}
void ikarus_entity_set_value(
@ -165,7 +326,155 @@ void ikarus_entity_set_value(
char const * value,
IkarusErrorData * error_out
) {
IKARUS_FAIL_IF_NULL(entity, );
IKARUS_FAIL_IF_NULL(name, );
IKARUS_FAIL_IF_NULL(value, );
IKARUS_FAIL_IF_NULL(entity, IKARUS_VOID_RETURN);
IKARUS_FAIL_IF_NOT_EXIST(entity, IKARUS_VOID_RETURN);
IKARUS_FAIL_IF_NULL(name, IKARUS_VOID_RETURN);
IKARUS_FAIL_IF_NULL(value, IKARUS_VOID_RETURN);
// parsing from & to here to ensure values are valid JSON & formatted
// uniformly
IKARUS_VTRYRV_OR_FAIL(
auto value_parsed,
IKARUS_VOID_RETURN,
"cannot parse value as JSON: {}",
IkarusErrorInfo_Client_InvalidInput,
IkarusValue::from_json(value)
);
IKARUS_TRYRV_OR_FAIL(
IKARUS_VOID_RETURN,
"failed to set value for entity: {}",
IkarusErrorInfo_Database_QueryFailed,
entity->project->db->execute(
"INSERT INTO `entity_values`(`entity`, `name`, `value`) VALUES(?, ?, ?) "
"ON CONFLICT(`entity`, `name`) DO UPDATE SET `value` = excluded.`value`",
entity->id,
name,
IkarusValue::to_json(value_parsed).dump()
)
);
}
void ikarus_entity_delete_value(
IkarusEntity * entity,
char const * name,
IkarusEntityDeleteValueFlags flags,
IkarusErrorData * error_out
) {
IKARUS_FAIL_IF_NULL(entity, IKARUS_VOID_RETURN);
IKARUS_FAIL_IF_NOT_EXIST(entity, IKARUS_VOID_RETURN);
IKARUS_FAIL_IF_NULL(name, IKARUS_VOID_RETURN);
IKARUS_TRYRV_OR_FAIL(
IKARUS_VOID_RETURN,
"failed to delete value for entity: {}",
IkarusErrorInfo_Database_QueryFailed,
entity->project->db->execute(
"DELETE FROM `entity_values` WHERE `entity` = ? AND `name` = ?",
entity->id,
name
)
);
}
IkarusEntityPropertyValue * ikarus_entity_get_property_values(
IkarusEntity * entity,
size_t * size_out,
IkarusErrorData * error_out
) {
IKARUS_FAIL_IF_NULL(entity, nullptr);
IKARUS_FAIL_IF_NOT_EXIST(entity, nullptr);
IKARUS_VTRYRV_OR_FAIL(
auto values_plain,
nullptr,
"failed to get property values for entity: {}",
IkarusErrorInfo_Database_QueryFailed,
entity->project->db->query_many<int64_t, char const *>(
"SELECT `property`, `value` FROM `entity_property_values` WHERE `entity` = ?",
entity->id
)
);
IkarusEntityPropertyValue * values =
new IkarusEntityPropertyValue[values_plain.size()];
std::transform(
std::cbegin(values_plain),
std::cend(values_plain),
values,
[entity](auto const & tuple) {
return IkarusEntityPropertyValue{
new IkarusProperty{entity->project, tuple.template get<0>()},
tuple.template get<1>()
};
}
);
if (size_out) {
*size_out = values_plain.size();
}
return values;
}
char const * ikarus_entity_get_property_value(
IkarusEntity * entity,
struct IkarusProperty * property,
IkarusErrorData * error_out
) {
IKARUS_FAIL_IF_NULL(entity, nullptr);
IKARUS_FAIL_IF_NOT_EXIST(entity, nullptr);
IKARUS_FAIL_IF_NULL(property, nullptr);
IKARUS_FAIL_IF_NOT_EXIST(property, nullptr);
IKARUS_VTRYRV_OR_FAIL(
auto value,
nullptr,
"failed to get property value for entity: {}",
IkarusErrorInfo_Database_QueryFailed,
entity->project->db->query_one<char const *>(
"SELECT `value` FROM `entity_property_values` WHERE `entity` = ? AND `property` = ?",
entity->id,
property->id
)
);
return value;
}
void ikarus_entity_set_property_value(
IkarusEntity * entity,
struct IkarusProperty * property,
char const * value,
IkarusEntitySetPropertyValueFlags flags,
IkarusErrorData * error_out
) {
IKARUS_FAIL_IF_NULL(entity, IKARUS_VOID_RETURN);
IKARUS_FAIL_IF_NOT_EXIST(entity, IKARUS_VOID_RETURN);
IKARUS_FAIL_IF_NULL(property, IKARUS_VOID_RETURN);
IKARUS_FAIL_IF_NOT_EXIST(property, IKARUS_VOID_RETURN);
IKARUS_FAIL_IF_NULL(value, IKARUS_VOID_RETURN);
// parsing from & to here to ensure values are valid JSON & formatted
// uniformly
IKARUS_VTRYRV_OR_FAIL(
auto value_parsed,
IKARUS_VOID_RETURN,
"cannot parse value as JSON: {}",
IkarusErrorInfo_Client_InvalidInput,
IkarusValue::from_json(value)
);
IKARUS_TRYRV_OR_FAIL(
IKARUS_VOID_RETURN,
"failed to set property value for entity: {}",
IkarusErrorInfo_Database_QueryFailed,
entity->project->db->execute(
"INSERT INTO `entity_property_values`(`entity`, `property`, `value`) VALUES(?, ?, ?) "
"ON CONFLICT(`entity`, `property`) DO UPDATE SET `value` = excluded.`value`",
entity->id,
property->id,
IkarusValue::to_json(value_parsed).dump()
)
);
}

View file

@ -9,16 +9,8 @@ struct IkarusEntity {
constinit static inline auto object_name = "entity";
constinit static inline auto table_name = "entities";
IkarusEntity(
struct IkarusProject * project,
int64_t id,
std::string_view name
);
IkarusEntity(struct IkarusProject * project, int64_t id);
struct IkarusProject * project;
int64_t id;
std::string name;
std::vector<std::pair<std::string_view, IkarusValue *>> values_ordered;
std::unordered_map<std::string, IkarusValue> values;
};

View file

@ -5,11 +5,6 @@
#include <ikarus/objects/property.h>
#include <ikarus/persistence/project.hpp>
IkarusProperty::IkarusProperty(
struct IkarusProject * project,
int64_t id,
std::string_view name
):
IkarusProperty::IkarusProperty(struct IkarusProject * project, int64_t id):
project{project},
id{id},
name{name} {}
id{id} {}

View file

@ -3,21 +3,11 @@
#include <string>
struct IkarusProperty {
consteval static inline auto OBJECT_NAME() -> std::string_view {
return "property";
}
constinit static inline auto object_name = "property";
constinit static inline auto table_name = "properties";
consteval static inline auto TABLE_NAME() -> std::string_view {
return "properties";
}
IkarusProperty(
struct IkarusProject * project,
int64_t id,
std::string_view name
);
IkarusProperty(struct IkarusProject * project, int64_t id);
struct IkarusProject * project;
int64_t id;
std::string name;
};

View file

@ -6,7 +6,6 @@ CREATE TABLE `entities`
CREATE TABLE `entity_values`
(
`id` INTEGER PRIMARY KEY,
`entity` INTEGER NOT NULL REFERENCES `entities` (`id`) ON DELETE CASCADE,
`name` TEXT NOT NULL,
`value` TEXT NOT NULL,
@ -36,12 +35,12 @@ CREATE TABLE `entity_blueprint_links`
`entity` INTEGER NOT NULL REFERENCES `entities` (`id`) ON DELETE CASCADE,
`blueprint` INTEGER NOT NULL REFERENCES `blueprints` (`id`) ON DELETE CASCADE,
PRIMARY KEY (`entity`, `blueprint`)
PRIMARY KEY (`entity`, `blueprint`),
FOREIGN KEY (`entity`, `blueprint`) REFERENCES `entity_blueprint_links` (`entity`, `blueprint`) ON DELETE CASCADE
) STRICT;
CREATE TABLE `entity_property_values`
(
`id` INTEGER PRIMARY KEY,
`entity` INTEGER NOT NULL REFERENCES `entities` (`id`) ON DELETE CASCADE,
`property` INTEGER NOT NULL REFERENCES `properties` (`id`) ON DELETE CASCADE,
`value` TEXT NOT NULL,

View file

@ -232,18 +232,18 @@ void ikarus_project_set_name(
char const * new_name,
IkarusErrorData * error_out
) {
IKARUS_FAIL_IF_NULL(project, );
IKARUS_FAIL_IF_NULL(new_name, );
IKARUS_FAIL_IF_NULL(project, IKARUS_VOID_RETURN);
IKARUS_FAIL_IF_NULL(new_name, IKARUS_VOID_RETURN);
IKARUS_FAIL_IF(
cppbase::is_empty_or_blank(new_name),
,
IKARUS_VOID_RETURN,
"name must not be empty",
IkarusErrorInfo_Client_InvalidInput
);
IKARUS_TRYRV_OR_FAIL(
,
IKARUS_VOID_RETURN,
"failed to update project name: {}",
IkarusErrorInfo_Database_QueryFailed,
project->db->execute(
@ -269,15 +269,15 @@ void ikarus_project_get_entities(
uint64_t ids_out_size,
IkarusErrorData * error_out
) {
IKARUS_FAIL_IF_NULL(project, );
IKARUS_FAIL_IF_NULL(ids_out, );
IKARUS_FAIL_IF_NULL(project, IKARUS_VOID_RETURN);
IKARUS_FAIL_IF_NULL(ids_out, IKARUS_VOID_RETURN);
if (ids_out == 0) {
return;
}
IKARUS_TRYRV_OR_FAIL(
,
IKARUS_VOID_RETURN,
"unable to fetch project entities from database: {}",
IkarusErrorInfo_Database_QueryFailed,
project->db->query_many_buffered<int64_t>(
@ -311,8 +311,8 @@ void ikarus_project_get_blueprints(
uint64_t ids_out_size,
IkarusErrorData * error_out
) {
IKARUS_FAIL_IF_NULL(project, );
IKARUS_FAIL_IF_NULL(ids_out, );
IKARUS_FAIL_IF_NULL(project, IKARUS_VOID_RETURN);
IKARUS_FAIL_IF_NULL(ids_out, IKARUS_VOID_RETURN);
if (ids_out == 0) {
return;

View file

@ -152,10 +152,9 @@ auto IkarusValueData::from_json(nlohmann::json const & json)
return cppbase::ok(value);
}
auto IkarusValueData::to_json(
nlohmann::json & json,
IkarusValueData const & value
) -> void {
auto IkarusValueData::to_json(IkarusValueData const & value) -> nlohmann::json {
nlohmann::json json = nlohmann::json::object();
std::visit(
cppbase::overloaded{
[&](IkarusValueDataPrimitive const & primitive) {
@ -184,9 +183,7 @@ auto IkarusValueData::to_json(
json["type"] = IkarusValueDataType_List;
json["data"] = list.values |
std::views::transform([](auto const & data) {
nlohmann::json j;
IkarusValueData::to_json(j, *data);
return j;
return IkarusValueData::to_json(*data);
}) |
std::ranges::to<std::vector<nlohmann::json>>();
},
@ -195,8 +192,8 @@ auto IkarusValueData::to_json(
json["data"] =
map.values | std::views::transform([](auto const & pair) {
nlohmann::json j;
IkarusValueData::to_json(j["key"], *pair.first);
IkarusValueData::to_json(j["value"], *pair.second);
j["key"] = IkarusValueData::to_json(*pair.first);
j["value"] = IkarusValueData::to_json(*pair.second);
return j;
}) |
std::ranges::to<std::vector<nlohmann::json>>();
@ -205,13 +202,13 @@ auto IkarusValueData::to_json(
json["type"] = IkarusValueDataType_Tuple;
json["data"] = tuple.values |
std::views::transform([](auto const & data) {
nlohmann::json j;
IkarusValueData::to_json(j, *data);
return j;
return IkarusValueData::to_json(*data);
}) |
std::ranges::to<std::vector<nlohmann::json>>();
}
},
value.variant
);
return json;
}

View file

@ -55,8 +55,7 @@ struct IkarusValueData {
static auto from_json(nlohmann::json const & json)
-> cppbase::Result<IkarusValueData, IkarusValueDataParseError>;
static auto to_json(nlohmann::json & json, IkarusValueData const & value)
-> void;
static auto to_json(IkarusValueData const & value) -> nlohmann::json;
IkarusValueDataVariant variant;
};

View file

@ -2,6 +2,8 @@
#include <variant>
#include <cppbase/format.hpp>
struct IkarusJsonMissingKeyError {};
struct IkarusJsonInvalidTypeError {};
@ -34,3 +36,82 @@ using IkarusValueParseError = std::variant<
using IkarusValuesParseError =
std::variant<IkarusJsonMissingKeyError, IkarusValueParseError>;
template<>
struct fmt::formatter<IkarusJsonMissingKeyError> : formatter<string_view> {
constexpr static auto format(
[[maybe_unused]] IkarusJsonMissingKeyError const & error,
fmt::format_context & ctx
) {
return fmt::format_to(ctx.out(), "missing JSON key");
}
};
template<>
struct fmt::formatter<IkarusJsonInvalidTypeError> : formatter<string_view> {
constexpr static auto format(
[[maybe_unused]] IkarusJsonInvalidTypeError const & error,
fmt::format_context & ctx
) {
return fmt::format_to(ctx.out(), "invalid JSON type");
}
};
template<>
struct fmt::formatter<IkarusJsonEnumOutOfBoundsError> : formatter<string_view> {
constexpr static auto format(
[[maybe_unused]] IkarusJsonEnumOutOfBoundsError const & error,
fmt::format_context & ctx
) {
return fmt::format_to(ctx.out(), "JSON enum is out of bounds");
}
};
template<>
struct fmt::formatter<IkarusJsonUnknownError> : formatter<string_view> {
constexpr static auto format(
[[maybe_unused]] IkarusJsonUnknownError const & error,
fmt::format_context & ctx
) {
return fmt::format_to(ctx.out(), "unknown JSON error");
}
};
template<>
struct fmt::formatter<IkarusValueSchemaParseError> : formatter<string_view> {
constexpr static auto format(
[[maybe_unused]] IkarusValueSchemaParseError const & error,
fmt::format_context & ctx
) {
return fmt::format_to(
ctx.out(),
"failed to parse value schema: {}",
error.error
);
}
};
template<>
struct fmt::formatter<IkarusValueDataParseError> : formatter<string_view> {
constexpr static auto format(
[[maybe_unused]] IkarusValueDataParseError const & error,
fmt::format_context & ctx
) {
return fmt::format_to(
ctx.out(),
"failed to parse value data: {}",
error.error
);
}
};
template<>
struct fmt::formatter<IkarusValueParseErrorDataSchemaMismatch> :
formatter<string_view> {
constexpr static auto format(
[[maybe_unused]] IkarusValueParseErrorDataSchemaMismatch const & error,
fmt::format_context & ctx
) {
return fmt::format_to(ctx.out(), "value data and schema mismatched");
}
};

View file

@ -85,10 +85,10 @@ auto IkarusValueSchema::from_json(nlohmann::json const & json)
return cppbase::ok(std::move(schema));
}
auto IkarusValueSchema::to_json(
nlohmann::json & json,
IkarusValueSchema const & schema
) -> void {
auto IkarusValueSchema::to_json(IkarusValueSchema const & schema)
-> nlohmann::json {
nlohmann::json json = nlohmann::json::object();
std::visit(
cppbase::overloaded{
[&json](IkarusValueSchemaPrimitive const & schema) {
@ -97,18 +97,14 @@ auto IkarusValueSchema::to_json(
},
[&json](IkarusValueSchemaList const & schema) {
json["type"] = IkarusValueSchemaType_List;
IkarusValueSchema::to_json(json["schema"], *schema.sub_schema);
json["schema"] = IkarusValueSchema::to_json(*schema.sub_schema);
},
[&json](IkarusValueSchemaMap const & schema) {
json["type"] = IkarusValueSchemaType_Map;
IkarusValueSchema::to_json(
json["key_schema"],
*schema.key_schema
);
IkarusValueSchema::to_json(
json["value_schema"],
*schema.value_schema
);
json["key_schema"] =
IkarusValueSchema::to_json(*schema.key_schema);
json["value_schema"] =
IkarusValueSchema::to_json(*schema.value_schema);
},
[&json](IkarusValueSchemaTuple const & schema) {
json["type"] = IkarusValueSchemaType_Tuple;
@ -117,9 +113,9 @@ auto IkarusValueSchema::to_json(
sub_schemas.reserve(schema.sub_schemas.size());
for (auto const & sub_schema : schema.sub_schemas) {
nlohmann::json sub_schema_json{};
IkarusValueSchema::to_json(sub_schema_json, *sub_schema);
sub_schemas.push_back(sub_schema_json);
sub_schemas.push_back(
IkarusValueSchema::to_json(*sub_schema)
);
}
json["schemas"] = sub_schemas;
@ -127,6 +123,8 @@ auto IkarusValueSchema::to_json(
},
schema.variant
);
return json;
}
auto IkarusValueSchema::validate(IkarusValueData const & data) const -> bool {

View file

@ -42,8 +42,7 @@ struct IkarusValueSchema {
static auto from_json(nlohmann::json const & json)
-> cppbase::Result<IkarusValueSchema, IkarusValueSchemaParseError>;
static auto to_json(nlohmann::json & json, IkarusValueSchema const & value)
-> void;
static auto to_json(IkarusValueSchema const & value) -> nlohmann::json;
auto validate(IkarusValueData const & data) const -> bool;

View file

@ -25,34 +25,11 @@ auto IkarusValue::from_json(nlohmann::json const & json)
return cppbase::ok(std::move(value));
}
auto IkarusValue::to_json(nlohmann::json & json, IkarusValue const & value)
-> void {
IkarusValueSchema::to_json(json["schema"], value.schema);
IkarusValueData::to_json(json["data"], value.data);
}
auto IkarusValues::from_json(nlohmann::json const & json)
-> cppbase::Result<IkarusValues, IkarusValuesParseError> {
IkarusValues values{};
for (auto const & json_entry : json) {
VTRY(auto name_json, get_key(json_entry, "name"));
if (!name_json->is_string()) {
return cppbase::err(IkarusJsonInvalidTypeError{});
}
VTRY(auto value_json, get_key(json_entry, "value"));
VTRY(auto value, IkarusValue::from_json(*value_json));
values.values.emplace_back(
std::make_pair(
std::move(name_json->get<std::string_view>()),
std::move(value)
)
);
}
return cppbase::ok(std::move(values));
auto IkarusValue::to_json(IkarusValue const & value) -> nlohmann::json {
nlohmann::json json = nlohmann::json::object();
json["schema"] = IkarusValueSchema::to_json(value.schema);
json["data"] = IkarusValueData::to_json(value.data);
return json;
}

View file

@ -14,15 +14,5 @@ struct IkarusValue {
static auto from_json(nlohmann::json const & json)
-> cppbase::Result<IkarusValue, IkarusValueParseError>;
static auto to_json(nlohmann::json & json, IkarusValue const & value)
-> void;
};
struct IkarusValues {
static auto from_json(nlohmann::json const & json)
-> cppbase::Result<IkarusValues, IkarusValuesParseError>;
static auto to_json(nlohmann::json & json, IkarusValues const & values)
-> void;
std::vector<std::pair<std::string, IkarusValue>> values;
static auto to_json(IkarusValue const & value) -> nlohmann::json;
};