mirror of
https://github.com/oatpp/oatpp.git
synced 2025-04-24 19:10:23 +08:00
Add changelog/1.1.0.md
This commit is contained in:
parent
e0828a83ab
commit
b46bcfc7b1
256
changelog/1.1.0.md
Normal file
256
changelog/1.1.0.md
Normal file
@ -0,0 +1,256 @@
|
||||
# Oat++ 1.1.0
|
||||
|
||||
Oat++ `1.1.0` is introducing breaking changes.
|
||||
Please read carefully to prepare for migration.
|
||||
|
||||
## 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<Any>, listOfAny);
|
||||
DTO_FIELD(Fields<List<String>>, mapOfLists);
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
ApiController:
|
||||
|
||||
```cpp
|
||||
ENDPOINT("POST", "body-dto", postWithBody,
|
||||
BODY_DTO(MyDto, body)) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
## Object-Mapping type 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::<Type> here
|
||||
DTO_FIELD(List<Any>, listOfAny)
|
||||
DTO_FIELD(Fields<Any>, 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<Any>`.
|
||||
- JSON lists are deserialized to `Any` holding `oatpp::List<Any>`.
|
||||
- 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<oatpp::Any> map = {
|
||||
{"title", oatpp::String("Hello Any!")},
|
||||
{"listOfAny",
|
||||
oatpp::List<oatpp::Any>({
|
||||
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 Collections
|
||||
|
||||
Now `oatpp::<mapping-enabled-collections>` are based on `std::<collections>`
|
||||
|
||||
Example:
|
||||
|
||||
```cpp
|
||||
oatpp::Vector<oatpp::String> vector = oatpp::Vector<oatpp::String>::createShared();
|
||||
oatpp::List<oatpp::String> list = oatpp::List<oatpp::String>::createShared();
|
||||
oatpp::Fields<oatpp::String> pairList= oatpp::Fields<oatpp::String>::createShared();
|
||||
oatpp::UnorderedFields<oatpp::String> hashMap = oatpp::UnorderedFields<oatpp::String>::createShared();
|
||||
|
||||
oatpp::Vector<oatpp::String> vector = {"a", "b", "c"};
|
||||
oatpp::List<oatpp::String> list = {"a", "b", "c"};
|
||||
oatpp::Fields<oatpp::String> pairList = {{"k1", "v1"}, {"k2", "v2"}, {"k3", "v3"}};
|
||||
oatpp::UnorderedFields<oatpp::String> 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) {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
## Object-Mapping Simplified Primitives
|
||||
|
||||
No more `<primitive>->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 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<MyEnum>, enum1); // Default interpretation - AsString
|
||||
DTO_FIELD(Enum<MyEnum>::NotNull, enum2); // NOT_NULL constraint for Ser/De
|
||||
|
||||
DTO_FIELD(Enum<MyEnum>::AsString, enum3); // Ser/De as string name
|
||||
DTO_FIELD(Enum<MyEnum>::AsNumber, enum4); // Ser/De as a corresponding integral value
|
||||
|
||||
DTO_FIELD(Enum<MyEnum>::AsString::NotNull, enum5);
|
||||
DTO_FIELD(Enum<MyEnum>::AsNumber::NotNull, enum6);
|
||||
|
||||
};
|
||||
```
|
||||
|
||||
#### ApiController
|
||||
|
||||
```cpp
|
||||
ENDPOINT("GET", "enum/as-string", testEnumString,
|
||||
HEADER(Enum<AllowedHeaderValues>::AsString, enumValue, "X-MyEnum"))
|
||||
{
|
||||
return createResponse(Status::CODE_200, "OK");
|
||||
}
|
||||
|
||||
ENDPOINT("GET", "enum/as-number", testEnumNumber,
|
||||
HEADER(Enum<AllowedHeaderValues>::AsNumber, enumValue, "X-MyEnum"))
|
||||
{
|
||||
return createResponse(Status::CODE_200, "OK");
|
||||
}
|
||||
```
|
||||
|
||||
#### ApiClient
|
||||
|
||||
```cpp
|
||||
API_CALL("GET", "enum/as-string", getWithEnumHeaderAsString, HEADER(Enum<AllowedHeaderValues>::AsString, enumValue, "X-MyEnum"))
|
||||
API_CALL("GET", "enum/as-number", getWithEnumHeaderAsNumber, HEADER(Enum<AllowedHeaderValues>::AsNumber, enumValue, "X-MyEnum"))
|
||||
```
|
||||
|
||||
### Meta functions
|
||||
|
||||
```cpp
|
||||
{
|
||||
auto entry = oatpp::Enum<MyEnum>::getEntryByName("<name>");
|
||||
auto entry = oatpp::Enum<MyEnum>::getEntryByValue(MyEnum::VALUE);
|
||||
auto entry = oatpp::Enum<MyEnum>::getEntryByUnderlyingValue(123);
|
||||
auto entry = oatpp::Enum<MyEnum>::getEntryByIndex(0);
|
||||
...
|
||||
OATPP_LOGD("Entry", "%d, %s, %d, %d, %s", entry.index, entry.name, entry.value, entry.description);
|
||||
}
|
||||
|
||||
{
|
||||
const auto& entries = oatpp::Enum<MyEnum>::getEntries();
|
||||
for(const auto& e : entries) {
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
Loading…
x
Reference in New Issue
Block a user