update dependencies
Signed-off-by: Folling <mail@folling.io>
This commit is contained in:
parent
c489e9e8ae
commit
6310335e41
21 changed files with 800 additions and 370 deletions
|
|
@ -66,7 +66,7 @@ BreakConstructorInitializers: AfterColon
|
|||
BreakInheritanceList: AfterColon
|
||||
BreakStringLiterals: false
|
||||
|
||||
ColumnLimit: 80
|
||||
ColumnLimit: 120
|
||||
CommentPragmas: '^\\.+'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
|
|
@ -148,6 +148,7 @@ PPIndentWidth: -1
|
|||
PackConstructorInitializers: Never
|
||||
|
||||
PointerAlignment: Middle
|
||||
|
||||
QualifierAlignment: Right
|
||||
# QualifierOrder: [ 'friend', 'constexpr', 'inline', 'static', 'type', 'const', 'volatile' ]
|
||||
ReferenceAlignment: Middle
|
||||
|
|
|
|||
|
|
@ -31,24 +31,27 @@ enum IkarusErrorInfo {
|
|||
/// \brief The client provided a non-existent resource.
|
||||
/// Example: Passing an entity to a function after it has been deleted.
|
||||
IkarusErrorInfo_Client_NonExistent = 0x01000003,
|
||||
/// \brief The client provided a resource which exists but is not linked to the current context.
|
||||
/// Example: Passing a property that isn't linked to the current entity.
|
||||
IkarusErrorInfo_Client_NotLinked = 0x01000004,
|
||||
/// \brief The client provided an index that was out of bounds for some array.
|
||||
/// Example: Passing the index 3 for an `IkarusToggleValue` with size 3.
|
||||
IkarusErrorInfo_Client_IndexOutOfBounds = 0x01000004,
|
||||
IkarusErrorInfo_Client_IndexOutOfBounds = 0x01000005,
|
||||
/// \brief The client provided a numeric value that was out of bounds
|
||||
/// Example: Passing the value 2^32 to an i32 (might be passed as a string).
|
||||
IkarusErrorInfo_Client_ValueOutOfBounds = 0x01000005,
|
||||
IkarusErrorInfo_Client_ValueOutOfBounds = 0x01000006,
|
||||
/// \brief The client provided invalid input that doesn't fit in any of the other categories.
|
||||
/// Example: Passing an empty/blank string for a string that must be
|
||||
/// non-empty/-blank.
|
||||
IkarusErrorInfo_Client_InvalidInput = 0x01000006,
|
||||
IkarusErrorInfo_Client_InvalidInput = 0x01000007,
|
||||
/// \brief The client provided valid data in an invalid format.
|
||||
/// Example: Passing a malformed JSON string.
|
||||
IkarusErrorInfo_Client_InvalidFormat = 0x01000007,
|
||||
IkarusErrorInfo_Client_InvalidFormat = 0x01000008,
|
||||
/// \brief The client violated a constraint.
|
||||
/// \details This error is most likely caused by clients.
|
||||
/// Example: A user tries to set the age of a character to a value outside
|
||||
/// its specified range.
|
||||
IkarusErrorInfo_Client_ConstraintViolated = 0x10000008,
|
||||
IkarusErrorInfo_Client_ConstraintViolated = 0x10000009,
|
||||
|
||||
// 0x02 reserved for dependency errors
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,13 @@ IKARUS_BEGIN_HEADER
|
|||
/// in all linked entities.
|
||||
struct IkarusBlueprint;
|
||||
|
||||
/// \brief Checks whether a blueprint exists.
|
||||
/// \param blueprint The blueprint to check.
|
||||
/// \pre \li Must not be null.
|
||||
/// \param error_out \see errors.h
|
||||
/// \return True if the blueprint exists, false otherwise or if an error occurs.
|
||||
IKA_API bool ikarus_blueprint_exists(IkarusBlueprint * blueprint, IkarusErrorData * error_out);
|
||||
|
||||
/// \brief Flags for creating a blueprint.
|
||||
enum IkarusBlueprintCreateFlags {
|
||||
/// \brief No flags.
|
||||
|
|
@ -48,14 +55,10 @@ IKA_API IkarusBlueprint * ikarus_blueprint_create(
|
|||
enum IkarusBlueprintCreateFromEntityFlags {
|
||||
/// \brief No flags.
|
||||
IkarusBlueprintCreateFromEntityFlags_None = 0,
|
||||
/// \brief The default values of the properties will be set to the values of the source entity.
|
||||
IkarusBlueprintCreateFromEntityFlags_AdoptDefaultValues = 1 << 0,
|
||||
/// \brief The entity will be linked to the blueprint, and all values will be turned into properties.
|
||||
IkarusBlueprintCreateFromEntityFlags_LinkEntity = 1 << 1,
|
||||
};
|
||||
|
||||
/// \brief Creates a new blueprint from an entity.
|
||||
/// \details Each value of the entity will be copied into the blueprint as a property.
|
||||
/// \details Each value of the entity will be copied into the blueprint as a blueprint.
|
||||
/// \param entity The entity to create the blueprint from.
|
||||
/// \pre \li Must not be null.
|
||||
/// \pre \li Must exist.
|
||||
|
|
@ -117,10 +120,8 @@ IKA_API void ikarus_blueprint_delete(
|
|||
/// \param error_out \see errors.h
|
||||
/// \return The project the blueprint belongs to.
|
||||
/// \remark Ownership remains with libikarus.
|
||||
IKA_API struct IkarusProject * ikarus_blueprint_get_project(
|
||||
struct IkarusBlueprint * blueprint,
|
||||
struct IkarusErrorData * error_out
|
||||
);
|
||||
IKA_API struct IkarusProject *
|
||||
ikarus_blueprint_get_project(struct IkarusBlueprint * blueprint, struct IkarusErrorData * error_out);
|
||||
|
||||
/// \brief Gets the name of a blueprint.
|
||||
/// \param blueprint The blueprint to get the name of.
|
||||
|
|
@ -129,10 +130,7 @@ IKA_API struct IkarusProject * ikarus_blueprint_get_project(
|
|||
/// \param error_out \see errors.h
|
||||
/// \return The name of the blueprint.
|
||||
/// \remark Ownership remains with libikarus.
|
||||
IKA_API char const * ikarus_blueprint_get_name(
|
||||
struct IkarusBlueprint * blueprint,
|
||||
struct IkarusErrorData * error_out
|
||||
);
|
||||
IKA_API char const * ikarus_blueprint_get_name(struct IkarusBlueprint * blueprint, struct IkarusErrorData * error_out);
|
||||
|
||||
/// \brief Flags for setting the name of a blueprint.
|
||||
enum IkarusBlueprintSetNameFlags {
|
||||
|
|
@ -163,7 +161,7 @@ IKA_API void ikarus_blueprint_set_name(
|
|||
/// \param size_out An out parameter for the number of items in the returned array or undefined if an error occurs.
|
||||
/// \param error_out \see errors.h
|
||||
/// \return The properties of the blueprint or null if an error occurs.
|
||||
IKA_API struct IkarusProperty ** ikarus_blueprint_get_properties(
|
||||
IKA_API struct IkarusBlueprint ** ikarus_blueprint_get_properties(
|
||||
struct IkarusBlueprint * blueprint,
|
||||
size_t * size_out,
|
||||
struct IkarusErrorData * error_out
|
||||
|
|
@ -175,10 +173,8 @@ IKA_API struct IkarusProperty ** ikarus_blueprint_get_properties(
|
|||
/// \pre \li Must exist.
|
||||
/// \param error_out \see errors.h
|
||||
/// \return The number of properties of the blueprint or 0 if an error occurs.
|
||||
IKA_API size_t ikarus_blueprint_get_properties_count(
|
||||
struct IkarusBlueprint * blueprint,
|
||||
struct IkarusErrorData * error_out
|
||||
);
|
||||
IKA_API size_t
|
||||
ikarus_blueprint_get_properties_count(struct IkarusBlueprint * blueprint, struct IkarusErrorData * error_out);
|
||||
|
||||
/// \brief Gets all entities linked to a blueprint.
|
||||
/// \param blueprint The blueprint to get the entities of.
|
||||
|
|
@ -200,10 +196,8 @@ IKA_API struct IkarusEntity ** ikarus_blueprint_get_entities(
|
|||
/// \pre \li Must exist.
|
||||
/// \param error_out \see errors.h
|
||||
/// \return The number of entities linked to the blueprint or 0 if an error occurs.
|
||||
IKA_API size_t ikarus_blueprint_get_entities_count(
|
||||
struct IkarusBlueprint * blueprint,
|
||||
struct IkarusErrorData * error_out
|
||||
);
|
||||
IKA_API size_t
|
||||
ikarus_blueprint_get_entities_count(struct IkarusBlueprint * blueprint, struct IkarusErrorData * error_out);
|
||||
|
||||
IKARUS_END_HEADER
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,14 @@ enum IkarusEntityCreateFlags {
|
|||
IkarusEntityCreateFlags_None = 0,
|
||||
};
|
||||
|
||||
/// \brief Checks whether an entity exists.
|
||||
/// \param entity The entity to check.
|
||||
/// \pre \li Must not be null.
|
||||
/// \param error_out \see errors.h
|
||||
/// \return True if the entity exists, false otherwise or if an error occurs.
|
||||
IKA_API bool
|
||||
ikarus_entity_exists(IkarusEntity * entity, IkarusErrorData * error_out);
|
||||
|
||||
/// \brief Creates a new entity.
|
||||
/// \param project The project to create the entity in.
|
||||
/// \pre \li Must not be null.
|
||||
|
|
@ -127,6 +135,22 @@ IKA_API void ikarus_entity_set_name(
|
|||
IkarusErrorData * error_out
|
||||
);
|
||||
|
||||
/// \brief Gets whether an entity is linked to a blueprint.
|
||||
/// \param entity The entity to check the blueprint of.
|
||||
/// \pre \li Must not be null.
|
||||
/// \pre \li Must exist.
|
||||
/// \param blueprint The blueprint to check the entity's link to.
|
||||
/// \pre \li Must not be null.
|
||||
/// \pre \li Must exist.
|
||||
/// \pre \li Must be in the same project as the entity.
|
||||
/// \param error_out \see errors.h
|
||||
/// \return True if the entity is linked to the blueprint, false otherwise or if an error occurs.
|
||||
IKA_API bool ikarus_entity_is_linked_to_blueprint(
|
||||
IkarusEntity * entity,
|
||||
struct IkarusBlueprint * blueprint,
|
||||
IkarusErrorData * error_out
|
||||
);
|
||||
|
||||
/// \brief Gets the blueprints an entity is linked to.
|
||||
/// \param entity The entity to get the blueprints of.
|
||||
/// \pre \li Must not be null.
|
||||
|
|
@ -191,6 +215,7 @@ enum IkarusEntityUnlinkBlueprintFlags {
|
|||
/// \param blueprint The blueprint to unlink from.
|
||||
/// \pre \li Must not be null.
|
||||
/// \pre \li Must exist.
|
||||
/// \pre \li Must be in the same project as the entity.
|
||||
/// \remark If the entity is not linked to the blueprint, nothing happens.
|
||||
/// \param flags Flags for unlinking the entity from the blueprint.
|
||||
/// \param error_out \see errors.h
|
||||
|
|
@ -201,6 +226,20 @@ IKA_API void ikarus_entity_unlink_blueprint(
|
|||
IkarusErrorData * error_out
|
||||
);
|
||||
|
||||
/// \brief Gets whether an entity has a value.
|
||||
/// \param entity The entity to check the value of.
|
||||
/// \pre \li Must not be null.
|
||||
/// \pre \li Must exist.
|
||||
/// \param name The value's name.
|
||||
/// \pre \li Must not be null.
|
||||
/// \param error_out \see errors.h
|
||||
/// \return True if the entity has a value with the name, false otherwise or if an error occurs.
|
||||
IKA_API bool ikarus_entity_has_value(
|
||||
IkarusEntity * entity,
|
||||
char const * name,
|
||||
IkarusErrorData * error_out
|
||||
);
|
||||
|
||||
/// \brief Struct for an entity value.
|
||||
struct IkarusEntityValue {
|
||||
/// \brief The name of the value.
|
||||
|
|
@ -229,7 +268,7 @@ IKA_API IkarusEntityValue * ikarus_entity_get_values(
|
|||
/// \pre \li Must exist.
|
||||
/// \param name The value's name.
|
||||
/// \pre \li Must not be null.
|
||||
/// \remark Ownership remains with the client.
|
||||
/// \pre \li Must exist.
|
||||
/// \param error_out \see errors.h
|
||||
/// \return The value, in json format of or null if an error occurs. \see value.h
|
||||
IKA_API char const * ikarus_entity_get_value(
|
||||
|
|
@ -287,6 +326,22 @@ IKA_API void ikarus_entity_delete_value(
|
|||
IkarusErrorData * error_out
|
||||
);
|
||||
|
||||
/// \brief Gets whether an entity has a property value.
|
||||
/// \param entity The entity to check the property value of.
|
||||
/// \pre \li Must not be null.
|
||||
/// \pre \li Must exist.
|
||||
/// \param property The property to check the value of.
|
||||
/// \pre \li Must not be null.
|
||||
/// \pre \li Must exist.
|
||||
/// \pre \li Must be in the same project as the entity.
|
||||
/// \param error_out \see errors.h
|
||||
/// \return True if the entity has a value for the property, false otherwise or if an error occurs.
|
||||
IKA_API bool ikarus_entity_has_property_value(
|
||||
IkarusEntity * entity,
|
||||
struct IkarusProperty * property,
|
||||
IkarusErrorData * error_out
|
||||
);
|
||||
|
||||
/// \brief Struct for an entity property value.
|
||||
struct IkarusEntityPropertyValue {
|
||||
/// \brief The property.
|
||||
|
|
@ -355,6 +410,29 @@ IKA_API void ikarus_entity_set_property_value(
|
|||
IkarusErrorData * error_out
|
||||
);
|
||||
|
||||
/// \brief Flags for clearing the value of a property of an entity.
|
||||
enum IkarusEntityClearPropertyValueFlags {
|
||||
/// \brief No flags.
|
||||
IkarusEntityClearPropertyValueFlags_None = 0,
|
||||
};
|
||||
|
||||
/// \brief Clears the value of a property of an entity.
|
||||
/// \param entity The entity to clear the value of.
|
||||
/// \pre \li Must not be null.
|
||||
/// \pre \li Must exist.
|
||||
/// \param property The property to clear the value of.
|
||||
/// \pre \li Must not be null.
|
||||
/// \pre \li Must exist.
|
||||
/// \pre \li Must be linked to the entity.
|
||||
/// \param flags Flags for clearing the property value.
|
||||
/// \param error_out \see errors.h
|
||||
IKA_API void ikarus_entity_clear_property_value(
|
||||
IkarusEntity * entity,
|
||||
struct IkarusProperty * property,
|
||||
IkarusEntitySetPropertyValueFlags flags,
|
||||
IkarusErrorData * error_out
|
||||
);
|
||||
|
||||
IKARUS_END_HEADER
|
||||
|
||||
/// @}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,13 @@ IKARUS_BEGIN_HEADER
|
|||
/// property's default value if none is specified.
|
||||
struct IkarusProperty;
|
||||
|
||||
/// \brief Checks whether a property exists.
|
||||
/// \param property The property to check.
|
||||
/// \pre \li Must not be null.
|
||||
/// \param error_out \see errors.h
|
||||
/// \return True if the property exists, false otherwise or if an error occurs.
|
||||
IKA_API bool ikarus_property_exists(IkarusProperty * property, IkarusErrorData * error_out);
|
||||
|
||||
/// \brief Flags for creating a property.
|
||||
enum IkarusPropertyCreateFlags {
|
||||
/// \brief No flags.
|
||||
|
|
@ -73,11 +80,8 @@ enum IkarusPropertyDeleteFlags {
|
|||
/// \param property The property to delete.
|
||||
/// \param flags Flags for deleting the property.
|
||||
/// \param error_out \see errors.h
|
||||
IKA_API void ikarus_property_delete(
|
||||
IkarusProperty * property,
|
||||
IkarusPropertyDeleteFlags flags,
|
||||
IkarusErrorData * error_out
|
||||
);
|
||||
IKA_API void
|
||||
ikarus_property_delete(IkarusProperty * property, IkarusPropertyDeleteFlags flags, IkarusErrorData * error_out);
|
||||
|
||||
/// \brief Get the project a property belongs to.
|
||||
/// \param property The property to get the project of.
|
||||
|
|
@ -86,10 +90,7 @@ IKA_API void ikarus_property_delete(
|
|||
/// \param error_out \see errors.h
|
||||
/// \return The project the property belongs to or null if an error occurred.
|
||||
/// \remark Ownership remains with libikarus.
|
||||
IKA_API struct IkarusProject * ikarus_property_get_project(
|
||||
IkarusProperty * property,
|
||||
IkarusErrorData * error_out
|
||||
);
|
||||
IKA_API struct IkarusProject * ikarus_property_get_project(IkarusProperty * property, IkarusErrorData * error_out);
|
||||
|
||||
/// \brief Get the name of a property.
|
||||
/// \param property The property to get the name of.
|
||||
|
|
@ -98,10 +99,7 @@ IKA_API struct IkarusProject * ikarus_property_get_project(
|
|||
/// \param error_out \see errors.h
|
||||
/// \return The name of the property or null if an error occurred.
|
||||
/// \remark Ownership remains with libikarus.
|
||||
IKA_API char const * ikarus_property_get_name(
|
||||
IkarusProperty * property,
|
||||
IkarusErrorData * error_out
|
||||
);
|
||||
IKA_API char const * ikarus_property_get_name(IkarusProperty * property, IkarusErrorData * error_out);
|
||||
|
||||
/// \brief Get the schema of a property.
|
||||
/// \param property The property to get the schema of.
|
||||
|
|
@ -110,10 +108,7 @@ IKA_API char const * ikarus_property_get_name(
|
|||
/// \param error_out \see errors.h
|
||||
/// \return The schema of the property or null if an error occurred.
|
||||
/// \remark Ownership remains with libikarus.
|
||||
IKA_API struct IkarusValueSchema * ikarus_property_get_schema(
|
||||
IkarusProperty * property,
|
||||
IkarusErrorData * error_out
|
||||
);
|
||||
IKA_API struct IkarusValueSchema * ikarus_property_get_schema(IkarusProperty * property, IkarusErrorData * error_out);
|
||||
|
||||
/// \brief Flags for setting the name of a property.
|
||||
enum IkarusPropertySetNameFlags {
|
||||
|
|
|
|||
|
|
@ -64,9 +64,9 @@ char const * ikarus_get_error_info_name(IkarusErrorInfo info) {
|
|||
}
|
||||
|
||||
bool ikarus_error_data_is_success(IkarusErrorData const * data) {
|
||||
return data->info == IkarusErrorInfo_None;
|
||||
return data && data->info == IkarusErrorInfo_None;
|
||||
}
|
||||
|
||||
bool ikarus_error_data_is_error(IkarusErrorData const * data) {
|
||||
return data->info != IkarusErrorInfo_None;
|
||||
return data && data->info != IkarusErrorInfo_None;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,23 +3,32 @@
|
|||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
#include <cppbase/result.hpp>
|
||||
#include <cppbase/strings.hpp>
|
||||
#include <cppbase/templates.hpp>
|
||||
|
||||
#include <ikarus/errors.h>
|
||||
|
||||
void safe_strcpy(
|
||||
std::string_view const src,
|
||||
char * dest,
|
||||
size_t const dest_size
|
||||
void safe_strcpy(std::string_view const src, char * dest, size_t const dest_size);
|
||||
|
||||
template<>
|
||||
struct fmt::formatter<IkarusErrorData> : formatter<string_view> {
|
||||
constexpr static auto format([[maybe_unused]] IkarusErrorData const & error, fmt::format_context & ctx) {
|
||||
return fmt::format_to(
|
||||
ctx.out(),
|
||||
"ERROR {}({}): {}",
|
||||
ikarus_error_info_get_name(error.info),
|
||||
static_cast<std::underlying_type_t<IkarusErrorInfo>>(error.info),
|
||||
error.message
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
#define IKARUS_VOID_RETURN
|
||||
|
||||
#define IKARUS_SET_ERROR(msg, err_info) \
|
||||
if (error_out != nullptr) { \
|
||||
safe_strcpy( \
|
||||
msg, \
|
||||
static_cast<char *>(error_out->message), \
|
||||
IKARUS_ERROR_DATA_MAX_MESSAGE_LIMIT \
|
||||
); \
|
||||
safe_strcpy(msg, static_cast<char *>(error_out->message), IKARUS_ERROR_DATA_MAX_MESSAGE_LIMIT); \
|
||||
error_out->info = err_info; \
|
||||
}
|
||||
|
||||
|
|
@ -36,139 +45,72 @@ void safe_strcpy(
|
|||
#define IKARUS_TRY_OR_FAIL_IMPL(var_name, msg, err_info, ...) \
|
||||
auto var_name = __VA_ARGS__; \
|
||||
if (var_name.is_error()) { \
|
||||
IKARUS_SET_ERROR( \
|
||||
fmt::format( \
|
||||
fmt::runtime(msg), \
|
||||
std::move(var_name).unwrap_error() \
|
||||
), \
|
||||
err_info \
|
||||
); \
|
||||
IKARUS_SET_ERROR(fmt::format(fmt::runtime(msg), std::move(var_name).unwrap_error()), err_info); \
|
||||
return var_name; \
|
||||
}
|
||||
|
||||
#define IKARUS_TRY_OR_FAIL(msg, err_info, ...) \
|
||||
IKARUS_TRY_OR_FAIL_IMPL( \
|
||||
CPPBASE_UNIQUE_NAME(result), \
|
||||
msg, \
|
||||
err_info, \
|
||||
__VA_ARGS__ \
|
||||
);
|
||||
IKARUS_TRY_OR_FAIL_IMPL(CPPBASE_UNIQUE_NAME(result), msg, err_info, __VA_ARGS__);
|
||||
|
||||
#define IKARUS_TRYRV_OR_FAIL_IMPL(var_name, ret, msg, err_info, ...) \
|
||||
auto var_name = __VA_ARGS__; \
|
||||
if (var_name.is_error()) { \
|
||||
IKARUS_SET_ERROR( \
|
||||
fmt::format( \
|
||||
fmt::runtime(msg), \
|
||||
std::move(var_name).unwrap_error() \
|
||||
), \
|
||||
err_info \
|
||||
); \
|
||||
IKARUS_SET_ERROR(fmt::format(fmt::runtime(msg), std::move(var_name).unwrap_error()), err_info); \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
#define IKARUS_TRYRV_OR_FAIL(ret, msg, err_info, ...) \
|
||||
IKARUS_TRYRV_OR_FAIL_IMPL( \
|
||||
CPPBASE_UNIQUE_NAME(result), \
|
||||
ret, \
|
||||
msg, \
|
||||
err_info, \
|
||||
__VA_ARGS__ \
|
||||
);
|
||||
IKARUS_TRYRV_OR_FAIL_IMPL(CPPBASE_UNIQUE_NAME(result), ret, msg, err_info, __VA_ARGS__);
|
||||
|
||||
#define IKARUS_VTRY_OR_FAIL_IMPL(var_name, value, msg, err_info, ...) \
|
||||
auto var_name = __VA_ARGS__; \
|
||||
if (var_name.is_error()) { \
|
||||
IKARUS_SET_ERROR( \
|
||||
fmt::format( \
|
||||
fmt::runtime(msg), \
|
||||
std::move(var_name).unwrap_error() \
|
||||
), \
|
||||
err_info \
|
||||
); \
|
||||
IKARUS_SET_ERROR(fmt::format(fmt::runtime(msg), std::move(var_name).unwrap_error()), err_info); \
|
||||
return var_name; \
|
||||
} \
|
||||
value = std::move(var_name).unwrap_value()
|
||||
|
||||
#define IKARUS_VTRY_OR_FAIL(value, msg, err_info, ...) \
|
||||
IKARUS_VTRY_OR_FAIL_IMPL( \
|
||||
CPPBASE_UNIQUE_NAME(result), \
|
||||
value, \
|
||||
msg, \
|
||||
err_info, \
|
||||
__VA_ARGS__ \
|
||||
);
|
||||
IKARUS_VTRY_OR_FAIL_IMPL(CPPBASE_UNIQUE_NAME(result), value, msg, err_info, __VA_ARGS__);
|
||||
|
||||
#define IKARUS_VTRYRV_OR_FAIL_IMPL(var_name, value, ret, msg, err_info, ...) \
|
||||
auto var_name = __VA_ARGS__; \
|
||||
if (var_name.is_error()) { \
|
||||
IKARUS_SET_ERROR( \
|
||||
fmt::format(fmt::runtime(msg), var_name.unwrap_error()), \
|
||||
err_info \
|
||||
); \
|
||||
IKARUS_SET_ERROR(fmt::format(fmt::runtime(msg), var_name.unwrap_error()), err_info); \
|
||||
return ret; \
|
||||
} \
|
||||
value = std::move(var_name).unwrap_value()
|
||||
|
||||
#define IKARUS_VTRYRV_OR_FAIL(value, ret, msg, err_info, ...) \
|
||||
IKARUS_VTRYRV_OR_FAIL_IMPL( \
|
||||
CPPBASE_UNIQUE_NAME(result), \
|
||||
value, \
|
||||
ret, \
|
||||
msg, \
|
||||
err_info, \
|
||||
__VA_ARGS__ \
|
||||
);
|
||||
IKARUS_VTRYRV_OR_FAIL_IMPL(CPPBASE_UNIQUE_NAME(result), value, ret, msg, err_info, __VA_ARGS__);
|
||||
|
||||
#define IKARUS_FAIL_IF_ERROR(ret) \
|
||||
if (ikarus_error_data_is_error(error_out)) { \
|
||||
#define IKARUS_FAIL_IF_ERROR(ret, error) \
|
||||
if (ikarus_error_data_is_error(error)) { \
|
||||
if (error_out) { \
|
||||
*error_out = *error; \
|
||||
} \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
#define IKARUS_FAIL_IF_NULL(ptr, ret) \
|
||||
IKARUS_FAIL_IF( \
|
||||
((ptr) == nullptr), \
|
||||
ret, \
|
||||
#ptr " must not be null", \
|
||||
IkarusErrorInfo_Client_InvalidNull \
|
||||
)
|
||||
IKARUS_FAIL_IF(((ptr) == nullptr), ret, #ptr " must not be null", IkarusErrorInfo_Client_InvalidNull)
|
||||
|
||||
#define IKARUS_FAIL_IF_NAME_INVALID(name, ret) \
|
||||
IKARUS_FAIL_IF_NULL(name, ret); \
|
||||
IKARUS_FAIL_IF( \
|
||||
cppbase::is_empty_or_blank(name), \
|
||||
ret, \
|
||||
#name " must not be empty", \
|
||||
IkarusErrorInfo_Client_InvalidInput \
|
||||
);
|
||||
IKARUS_FAIL_IF(cppbase::is_empty_or_blank(name), ret, "name must not be empty", IkarusErrorInfo_Client_InvalidInput)
|
||||
|
||||
#define IKARUS_FAIL_IF_NOT_EXIST_IMPL(exists_name, object, ret) \
|
||||
IKARUS_VTRYRV_OR_FAIL( \
|
||||
auto exists_name, \
|
||||
ret, \
|
||||
fmt::format( \
|
||||
"failed to check if {} exists", \
|
||||
std::remove_cvref_t<decltype(*object)>::object_name \
|
||||
), \
|
||||
IkarusErrorInfo_Database_QueryFailed, \
|
||||
object->project->db->query_one<bool>( \
|
||||
fmt::format( \
|
||||
"SELECT EXISTS(SELECT 1 FROM `{}` WHERE `id` = ?)", \
|
||||
std::remove_cvref_t<decltype(*object)>::table_name \
|
||||
), \
|
||||
object->id \
|
||||
) \
|
||||
); \
|
||||
\
|
||||
IKARUS_FAIL_IF( \
|
||||
!exists_name, \
|
||||
ret, \
|
||||
fmt::format( \
|
||||
"{} doesn't exist", \
|
||||
std::remove_cvref_t<decltype(*object)>::object_name \
|
||||
), \
|
||||
IkarusErrorInfo_Client_NonExistent \
|
||||
)
|
||||
#define IKARUS_ASCERTAIN_IMPL(cond_name, ret, msg, err_info, func, ...) \
|
||||
auto cond_name = std::invoke(func, __VA_ARGS__, error_out); \
|
||||
IKARUS_FAIL_IF_ERROR(ret, error_out) \
|
||||
IKARUS_FAIL_IF(!cond_name, ret, msg, err_info)
|
||||
|
||||
#define IKARUS_FAIL_IF_NOT_EXIST(object, ret) \
|
||||
IKARUS_FAIL_IF_NOT_EXIST_IMPL(CPPBASE_UNIQUE_NAME(exists), object, ret)
|
||||
#define IKARUS_ASCERTAIN(ret, msg, err_info, func, ...) \
|
||||
IKARUS_ASCERTAIN_IMPL(CPPBASE_UNIQUE_NAME(cond), ret, msg, err_info, func, __VA_ARGS__);
|
||||
|
||||
#define IKARUS_CALL(ret, func, ...) \
|
||||
std::invoke(func, __VA_ARGS__, error_out); \
|
||||
IKARUS_FAIL_IF_ERROR(ret, error_out);
|
||||
|
||||
#define IKARUS_VCALL(value, ret, func, ...) \
|
||||
value = std::invoke(func, __VA_ARGS__, error_out); \
|
||||
IKARUS_FAIL_IF_ERROR(ret, error_out);
|
||||
|
|
|
|||
|
|
@ -2,8 +2,72 @@
|
|||
|
||||
#include <ikarus/errors.hpp>
|
||||
#include <ikarus/objects/blueprint.hpp>
|
||||
#include <ikarus/objects/entity.h>
|
||||
#include <ikarus/persistence/project.hpp>
|
||||
|
||||
IkarusBlueprint::IkarusBlueprint(struct IkarusProject * project, int64_t id):
|
||||
project{project},
|
||||
id{id} {}
|
||||
|
||||
IkarusBlueprint * ikarus_blueprint_create(
|
||||
struct IkarusProject * project,
|
||||
char const * name,
|
||||
IkarusBlueprintCreateFlags flags,
|
||||
struct IkarusErrorData * error_out
|
||||
) {
|
||||
IKARUS_FAIL_IF_NULL(project, nullptr);
|
||||
IKARUS_FAIL_IF_NAME_INVALID(name, nullptr);
|
||||
|
||||
IKARUS_TRYRV_OR_FAIL(
|
||||
nullptr,
|
||||
"failed to create entity: {}",
|
||||
IkarusErrorInfo_Database_QueryFailed,
|
||||
project->db->execute("INSERT INTO `blueprints`(`name`) VALUES(?)", name)
|
||||
);
|
||||
|
||||
auto const id = project->db->last_insert_rowid();
|
||||
return new IkarusBlueprint{project, id};
|
||||
}
|
||||
|
||||
IkarusBlueprint * ikarus_blueprint_create_from_entity(
|
||||
struct IkarusEntity * entity,
|
||||
char const * name,
|
||||
IkarusBlueprintCreateFromEntityFlags flags,
|
||||
struct IkarusErrorData * error_out
|
||||
) {
|
||||
IKARUS_TRYRV_OR_FAIL(
|
||||
nullptr,
|
||||
"{}",
|
||||
IkarusErrorInfo_Database_QueryFailed,
|
||||
ikarus_libikarus_func_call_to_result(
|
||||
error_out,
|
||||
ikarus_must_return_true(ikarus_entity_exists, "entity doesn't exist", IkarusErrorInfo_Client_NonExistent),
|
||||
entity
|
||||
)
|
||||
);
|
||||
IKARUS_FAIL_IF_NAME_INVALID(name, nullptr);
|
||||
|
||||
IKARUS_VTRYRV_OR_FAIL(
|
||||
auto id,
|
||||
nullptr,
|
||||
"failed to create blueprint from entity: {}",
|
||||
IkarusErrorInfo_Database_QueryFailed,
|
||||
entity->project->db->transact([&](auto * db) -> cppbase::Result<int64_t, sqlitecpp::TransactionError> {
|
||||
CPPBASE_TRY(db->execute("INSERT INTO `blueprints`(`name`) VALUES(?)", name));
|
||||
|
||||
auto const id = db->last_insert_rowid();
|
||||
|
||||
CPPBASE_TRY(entity->project->db->execute(
|
||||
"INSERT INTO `properties`(`blueprint`, `name`, `schema`) "
|
||||
"SELECT ?, `name`, json_extract(`value`, '$.schema') FROM `entity_values` "
|
||||
"WHERE `entity` = ?",
|
||||
id,
|
||||
entity->id
|
||||
))
|
||||
|
||||
return cppbase::ok(entity->project->db->last_insert_rowid());
|
||||
})
|
||||
);
|
||||
|
||||
return new IkarusBlueprint{entity->project, id};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,13 +4,28 @@
|
|||
|
||||
#include <ikarus/errors.h>
|
||||
#include <ikarus/errors.hpp>
|
||||
#include <ikarus/objects/blueprint.h>
|
||||
#include <ikarus/objects/entity.h>
|
||||
#include <ikarus/objects/property.h>
|
||||
#include <ikarus/persistence/project.hpp>
|
||||
|
||||
IkarusEntity::IkarusEntity(struct IkarusProject * project, int64_t id):
|
||||
project{project},
|
||||
id{id} {}
|
||||
|
||||
bool ikarus_entity_exists(IkarusEntity * entity, IkarusErrorData * error_out) {
|
||||
IKARUS_FAIL_IF_NULL(entity, false);
|
||||
IKARUS_VTRYRV_OR_FAIL(
|
||||
auto exists,
|
||||
false,
|
||||
"failed to check whether entity exists: {}",
|
||||
IkarusErrorInfo_Database_QueryFailed,
|
||||
entity->project->db->query_one<bool>("SELECT EXISTS(SELECT 1 FROM `entities` WHERE `id` = ?)", entity->id)
|
||||
);
|
||||
|
||||
return exists;
|
||||
}
|
||||
|
||||
IkarusEntity * ikarus_entity_create(
|
||||
struct IkarusProject * project,
|
||||
char const * name,
|
||||
|
|
@ -31,62 +46,55 @@ IkarusEntity * ikarus_entity_create(
|
|||
return new IkarusEntity{project, id};
|
||||
}
|
||||
|
||||
void ikarus_entity_delete(
|
||||
IkarusEntity * entity,
|
||||
IkarusEntityDeleteFlags flags,
|
||||
IkarusErrorData * error_out
|
||||
) {
|
||||
IKARUS_FAIL_IF_NULL(entity, IKARUS_VOID_RETURN);
|
||||
IKARUS_FAIL_IF_NOT_EXIST(entity, IKARUS_VOID_RETURN);
|
||||
void ikarus_entity_delete(IkarusEntity * entity, IkarusEntityDeleteFlags flags, IkarusErrorData * error_out) {
|
||||
IKARUS_ASCERTAIN(
|
||||
IKARUS_VOID_RETURN,
|
||||
"entity doesn't exist",
|
||||
IkarusErrorInfo_Client_NonExistent,
|
||||
ikarus_entity_exists,
|
||||
entity
|
||||
);
|
||||
|
||||
IKARUS_TRYRV_OR_FAIL(
|
||||
IKARUS_VOID_RETURN,
|
||||
"failed to delete entity: {}",
|
||||
IkarusErrorInfo_Database_QueryFailed,
|
||||
entity->project->db
|
||||
->execute("DELETE FROM `entities` WHERE `id` = ?", entity->id)
|
||||
entity->project->db->execute("DELETE FROM `entities` WHERE `id` = ?", entity->id)
|
||||
);
|
||||
|
||||
delete entity;
|
||||
}
|
||||
|
||||
IkarusEntity * ikarus_entity_copy(
|
||||
IkarusEntity * entity,
|
||||
IkarusEntityCopyFlags flags,
|
||||
IkarusErrorData * error_out
|
||||
) {
|
||||
IKARUS_FAIL_IF_NULL(entity, nullptr);
|
||||
IKARUS_FAIL_IF_NOT_EXIST(entity, nullptr);
|
||||
IkarusEntity * ikarus_entity_copy(IkarusEntity * entity, IkarusEntityCopyFlags flags, IkarusErrorData * error_out) {
|
||||
IKARUS_ASCERTAIN(nullptr, "entity doesn't exist", IkarusErrorInfo_Client_NonExistent, ikarus_entity_exists, entity);
|
||||
|
||||
IKARUS_VTRYRV_OR_FAIL(
|
||||
auto id,
|
||||
nullptr,
|
||||
"failed to copy entity: {}",
|
||||
IkarusErrorInfo_Database_QueryFailed,
|
||||
entity->project->db->transact(
|
||||
[entity](auto * db)
|
||||
-> cppbase::Result<int64_t, sqlitecpp::TransactionError> {
|
||||
TRY(entity->project->db->execute(
|
||||
entity->project->db->transact([entity](auto * db) -> cppbase::Result<int64_t, sqlitecpp::TransactionError> {
|
||||
CPPBASE_TRY(entity->project->db->execute(
|
||||
"INSERT INTO `entities`(`name`) "
|
||||
"SELECT `name` FROM `entities` WHERE `id` = ?",
|
||||
entity->id
|
||||
));
|
||||
|
||||
TRY(entity->project->db->execute(
|
||||
CPPBASE_TRY(entity->project->db->execute(
|
||||
"INSERT INTO `entity_values`(`entity`, `name`, `value`) "
|
||||
"SELECT ?1, `name`, `value` FROM `entity_values` WHERE "
|
||||
"`entity` = ?1",
|
||||
entity->id
|
||||
))
|
||||
|
||||
TRY(entity->project->db->execute(
|
||||
CPPBASE_TRY(entity->project->db->execute(
|
||||
"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(
|
||||
CPPBASE_TRY(entity->project->db->execute(
|
||||
"INSERT INTO `entity_blueprint_links`(`entity`, `blueprint`) "
|
||||
"SELECT ?1, `property`, `value` FROM `entity_property_values` "
|
||||
"WHERE `entity` = ?1",
|
||||
|
|
@ -94,35 +102,27 @@ IkarusEntity * ikarus_entity_copy(
|
|||
))
|
||||
|
||||
return cppbase::ok(entity->project->db->last_insert_rowid());
|
||||
}
|
||||
)
|
||||
})
|
||||
);
|
||||
|
||||
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_NOT_EXIST(entity, nullptr);
|
||||
IkarusProject * ikarus_entity_get_project(IkarusEntity * entity, IkarusErrorData * error_out) {
|
||||
IKARUS_ASCERTAIN(nullptr, "entity doesn't exist", IkarusErrorInfo_Client_NonExistent, ikarus_entity_exists, entity);
|
||||
|
||||
return entity->project;
|
||||
}
|
||||
|
||||
char const *
|
||||
ikarus_entity_get_name(IkarusEntity * entity, IkarusErrorData * error_out) {
|
||||
IKARUS_FAIL_IF_NULL(entity, nullptr);
|
||||
IKARUS_FAIL_IF_NOT_EXIST(entity, nullptr);
|
||||
char const * ikarus_entity_get_name(IkarusEntity * entity, IkarusErrorData * error_out) {
|
||||
IKARUS_ASCERTAIN(nullptr, "entity doesn't exist", IkarusErrorInfo_Client_NonExistent, ikarus_entity_exists, entity);
|
||||
|
||||
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
|
||||
)
|
||||
entity->project->db->query_one<char const *>("SELECT `name` FROM `entities` WHERE `id` = ?", entity->id)
|
||||
);
|
||||
|
||||
return name;
|
||||
|
|
@ -134,33 +134,63 @@ void ikarus_entity_set_name(
|
|||
IkarusEntitySetNameFlags flags,
|
||||
IkarusErrorData * error_out
|
||||
) {
|
||||
IKARUS_FAIL_IF_NULL(entity, IKARUS_VOID_RETURN);
|
||||
IKARUS_FAIL_IF_NOT_EXIST(entity, IKARUS_VOID_RETURN);
|
||||
IKARUS_ASCERTAIN(
|
||||
IKARUS_VOID_RETURN,
|
||||
"entity doesn't exist",
|
||||
IkarusErrorInfo_Client_NonExistent,
|
||||
ikarus_entity_exists,
|
||||
entity
|
||||
);
|
||||
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(
|
||||
"UPDATE `entities` SET `name` = ? WHERE `id` = ?",
|
||||
name,
|
||||
entity->id
|
||||
)
|
||||
entity->project->db->execute("UPDATE `entities` SET `name` = ? WHERE `id` = ?", name, entity->id)
|
||||
);
|
||||
}
|
||||
|
||||
struct IkarusBlueprint ** ikarus_entity_get_linked_blueprints(
|
||||
bool ikarus_entity_is_linked_to_blueprint(
|
||||
IkarusEntity * entity,
|
||||
size_t * size_out,
|
||||
struct IkarusBlueprint * blueprint,
|
||||
IkarusErrorData * error_out
|
||||
) {
|
||||
IKARUS_FAIL_IF_NULL(entity, nullptr);
|
||||
IKARUS_FAIL_IF_NOT_EXIST(entity, nullptr);
|
||||
IKARUS_FAIL_IF_NULL(size_out, nullptr);
|
||||
IKARUS_ASCERTAIN(false, "entity doesn't exist", IkarusErrorInfo_Client_NonExistent, ikarus_entity_exists, entity);
|
||||
IKARUS_ASCERTAIN(
|
||||
false,
|
||||
"blueprint doesn't exist",
|
||||
IkarusErrorInfo_Client_NonExistent,
|
||||
ikarus_blueprint_exists,
|
||||
blueprint
|
||||
);
|
||||
|
||||
auto count = ikarus_entity_get_linked_blueprints_count(entity, error_out);
|
||||
IKARUS_FAIL_IF_ERROR(nullptr);
|
||||
IKARUS_FAIL_IF(
|
||||
entity->project != blueprint->project,
|
||||
false,
|
||||
"blueprint does not belong to entity's project",
|
||||
IkarusErrorInfo_Client_NotLinked
|
||||
);
|
||||
|
||||
IKARUS_VTRYRV_OR_FAIL(
|
||||
auto exists,
|
||||
false,
|
||||
"failed to check if entity is linked to blueprint: {}",
|
||||
IkarusErrorInfo_Database_QueryFailed,
|
||||
entity->project->db->query_one<bool>(
|
||||
"SELECT EXISTS(SELECT 1 FROM `entity_blueprint_links` WHERE `entity` = ? AND `blueprint` = ?)",
|
||||
entity->id,
|
||||
blueprint->id
|
||||
)
|
||||
);
|
||||
|
||||
return exists;
|
||||
}
|
||||
|
||||
struct IkarusBlueprint **
|
||||
ikarus_entity_get_linked_blueprints(IkarusEntity * entity, size_t * size_out, IkarusErrorData * error_out) {
|
||||
IKARUS_ASCERTAIN(false, "entity doesn't exist", IkarusErrorInfo_Client_NonExistent, ikarus_entity_exists, entity);
|
||||
IKARUS_VCALL(auto count, false, ikarus_entity_get_linked_blueprints_count, entity);
|
||||
|
||||
std::int64_t ids[count];
|
||||
|
||||
|
|
@ -189,22 +219,16 @@ struct IkarusBlueprint ** ikarus_entity_get_linked_blueprints(
|
|||
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);
|
||||
size_t ikarus_entity_get_linked_blueprints_count(IkarusEntity * entity, IkarusErrorData * error_out) {
|
||||
IKARUS_ASCERTAIN(false, "entity doesn't exist", IkarusErrorInfo_Client_NonExistent, ikarus_entity_exists, entity);
|
||||
|
||||
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
|
||||
)
|
||||
entity->project->db
|
||||
->query_one<std::int64_t>("SELECT COUNT(*) FROM `entity_blueprint_links` WHERE `entity` = ?", entity->id)
|
||||
);
|
||||
|
||||
return count;
|
||||
|
|
@ -216,10 +240,28 @@ void ikarus_entity_link_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_ASCERTAIN(
|
||||
IKARUS_VOID_RETURN,
|
||||
"entity doesn't exist",
|
||||
IkarusErrorInfo_Client_NonExistent,
|
||||
ikarus_entity_exists,
|
||||
entity
|
||||
);
|
||||
|
||||
IKARUS_ASCERTAIN(
|
||||
IKARUS_VOID_RETURN,
|
||||
"blueprint doesn't exist",
|
||||
IkarusErrorInfo_Client_NonExistent,
|
||||
ikarus_blueprint_exists,
|
||||
blueprint
|
||||
);
|
||||
|
||||
IKARUS_FAIL_IF(
|
||||
entity->project != blueprint->project,
|
||||
IKARUS_VOID_RETURN,
|
||||
"blueprint does not belong to entity's project",
|
||||
IkarusErrorInfo_Client_NotLinked
|
||||
);
|
||||
|
||||
IKARUS_TRYRV_OR_FAIL(
|
||||
IKARUS_VOID_RETURN,
|
||||
|
|
@ -239,10 +281,28 @@ void ikarus_entity_unlink_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_ASCERTAIN(
|
||||
IKARUS_VOID_RETURN,
|
||||
"entity doesn't exist",
|
||||
IkarusErrorInfo_Client_NonExistent,
|
||||
ikarus_entity_exists,
|
||||
entity
|
||||
);
|
||||
|
||||
IKARUS_ASCERTAIN(
|
||||
IKARUS_VOID_RETURN,
|
||||
"blueprint doesn't exist",
|
||||
IkarusErrorInfo_Client_NonExistent,
|
||||
ikarus_blueprint_exists,
|
||||
blueprint
|
||||
);
|
||||
|
||||
IKARUS_FAIL_IF(
|
||||
entity->project != blueprint->project,
|
||||
IKARUS_VOID_RETURN,
|
||||
"blueprint does not belong to entity's project",
|
||||
IkarusErrorInfo_Client_NotLinked
|
||||
);
|
||||
|
||||
IKARUS_TRYRV_OR_FAIL(
|
||||
IKARUS_VOID_RETURN,
|
||||
|
|
@ -256,13 +316,28 @@ void ikarus_entity_unlink_blueprint(
|
|||
);
|
||||
}
|
||||
|
||||
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);
|
||||
bool ikarus_entity_has_value(IkarusEntity * entity, char const * name, IkarusErrorData * error_out) {
|
||||
IKARUS_FAIL_IF_NULL(name, false);
|
||||
|
||||
IKARUS_ASCERTAIN(false, "entity doesn't exist", IkarusErrorInfo_Client_NonExistent, ikarus_entity_exists, entity);
|
||||
|
||||
IKARUS_VTRYRV_OR_FAIL(
|
||||
auto exists,
|
||||
false,
|
||||
"failed to check if entity has value: {}",
|
||||
IkarusErrorInfo_Database_QueryFailed,
|
||||
entity->project->db->query_one<bool>(
|
||||
"SELECT EXISTS(SELECT 1 FROM `entity_values` WHERE `entity` = ? AND `name` = ?)",
|
||||
entity->id,
|
||||
name
|
||||
)
|
||||
);
|
||||
|
||||
return exists;
|
||||
}
|
||||
|
||||
IkarusEntityValue * ikarus_entity_get_values(IkarusEntity * entity, size_t * size_out, IkarusErrorData * error_out) {
|
||||
IKARUS_ASCERTAIN(nullptr, "entity doesn't exist", IkarusErrorInfo_Client_NonExistent, ikarus_entity_exists, entity);
|
||||
|
||||
IKARUS_VTRYRV_OR_FAIL(
|
||||
auto values_plain,
|
||||
|
|
@ -277,17 +352,9 @@ IkarusEntityValue * ikarus_entity_get_values(
|
|||
|
||||
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>()
|
||||
};
|
||||
}
|
||||
);
|
||||
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();
|
||||
|
|
@ -296,15 +363,19 @@ IkarusEntityValue * ikarus_entity_get_values(
|
|||
return values;
|
||||
}
|
||||
|
||||
char const * ikarus_entity_get_value(
|
||||
IkarusEntity * entity,
|
||||
char const * name,
|
||||
IkarusErrorData * error_out
|
||||
) {
|
||||
IKARUS_FAIL_IF_NULL(entity, nullptr);
|
||||
IKARUS_FAIL_IF_NOT_EXIST(entity, nullptr);
|
||||
char const * ikarus_entity_get_value(IkarusEntity * entity, char const * name, IkarusErrorData * error_out) {
|
||||
IKARUS_FAIL_IF_NULL(name, nullptr);
|
||||
|
||||
IKARUS_ASCERTAIN(nullptr, "entity doesn't exist", IkarusErrorInfo_Client_NonExistent, ikarus_entity_exists, entity);
|
||||
IKARUS_ASCERTAIN(
|
||||
nullptr,
|
||||
"entity doesn't have value",
|
||||
IkarusErrorInfo_Client_NotLinked,
|
||||
ikarus_entity_has_value,
|
||||
entity,
|
||||
name
|
||||
);
|
||||
|
||||
IKARUS_VTRYRV_OR_FAIL(
|
||||
auto value,
|
||||
nullptr,
|
||||
|
|
@ -326,10 +397,16 @@ void ikarus_entity_set_value(
|
|||
char const * value,
|
||||
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_FAIL_IF_NULL(value, IKARUS_VOID_RETURN);
|
||||
IKARUS_FAIL_IF_NAME_INVALID(name, IKARUS_VOID_RETURN);
|
||||
|
||||
IKARUS_ASCERTAIN(
|
||||
IKARUS_VOID_RETURN,
|
||||
"entity doesn't exist",
|
||||
IkarusErrorInfo_Client_NonExistent,
|
||||
ikarus_entity_exists,
|
||||
entity
|
||||
);
|
||||
|
||||
// parsing from & to here to ensure values are valid JSON & formatted
|
||||
// uniformly
|
||||
|
|
@ -338,7 +415,7 @@ void ikarus_entity_set_value(
|
|||
IKARUS_VOID_RETURN,
|
||||
"cannot parse value as JSON: {}",
|
||||
IkarusErrorInfo_Client_InvalidInput,
|
||||
IkarusValue::from_json(value)
|
||||
IkarusValue::from_json_str(value)
|
||||
);
|
||||
|
||||
IKARUS_TRYRV_OR_FAIL(
|
||||
|
|
@ -361,29 +438,64 @@ void ikarus_entity_delete_value(
|
|||
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_ASCERTAIN(
|
||||
IKARUS_VOID_RETURN,
|
||||
"entity doesn't exist",
|
||||
IkarusErrorInfo_Client_NonExistent,
|
||||
ikarus_entity_exists,
|
||||
entity
|
||||
);
|
||||
|
||||
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
|
||||
)
|
||||
entity->project->db->execute("DELETE FROM `entity_values` WHERE `entity` = ? AND `name` = ?", entity->id, name)
|
||||
);
|
||||
}
|
||||
|
||||
IkarusEntityPropertyValue * ikarus_entity_get_property_values(
|
||||
bool ikarus_entity_has_property_value(
|
||||
IkarusEntity * entity,
|
||||
size_t * size_out,
|
||||
struct IkarusProperty * property,
|
||||
IkarusErrorData * error_out
|
||||
) {
|
||||
IKARUS_FAIL_IF_NULL(entity, nullptr);
|
||||
IKARUS_FAIL_IF_NOT_EXIST(entity, nullptr);
|
||||
IKARUS_ASCERTAIN(false, "entity doesn't exist", IkarusErrorInfo_Client_NonExistent, ikarus_entity_exists, entity);
|
||||
|
||||
IKARUS_ASCERTAIN(
|
||||
false,
|
||||
"property doesn't exist",
|
||||
IkarusErrorInfo_Client_NonExistent,
|
||||
ikarus_property_exists,
|
||||
property
|
||||
);
|
||||
|
||||
IKARUS_FAIL_IF(
|
||||
entity->project != property->project,
|
||||
false,
|
||||
"property does not belong to entity's project",
|
||||
IkarusErrorInfo_Client_NotLinked
|
||||
);
|
||||
|
||||
IKARUS_VTRYRV_OR_FAIL(
|
||||
auto exists,
|
||||
false,
|
||||
"failed to check if entity has property value: {}",
|
||||
IkarusErrorInfo_Database_QueryFailed,
|
||||
entity->project->db->query_one<bool>(
|
||||
"SELECT EXISTS(SELECT 1 FROM `entity_property_values` WHERE `entity` = ? AND `property` = ?)",
|
||||
entity->id,
|
||||
property->id
|
||||
)
|
||||
);
|
||||
|
||||
return exists;
|
||||
}
|
||||
|
||||
IkarusEntityPropertyValue *
|
||||
ikarus_entity_get_property_values(IkarusEntity * entity, size_t * size_out, IkarusErrorData * error_out) {
|
||||
IKARUS_ASCERTAIN(false, "entity doesn't exist", IkarusErrorInfo_Client_NonExistent, ikarus_entity_exists, entity);
|
||||
|
||||
IKARUS_VTRYRV_OR_FAIL(
|
||||
auto values_plain,
|
||||
|
|
@ -391,24 +503,20 @@ IkarusEntityPropertyValue * ikarus_entity_get_property_values(
|
|||
"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` = ?",
|
||||
"SELECT `e`.`property`, IFNULL(`e`.`value`, ikarus_default_value(`p`.`schema`)) FROM `entity_property_values` AS `e` "
|
||||
"INNER JOIN `properties` AS `p` ON `p`.`id` = `e`.`property` "
|
||||
" WHERE `e`.`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) {
|
||||
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();
|
||||
|
|
@ -417,15 +525,23 @@ IkarusEntityPropertyValue * ikarus_entity_get_property_values(
|
|||
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);
|
||||
char const *
|
||||
ikarus_entity_get_property_value(IkarusEntity * entity, struct IkarusProperty * property, IkarusErrorData * error_out) {
|
||||
IKARUS_ASCERTAIN(false, "entity doesn't exist", IkarusErrorInfo_Client_NonExistent, ikarus_entity_exists, entity);
|
||||
IKARUS_ASCERTAIN(
|
||||
false,
|
||||
"property doesn't exist",
|
||||
IkarusErrorInfo_Client_NonExistent,
|
||||
ikarus_property_exists,
|
||||
property
|
||||
);
|
||||
|
||||
IKARUS_FAIL_IF(
|
||||
entity->project != property->project,
|
||||
nullptr,
|
||||
"property does not belong to entity's project",
|
||||
IkarusErrorInfo_Client_NotLinked
|
||||
);
|
||||
|
||||
IKARUS_VTRYRV_OR_FAIL(
|
||||
auto value,
|
||||
|
|
@ -433,7 +549,9 @@ char const * ikarus_entity_get_property_value(
|
|||
"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` = ?",
|
||||
"SELECT IFNULL(`e`.`value`, ikarus_default_value(`p`.`schema`)) FROM `entity_property_values` AS `e` "
|
||||
"INNER JOIN `properties` AS `p` ON `p`.`id` = `e`.`property` "
|
||||
"WHERE `e`.`entity` = ? AND `e`.`property` = ?",
|
||||
entity->id,
|
||||
property->id
|
||||
)
|
||||
|
|
@ -449,12 +567,38 @@ void ikarus_entity_set_property_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_ASCERTAIN(
|
||||
IKARUS_VOID_RETURN,
|
||||
"entity doesn't exist",
|
||||
IkarusErrorInfo_Client_NonExistent,
|
||||
ikarus_entity_exists,
|
||||
entity
|
||||
);
|
||||
IKARUS_ASCERTAIN(
|
||||
IKARUS_VOID_RETURN,
|
||||
"property doesn't exist",
|
||||
IkarusErrorInfo_Client_NonExistent,
|
||||
ikarus_property_exists,
|
||||
property
|
||||
);
|
||||
IKARUS_FAIL_IF_NULL(value, IKARUS_VOID_RETURN);
|
||||
|
||||
IKARUS_FAIL_IF(
|
||||
entity->project != property->project,
|
||||
IKARUS_VOID_RETURN,
|
||||
"property does not belong to entity's project",
|
||||
IkarusErrorInfo_Client_NotLinked
|
||||
);
|
||||
|
||||
IKARUS_ASCERTAIN(
|
||||
IKARUS_VOID_RETURN,
|
||||
"entity does not have property value",
|
||||
IkarusErrorInfo_Client_NotLinked,
|
||||
ikarus_entity_has_property_value,
|
||||
entity,
|
||||
property
|
||||
);
|
||||
|
||||
// parsing from & to here to ensure values are valid JSON & formatted
|
||||
// uniformly
|
||||
IKARUS_VTRYRV_OR_FAIL(
|
||||
|
|
@ -462,7 +606,7 @@ void ikarus_entity_set_property_value(
|
|||
IKARUS_VOID_RETURN,
|
||||
"cannot parse value as JSON: {}",
|
||||
IkarusErrorInfo_Client_InvalidInput,
|
||||
IkarusValue::from_json(value)
|
||||
IkarusValue::from_json_str(value)
|
||||
);
|
||||
|
||||
IKARUS_TRYRV_OR_FAIL(
|
||||
|
|
@ -478,3 +622,51 @@ void ikarus_entity_set_property_value(
|
|||
)
|
||||
);
|
||||
}
|
||||
|
||||
void ikarus_entity_clear_property_value(
|
||||
IkarusEntity * entity,
|
||||
struct IkarusProperty * property,
|
||||
IkarusEntitySetPropertyValueFlags flags,
|
||||
IkarusErrorData * error_out
|
||||
) {
|
||||
IKARUS_ASCERTAIN(
|
||||
IKARUS_VOID_RETURN,
|
||||
"entity doesn't exist",
|
||||
IkarusErrorInfo_Client_NonExistent,
|
||||
ikarus_entity_exists,
|
||||
entity
|
||||
);
|
||||
IKARUS_ASCERTAIN(
|
||||
IKARUS_VOID_RETURN,
|
||||
"property doesn't exist",
|
||||
IkarusErrorInfo_Client_NonExistent,
|
||||
ikarus_property_exists,
|
||||
property
|
||||
);
|
||||
|
||||
IKARUS_FAIL_IF(
|
||||
entity->project != property->project,
|
||||
IKARUS_VOID_RETURN,
|
||||
"property does not belong to entity's project",
|
||||
IkarusErrorInfo_Client_NotLinked
|
||||
);
|
||||
IKARUS_ASCERTAIN(
|
||||
IKARUS_VOID_RETURN,
|
||||
"entity doesn't have property",
|
||||
IkarusErrorInfo_Client_NotLinked,
|
||||
ikarus_entity_has_property_value,
|
||||
entity,
|
||||
property
|
||||
);
|
||||
|
||||
IKARUS_TRYRV_OR_FAIL(
|
||||
IKARUS_VOID_RETURN,
|
||||
"failed to clear property value for entity: {}",
|
||||
IkarusErrorInfo_Database_QueryFailed,
|
||||
entity->project->db->execute(
|
||||
"DELETE FROM `entity_property_values` WHERE `entity` = ? AND `property` = ?",
|
||||
entity->id,
|
||||
property->id
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,8 +26,7 @@ CREATE TABLE `properties`
|
|||
`blueprint` INTEGER NOT NULL REFERENCES `blueprints` (`id`) ON DELETE CASCADE,
|
||||
`name` TEXT NOT NULL,
|
||||
`schema` TEXT NOT NULL,
|
||||
`default_value` TEXT NOT NULL,
|
||||
`settings` TEXT NOT NULL
|
||||
`default_value` TEXT
|
||||
) STRICT;
|
||||
|
||||
CREATE TABLE `entity_blueprint_links`
|
||||
|
|
|
|||
|
|
@ -73,6 +73,49 @@ auto create_impl(
|
|||
.on_error(close_db)
|
||||
);
|
||||
|
||||
db->create_function(
|
||||
"ikarus_default_value",
|
||||
1,
|
||||
SQLITE_UTF8 | SQLITE_DETERMINISTIC,
|
||||
nullptr,
|
||||
[](sqlite3_context * ctx, int argc, sqlite3_value ** argv) {
|
||||
if (sqlite3_value_type(argv[0]) != SQLITE_TEXT) {
|
||||
sqlite3_result_error(
|
||||
ctx,
|
||||
"expected the 'schema' parameter to be of type text",
|
||||
SQLITE_MISMATCH
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
auto const schema_json =
|
||||
reinterpret_cast<char const *>(sqlite3_value_text(argv[0]));
|
||||
|
||||
auto schema_res = IkarusValueSchema::from_json_str(schema_json);
|
||||
|
||||
if (schema_res.is_error()) {
|
||||
sqlite3_result_error(
|
||||
ctx,
|
||||
"failed to parse schema",
|
||||
SQLITE_ERROR
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
auto schema = std::move(schema_res).unwrap_value();
|
||||
|
||||
auto default_value_json =
|
||||
IkarusValue::to_json(schema.default_value()).dump();
|
||||
|
||||
sqlite3_result_text(
|
||||
ctx,
|
||||
default_value_json.data(),
|
||||
default_value_json.size(),
|
||||
SQLITE_TRANSIENT
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
return std::move(db);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ auto get_primitive_type(IkarusValueDataPrimitive const & primitive)
|
|||
[](IkarusValueDataPrimitiveNumber const &) {
|
||||
return IkarusValuePrimitiveType_Number;
|
||||
},
|
||||
[](IkarusValueDataPrimitiveString const &) {
|
||||
[](IkarusValueDataPrimitiveText const &) {
|
||||
return IkarusValuePrimitiveType_Text;
|
||||
}
|
||||
},
|
||||
|
|
@ -36,7 +36,7 @@ auto IkarusValueData::from_json(nlohmann::json const & json)
|
|||
|
||||
IkarusValueData value{};
|
||||
|
||||
VTRY(
|
||||
CPPBASE_VTRY(
|
||||
auto type,
|
||||
deserialize_enum<IkarusValueDataType>(
|
||||
json,
|
||||
|
|
@ -48,7 +48,7 @@ auto IkarusValueData::from_json(nlohmann::json const & json)
|
|||
|
||||
switch (type) {
|
||||
case IkarusValueDataType_Primitive: {
|
||||
VTRY(
|
||||
CPPBASE_VTRY(
|
||||
auto primitive,
|
||||
deserialize_enum<IkarusValuePrimitiveType>(
|
||||
json,
|
||||
|
|
@ -60,21 +60,21 @@ auto IkarusValueData::from_json(nlohmann::json const & json)
|
|||
|
||||
switch (primitive) {
|
||||
case IkarusValuePrimitiveType_Toggle: {
|
||||
VTRY(auto data, deserialize_any<bool>(json, "data"));
|
||||
CPPBASE_VTRY(auto data, deserialize_any<bool>(json, "data"));
|
||||
|
||||
value.variant = IkarusValueDataPrimitiveToggle{data};
|
||||
break;
|
||||
}
|
||||
case IkarusValuePrimitiveType_Number: {
|
||||
VTRY(auto data, deserialize_any<double>(json, "data"));
|
||||
CPPBASE_VTRY(auto data, deserialize_any<double>(json, "data"));
|
||||
|
||||
value.variant = IkarusValueDataPrimitiveNumber{data};
|
||||
break;
|
||||
}
|
||||
case IkarusValuePrimitiveType_Text: {
|
||||
VTRY(auto data, deserialize_any<std::string>(json, "data"));
|
||||
CPPBASE_VTRY(auto data, deserialize_any<std::string>(json, "data"));
|
||||
|
||||
value.variant = IkarusValueDataPrimitiveString{data};
|
||||
value.variant = IkarusValueDataPrimitiveText{data};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -83,14 +83,17 @@ auto IkarusValueData::from_json(nlohmann::json const & json)
|
|||
}
|
||||
case IkarusValueDataType_List: {
|
||||
std::vector<cppbase::owning_ptr<IkarusValueData>> values_data{};
|
||||
VTRY(
|
||||
CPPBASE_VTRY(
|
||||
auto data_json,
|
||||
deserialize_any<std::vector<nlohmann::json>>(json, "data")
|
||||
);
|
||||
|
||||
values_data.reserve(data_json.size());
|
||||
for (auto const & data_json : data_json) {
|
||||
VTRY(auto value_data, IkarusValueData::from_json(data_json));
|
||||
CPPBASE_VTRY(
|
||||
auto value_data,
|
||||
IkarusValueData::from_json(data_json)
|
||||
);
|
||||
values_data.emplace_back(
|
||||
cppbase::make_owning<IkarusValueData>(std::move(value_data))
|
||||
);
|
||||
|
|
@ -105,7 +108,7 @@ auto IkarusValueData::from_json(nlohmann::json const & json)
|
|||
cppbase::owning_ptr<IkarusValueData>>>
|
||||
map_data{};
|
||||
|
||||
VTRY(
|
||||
CPPBASE_VTRY(
|
||||
auto map_data_json,
|
||||
deserialize_any<std::vector<nlohmann::json>>(json, "data")
|
||||
);
|
||||
|
|
@ -113,10 +116,10 @@ auto IkarusValueData::from_json(nlohmann::json const & json)
|
|||
map_data.reserve(map_data_json.size());
|
||||
|
||||
for (auto const & pair_json : map_data_json) {
|
||||
VTRY(auto key_json, get_key(pair_json, "key"));
|
||||
VTRY(auto value_json, get_key(pair_json, "value"));
|
||||
VTRY(auto key, IkarusValueData::from_json(*key_json));
|
||||
VTRY(auto value, IkarusValueData::from_json(*value_json));
|
||||
CPPBASE_VTRY(auto key_json, get_key(pair_json, "key"));
|
||||
CPPBASE_VTRY(auto value_json, get_key(pair_json, "value"));
|
||||
CPPBASE_VTRY(auto key, IkarusValueData::from_json(*key_json));
|
||||
CPPBASE_VTRY(auto value, IkarusValueData::from_json(*value_json));
|
||||
|
||||
map_data.emplace_back(
|
||||
cppbase::make_owning<IkarusValueData>(key),
|
||||
|
|
@ -130,7 +133,7 @@ auto IkarusValueData::from_json(nlohmann::json const & json)
|
|||
case IkarusValueDataType_Tuple: {
|
||||
std::vector<cppbase::owning_ptr<IkarusValueData>> values_data{};
|
||||
|
||||
VTRY(
|
||||
CPPBASE_VTRY(
|
||||
auto values_json,
|
||||
deserialize_any<std::vector<nlohmann::json>>(json, "data")
|
||||
);
|
||||
|
|
@ -138,7 +141,10 @@ auto IkarusValueData::from_json(nlohmann::json const & json)
|
|||
values_data.reserve(values_json.size());
|
||||
|
||||
for (auto const & value_json : values_json) {
|
||||
VTRY(auto value_data, IkarusValueData::from_json(value_json));
|
||||
CPPBASE_VTRY(
|
||||
auto value_data,
|
||||
IkarusValueData::from_json(value_json)
|
||||
);
|
||||
values_data.emplace_back(
|
||||
cppbase::make_owning<IkarusValueData>(value_data)
|
||||
);
|
||||
|
|
@ -152,6 +158,19 @@ auto IkarusValueData::from_json(nlohmann::json const & json)
|
|||
return cppbase::ok(value);
|
||||
}
|
||||
|
||||
auto IkarusValueData::from_json_str(std::string_view json_str)
|
||||
-> cppbase::Result<IkarusValueData, IkarusValueDataParseError> {
|
||||
auto json = nlohmann::json::parse(json_str, nullptr, false);
|
||||
|
||||
if (json.is_discarded()) {
|
||||
return cppbase::err(
|
||||
IkarusValueDataParseError{IkarusJsonError{IkarusJsonParseError{}}}
|
||||
);
|
||||
}
|
||||
|
||||
return IkarusValueData::from_json(json);
|
||||
}
|
||||
|
||||
auto IkarusValueData::to_json(IkarusValueData const & value) -> nlohmann::json {
|
||||
nlohmann::json json = nlohmann::json::object();
|
||||
|
||||
|
|
@ -170,7 +189,7 @@ auto IkarusValueData::to_json(IkarusValueData const & value) -> nlohmann::json {
|
|||
json["primitive"] = IkarusValuePrimitiveType_Number;
|
||||
json["data"] = number.value;
|
||||
},
|
||||
[&](IkarusValueDataPrimitiveString const & string) {
|
||||
[&](IkarusValueDataPrimitiveText const & string) {
|
||||
json["type"] = IkarusValueDataType_Primitive;
|
||||
json["primitive"] = IkarusValuePrimitiveType_Text;
|
||||
json["data"] = string.value;
|
||||
|
|
|
|||
|
|
@ -22,14 +22,14 @@ struct IkarusValueDataPrimitiveNumber {
|
|||
double value;
|
||||
};
|
||||
|
||||
struct IkarusValueDataPrimitiveString {
|
||||
struct IkarusValueDataPrimitiveText {
|
||||
std::string value;
|
||||
};
|
||||
|
||||
using IkarusValueDataPrimitive = std::variant<
|
||||
IkarusValueDataPrimitiveToggle,
|
||||
IkarusValueDataPrimitiveNumber,
|
||||
IkarusValueDataPrimitiveString>;
|
||||
IkarusValueDataPrimitiveText>;
|
||||
|
||||
struct IkarusValueDataList {
|
||||
std::vector<cppbase::owning_ptr<IkarusValueData>> values;
|
||||
|
|
@ -53,7 +53,9 @@ struct IkarusValueData {
|
|||
IkarusValueDataMap,
|
||||
IkarusValueDataTuple>;
|
||||
|
||||
static auto from_json(nlohmann::json const & json)
|
||||
static auto from_json(nlohmann::json const & json_str)
|
||||
-> cppbase::Result<IkarusValueData, IkarusValueDataParseError>;
|
||||
static auto from_json_str(std::string_view json_str)
|
||||
-> cppbase::Result<IkarusValueData, IkarusValueDataParseError>;
|
||||
static auto to_json(IkarusValueData const & value) -> nlohmann::json;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,12 +10,15 @@ struct IkarusJsonInvalidTypeError {};
|
|||
|
||||
struct IkarusJsonEnumOutOfBoundsError {};
|
||||
|
||||
struct IkarusJsonParseError {};
|
||||
|
||||
struct IkarusJsonUnknownError {};
|
||||
|
||||
using IkarusJsonError = std::variant<
|
||||
IkarusJsonMissingKeyError,
|
||||
IkarusJsonInvalidTypeError,
|
||||
IkarusJsonEnumOutOfBoundsError,
|
||||
IkarusJsonParseError,
|
||||
IkarusJsonUnknownError>;
|
||||
|
||||
struct IkarusValueSchemaParseError {
|
||||
|
|
@ -57,6 +60,16 @@ struct fmt::formatter<IkarusJsonInvalidTypeError> : formatter<string_view> {
|
|||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct fmt::formatter<IkarusJsonParseError> : formatter<string_view> {
|
||||
constexpr static auto format(
|
||||
[[maybe_unused]] IkarusJsonParseError const & error,
|
||||
fmt::format_context & ctx
|
||||
) {
|
||||
return fmt::format_to(ctx.out(), "buffer isn't valid JSON");
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct fmt::formatter<IkarusJsonEnumOutOfBoundsError> : formatter<string_view> {
|
||||
constexpr static auto format(
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include <ikarus/values/data.hpp>
|
||||
#include <ikarus/values/schema.h>
|
||||
#include <ikarus/values/shared.hpp>
|
||||
#include <ikarus/values/value.hpp>
|
||||
|
||||
auto IkarusValueSchema::from_json(nlohmann::json const & json)
|
||||
-> cppbase::Result<IkarusValueSchema, IkarusValueSchemaParseError> {
|
||||
|
|
@ -18,7 +19,7 @@ auto IkarusValueSchema::from_json(nlohmann::json const & json)
|
|||
|
||||
IkarusValueSchema schema{};
|
||||
|
||||
VTRY(
|
||||
CPPBASE_VTRY(
|
||||
auto type,
|
||||
deserialize_enum<IkarusValueSchemaType>(
|
||||
json,
|
||||
|
|
@ -30,7 +31,7 @@ auto IkarusValueSchema::from_json(nlohmann::json const & json)
|
|||
|
||||
switch (type) {
|
||||
case IkarusValueSchemaType_Primitive: {
|
||||
VTRY(
|
||||
CPPBASE_VTRY(
|
||||
auto primitive,
|
||||
deserialize_enum<IkarusValuePrimitiveType>(
|
||||
json,
|
||||
|
|
@ -43,15 +44,21 @@ auto IkarusValueSchema::from_json(nlohmann::json const & json)
|
|||
break;
|
||||
}
|
||||
case IkarusValueSchemaType_List: {
|
||||
VTRY(auto sub_schema, IkarusValueSchema::from_json(json["schema"]));
|
||||
CPPBASE_VTRY(
|
||||
auto sub_schema,
|
||||
IkarusValueSchema::from_json(json["schema"])
|
||||
);
|
||||
schema.variant = IkarusValueSchemaList{
|
||||
cppbase::make_owning<IkarusValueSchema>(std::move(sub_schema))
|
||||
};
|
||||
break;
|
||||
}
|
||||
case IkarusValueSchemaType_Map: {
|
||||
VTRY(auto key_schema, IkarusValueSchema::from_json(json["key_schema"]));
|
||||
VTRY(
|
||||
CPPBASE_VTRY(
|
||||
auto key_schema,
|
||||
IkarusValueSchema::from_json(json["key_schema"])
|
||||
);
|
||||
CPPBASE_VTRY(
|
||||
auto value_schema,
|
||||
IkarusValueSchema::from_json(json["value_schema"])
|
||||
);
|
||||
|
|
@ -62,7 +69,7 @@ auto IkarusValueSchema::from_json(nlohmann::json const & json)
|
|||
break;
|
||||
}
|
||||
case IkarusValueSchemaType_Tuple: {
|
||||
VTRY(
|
||||
CPPBASE_VTRY(
|
||||
auto sub_schemas_json,
|
||||
deserialize_any<std::vector<nlohmann::json>>(json, "schemas")
|
||||
);
|
||||
|
|
@ -71,7 +78,10 @@ auto IkarusValueSchema::from_json(nlohmann::json const & json)
|
|||
sub_schemas.reserve(sub_schemas_json.size());
|
||||
|
||||
for (auto const & sub_schema_json : sub_schemas_json) {
|
||||
VTRY(auto schema, IkarusValueSchema::from_json(sub_schema_json));
|
||||
CPPBASE_VTRY(
|
||||
auto schema,
|
||||
IkarusValueSchema::from_json(sub_schema_json)
|
||||
);
|
||||
sub_schemas.emplace_back(
|
||||
cppbase::make_owning<IkarusValueSchema>(std::move(schema))
|
||||
);
|
||||
|
|
@ -85,6 +95,19 @@ auto IkarusValueSchema::from_json(nlohmann::json const & json)
|
|||
return cppbase::ok(std::move(schema));
|
||||
}
|
||||
|
||||
auto IkarusValueSchema::from_json_str(std::string_view json_str)
|
||||
-> cppbase::Result<IkarusValueSchema, IkarusValueSchemaParseError> {
|
||||
auto json = nlohmann::json::parse(json_str, nullptr, false);
|
||||
|
||||
if (json.is_discarded()) {
|
||||
return cppbase::err(
|
||||
IkarusValueSchemaParseError{IkarusJsonError{IkarusJsonParseError{}}}
|
||||
);
|
||||
}
|
||||
|
||||
return IkarusValueSchema::from_json(json);
|
||||
}
|
||||
|
||||
auto IkarusValueSchema::to_json(IkarusValueSchema const & schema)
|
||||
-> nlohmann::json {
|
||||
nlohmann::json json = nlohmann::json::object();
|
||||
|
|
@ -173,3 +196,46 @@ auto IkarusValueSchema::validate(IkarusValueData const & data) const -> bool {
|
|||
data.variant
|
||||
);
|
||||
}
|
||||
|
||||
auto IkarusValueSchema::default_value_data() const -> IkarusValueData {
|
||||
return std::visit(
|
||||
cppbase::overloaded{
|
||||
[](IkarusValueSchemaPrimitive const & schema) -> IkarusValueData {
|
||||
switch (schema.type) {
|
||||
case IkarusValuePrimitiveType_Toggle: {
|
||||
return {{IkarusValueDataPrimitiveToggle{false}}};
|
||||
}
|
||||
case IkarusValuePrimitiveType_Number:
|
||||
return {{IkarusValueDataPrimitiveNumber{0.0}}};
|
||||
case IkarusValuePrimitiveType_Text:
|
||||
return {{IkarusValueDataPrimitiveText{""}}};
|
||||
}
|
||||
},
|
||||
[](IkarusValueSchemaList const & schema) -> IkarusValueData {
|
||||
return {IkarusValueDataList{{}}};
|
||||
},
|
||||
[](IkarusValueSchemaMap const & schema) -> IkarusValueData {
|
||||
return {IkarusValueDataMap{{}}};
|
||||
},
|
||||
[](IkarusValueSchemaTuple const & schema) -> IkarusValueData {
|
||||
IkarusValueDataTuple data{};
|
||||
data.values.reserve(schema.sub_schemas.size());
|
||||
|
||||
for (auto const & sub_schema : schema.sub_schemas) {
|
||||
data.values.emplace_back(
|
||||
cppbase::make_owning<IkarusValueData>(
|
||||
sub_schema->default_value().data
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return {data};
|
||||
}
|
||||
},
|
||||
variant
|
||||
);
|
||||
}
|
||||
|
||||
auto IkarusValueSchema::default_value() const -> IkarusValue {
|
||||
return IkarusValue{*this, default_value_data()};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,9 +42,13 @@ struct IkarusValueSchema {
|
|||
|
||||
static auto from_json(nlohmann::json const & json)
|
||||
-> cppbase::Result<IkarusValueSchema, IkarusValueSchemaParseError>;
|
||||
static auto from_json_str(std::string_view json_str)
|
||||
-> cppbase::Result<IkarusValueSchema, IkarusValueSchemaParseError>;
|
||||
static auto to_json(IkarusValueSchema const & value) -> nlohmann::json;
|
||||
|
||||
auto validate(IkarusValueData const & data) const -> bool;
|
||||
auto default_value_data() const -> IkarusValueData;
|
||||
auto default_value() const -> IkarusValue;
|
||||
|
||||
IkarusValueSchemaVariant variant;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ auto deserialize_enum(
|
|||
E min,
|
||||
E max
|
||||
) -> cppbase::Result<E, IkarusJsonError> {
|
||||
VTRY(auto iter, get_key(json, key));
|
||||
CPPBASE_VTRY(auto iter, get_key(json, key));
|
||||
|
||||
if (!iter->is_number_integer()) {
|
||||
return cppbase::err(IkarusJsonError{});
|
||||
|
|
@ -51,7 +51,7 @@ auto deserialize_enum(
|
|||
template<typename T>
|
||||
auto deserialize_any(nlohmann::json const & json, std::string_view key)
|
||||
-> cppbase::Result<T, IkarusJsonError> {
|
||||
VTRY(auto iter, get_key(json, key));
|
||||
CPPBASE_VTRY(auto iter, get_key(json, key));
|
||||
|
||||
try {
|
||||
return cppbase::ok(iter->get<T>());
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ auto IkarusValue::from_json(nlohmann::json const & json)
|
|||
|
||||
IkarusValue value{};
|
||||
|
||||
VTRY(value.schema, IkarusValueSchema::from_json(json["schema"]));
|
||||
VTRY(value.data, IkarusValueData::from_json(json["data"]));
|
||||
CPPBASE_VTRY(value.schema, IkarusValueSchema::from_json(json["schema"]));
|
||||
CPPBASE_VTRY(value.data, IkarusValueData::from_json(json["data"]));
|
||||
|
||||
if (!value.schema.validate(value.data)) {
|
||||
return cppbase::err(IkarusValueParseErrorDataSchemaMismatch{});
|
||||
|
|
@ -25,6 +25,19 @@ auto IkarusValue::from_json(nlohmann::json const & json)
|
|||
return cppbase::ok(std::move(value));
|
||||
}
|
||||
|
||||
auto IkarusValue::from_json_str(std::string_view json_str)
|
||||
-> cppbase::Result<IkarusValue, IkarusValueParseError> {
|
||||
auto json = nlohmann::json::parse(json_str, nullptr, false);
|
||||
|
||||
if (json.is_discarded()) {
|
||||
return cppbase::err(
|
||||
IkarusValueDataParseError{IkarusJsonError{IkarusJsonParseError{}}}
|
||||
);
|
||||
}
|
||||
|
||||
return IkarusValue::from_json(json);
|
||||
}
|
||||
|
||||
auto IkarusValue::to_json(IkarusValue const & value) -> nlohmann::json {
|
||||
nlohmann::json json = nlohmann::json::object();
|
||||
|
||||
|
|
|
|||
|
|
@ -14,5 +14,7 @@ struct IkarusValue {
|
|||
|
||||
static auto from_json(nlohmann::json const & json)
|
||||
-> cppbase::Result<IkarusValue, IkarusValueParseError>;
|
||||
static auto from_json_str(std::string_view json_str)
|
||||
-> cppbase::Result<IkarusValue, IkarusValueParseError>;
|
||||
static auto to_json(IkarusValue const & value) -> nlohmann::json;
|
||||
};
|
||||
|
|
|
|||
2
vendor/cppbase
vendored
2
vendor/cppbase
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit e7741e0e60f380f8b473c0881f3d8b4f23d0df91
|
||||
Subproject commit 82da6775fc56649cff6e611d6826a8e8fd321baa
|
||||
2
vendor/sqlitecpp
vendored
2
vendor/sqlitecpp
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 5bfd32f66164ed3d2c28003139fc5f76ef5e206d
|
||||
Subproject commit 5fd5731c98d6e260e35d05a59c99822e32fe7191
|
||||
Loading…
Add table
Add a link
Reference in a new issue