finalize entity functions
Signed-off-by: Folling <mail@folling.io>
This commit is contained in:
parent
f0e6dec7de
commit
c489e9e8ae
18 changed files with 523 additions and 181 deletions
|
|
@ -64,7 +64,7 @@ BreakBeforeInlineASMColon: OnlyMultiline
|
||||||
BreakBeforeTernaryOperators: false
|
BreakBeforeTernaryOperators: false
|
||||||
BreakConstructorInitializers: AfterColon
|
BreakConstructorInitializers: AfterColon
|
||||||
BreakInheritanceList: AfterColon
|
BreakInheritanceList: AfterColon
|
||||||
BreakStringLiterals: true
|
BreakStringLiterals: false
|
||||||
|
|
||||||
ColumnLimit: 80
|
ColumnLimit: 80
|
||||||
CommentPragmas: '^\\.+'
|
CommentPragmas: '^\\.+'
|
||||||
|
|
|
||||||
|
|
@ -181,8 +181,6 @@ IKA_API void ikarus_entity_link_blueprint(
|
||||||
enum IkarusEntityUnlinkBlueprintFlags {
|
enum IkarusEntityUnlinkBlueprintFlags {
|
||||||
/// \brief No flags.
|
/// \brief No flags.
|
||||||
IkarusEntityUnlinkBlueprintFlags_None = 0,
|
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.
|
/// \brief Unlinks an entity from a blueprint.
|
||||||
|
|
@ -203,17 +201,27 @@ IKA_API void ikarus_entity_unlink_blueprint(
|
||||||
IkarusErrorData * error_out
|
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.
|
/// \brief Gets the values of an entity.
|
||||||
/// \param entity The entity to get the values of.
|
/// \param entity The entity to get the values of.
|
||||||
/// \pre \li Must not be null.
|
/// \pre \li Must not be null.
|
||||||
/// \pre \li Must exist.
|
/// \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
|
/// \param error_out \see errors.h
|
||||||
/// \return The values, in json format of or null if an error occurs.
|
/// \return The values or null if an error occurs.
|
||||||
/// The json representation is an array of objects with the following keys:
|
IKA_API IkarusEntityValue * ikarus_entity_get_values(
|
||||||
/// - `name`: The name of the value.
|
IkarusEntity * entity,
|
||||||
/// - `value`: The value itself. \see value.h
|
size_t * size_out,
|
||||||
IKA_API char const *
|
IkarusErrorData * error_out
|
||||||
ikarus_entity_get_values(IkarusEntity * entity, IkarusErrorData * error_out);
|
);
|
||||||
|
|
||||||
/// \brief Gets a value of an entity.
|
/// \brief Gets a value of an entity.
|
||||||
/// \param entity The entity to get the value of.
|
/// \param entity The entity to get the value of.
|
||||||
|
|
@ -279,16 +287,25 @@ IKA_API void ikarus_entity_delete_value(
|
||||||
IkarusErrorData * error_out
|
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.
|
/// \brief Gets the property values of an entity.
|
||||||
/// \param entity The entity to get the property values of.
|
/// \param entity The entity to get the property values of.
|
||||||
/// \pre \li Must not be null.
|
/// \pre \li Must not be null.
|
||||||
/// \pre \li Must exist.
|
/// \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
|
/// \param error_out \see errors.h
|
||||||
/// \return The property values, in msgpack format of or null if an error occurs.
|
/// \return The property values, or null if an error occurs.
|
||||||
/// The format is a map of property pointers (as integers) to values. \see
|
IKA_API IkarusEntityPropertyValue * ikarus_entity_get_property_values(
|
||||||
/// value.h
|
|
||||||
IKA_API char const * ikarus_entity_get_property_values(
|
|
||||||
IkarusEntity * entity,
|
IkarusEntity * entity,
|
||||||
|
size_t * size_out,
|
||||||
IkarusErrorData * error_out
|
IkarusErrorData * error_out
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ void safe_strcpy(
|
||||||
size_t const dest_size
|
size_t const dest_size
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#define IKARUS_VOID_RETURN
|
||||||
|
|
||||||
#define IKARUS_SET_ERROR(msg, err_info) \
|
#define IKARUS_SET_ERROR(msg, err_info) \
|
||||||
if (error_out != nullptr) { \
|
if (error_out != nullptr) { \
|
||||||
safe_strcpy( \
|
safe_strcpy( \
|
||||||
|
|
@ -140,9 +142,9 @@ void safe_strcpy(
|
||||||
IkarusErrorInfo_Client_InvalidInput \
|
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( \
|
IKARUS_VTRYRV_OR_FAIL( \
|
||||||
auto exists, \
|
auto exists_name, \
|
||||||
ret, \
|
ret, \
|
||||||
fmt::format( \
|
fmt::format( \
|
||||||
"failed to check if {} exists", \
|
"failed to check if {} exists", \
|
||||||
|
|
@ -159,7 +161,7 @@ void safe_strcpy(
|
||||||
); \
|
); \
|
||||||
\
|
\
|
||||||
IKARUS_FAIL_IF( \
|
IKARUS_FAIL_IF( \
|
||||||
!exists, \
|
!exists_name, \
|
||||||
ret, \
|
ret, \
|
||||||
fmt::format( \
|
fmt::format( \
|
||||||
"{} doesn't exist", \
|
"{} doesn't exist", \
|
||||||
|
|
@ -167,3 +169,6 @@ void safe_strcpy(
|
||||||
), \
|
), \
|
||||||
IkarusErrorInfo_Client_NonExistent \
|
IkarusErrorInfo_Client_NonExistent \
|
||||||
)
|
)
|
||||||
|
|
||||||
|
#define IKARUS_FAIL_IF_NOT_EXIST(object, ret) \
|
||||||
|
IKARUS_FAIL_IF_NOT_EXIST_IMPL(CPPBASE_UNIQUE_NAME(exists), object, ret)
|
||||||
|
|
|
||||||
|
|
@ -3,3 +3,7 @@
|
||||||
#include <ikarus/errors.hpp>
|
#include <ikarus/errors.hpp>
|
||||||
#include <ikarus/objects/blueprint.hpp>
|
#include <ikarus/objects/blueprint.hpp>
|
||||||
#include <ikarus/persistence/project.hpp>
|
#include <ikarus/persistence/project.hpp>
|
||||||
|
|
||||||
|
IkarusBlueprint::IkarusBlueprint(struct IkarusProject * project, int64_t id):
|
||||||
|
project{project},
|
||||||
|
id{id} {}
|
||||||
|
|
|
||||||
|
|
@ -3,21 +3,11 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
struct IkarusBlueprint {
|
struct IkarusBlueprint {
|
||||||
consteval static inline auto OBJECT_NAME() -> std::string_view {
|
constinit static inline auto object_name = "blueprint";
|
||||||
return "blueprint";
|
constinit static inline auto table_name = "blueprints";
|
||||||
}
|
|
||||||
|
|
||||||
consteval static inline auto TABLE_NAME() -> std::string_view {
|
IkarusBlueprint(struct IkarusProject * project, int64_t id);
|
||||||
return "blueprints";
|
|
||||||
}
|
|
||||||
|
|
||||||
IkarusBlueprint(
|
|
||||||
struct IkarusProject * project,
|
|
||||||
int64_t id,
|
|
||||||
std::string_view name
|
|
||||||
);
|
|
||||||
|
|
||||||
struct IkarusProject * project;
|
struct IkarusProject * project;
|
||||||
int64_t id;
|
int64_t id;
|
||||||
std::string name;
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,15 @@
|
||||||
#include "entity.hpp"
|
#include "entity.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include <ikarus/errors.h>
|
#include <ikarus/errors.h>
|
||||||
#include <ikarus/errors.hpp>
|
#include <ikarus/errors.hpp>
|
||||||
#include <ikarus/objects/entity.h>
|
#include <ikarus/objects/entity.h>
|
||||||
#include <ikarus/persistence/project.hpp>
|
#include <ikarus/persistence/project.hpp>
|
||||||
|
|
||||||
IkarusEntity::IkarusEntity(
|
IkarusEntity::IkarusEntity(struct IkarusProject * project, int64_t id):
|
||||||
struct IkarusProject * project,
|
|
||||||
int64_t id,
|
|
||||||
std::string_view name
|
|
||||||
):
|
|
||||||
project{project},
|
project{project},
|
||||||
id{id},
|
id{id} {}
|
||||||
name{name} {}
|
|
||||||
|
|
||||||
IkarusEntity * ikarus_entity_create(
|
IkarusEntity * ikarus_entity_create(
|
||||||
struct IkarusProject * project,
|
struct IkarusProject * project,
|
||||||
|
|
@ -31,7 +28,7 @@ IkarusEntity * ikarus_entity_create(
|
||||||
);
|
);
|
||||||
|
|
||||||
auto const id = project->db->last_insert_rowid();
|
auto const id = project->db->last_insert_rowid();
|
||||||
return new IkarusEntity{project, id, name};
|
return new IkarusEntity{project, id};
|
||||||
}
|
}
|
||||||
|
|
||||||
void ikarus_entity_delete(
|
void ikarus_entity_delete(
|
||||||
|
|
@ -39,12 +36,11 @@ void ikarus_entity_delete(
|
||||||
IkarusEntityDeleteFlags flags,
|
IkarusEntityDeleteFlags flags,
|
||||||
IkarusErrorData * error_out
|
IkarusErrorData * error_out
|
||||||
) {
|
) {
|
||||||
IKARUS_FAIL_IF_NULL(entity, );
|
IKARUS_FAIL_IF_NULL(entity, IKARUS_VOID_RETURN);
|
||||||
IKARUS_FAIL_IF_NOT_EXIST(entity, );
|
IKARUS_FAIL_IF_NOT_EXIST(entity, IKARUS_VOID_RETURN);
|
||||||
IKARUS_FAIL_IF_NULL(entity->project, );
|
|
||||||
|
|
||||||
IKARUS_TRYRV_OR_FAIL(
|
IKARUS_TRYRV_OR_FAIL(
|
||||||
,
|
IKARUS_VOID_RETURN,
|
||||||
"failed to delete entity: {}",
|
"failed to delete entity: {}",
|
||||||
IkarusErrorInfo_Database_QueryFailed,
|
IkarusErrorInfo_Database_QueryFailed,
|
||||||
entity->project->db
|
entity->project->db
|
||||||
|
|
@ -61,7 +57,6 @@ IkarusEntity * ikarus_entity_copy(
|
||||||
) {
|
) {
|
||||||
IKARUS_FAIL_IF_NULL(entity, nullptr);
|
IKARUS_FAIL_IF_NULL(entity, nullptr);
|
||||||
IKARUS_FAIL_IF_NOT_EXIST(entity, nullptr);
|
IKARUS_FAIL_IF_NOT_EXIST(entity, nullptr);
|
||||||
IKARUS_FAIL_IF_NULL(entity->project, nullptr);
|
|
||||||
|
|
||||||
IKARUS_VTRYRV_OR_FAIL(
|
IKARUS_VTRYRV_OR_FAIL(
|
||||||
auto id,
|
auto id,
|
||||||
|
|
@ -72,34 +67,28 @@ IkarusEntity * ikarus_entity_copy(
|
||||||
[entity](auto * db)
|
[entity](auto * db)
|
||||||
-> cppbase::Result<int64_t, sqlitecpp::TransactionError> {
|
-> cppbase::Result<int64_t, sqlitecpp::TransactionError> {
|
||||||
TRY(entity->project->db->execute(
|
TRY(entity->project->db->execute(
|
||||||
"INSERT INTO `entities`(`name`) VALUES(?)",
|
"INSERT INTO `entities`(`name`) "
|
||||||
entity->name.data()
|
"SELECT `name` FROM `entities` WHERE `id` = ?",
|
||||||
|
entity->id
|
||||||
));
|
));
|
||||||
|
|
||||||
TRY(entity->project->db->execute(
|
TRY(entity->project->db->execute(
|
||||||
"INSERT INTO `entity_values`(`entity`, `name`, `value`)"
|
"INSERT INTO `entity_values`(`entity`, `name`, `value`) "
|
||||||
" SELECT ?1, `name`, `value` FROM `entity_values` WHERE "
|
"SELECT ?1, `name`, `value` FROM `entity_values` WHERE "
|
||||||
"`entity` = ?1",
|
"`entity` = ?1",
|
||||||
entity->id
|
entity->id
|
||||||
))
|
))
|
||||||
|
|
||||||
TRY(entity->project->db->execute(
|
TRY(entity->project->db->execute(
|
||||||
"INSERT INTO `entity_property_values`("
|
"INSERT INTO `entity_property_values`(`entity`, `property`, `value`) "
|
||||||
" `entity`, "
|
"SELECT ?1, `property`, `value` FROM `entity_property_values` "
|
||||||
" `property`,"
|
|
||||||
" `value`"
|
|
||||||
") "
|
|
||||||
"SELECT ?1, `property`, `value` FROM "
|
|
||||||
"`entity_property_values` "
|
|
||||||
"WHERE `entity` = ?1",
|
"WHERE `entity` = ?1",
|
||||||
entity->id
|
entity->id
|
||||||
))
|
))
|
||||||
|
|
||||||
TRY(entity->project->db->execute(
|
TRY(entity->project->db->execute(
|
||||||
"INSERT INTO `entity_blueprint_links`(`entity`, "
|
"INSERT INTO `entity_blueprint_links`(`entity`, `blueprint`) "
|
||||||
"`blueprint`)"
|
"SELECT ?1, `property`, `value` FROM `entity_property_values` "
|
||||||
"SELECT ?1, `property`, `value` FROM "
|
|
||||||
"`entity_property_values` "
|
|
||||||
"WHERE `entity` = ?1",
|
"WHERE `entity` = ?1",
|
||||||
entity->id
|
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 *
|
IkarusProject *
|
||||||
ikarus_entity_get_project(IkarusEntity * entity, IkarusErrorData * error_out) {
|
ikarus_entity_get_project(IkarusEntity * entity, IkarusErrorData * error_out) {
|
||||||
IKARUS_FAIL_IF_NULL(entity, nullptr);
|
IKARUS_FAIL_IF_NULL(entity, nullptr);
|
||||||
IKARUS_FAIL_IF_NULL(entity->project, nullptr);
|
IKARUS_FAIL_IF_NOT_EXIST(entity, nullptr);
|
||||||
|
|
||||||
return entity->project;
|
return entity->project;
|
||||||
}
|
}
|
||||||
|
|
@ -123,8 +112,20 @@ ikarus_entity_get_project(IkarusEntity * entity, IkarusErrorData * error_out) {
|
||||||
char const *
|
char const *
|
||||||
ikarus_entity_get_name(IkarusEntity * entity, IkarusErrorData * error_out) {
|
ikarus_entity_get_name(IkarusEntity * entity, IkarusErrorData * error_out) {
|
||||||
IKARUS_FAIL_IF_NULL(entity, nullptr);
|
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(
|
void ikarus_entity_set_name(
|
||||||
|
|
@ -133,11 +134,12 @@ void ikarus_entity_set_name(
|
||||||
IkarusEntitySetNameFlags flags,
|
IkarusEntitySetNameFlags flags,
|
||||||
IkarusErrorData * error_out
|
IkarusErrorData * error_out
|
||||||
) {
|
) {
|
||||||
IKARUS_FAIL_IF_NULL(entity, );
|
IKARUS_FAIL_IF_NULL(entity, IKARUS_VOID_RETURN);
|
||||||
IKARUS_FAIL_IF_NAME_INVALID(name, );
|
IKARUS_FAIL_IF_NOT_EXIST(entity, IKARUS_VOID_RETURN);
|
||||||
|
IKARUS_FAIL_IF_NAME_INVALID(name, IKARUS_VOID_RETURN);
|
||||||
|
|
||||||
IKARUS_TRYRV_OR_FAIL(
|
IKARUS_TRYRV_OR_FAIL(
|
||||||
,
|
IKARUS_VOID_RETURN,
|
||||||
"failed to set name for entity: {}",
|
"failed to set name for entity: {}",
|
||||||
IkarusErrorInfo_Database_QueryFailed,
|
IkarusErrorInfo_Database_QueryFailed,
|
||||||
entity->project->db->execute(
|
entity->project->db->execute(
|
||||||
|
|
@ -146,8 +148,152 @@ void ikarus_entity_set_name(
|
||||||
entity->id
|
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(
|
char const * ikarus_entity_get_value(
|
||||||
|
|
@ -156,7 +302,22 @@ char const * ikarus_entity_get_value(
|
||||||
IkarusErrorData * error_out
|
IkarusErrorData * error_out
|
||||||
) {
|
) {
|
||||||
IKARUS_FAIL_IF_NULL(entity, nullptr);
|
IKARUS_FAIL_IF_NULL(entity, nullptr);
|
||||||
|
IKARUS_FAIL_IF_NOT_EXIST(entity, nullptr);
|
||||||
IKARUS_FAIL_IF_NULL(name, 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(
|
void ikarus_entity_set_value(
|
||||||
|
|
@ -165,7 +326,155 @@ void ikarus_entity_set_value(
|
||||||
char const * value,
|
char const * value,
|
||||||
IkarusErrorData * error_out
|
IkarusErrorData * error_out
|
||||||
) {
|
) {
|
||||||
IKARUS_FAIL_IF_NULL(entity, );
|
IKARUS_FAIL_IF_NULL(entity, IKARUS_VOID_RETURN);
|
||||||
IKARUS_FAIL_IF_NULL(name, );
|
IKARUS_FAIL_IF_NOT_EXIST(entity, IKARUS_VOID_RETURN);
|
||||||
IKARUS_FAIL_IF_NULL(value, );
|
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()
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,16 +9,8 @@ struct IkarusEntity {
|
||||||
constinit static inline auto object_name = "entity";
|
constinit static inline auto object_name = "entity";
|
||||||
constinit static inline auto table_name = "entities";
|
constinit static inline auto table_name = "entities";
|
||||||
|
|
||||||
IkarusEntity(
|
IkarusEntity(struct IkarusProject * project, int64_t id);
|
||||||
struct IkarusProject * project,
|
|
||||||
int64_t id,
|
|
||||||
std::string_view name
|
|
||||||
);
|
|
||||||
|
|
||||||
struct IkarusProject * project;
|
struct IkarusProject * project;
|
||||||
int64_t id;
|
int64_t id;
|
||||||
std::string name;
|
|
||||||
|
|
||||||
std::vector<std::pair<std::string_view, IkarusValue *>> values_ordered;
|
|
||||||
std::unordered_map<std::string, IkarusValue> values;
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,6 @@
|
||||||
#include <ikarus/objects/property.h>
|
#include <ikarus/objects/property.h>
|
||||||
#include <ikarus/persistence/project.hpp>
|
#include <ikarus/persistence/project.hpp>
|
||||||
|
|
||||||
IkarusProperty::IkarusProperty(
|
IkarusProperty::IkarusProperty(struct IkarusProject * project, int64_t id):
|
||||||
struct IkarusProject * project,
|
|
||||||
int64_t id,
|
|
||||||
std::string_view name
|
|
||||||
):
|
|
||||||
project{project},
|
project{project},
|
||||||
id{id},
|
id{id} {}
|
||||||
name{name} {}
|
|
||||||
|
|
|
||||||
|
|
@ -3,21 +3,11 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
struct IkarusProperty {
|
struct IkarusProperty {
|
||||||
consteval static inline auto OBJECT_NAME() -> std::string_view {
|
constinit static inline auto object_name = "property";
|
||||||
return "property";
|
constinit static inline auto table_name = "properties";
|
||||||
}
|
|
||||||
|
|
||||||
consteval static inline auto TABLE_NAME() -> std::string_view {
|
IkarusProperty(struct IkarusProject * project, int64_t id);
|
||||||
return "properties";
|
|
||||||
}
|
|
||||||
|
|
||||||
IkarusProperty(
|
|
||||||
struct IkarusProject * project,
|
|
||||||
int64_t id,
|
|
||||||
std::string_view name
|
|
||||||
);
|
|
||||||
|
|
||||||
struct IkarusProject * project;
|
struct IkarusProject * project;
|
||||||
int64_t id;
|
int64_t id;
|
||||||
std::string name;
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ CREATE TABLE `entities`
|
||||||
|
|
||||||
CREATE TABLE `entity_values`
|
CREATE TABLE `entity_values`
|
||||||
(
|
(
|
||||||
`id` INTEGER PRIMARY KEY,
|
|
||||||
`entity` INTEGER NOT NULL REFERENCES `entities` (`id`) ON DELETE CASCADE,
|
`entity` INTEGER NOT NULL REFERENCES `entities` (`id`) ON DELETE CASCADE,
|
||||||
`name` TEXT NOT NULL,
|
`name` TEXT NOT NULL,
|
||||||
`value` 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,
|
`entity` INTEGER NOT NULL REFERENCES `entities` (`id`) ON DELETE CASCADE,
|
||||||
`blueprint` INTEGER NOT NULL REFERENCES `blueprints` (`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;
|
) STRICT;
|
||||||
|
|
||||||
CREATE TABLE `entity_property_values`
|
CREATE TABLE `entity_property_values`
|
||||||
(
|
(
|
||||||
`id` INTEGER PRIMARY KEY,
|
|
||||||
`entity` INTEGER NOT NULL REFERENCES `entities` (`id`) ON DELETE CASCADE,
|
`entity` INTEGER NOT NULL REFERENCES `entities` (`id`) ON DELETE CASCADE,
|
||||||
`property` INTEGER NOT NULL REFERENCES `properties` (`id`) ON DELETE CASCADE,
|
`property` INTEGER NOT NULL REFERENCES `properties` (`id`) ON DELETE CASCADE,
|
||||||
`value` TEXT NOT NULL,
|
`value` TEXT NOT NULL,
|
||||||
|
|
|
||||||
|
|
@ -232,18 +232,18 @@ void ikarus_project_set_name(
|
||||||
char const * new_name,
|
char const * new_name,
|
||||||
IkarusErrorData * error_out
|
IkarusErrorData * error_out
|
||||||
) {
|
) {
|
||||||
IKARUS_FAIL_IF_NULL(project, );
|
IKARUS_FAIL_IF_NULL(project, IKARUS_VOID_RETURN);
|
||||||
IKARUS_FAIL_IF_NULL(new_name, );
|
IKARUS_FAIL_IF_NULL(new_name, IKARUS_VOID_RETURN);
|
||||||
|
|
||||||
IKARUS_FAIL_IF(
|
IKARUS_FAIL_IF(
|
||||||
cppbase::is_empty_or_blank(new_name),
|
cppbase::is_empty_or_blank(new_name),
|
||||||
,
|
IKARUS_VOID_RETURN,
|
||||||
"name must not be empty",
|
"name must not be empty",
|
||||||
IkarusErrorInfo_Client_InvalidInput
|
IkarusErrorInfo_Client_InvalidInput
|
||||||
);
|
);
|
||||||
|
|
||||||
IKARUS_TRYRV_OR_FAIL(
|
IKARUS_TRYRV_OR_FAIL(
|
||||||
,
|
IKARUS_VOID_RETURN,
|
||||||
"failed to update project name: {}",
|
"failed to update project name: {}",
|
||||||
IkarusErrorInfo_Database_QueryFailed,
|
IkarusErrorInfo_Database_QueryFailed,
|
||||||
project->db->execute(
|
project->db->execute(
|
||||||
|
|
@ -269,15 +269,15 @@ void ikarus_project_get_entities(
|
||||||
uint64_t ids_out_size,
|
uint64_t ids_out_size,
|
||||||
IkarusErrorData * error_out
|
IkarusErrorData * error_out
|
||||||
) {
|
) {
|
||||||
IKARUS_FAIL_IF_NULL(project, );
|
IKARUS_FAIL_IF_NULL(project, IKARUS_VOID_RETURN);
|
||||||
IKARUS_FAIL_IF_NULL(ids_out, );
|
IKARUS_FAIL_IF_NULL(ids_out, IKARUS_VOID_RETURN);
|
||||||
|
|
||||||
if (ids_out == 0) {
|
if (ids_out == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
IKARUS_TRYRV_OR_FAIL(
|
IKARUS_TRYRV_OR_FAIL(
|
||||||
,
|
IKARUS_VOID_RETURN,
|
||||||
"unable to fetch project entities from database: {}",
|
"unable to fetch project entities from database: {}",
|
||||||
IkarusErrorInfo_Database_QueryFailed,
|
IkarusErrorInfo_Database_QueryFailed,
|
||||||
project->db->query_many_buffered<int64_t>(
|
project->db->query_many_buffered<int64_t>(
|
||||||
|
|
@ -311,8 +311,8 @@ void ikarus_project_get_blueprints(
|
||||||
uint64_t ids_out_size,
|
uint64_t ids_out_size,
|
||||||
IkarusErrorData * error_out
|
IkarusErrorData * error_out
|
||||||
) {
|
) {
|
||||||
IKARUS_FAIL_IF_NULL(project, );
|
IKARUS_FAIL_IF_NULL(project, IKARUS_VOID_RETURN);
|
||||||
IKARUS_FAIL_IF_NULL(ids_out, );
|
IKARUS_FAIL_IF_NULL(ids_out, IKARUS_VOID_RETURN);
|
||||||
|
|
||||||
if (ids_out == 0) {
|
if (ids_out == 0) {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -152,10 +152,9 @@ auto IkarusValueData::from_json(nlohmann::json const & json)
|
||||||
return cppbase::ok(value);
|
return cppbase::ok(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto IkarusValueData::to_json(
|
auto IkarusValueData::to_json(IkarusValueData const & value) -> nlohmann::json {
|
||||||
nlohmann::json & json,
|
nlohmann::json json = nlohmann::json::object();
|
||||||
IkarusValueData const & value
|
|
||||||
) -> void {
|
|
||||||
std::visit(
|
std::visit(
|
||||||
cppbase::overloaded{
|
cppbase::overloaded{
|
||||||
[&](IkarusValueDataPrimitive const & primitive) {
|
[&](IkarusValueDataPrimitive const & primitive) {
|
||||||
|
|
@ -184,9 +183,7 @@ auto IkarusValueData::to_json(
|
||||||
json["type"] = IkarusValueDataType_List;
|
json["type"] = IkarusValueDataType_List;
|
||||||
json["data"] = list.values |
|
json["data"] = list.values |
|
||||||
std::views::transform([](auto const & data) {
|
std::views::transform([](auto const & data) {
|
||||||
nlohmann::json j;
|
return IkarusValueData::to_json(*data);
|
||||||
IkarusValueData::to_json(j, *data);
|
|
||||||
return j;
|
|
||||||
}) |
|
}) |
|
||||||
std::ranges::to<std::vector<nlohmann::json>>();
|
std::ranges::to<std::vector<nlohmann::json>>();
|
||||||
},
|
},
|
||||||
|
|
@ -195,8 +192,8 @@ auto IkarusValueData::to_json(
|
||||||
json["data"] =
|
json["data"] =
|
||||||
map.values | std::views::transform([](auto const & pair) {
|
map.values | std::views::transform([](auto const & pair) {
|
||||||
nlohmann::json j;
|
nlohmann::json j;
|
||||||
IkarusValueData::to_json(j["key"], *pair.first);
|
j["key"] = IkarusValueData::to_json(*pair.first);
|
||||||
IkarusValueData::to_json(j["value"], *pair.second);
|
j["value"] = IkarusValueData::to_json(*pair.second);
|
||||||
return j;
|
return j;
|
||||||
}) |
|
}) |
|
||||||
std::ranges::to<std::vector<nlohmann::json>>();
|
std::ranges::to<std::vector<nlohmann::json>>();
|
||||||
|
|
@ -205,13 +202,13 @@ auto IkarusValueData::to_json(
|
||||||
json["type"] = IkarusValueDataType_Tuple;
|
json["type"] = IkarusValueDataType_Tuple;
|
||||||
json["data"] = tuple.values |
|
json["data"] = tuple.values |
|
||||||
std::views::transform([](auto const & data) {
|
std::views::transform([](auto const & data) {
|
||||||
nlohmann::json j;
|
return IkarusValueData::to_json(*data);
|
||||||
IkarusValueData::to_json(j, *data);
|
|
||||||
return j;
|
|
||||||
}) |
|
}) |
|
||||||
std::ranges::to<std::vector<nlohmann::json>>();
|
std::ranges::to<std::vector<nlohmann::json>>();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
value.variant
|
value.variant
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return json;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,8 +55,7 @@ struct IkarusValueData {
|
||||||
|
|
||||||
static auto from_json(nlohmann::json const & json)
|
static auto from_json(nlohmann::json const & json)
|
||||||
-> cppbase::Result<IkarusValueData, IkarusValueDataParseError>;
|
-> cppbase::Result<IkarusValueData, IkarusValueDataParseError>;
|
||||||
static auto to_json(nlohmann::json & json, IkarusValueData const & value)
|
static auto to_json(IkarusValueData const & value) -> nlohmann::json;
|
||||||
-> void;
|
|
||||||
|
|
||||||
IkarusValueDataVariant variant;
|
IkarusValueDataVariant variant;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
|
#include <cppbase/format.hpp>
|
||||||
|
|
||||||
struct IkarusJsonMissingKeyError {};
|
struct IkarusJsonMissingKeyError {};
|
||||||
|
|
||||||
struct IkarusJsonInvalidTypeError {};
|
struct IkarusJsonInvalidTypeError {};
|
||||||
|
|
@ -34,3 +36,82 @@ using IkarusValueParseError = std::variant<
|
||||||
|
|
||||||
using IkarusValuesParseError =
|
using IkarusValuesParseError =
|
||||||
std::variant<IkarusJsonMissingKeyError, IkarusValueParseError>;
|
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");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -85,10 +85,10 @@ auto IkarusValueSchema::from_json(nlohmann::json const & json)
|
||||||
return cppbase::ok(std::move(schema));
|
return cppbase::ok(std::move(schema));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto IkarusValueSchema::to_json(
|
auto IkarusValueSchema::to_json(IkarusValueSchema const & schema)
|
||||||
nlohmann::json & json,
|
-> nlohmann::json {
|
||||||
IkarusValueSchema const & schema
|
nlohmann::json json = nlohmann::json::object();
|
||||||
) -> void {
|
|
||||||
std::visit(
|
std::visit(
|
||||||
cppbase::overloaded{
|
cppbase::overloaded{
|
||||||
[&json](IkarusValueSchemaPrimitive const & schema) {
|
[&json](IkarusValueSchemaPrimitive const & schema) {
|
||||||
|
|
@ -97,18 +97,14 @@ auto IkarusValueSchema::to_json(
|
||||||
},
|
},
|
||||||
[&json](IkarusValueSchemaList const & schema) {
|
[&json](IkarusValueSchemaList const & schema) {
|
||||||
json["type"] = IkarusValueSchemaType_List;
|
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](IkarusValueSchemaMap const & schema) {
|
||||||
json["type"] = IkarusValueSchemaType_Map;
|
json["type"] = IkarusValueSchemaType_Map;
|
||||||
IkarusValueSchema::to_json(
|
json["key_schema"] =
|
||||||
json["key_schema"],
|
IkarusValueSchema::to_json(*schema.key_schema);
|
||||||
*schema.key_schema
|
json["value_schema"] =
|
||||||
);
|
IkarusValueSchema::to_json(*schema.value_schema);
|
||||||
IkarusValueSchema::to_json(
|
|
||||||
json["value_schema"],
|
|
||||||
*schema.value_schema
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
[&json](IkarusValueSchemaTuple const & schema) {
|
[&json](IkarusValueSchemaTuple const & schema) {
|
||||||
json["type"] = IkarusValueSchemaType_Tuple;
|
json["type"] = IkarusValueSchemaType_Tuple;
|
||||||
|
|
@ -117,9 +113,9 @@ auto IkarusValueSchema::to_json(
|
||||||
sub_schemas.reserve(schema.sub_schemas.size());
|
sub_schemas.reserve(schema.sub_schemas.size());
|
||||||
|
|
||||||
for (auto const & sub_schema : schema.sub_schemas) {
|
for (auto const & sub_schema : schema.sub_schemas) {
|
||||||
nlohmann::json sub_schema_json{};
|
sub_schemas.push_back(
|
||||||
IkarusValueSchema::to_json(sub_schema_json, *sub_schema);
|
IkarusValueSchema::to_json(*sub_schema)
|
||||||
sub_schemas.push_back(sub_schema_json);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
json["schemas"] = sub_schemas;
|
json["schemas"] = sub_schemas;
|
||||||
|
|
@ -127,6 +123,8 @@ auto IkarusValueSchema::to_json(
|
||||||
},
|
},
|
||||||
schema.variant
|
schema.variant
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto IkarusValueSchema::validate(IkarusValueData const & data) const -> bool {
|
auto IkarusValueSchema::validate(IkarusValueData const & data) const -> bool {
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,7 @@ struct IkarusValueSchema {
|
||||||
|
|
||||||
static auto from_json(nlohmann::json const & json)
|
static auto from_json(nlohmann::json const & json)
|
||||||
-> cppbase::Result<IkarusValueSchema, IkarusValueSchemaParseError>;
|
-> cppbase::Result<IkarusValueSchema, IkarusValueSchemaParseError>;
|
||||||
static auto to_json(nlohmann::json & json, IkarusValueSchema const & value)
|
static auto to_json(IkarusValueSchema const & value) -> nlohmann::json;
|
||||||
-> void;
|
|
||||||
|
|
||||||
auto validate(IkarusValueData const & data) const -> bool;
|
auto validate(IkarusValueData const & data) const -> bool;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,34 +25,11 @@ auto IkarusValue::from_json(nlohmann::json const & json)
|
||||||
return cppbase::ok(std::move(value));
|
return cppbase::ok(std::move(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto IkarusValue::to_json(nlohmann::json & json, IkarusValue const & value)
|
auto IkarusValue::to_json(IkarusValue const & value) -> nlohmann::json {
|
||||||
-> void {
|
nlohmann::json json = nlohmann::json::object();
|
||||||
IkarusValueSchema::to_json(json["schema"], value.schema);
|
|
||||||
IkarusValueData::to_json(json["data"], value.data);
|
json["schema"] = IkarusValueSchema::to_json(value.schema);
|
||||||
}
|
json["data"] = IkarusValueData::to_json(value.data);
|
||||||
|
|
||||||
auto IkarusValues::from_json(nlohmann::json const & json)
|
return 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));
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,15 +14,5 @@ struct IkarusValue {
|
||||||
|
|
||||||
static auto from_json(nlohmann::json const & json)
|
static auto from_json(nlohmann::json const & json)
|
||||||
-> cppbase::Result<IkarusValue, IkarusValueParseError>;
|
-> cppbase::Result<IkarusValue, IkarusValueParseError>;
|
||||||
static auto to_json(nlohmann::json & json, IkarusValue const & value)
|
static auto to_json(IkarusValue const & value) -> nlohmann::json;
|
||||||
-> 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;
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue