#pragma once #include #include #include #include #include #include #include #include #include #include #include namespace ikarus::util { template [[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 [[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(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("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("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("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 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 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