#pragma once #include #include #include #include #include constexpr auto IKARUS_VALUE_JSON_TYPE_KEY = "type"; constexpr auto IKARUS_VALUE_JSON_CARDINALITY_KEY = "card"; constexpr auto IKARUS_VALUE_JSON_DATA_KEY = "data"; struct IkarusValue { public: using Data = std::variant; constexpr static auto SMALL_VEC_VALUE_SIZE = 8; public: explicit IkarusValue(Data data, IkarusValueCardinality cardinality); IkarusValue(IkarusValue const &) = default; IkarusValue(IkarusValue &&) noexcept = default; IkarusValue & operator=(IkarusValue const &) = default; IkarusValue & operator=(IkarusValue &&) noexcept = default; virtual ~IkarusValue() = default; public: struct FromJsonError {}; [[nodiscard]] static cppbase::Result from_json(boost::json::value json); [[nodiscard]] boost::json::value to_json() const; public: Data data; IkarusValueCardinality cardinality; }; template<> struct fmt::formatter { template constexpr static auto parse(FormatParseContext & ctx) { return ctx.end(); } constexpr static auto format([[maybe_unused]] IkarusValue::FromJsonError const & error, fmt::format_context & ctx) { return fmt::format_to(ctx.out(), "unable to parse ikarus value JSON"); } }; template IkarusValue * fetch_value_from_db(IkarusProject * project, IkarusErrorData * error_out, std::string_view query, Args &&... args) { IKARUS_VTRYRV_OR_FAIL( auto const value_str, nullptr, "unable to fetch entity property value from database: {}", IkarusErrorInfo_Database_QueryFailed, project->db->query_one(query, std::forward(args)...) ); boost::json::error_code ec{}; boost::json::value json_value = boost::json::parse(value_str, ec); if (ec) { IKARUS_SET_ERROR(fmt::format("invalid json is stored in database: {}", ec.message()), IkarusErrorInfo_Database_InvalidState); return nullptr; } IKARUS_VTRYRV_OR_FAIL( auto const ret, nullptr, "unable to fetch entity property value: {}", IkarusErrorInfo_LibIkarus_CannotPerformOperation, IkarusValue::from_json(std::move(json_value)) ); return ret; } #define IKARUS_FAIL_IF_VALUE_MISSING_IMPL(var_name, entity, name, ret) \ IKARUS_VTRYRV_OR_FAIL( \ bool const var_name, \ ret, \ "unable to check whether value exists: {}", \ IkarusErrorInfo_Database_QueryFailed, \ (entity)->project->db->template query_one( \ "SELECT EXISTS(SELECT 1 FROM `entity_values` WHERE `entity` = ? AND `name` = ?)", \ (entity)->id, \ name \ ) \ ) \ \ IKARUS_FAIL_IF(!(var_name), ret, "entity value does not exist", IkarusErrorInfo_Client_Misuse); #define IKARUS_FAIL_IF_VALUE_MISSING(entity, name, ret) IKARUS_FAIL_IF_VALUE_MISSING_IMPL(CPPBASE_UNIQUE_NAME(exists), entity, name, ret);