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