# Oat++ 1.1.0 Oat++ `1.1.0` is introducing breaking changes. Please read carefully to prepare for migration. Contents: - [No more explicit ObjectWrapper]() - [Object-Mapping Simplified Primitives]() - [Object-Mapping std Collections]() - [Type oatpp::Any]() - [Type oatpp::Enum] ## No more explicit ObjectWrapper Do not explicitly write `ObjectWrapper` DTO: ```cpp class MyDto : oatpp::Object { DTO_INIT(MyDto, Object) DTO_FIELD(MyDto, nested); DTO_FIELD(List, listOfAny); DTO_FIELD(Fields>, mapOfLists); } ``` ApiController: ```cpp ENDPOINT("POST", "body-dto", postWithBody, BODY_DTO(MyDto, body)) { ... } ``` ## Object-Mapping Simplified Primitives No more `->getValue()`. ```cpp oatpp::Int32 objV = 32; v_int32 v = objV; // You may check for nullptr before doing this bool equals = v == objV; // <--- NO NEED to check for nullptr here bool isNull = objV == nullptr; bool isNull = !objV; ``` ## Object-Mapping std Collections Now `oatpp::` are based on `std::` Example: ```cpp oatpp::Vector vector = oatpp::Vector::createShared(); oatpp::List list = oatpp::List::createShared(); oatpp::Fields pairList= oatpp::Fields::createShared(); oatpp::UnorderedFields hashMap = oatpp::UnorderedFields::createShared(); oatpp::Vector vector = {"a", "b", "c"}; oatpp::List list = {"a", "b", "c"}; oatpp::Fields pairList = {{"k1", "v1"}, {"k2", "v2"}, {"k3", "v3"}}; oatpp::UnorderedFields hashMap = {{"k1", "v1"}, {"k2", "v2"}, {"k3", "v3"}}; vector[0] = "z"; // <--- Complexity = O(1); vector->push_back("www"); list[0] = "z"; // <--- Complexity = O(n); list->push_back("www"); pairList["k1"] = "z"; // <--- Complexity = O(n); pairList->push_back({"key_z", "z"}); hashMap["k1"] = "z" // <--- Complexity = O(1); hashMap->insert({"key_z", "z"}); for(auto& item : *vector) { ... } for(auto& item : *list) { ... } for(auto& pair : *pairList) { ... } for(auto& pair : *hashMap) { ... } ``` ## Type oatpp::Any The new Type Introduced - `oatpp::Any`. Now it's possible to do like this: ```cpp class MyDto : public oatpp::Object { DTO_INIT(MyDto, Object) DTO_FIELD(Any, any); // Put any oatpp:: here DTO_FIELD(List, listOfAny) DTO_FIELD(Fields, mapOfAny); }; ``` ### JSON Serializer Will serialize Any depending on the value type it stores. ### JSON Deserializer Will try to guess the type of the `Any`. Currently, `Any` is deserialized as follows: - JSON objects are deserialized to `Any` holding `oatpp::Fields`. - JSON lists are deserialized to `Any` holding `oatpp::List`. - JSON `null` is deserialized to `Any` holding `nullptr`. - JSON `true`/`false` is deserialized to `Any` holding `oatpp::Boolean`. - JSON `number` is deserialized to `Any` holding `oatpp::Float64`. ### Example ```cpp oatpp::Fields map = { {"title", oatpp::String("Hello Any!")}, {"listOfAny", oatpp::List({ oatpp::Int32(32), oatpp::Float32(0.32), oatpp::Boolean(true) }) } }; auto json = mapper->writeToString(map); ``` **Output:** ```json { "title": "Hello Any!", "listOfAny": [ 32, 0.3199999928474426, true ] } ``` ## Object-Mapping Enum Enum is added to DTO codegen. ### Declaration ```cpp #include OATPP_CODEGEN_BEGIN(DTO) ENUM(Enum1, v_int32, // <-- type is mandatory VALUE(V_1, 1), // <-- integral value is mandatory VALUE(V_2, 2, "name-2"), VALUE(V_3, 3, "name-3", "description_3") ) #include OATPP_CODEGEN_END(DTO) ``` This will generate: ```cpp enum class Enum1 : v_int32 { V_1 = 1, V_2 = 2, V_3 = 3 } ... // PLUS Meta here ``` Current limitation - `ENUM` can not be declared nested in the class :(. This may be fixed later. ### Usage #### DTO ```cpp ENUM(MyEnum, v_int32, VALUE(V1, 10, "enum1-v1"), VALUE(V2, 20, "enum1-v2"), VALUE(V3, 30, "enum1-v3") ); class MyDto : public oatpp::Object { DTO_INIT(MyDto, Object) DTO_FIELD(Enum, enum1); // Default interpretation - AsString DTO_FIELD(Enum::NotNull, enum2); // NOT_NULL constraint for Ser/De DTO_FIELD(Enum::AsString, enum3); // Ser/De as string name DTO_FIELD(Enum::AsNumber, enum4); // Ser/De as a corresponding integral value DTO_FIELD(Enum::AsString::NotNull, enum5); DTO_FIELD(Enum::AsNumber::NotNull, enum6); }; ``` #### ApiController ```cpp ENDPOINT("GET", "enum/as-string", testEnumString, HEADER(Enum::AsString, enumValue, "X-MyEnum")) { return createResponse(Status::CODE_200, "OK"); } ENDPOINT("GET", "enum/as-number", testEnumNumber, HEADER(Enum::AsNumber, enumValue, "X-MyEnum")) { return createResponse(Status::CODE_200, "OK"); } ``` #### ApiClient ```cpp API_CALL("GET", "enum/as-string", getWithEnumHeaderAsString, HEADER(Enum::AsString, enumValue, "X-MyEnum")) API_CALL("GET", "enum/as-number", getWithEnumHeaderAsNumber, HEADER(Enum::AsNumber, enumValue, "X-MyEnum")) ``` ### Meta functions ```cpp { auto entry = oatpp::Enum::getEntryByName(""); auto entry = oatpp::Enum::getEntryByValue(MyEnum::VALUE); auto entry = oatpp::Enum::getEntryByUnderlyingValue(123); auto entry = oatpp::Enum::getEntryByIndex(0); ... OATPP_LOGD("Entry", "%d, %s, %d, %d, %s", entry.index, entry.name, entry.value, entry.description); } { const auto& entries = oatpp::Enum::getEntries(); for(const auto& e : entries) { ... } } ```