125 lines
4.9 KiB
C++
125 lines
4.9 KiB
C++
#pragma once
|
|
|
|
#include <string_view>
|
|
|
|
#include <cppbase/strings.hpp>
|
|
|
|
#include <ikarus/errors.h>
|
|
#include <ikarus/errors.hpp>
|
|
#include <ikarus/objects/blueprint.hpp>
|
|
#include <ikarus/objects/entity.hpp>
|
|
#include <ikarus/objects/object.hpp>
|
|
#include <ikarus/objects/properties/property.h>
|
|
#include <ikarus/objects/properties/property.hpp>
|
|
#include <ikarus/objects/properties/property_scope.hpp>
|
|
#include <ikarus/persistence/project.hpp>
|
|
|
|
namespace ikarus::util {
|
|
|
|
template<typename O>
|
|
[[nodiscard]] IkarusProject * object_get_project(O const * object, IkarusErrorData * error_out) {
|
|
IKARUS_FAIL_IF_NULL(object, nullptr);
|
|
IKARUS_FAIL_IF_OBJECT_MISSING(object, nullptr);
|
|
|
|
return object->project;
|
|
}
|
|
|
|
template<typename O>
|
|
[[nodiscard]] char const * object_get_name(O const * object, IkarusErrorData * error_out) {
|
|
IKARUS_FAIL_IF_NULL(object, nullptr);
|
|
IKARUS_FAIL_IF_OBJECT_MISSING(object, nullptr);
|
|
|
|
IKARUS_VTRYRV_OR_FAIL(
|
|
auto const ret,
|
|
nullptr,
|
|
fmt::runtime(fmt::format("unable to fetch {} name: {{}}", ikarus_object_type_to_string(ikarus_id_get_object_type(object->id)))),
|
|
IkarusErrorInfo_Database_QueryFailed,
|
|
object->project->db
|
|
->template query_one<std::string>(fmt::format("SELECT `name` FROM `{}` WHERE `id` = ?", object->get_table_name()), object->id)
|
|
);
|
|
|
|
return strdup(ret.data());
|
|
}
|
|
|
|
[[nodiscard]] inline bool name_is_unique(
|
|
IkarusProject const * project,
|
|
std::string_view name,
|
|
[[maybe_unused]] IkarusBlueprint const * blueprint,
|
|
IkarusErrorData * error_out
|
|
) {
|
|
IKARUS_VTRYRV_OR_FAIL(
|
|
bool const exists,
|
|
false,
|
|
"unable to check if blueprint name is unique",
|
|
IkarusErrorInfo_Database_QueryFailed,
|
|
project->db->query_one<bool>("SELECT EXISTS(SELECT 1 FROM `blueprints` WHERE `name` = ?)", name)
|
|
);
|
|
|
|
return exists;
|
|
}
|
|
|
|
[[nodiscard]] inline bool name_is_unique(
|
|
IkarusProject const * project,
|
|
std::string_view name,
|
|
[[maybe_unused]] IkarusEntity const * entity,
|
|
IkarusErrorData * error_out
|
|
) {
|
|
IKARUS_VTRYRV_OR_FAIL(
|
|
bool const exists,
|
|
false,
|
|
"unable to check if entity name is unique",
|
|
IkarusErrorInfo_Database_QueryFailed,
|
|
project->db->query_one<bool>("SELECT EXISTS(SELECT 1 FROM `entities` WHERE `name` = ?)", name)
|
|
);
|
|
|
|
return exists;
|
|
}
|
|
|
|
[[nodiscard]] inline bool
|
|
name_is_unique(IkarusProject const * project, std::string_view name, IkarusPropertyScope const * scope, IkarusErrorData * error_out) {
|
|
IKARUS_VTRYRV_OR_FAIL(
|
|
bool const exists,
|
|
false,
|
|
"unable to check if property name is unique",
|
|
IkarusErrorInfo_Database_QueryFailed,
|
|
project->db->query_one<bool>("SELECT EXISTS(SELECT 1 FROM `properties` WHERE `name` = ? AND `scope` = ?)", name, scope->get_id())
|
|
);
|
|
|
|
return exists;
|
|
}
|
|
|
|
[[nodiscard]] inline bool
|
|
name_is_unique(IkarusProject * project, std::string_view name, IkarusProperty const * property, IkarusErrorData * error_out) {
|
|
std::unique_ptr<IkarusPropertyScope const> scope{ikarus_property_get_scope(property, error_out)};
|
|
IKARUS_FAIL_IF_ERROR(false);
|
|
|
|
return name_is_unique(project, name, scope.get(), error_out);
|
|
}
|
|
|
|
#define IKARUS_FAIL_IF_NAME_INVALID(name, project, object, 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( \
|
|
!ikarus::util::name_is_unique(project, name, object, error_out), \
|
|
ret, \
|
|
"name must be unique", \
|
|
IkarusErrorInfo_Client_InvalidInput \
|
|
); \
|
|
IKARUS_FAIL_IF_ERROR(ret);
|
|
|
|
template<typename O>
|
|
void object_set_name(O * object, char const * name, IkarusErrorData * error_out) {
|
|
IKARUS_FAIL_IF_NULL(object, );
|
|
IKARUS_FAIL_IF_OBJECT_MISSING(object, );
|
|
IKARUS_FAIL_IF_NULL(name, );
|
|
IKARUS_FAIL_IF_NAME_INVALID(name, object->project, object, );
|
|
|
|
IKARUS_TRYRV_OR_FAIL(
|
|
,
|
|
fmt::runtime(fmt::format("unable to set {} name: {{}}", ikarus_object_type_to_string(ikarus_id_get_object_type(object->id)))),
|
|
IkarusErrorInfo_Database_QueryFailed,
|
|
object->project->db->execute(fmt::format("UPDATE `{}` SET `name` = ? WHERE `id` = ?", object->get_table_name()), name, object->id)
|
|
);
|
|
}
|
|
|
|
} // namespace ikarus::util
|