implement remaining logic

Signed-off-by: Folling <mail@folling.io>
This commit is contained in:
Folling 2024-01-03 17:14:26 +01:00 committed by Folling
parent e1bf97704a
commit 1ce811d566
No known key found for this signature in database
41 changed files with 1393 additions and 408 deletions

View file

@ -1,11 +1,13 @@
#include "ikarus/objects/blueprint.h"
#include "ikarus/objects/properties/property.h"
#include "objects/blueprint.hpp"
#include <cppbase/logger.hpp>
#include <cppbase/result.hpp>
#include <cppbase/strings.hpp>
#include <errors.hpp>
#include <objects/entity.hpp>
#include <objects/properties/property.hpp>
#include <persistence/project.hpp>
@ -13,117 +15,149 @@
IkarusBlueprint::IkarusBlueprint(IkarusProject * project, IkarusId id):
IkarusObject{project, id} {}
IkarusBlueprint * ikarus_blueprint_create(struct IkarusProject * project, char const * name) {
if (cppbase::is_empty_or_blank(name)) {
project->set_error("blueprint name must not be empty", true, IkarusErrorInfo_Source_Client, IkarusErrorInfo_Type_Client_Input);
IkarusBlueprint * ikarus_blueprint_create(struct IkarusProject * project, char const * name, IkarusErrorData * error_out) {
IKARUS_FAIL_IF_NULL(project, nullptr);
IKARUS_FAIL_IF_NULL(name, nullptr);
IKARUS_FAIL_IF(cppbase::is_empty_or_blank(name), nullptr, "name must not be empty", IkarusErrorInfo_Client_InvalidInput);
return nullptr;
}
project->db
->transact([name](auto * db) {
IKARUS_VTRYRV_OR_FAIL(
IkarusId const id,
nullptr,
"failed to create blueprint: {}",
IkarusErrorInfo_Database_QueryFailed,
project->db->transact([name](auto * db) -> cppbase::Result<IkarusId, sqlitecpp::TransactionError> {
TRY(db->execute("INSERT INTO `objects`(`type`, `name`) VALUES(?, ?, ?)", IkarusObjectType_Blueprint, name));
auto id = ikarus_id_from_data_and_type(db->last_insert_rowid(), IkarusObjectType_Blueprint);
TRY(db->execute("INSERT INTO `blueprints`(`id`) VALUES(?)", id));
return cppbase::ok();
return cppbase::ok(id);
})
.on_error([project](auto const & err) {
project->set_error(
fmt::format("failed to create blueprint: {}", err),
true,
IkarusErrorInfo_Source_SubSystem,
IkarusErrorInfo_Type_SubSystem_Database
);
});
);
return project->get_blueprint(id);
}
void ikarus_blueprint_delete(IkarusBlueprint * blueprint) {
blueprint->project->db->execute("DELETE FROM `objects` WHERE `id` = ?", blueprint->id).on_error([blueprint](auto const & err) {
blueprint->project->set_error(
fmt::format("failed to delete blueprint from objects table: {}", err),
true,
IkarusErrorInfo_Source_SubSystem,
IkarusErrorInfo_Type_SubSystem_Database
);
});
void ikarus_blueprint_delete(IkarusBlueprint * blueprint, IkarusErrorData * error_out) {
IKARUS_FAIL_IF_NULL(blueprint, );
IKARUS_FAIL_IF_OBJECT_MISSING(blueprint, );
IKARUS_TRYRV_OR_FAIL(
,
"unable to delete blueprint: {}",
IkarusErrorInfo_Database_QueryFailed,
blueprint->project->db->execute("DELETE FROM `objects` WHERE `id` = ?", blueprint->id)
);
blueprint->project->uncache(blueprint);
}
void ikarus_blueprint_get_properties(
IkarusBlueprint const * blueprint,
struct IkarusProperty ** properties_out,
size_t properties_out_size
size_t properties_out_size,
IkarusErrorData * error_out
) {
IkarusId ids[properties_out_size];
IKARUS_FAIL_IF_NULL(blueprint, );
IKARUS_FAIL_IF_OBJECT_MISSING(blueprint, );
IKARUS_FAIL_IF_NULL(properties_out, );
TRYRV(
if (properties_out_size == 0) {
return;
}
std::tuple<IkarusId, IkarusPropertyType> ids_and_types[properties_out_size];
IKARUS_TRYRV_OR_FAIL(
,
blueprint->project->db
->query_many_buffered<IkarusId>("SELECT `id` FROM `properties` WHERE `source` = ?", ids, properties_out_size, blueprint->id)
.on_error([&](auto const & err) {
blueprint->project->set_error(
fmt::format("failed to fetch blueprint properties from database: {}", err),
true,
IkarusErrorInfo_Source_SubSystem,
IkarusErrorInfo_Type_SubSystem_Database
);
})
);
"unable to fetch blueprint properties from database: {}",
IkarusErrorInfo_Database_QueryFailed,
blueprint->project->db->query_many_buffered<IkarusId, IkarusPropertyType>(
"SELECT `id` FROM `properties` WHERE `source` = ?",
ids_and_types,
properties_out_size,
blueprint->id
)
)
// not atomic, could be switched to two loops if necessary
for (size_t i = 0; i < properties_out_size; ++i) {
IkarusId id = ids[i];
VTRYRV(auto const type, , IkarusProperty::get_property_type(blueprint->project, id));
auto [id, type] = ids_and_types[i];
properties_out[i] = blueprint->project->get_property(id, type);
}
}
size_t ikarus_blueprint_get_property_count(IkarusBlueprint const * blueprint) {
return blueprint->project->db->query_one<int64_t>("SELECT COUNT(*) FROM `properties` WHERE `source` = ?", blueprint->id)
.unwrap_value_or(0);
size_t ikarus_blueprint_get_property_count(IkarusBlueprint const * blueprint, IkarusErrorData * error_out) {
IKARUS_FAIL_IF_NULL(blueprint, 0);
IKARUS_FAIL_IF_OBJECT_MISSING(blueprint, 0);
IKARUS_VTRYRV_OR_FAIL(
auto const ret,
0,
"unable to fetch blueprint property count from database: {}",
IkarusErrorInfo_Database_QueryFailed,
blueprint->project->db->query_one<int64_t>("SELECT COUNT(*) FROM `properties` WHERE `source` = ?", blueprint->id)
);
return ret;
}
void ikarus_blueprint_get_linked_entities(
IkarusBlueprint const * blueprint,
struct IkarusEntity ** entities_out,
size_t entities_out_size
size_t entities_out_size,
IkarusErrorData * error_out
) {
IKARUS_FAIL_IF_NULL(blueprint, );
IKARUS_FAIL_IF_OBJECT_MISSING(blueprint, );
IKARUS_FAIL_IF_NULL(entities_out, );
if (entities_out_size == 0) {
return;
}
IkarusId ids[entities_out_size];
TRYRV(
IKARUS_TRYRV_OR_FAIL(
,
blueprint->project->db
->query_many_buffered<IkarusId>(
"SELECT `entity` FROM `entity_blueprint_links` WHERE `blueprint` = ?",
ids,
entities_out_size,
blueprint->id
)
.on_error([&](auto const & err) {
blueprint->project->set_error(
fmt::format("failed to fetch linked entities from database: {}", err),
true,
IkarusErrorInfo_Source_SubSystem,
IkarusErrorInfo_Type_SubSystem_Database
);
})
);
"unable to fetch blueprint linked entities from database: {}",
IkarusErrorInfo_Database_QueryFailed,
blueprint->project->db->query_many_buffered<IkarusId>(
"SELECT `entity` FROM `entity_blueprint_links` WHERE `blueprint` = ?",
ids,
entities_out_size,
blueprint->id
)
)
for (size_t i = 0; i < entities_out_size; ++i) {
entities_out[i] = blueprint->project->get_entity(ids[i]);
}
}
size_t ikarus_blueprint_get_linked_entity_count(IkarusBlueprint const * blueprint) {
return blueprint->project->db->query_one<int64_t>("SELECT COUNT(*) FROM `entity_blueprint_links` WHERE `blueprint` = ?", blueprint->id)
.unwrap_value_or(0);
size_t ikarus_blueprint_get_linked_entity_count(IkarusBlueprint const * blueprint, IkarusErrorData * error_out) {
IKARUS_FAIL_IF_NULL(blueprint, 0);
IKARUS_FAIL_IF_OBJECT_MISSING(blueprint, 0);
IKARUS_VTRYRV_OR_FAIL(
auto const ret,
0,
"unable to fetch blueprint linked entity count from database: {}",
IkarusErrorInfo_Database_QueryFailed,
blueprint->project->db->query_one<int64_t>("SELECT COUNT(*) FROM `entity_blueprint_links` WHERE `blueprint` = ?", blueprint->id)
);
return ret;
}
IkarusObject * ikarus_blueprint_to_object(IkarusBlueprint * blueprint) {
// No existence checks here for performance reasons. All methods on IkarusObject perform this check anyway.
IkarusObject * ikarus_blueprint_to_object(IkarusBlueprint * blueprint, IkarusErrorData * error_out) {
IKARUS_FAIL_IF_NULL(blueprint, nullptr);
return static_cast<IkarusObject *>(blueprint);
}
IkarusObject const * ikarus_blueprint_to_object_const(IkarusBlueprint const * blueprint) {
IkarusObject const * ikarus_blueprint_to_object_const(IkarusBlueprint const * blueprint, IkarusErrorData * error_out) {
IKARUS_FAIL_IF_NULL(blueprint, nullptr);
return static_cast<IkarusObject const *>(blueprint);
}