mirror of
https://github.com/oatpp/oatpp.git
synced 2025-02-23 17:40:28 +08:00
commit
02c9fbf8e9
@ -20,7 +20,9 @@
|
||||
|
||||
**News**
|
||||
|
||||
- ⚠️ Attention! Oat++ main repo is bumping it's version to 1.4.0. While 1.4.0 is **IN DEVELOPMENT** use `1.3.0-latest` tag.
|
||||
- ⚠️ Attention! Oat++ main repo is bumping its version to 1.4.0. While 1.4.0 is **IN DEVELOPMENT** use `1.3.0-latest` tag.
|
||||
- Follow the [changelog](https://github.com/oatpp/oatpp/blob/master/changelog/1.4.0.md) for news and features in version `1.4.0`.
|
||||
- Consider supporting Oat++ via the [GitHub sponsors](https://github.com/sponsors/oatpp) page.
|
||||
|
||||
---
|
||||
|
||||
|
@ -8,6 +8,8 @@ Contents:
|
||||
|
||||
- [URL Encoder And Decoder](#url-encoder-and-decoder)
|
||||
- [Introduce async::ConditionVariable](#async-condition-variable)
|
||||
- [oatpp::Tree](#oatpptree)
|
||||
- [Remapper](#remapper)
|
||||
- [Restructuring](#restructuring)
|
||||
|
||||
|
||||
@ -49,6 +51,61 @@ OATPP_ASSERT(decoded == data)
|
||||
...
|
||||
```
|
||||
|
||||
## oatpp::Tree
|
||||
|
||||
New mapping-enabled type `oatpp::Tree` for flexible data access.
|
||||
|
||||
```cpp
|
||||
ENDPOINT("POST", "users", createUser,
|
||||
BODY_DTO(oatpp::Tree, user))
|
||||
{
|
||||
oatpp::String name = user["name"];
|
||||
v_uint16 age = user["age"];
|
||||
|
||||
auto& subs = user["subscriptions"].getVector();
|
||||
for(auto& s : subs) {
|
||||
...
|
||||
}
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Any node of oatpp::Tree can be mapped to DTO or to any mapping-enabled oatpp type - see [Remapper](#remapper)
|
||||
|
||||
## Remapper
|
||||
|
||||
`oatpp::data::mapping::Remapper`.
|
||||
|
||||
Remapper can be user to remap any oatpp type to any oatpp type.
|
||||
UnorderedFields can be mapped to DTOs, DTOs to vectors of values, vector items to other DTOs, DTOs to Trees, etc...
|
||||
|
||||
```cpp
|
||||
class User : public oatpp::DTO {
|
||||
|
||||
DTO_INIT(User, DTO)
|
||||
|
||||
DTO_FIELD(String, name);
|
||||
DTO_FIELD(UInt32, age);
|
||||
|
||||
};
|
||||
|
||||
...
|
||||
|
||||
oatpp::data::mapping::Remapper remapper;
|
||||
|
||||
auto user = User::createShared();
|
||||
user->name = "Jane";
|
||||
user->age = "25";
|
||||
|
||||
auto tree = remapper.remap<oatpp::Tree>(user); // remap to tree
|
||||
auto fields = remapper.remap<oatpp::Fields<oatpp::Tree>>(user); // remap to Fields
|
||||
auto otherDto = remapper.remap<oatpp::Object<OtherDto>>(user); // remap to OtherDto
|
||||
auto values = remapper.remap<oatpp::Vector<oatpp::Tree>>(user); // remap to Vector
|
||||
|
||||
oatpp::String name = values[0];
|
||||
v_uint32 age = values[1];
|
||||
```
|
||||
|
||||
## Restructuring
|
||||
|
||||
### Files
|
||||
|
@ -68,6 +68,8 @@ add_library(oatpp
|
||||
oatpp/data/buffer/IOBuffer.hpp
|
||||
oatpp/data/buffer/Processor.cpp
|
||||
oatpp/data/buffer/Processor.hpp
|
||||
oatpp/data/mapping/ObjectRemapper.cpp
|
||||
oatpp/data/mapping/ObjectRemapper.hpp
|
||||
oatpp/data/mapping/ObjectMapper.cpp
|
||||
oatpp/data/mapping/ObjectMapper.hpp
|
||||
oatpp/data/mapping/ObjectToTreeMapper.cpp
|
||||
|
@ -73,8 +73,9 @@ static v_int64 Z__PROPERTY_OFFSET_##NAME() { \
|
||||
static oatpp::data::type::BaseObject::Property* Z__PROPERTY_SINGLETON_##NAME() { \
|
||||
static oatpp::data::type::BaseObject::Property* property = \
|
||||
new oatpp::data::type::BaseObject::Property(Z__PROPERTY_OFFSET_##NAME(), \
|
||||
#NAME, \
|
||||
TYPE::Class::getType()); \
|
||||
#NAME, \
|
||||
#NAME, \
|
||||
TYPE::Class::getType()); \
|
||||
return property; \
|
||||
} \
|
||||
\
|
||||
@ -104,8 +105,9 @@ static v_int64 Z__PROPERTY_OFFSET_##NAME() { \
|
||||
static oatpp::data::type::BaseObject::Property* Z__PROPERTY_SINGLETON_##NAME() { \
|
||||
static oatpp::data::type::BaseObject::Property* property = \
|
||||
new oatpp::data::type::BaseObject::Property(Z__PROPERTY_OFFSET_##NAME(), \
|
||||
QUALIFIER, \
|
||||
TYPE::Class::getType()); \
|
||||
QUALIFIER, \
|
||||
#NAME, \
|
||||
TYPE::Class::getType()); \
|
||||
return property; \
|
||||
} \
|
||||
\
|
||||
|
@ -52,24 +52,27 @@ OATPP_MACRO_EXPAND(OATPP_MACRO_MACRO_SELECTOR(MACRO, (__VA_ARGS__)) (NAME, __VA_
|
||||
|
||||
#define OATPP_MACRO_DTO_ENUM_VALUE_1(NAME, VAL) \
|
||||
{ \
|
||||
oatpp::data::type::EnumValueInfo<EnumType> entry = {EnumType::NAME, index ++, #NAME, nullptr}; \
|
||||
oatpp::data::type::EnumValueInfo<EnumType> entry = {EnumType::NAME, index ++, #NAME, #NAME, nullptr}; \
|
||||
info.byName.insert({#NAME, entry}); \
|
||||
info.byUnqualifiedName.insert({#NAME, entry}); \
|
||||
info.byValue.insert({static_cast<v_uint64>(EnumType::NAME), entry}); \
|
||||
info.byIndex.push_back(entry); \
|
||||
}
|
||||
|
||||
#define OATPP_MACRO_DTO_ENUM_VALUE_2(NAME, VAL, QUALIFIER) \
|
||||
{ \
|
||||
oatpp::data::type::EnumValueInfo<EnumType> entry = {EnumType::NAME, index ++, QUALIFIER, nullptr}; \
|
||||
oatpp::data::type::EnumValueInfo<EnumType> entry = {EnumType::NAME, index ++, QUALIFIER, #NAME, nullptr}; \
|
||||
info.byName.insert({QUALIFIER, entry}); \
|
||||
info.byUnqualifiedName.insert({#NAME, entry}); \
|
||||
info.byValue.insert({static_cast<v_uint64>(EnumType::NAME), entry}); \
|
||||
info.byIndex.push_back(entry); \
|
||||
}
|
||||
|
||||
#define OATPP_MACRO_DTO_ENUM_VALUE_3(NAME, VAL, QUALIFIER, DESCRIPTION) \
|
||||
{ \
|
||||
oatpp::data::type::EnumValueInfo<EnumType> entry = {EnumType::NAME, index ++, QUALIFIER, DESCRIPTION}; \
|
||||
oatpp::data::type::EnumValueInfo<EnumType> entry = {EnumType::NAME, index ++, QUALIFIER, #NAME, DESCRIPTION}; \
|
||||
info.byName.insert({QUALIFIER, entry}); \
|
||||
info.byUnqualifiedName.insert({#NAME, entry}); \
|
||||
info.byValue.insert({static_cast<v_uint64>(EnumType::NAME), entry}); \
|
||||
info.byIndex.push_back(entry); \
|
||||
}
|
||||
|
107
src/oatpp/data/mapping/ObjectRemapper.cpp
Normal file
107
src/oatpp/data/mapping/ObjectRemapper.cpp
Normal file
@ -0,0 +1,107 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "ObjectRemapper.hpp"
|
||||
|
||||
namespace oatpp { namespace data { namespace mapping {
|
||||
|
||||
oatpp::Void ObjectRemapper::remap(const Tree& tree, const oatpp::Type* toType, ErrorStack& errorStack) const {
|
||||
TreeToObjectMapper::State state;
|
||||
state.tree = std::addressof(tree);
|
||||
state.config = &m_treeToObjectConfig;
|
||||
const auto & result = m_treeToObjectMapper.map(state, toType);
|
||||
if(!state.errorStack.empty()) {
|
||||
errorStack = std::move(state.errorStack);
|
||||
return nullptr;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
oatpp::Void ObjectRemapper::remap(const oatpp::Void& polymorph, const oatpp::Type* toType, ErrorStack& errorStack) const {
|
||||
|
||||
if(polymorph == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* if polymorph is a Tree - we can map it right away */
|
||||
if(polymorph.getValueType() == oatpp::Tree::Class::getType()) {
|
||||
auto tree = static_cast<const Tree*>(polymorph.get());
|
||||
return remap(*tree, toType, errorStack);
|
||||
}
|
||||
|
||||
Tree tree;
|
||||
|
||||
{
|
||||
ObjectToTreeMapper::State state;
|
||||
state.tree = &tree;
|
||||
state.config = &m_objectToTreeConfig;
|
||||
m_objectToTreeMapper.map(state, polymorph);
|
||||
if(!state.errorStack.empty()) {
|
||||
errorStack = std::move(state.errorStack);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* if expected type is a Tree (root element is a Tree) - then we can just move mapped tree */
|
||||
if(toType == data::type::Tree::Class::getType()) {
|
||||
return oatpp::Tree(std::move(tree));
|
||||
}
|
||||
|
||||
return remap(tree, toType, errorStack);
|
||||
|
||||
}
|
||||
|
||||
ObjectToTreeMapper::Config& ObjectRemapper::objectToTreeConfig() {
|
||||
return m_objectToTreeConfig;
|
||||
}
|
||||
|
||||
TreeToObjectMapper::Config& ObjectRemapper::treeToObjectConfig() {
|
||||
return m_treeToObjectConfig;
|
||||
}
|
||||
|
||||
ObjectToTreeMapper& ObjectRemapper::objectToTreeMapper() {
|
||||
return m_objectToTreeMapper;
|
||||
}
|
||||
|
||||
TreeToObjectMapper& ObjectRemapper::treeToObjectMapper() {
|
||||
return m_treeToObjectMapper;
|
||||
}
|
||||
|
||||
const ObjectToTreeMapper::Config& ObjectRemapper::objectToTreeConfig() const {
|
||||
return m_objectToTreeConfig;
|
||||
}
|
||||
|
||||
const TreeToObjectMapper::Config& ObjectRemapper::treeToObjectConfig() const {
|
||||
return m_treeToObjectConfig;
|
||||
}
|
||||
|
||||
const ObjectToTreeMapper& ObjectRemapper::objectToTreeMapper() const {
|
||||
return m_objectToTreeMapper;
|
||||
}
|
||||
|
||||
const TreeToObjectMapper& ObjectRemapper::treeToObjectMapper() const {
|
||||
return m_treeToObjectMapper;
|
||||
}
|
||||
|
||||
}}}
|
100
src/oatpp/data/mapping/ObjectRemapper.hpp
Normal file
100
src/oatpp/data/mapping/ObjectRemapper.hpp
Normal file
@ -0,0 +1,100 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef oatpp_data_mapping_ObjectRemapper_hpp
|
||||
#define oatpp_data_mapping_ObjectRemapper_hpp
|
||||
|
||||
#include "./ObjectToTreeMapper.hpp"
|
||||
#include "./TreeToObjectMapper.hpp"
|
||||
|
||||
#include "oatpp/Types.hpp"
|
||||
|
||||
namespace oatpp { namespace data { namespace mapping {
|
||||
|
||||
class ObjectRemapper {
|
||||
protected:
|
||||
ObjectToTreeMapper::Config m_objectToTreeConfig;
|
||||
TreeToObjectMapper::Config m_treeToObjectConfig;
|
||||
ObjectToTreeMapper m_objectToTreeMapper;
|
||||
TreeToObjectMapper m_treeToObjectMapper;
|
||||
public:
|
||||
|
||||
ObjectRemapper() = default;
|
||||
virtual ~ObjectRemapper() = default;
|
||||
|
||||
oatpp::Void remap(const Tree& tree, const oatpp::Type* toType, ErrorStack& errorStack) const;
|
||||
|
||||
template<class Wrapper>
|
||||
Wrapper remap(const Tree& tree, ErrorStack& errorStack) const {
|
||||
auto toType = Wrapper::Class::getType();
|
||||
return remap(tree, toType, errorStack).template cast<Wrapper>();
|
||||
}
|
||||
|
||||
template<class Wrapper>
|
||||
Wrapper remap(const Tree& tree) const {
|
||||
auto toType = Wrapper::Class::getType();
|
||||
ErrorStack errorStack;
|
||||
const auto& result = remap(tree, toType, errorStack).template cast<Wrapper>();
|
||||
if(!errorStack.empty()) {
|
||||
throw MappingError(std::move(errorStack));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
oatpp::Void remap(const oatpp::Void& polymorph, const oatpp::Type* toType, ErrorStack& errorStack) const;
|
||||
|
||||
template<class Wrapper>
|
||||
Wrapper remap(const oatpp::Void& polymorph, ErrorStack& errorStack) const {
|
||||
auto toType = Wrapper::Class::getType();
|
||||
return remap(polymorph, toType, errorStack).template cast<Wrapper>();
|
||||
}
|
||||
|
||||
template<class Wrapper>
|
||||
Wrapper remap(const oatpp::Void& polymorph) const {
|
||||
auto toType = Wrapper::Class::getType();
|
||||
ErrorStack errorStack;
|
||||
const auto& result = remap(polymorph, toType, errorStack).template cast<Wrapper>();
|
||||
if(!errorStack.empty()) {
|
||||
throw MappingError(std::move(errorStack));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ObjectToTreeMapper::Config& objectToTreeConfig();
|
||||
TreeToObjectMapper::Config& treeToObjectConfig();
|
||||
|
||||
ObjectToTreeMapper& objectToTreeMapper();
|
||||
TreeToObjectMapper& treeToObjectMapper();
|
||||
|
||||
const ObjectToTreeMapper::Config& objectToTreeConfig() const;
|
||||
const TreeToObjectMapper::Config& treeToObjectConfig() const;
|
||||
|
||||
const ObjectToTreeMapper& objectToTreeMapper() const;
|
||||
const TreeToObjectMapper& treeToObjectMapper() const;
|
||||
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif // oatpp_data_mapping_ObjectRemapper_hpp
|
@ -127,7 +127,7 @@ void ObjectToTreeMapper::mapEnum(const ObjectToTreeMapper* mapper, State& state,
|
||||
);
|
||||
|
||||
data::type::EnumInterpreterError e = data::type::EnumInterpreterError::OK;
|
||||
mapper->map(state, polymorphicDispatcher->toInterpretation(polymorph, e));
|
||||
mapper->map(state, polymorphicDispatcher->toInterpretation(polymorph, state.config->useUnqualifiedEnumNames, e));
|
||||
|
||||
if(e == data::type::EnumInterpreterError::OK) {
|
||||
return;
|
||||
@ -273,23 +273,28 @@ void ObjectToTreeMapper::mapObject(const ObjectToTreeMapper* mapper, State& stat
|
||||
}
|
||||
|
||||
if(field->info.required && value == nullptr) {
|
||||
oatpp::String key;
|
||||
state.config->useUnqualifiedFieldNames ? key = field->unqualifiedName : key = field->name;
|
||||
state.errorStack.push("[oatpp::data::mapping::ObjectToTreeMapper::mapObject()]: "
|
||||
"Error. " + std::string(type->nameQualifier) + "::"
|
||||
+ std::string(field->name) + " is required!");
|
||||
+ key + " is required!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (value || state.config->includeNullFields || (field->info.required && state.config->alwaysIncludeRequired)) {
|
||||
|
||||
oatpp::String key;
|
||||
state.config->useUnqualifiedFieldNames ? key = field->unqualifiedName : key = field->name;
|
||||
|
||||
State nestedState;
|
||||
nestedState.tree = childrenOperator.putPair(oatpp::String(field->name), {});
|
||||
nestedState.tree = childrenOperator.putPair(key, {});
|
||||
nestedState.config = state.config;
|
||||
|
||||
mapper->map(nestedState, value);
|
||||
|
||||
if(!nestedState.errorStack.empty()) {
|
||||
state.errorStack.splice(nestedState.errorStack);
|
||||
state.errorStack.push("[oatpp::data::mapping::ObjectToTreeMapper::mapObject()]: field='" + oatpp::String(field->name) + "'");
|
||||
state.errorStack.push("[oatpp::data::mapping::ObjectToTreeMapper::mapObject()]: field='" + key + "'");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -37,6 +37,8 @@ public:
|
||||
bool includeNullFields = true;
|
||||
bool alwaysIncludeRequired = false;
|
||||
bool alwaysIncludeNullCollectionElements = false;
|
||||
bool useUnqualifiedFieldNames = false;
|
||||
bool useUnqualifiedEnumNames = false;
|
||||
std::vector<std::string> enabledInterpretations = {};
|
||||
};
|
||||
|
||||
|
@ -36,8 +36,10 @@ Tree::Attributes::Attributes()
|
||||
{}
|
||||
|
||||
Tree::Attributes::Attributes(const Attributes& other)
|
||||
: m_attributes(other.m_attributes != nullptr ? new std::unordered_map<type::String, type::String>(*other.m_attributes) : nullptr)
|
||||
{}
|
||||
: Attributes()
|
||||
{
|
||||
operator=(other);
|
||||
}
|
||||
|
||||
Tree::Attributes::Attributes(Attributes&& other) noexcept
|
||||
: m_attributes(other.m_attributes)
|
||||
@ -46,37 +48,101 @@ Tree::Attributes::Attributes(Attributes&& other) noexcept
|
||||
}
|
||||
|
||||
Tree::Attributes& Tree::Attributes::operator = (const Attributes& other) {
|
||||
|
||||
if(other.m_attributes) {
|
||||
|
||||
if(m_attributes) {
|
||||
*m_attributes = *other.m_attributes;
|
||||
} else {
|
||||
m_attributes = new std::unordered_map<type::String, type::String>(*other.m_attributes);
|
||||
m_attributes = new Attrs(*other.m_attributes);
|
||||
}
|
||||
|
||||
for(auto & po : m_attributes->order){
|
||||
po.second = &m_attributes->map.at(po.first.lock());
|
||||
}
|
||||
|
||||
} else {
|
||||
delete m_attributes;
|
||||
m_attributes = nullptr;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Tree::Attributes& Tree::Attributes::operator = (Attributes&& other) noexcept {
|
||||
|
||||
delete m_attributes;
|
||||
|
||||
m_attributes = other.m_attributes;
|
||||
other.m_attributes = nullptr;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Tree::Attributes::~Attributes() {
|
||||
delete m_attributes;
|
||||
m_attributes = nullptr;
|
||||
}
|
||||
|
||||
void Tree::Attributes::initAttributes() {
|
||||
if(m_attributes == nullptr) {
|
||||
m_attributes = new Attrs();
|
||||
}
|
||||
}
|
||||
|
||||
type::String& Tree::Attributes::operator [] (const type::String& key) {
|
||||
initAttributes();
|
||||
auto it = m_attributes->map.find(key);
|
||||
if(it == m_attributes->map.end()) {
|
||||
auto& result = m_attributes->map[key];
|
||||
m_attributes->order.emplace_back(key.getPtr(), &result);
|
||||
return result;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
const type::String& Tree::Attributes::operator [] (const type::String& key) const {
|
||||
if(m_attributes != nullptr) {
|
||||
auto it = m_attributes->map.find(key);
|
||||
if (it != m_attributes->map.end()) {
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("[oatpp::data::mapping::Tree::Attributes::operator []]: const operator[] can't add items.");
|
||||
}
|
||||
|
||||
std::pair<type::String, std::reference_wrapper<type::String>> Tree::Attributes::operator [] (v_uint64 index) {
|
||||
if(m_attributes != nullptr) {
|
||||
auto &item = m_attributes->order.at(index);
|
||||
return {item.first.lock(), *item.second};
|
||||
}
|
||||
throw std::runtime_error("[oatpp::data::mapping::Tree::Attributes::operator []]: const operator[] can't get item - empty attributes.");
|
||||
}
|
||||
|
||||
std::pair<type::String, std::reference_wrapper<const type::String>> Tree::Attributes::operator [] (v_uint64 index) const {
|
||||
if(m_attributes != nullptr) {
|
||||
auto &item = m_attributes->order.at(index);
|
||||
return {item.first.lock(), *item.second};
|
||||
}
|
||||
throw std::runtime_error("[oatpp::data::mapping::Tree::Attributes::operator []]: const operator[] can't get item - empty attributes.");
|
||||
}
|
||||
|
||||
type::String Tree::Attributes::get(const type::String& key) const {
|
||||
if(m_attributes == nullptr) return nullptr;
|
||||
auto it = m_attributes->map.find(key);
|
||||
if(it != m_attributes->map.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Tree::Attributes::empty() const {
|
||||
return m_attributes == nullptr || m_attributes->empty();
|
||||
return m_attributes == nullptr || m_attributes->map.empty();
|
||||
}
|
||||
|
||||
v_uint64 Tree::Attributes::size() const {
|
||||
if(m_attributes) {
|
||||
return m_attributes->size();
|
||||
return m_attributes->map.size();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -725,13 +791,9 @@ TreeMap::TreeMap(TreeMap&& other) noexcept {
|
||||
|
||||
TreeMap& TreeMap::operator = (const TreeMap& other) {
|
||||
m_map = other.m_map;
|
||||
m_order.resize(other.m_order.size());
|
||||
for(v_uint64 i = 0; i < other.m_order.size(); i ++) {
|
||||
auto& po = other.m_order[i];
|
||||
auto& pt = m_order[i];
|
||||
pt.first = po.first;
|
||||
|
||||
pt.second = &m_map.at(po.first.lock());
|
||||
m_order = other.m_order;
|
||||
for(auto & po : m_order){
|
||||
po.second = &m_map.at(po.first.lock());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
@ -72,7 +72,14 @@ public:
|
||||
|
||||
class Attributes {
|
||||
private:
|
||||
std::unordered_map<type::String, type::String>* m_attributes;
|
||||
struct Attrs {
|
||||
std::unordered_map<type::String, type::String> map;
|
||||
std::vector<std::pair<std::weak_ptr<std::string>, type::String*>> order;
|
||||
};
|
||||
private:
|
||||
void initAttributes();
|
||||
private:
|
||||
Attrs* m_attributes;
|
||||
public:
|
||||
|
||||
Attributes();
|
||||
@ -84,8 +91,15 @@ public:
|
||||
|
||||
~Attributes();
|
||||
|
||||
bool empty() const;
|
||||
type::String& operator [] (const type::String& key);
|
||||
const type::String& operator [] (const type::String& key) const;
|
||||
|
||||
std::pair<type::String, std::reference_wrapper<type::String>> operator [] (v_uint64 index);
|
||||
std::pair<type::String, std::reference_wrapper<const type::String>> operator [] (v_uint64 index) const;
|
||||
|
||||
type::String get(const type::String& key) const;
|
||||
|
||||
bool empty() const;
|
||||
v_uint64 size() const;
|
||||
|
||||
};
|
||||
|
@ -177,7 +177,7 @@ oatpp::Void TreeToObjectMapper::mapEnum(const TreeToObjectMapper* mapper, State&
|
||||
state.errorStack.push("[oatpp::data::mapping::TreeToObjectMapper::mapEnum()]");
|
||||
return nullptr;
|
||||
}
|
||||
const auto& result = polymorphicDispatcher->fromInterpretation(value, e);
|
||||
const auto& result = polymorphicDispatcher->fromInterpretation(value, state.config->useUnqualifiedEnumNames, e);
|
||||
|
||||
if(e == data::type::EnumInterpreterError::OK) {
|
||||
return result;
|
||||
@ -287,7 +287,13 @@ oatpp::Void TreeToObjectMapper::mapObject(const TreeToObjectMapper* mapper, Stat
|
||||
|
||||
auto dispatcher = static_cast<const oatpp::data::type::__class::AbstractObject::PolymorphicDispatcher*>(type->polymorphicDispatcher);
|
||||
auto object = dispatcher->createObject();
|
||||
const auto& fieldsMap = dispatcher->getProperties()->getMap();
|
||||
const std::unordered_map<std::string, BaseObject::Property*>* fieldsMap;
|
||||
|
||||
if(state.config->useUnqualifiedFieldNames) {
|
||||
fieldsMap = std::addressof(dispatcher->getProperties()->getUnqualifiedMap());
|
||||
} else {
|
||||
fieldsMap = std::addressof(dispatcher->getProperties()->getMap());
|
||||
}
|
||||
|
||||
std::vector<std::pair<oatpp::BaseObject::Property*, const Tree*>> polymorphs;
|
||||
|
||||
@ -298,8 +304,8 @@ oatpp::Void TreeToObjectMapper::mapObject(const TreeToObjectMapper* mapper, Stat
|
||||
|
||||
const auto& pair = childrenOperator.getPair(i);
|
||||
|
||||
auto fieldIterator = fieldsMap.find(pair.first);
|
||||
if(fieldIterator != fieldsMap.end()){
|
||||
auto fieldIterator = fieldsMap->find(pair.first);
|
||||
if(fieldIterator != fieldsMap->end()){
|
||||
|
||||
auto field = fieldIterator->second;
|
||||
|
||||
|
@ -35,6 +35,8 @@ public:
|
||||
|
||||
struct Config {
|
||||
bool allowUnknownFields = true;
|
||||
bool useUnqualifiedFieldNames = false;
|
||||
bool useUnqualifiedEnumNames = false;
|
||||
std::vector<std::string> enabledInterpretations = {};
|
||||
};
|
||||
|
||||
|
@ -93,10 +93,10 @@ namespace __class {
|
||||
|
||||
virtual type::Void createObject() const = 0;
|
||||
|
||||
virtual type::Void toInterpretation(const type::Void& enumValue, EnumInterpreterError& error) const = 0;
|
||||
virtual type::Void fromInterpretation(const type::Void& interValue, EnumInterpreterError& error) const = 0;
|
||||
virtual type::Void toInterpretation(const type::Void& enumValue, bool useUnqualifiedNames, EnumInterpreterError& error) const = 0;
|
||||
virtual type::Void fromInterpretation(const type::Void& interValue, bool useUnqualifiedNames, EnumInterpreterError& error) const = 0;
|
||||
virtual type::Type* getInterpretationType() const = 0;
|
||||
virtual std::vector<type::Any> getInterpretedEnum() const = 0;
|
||||
virtual std::vector<type::Any> getInterpretedEnum(bool useUnqualifiedNames) const = 0;
|
||||
|
||||
};
|
||||
|
||||
@ -128,6 +128,12 @@ struct EnumValueInfo {
|
||||
* &id:oatpp::data::share::StringKeyLabel;.
|
||||
*/
|
||||
const data::share::StringKeyLabel name;
|
||||
|
||||
/**
|
||||
* Name of the enum entry <br>
|
||||
* &id:oatpp::data::share::StringKeyLabel;.
|
||||
*/
|
||||
const data::share::StringKeyLabel unqualifiedName;
|
||||
|
||||
/**
|
||||
* Description of the enum etry. <br>
|
||||
@ -141,6 +147,7 @@ struct EnumInfo {
|
||||
public:
|
||||
const char* nameQualifier = nullptr;
|
||||
std::unordered_map<data::share::StringKeyLabel, EnumValueInfo<T>> byName;
|
||||
std::unordered_map<data::share::StringKeyLabel, EnumValueInfo<T>> byUnqualifiedName;
|
||||
std::unordered_map<v_uint64, EnumValueInfo<T>> byValue;
|
||||
std::vector<EnumValueInfo<T>> byIndex;
|
||||
};
|
||||
@ -181,8 +188,8 @@ public:
|
||||
public:
|
||||
constexpr static bool notNull = notnull;
|
||||
public:
|
||||
static Void toInterpretation(const Void& enumValue, EnumInterpreterError& error);
|
||||
static Void fromInterpretation(const Void& interValue, EnumInterpreterError& error);
|
||||
static Void toInterpretation(const Void& enumValue, bool useUnqualifiedNames, EnumInterpreterError& error);
|
||||
static Void fromInterpretation(const Void& interValue, bool useUnqualifiedNames, EnumInterpreterError& error);
|
||||
static Type* getInterpretationType();
|
||||
};
|
||||
|
||||
@ -203,8 +210,8 @@ public:
|
||||
public:
|
||||
constexpr static bool notNull = notnull;
|
||||
public:
|
||||
static Void toInterpretation(const Void& enumValue, EnumInterpreterError& error);
|
||||
static Void fromInterpretation(const Void& interValue, EnumInterpreterError& error);
|
||||
static Void toInterpretation(const Void& enumValue, bool useUnqualifiedNames, EnumInterpreterError& error);
|
||||
static Void fromInterpretation(const Void& interValue, bool useUnqualifiedNames, EnumInterpreterError& error);
|
||||
static Type* getInterpretationType();
|
||||
};
|
||||
|
||||
@ -398,6 +405,20 @@ public:
|
||||
throw std::runtime_error("[oatpp::data::type::Enum::getEntryByName()]: Error. Entry not found.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get &l:EnumValueInfo <T>; by unqualified name.
|
||||
* @param name - name of the enum entry.
|
||||
* @return - &l:EnumValueInfo <T>;.
|
||||
* @throws - `std::runtime_error` if not found.
|
||||
*/
|
||||
static const EnumValueInfo<T>& getEntryByUnqualifiedName(const String& unqualifiedName) {
|
||||
auto it = EnumMeta<T>::getInfo()->byUnqualifiedName.find(unqualifiedName);
|
||||
if(it != EnumMeta<T>::getInfo()->byUnqualifiedName.end()) {
|
||||
return it->second;
|
||||
}
|
||||
throw std::runtime_error("[oatpp::data::type::Enum::getEntryByUnqualifiedName()]: Error. Entry not found.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get &l:EnumValueInfo <T>; by enum value.
|
||||
* @param value - enum value.
|
||||
@ -456,7 +477,7 @@ template <class T>
|
||||
using Enum = EnumObjectWrapper<T, EnumInterpreterAsString<T, false>>;
|
||||
|
||||
template<class T, bool notnull>
|
||||
Void EnumInterpreterAsString<T, notnull>::toInterpretation(const Void& enumValue, EnumInterpreterError& error) {
|
||||
Void EnumInterpreterAsString<T, notnull>::toInterpretation(const Void& enumValue, bool useUnqualifiedNames, EnumInterpreterError& error) {
|
||||
typedef EnumObjectWrapper<T, EnumInterpreterAsString<T, notnull>> EnumOW;
|
||||
|
||||
if(enumValue.getValueType() != EnumOW::Class::getType()) {
|
||||
@ -474,11 +495,14 @@ Void EnumInterpreterAsString<T, notnull>::toInterpretation(const Void& enumValue
|
||||
|
||||
const auto& ow = enumValue.template cast<EnumOW>();
|
||||
const auto& entry = EnumOW::getEntryByValue(*ow);
|
||||
if(useUnqualifiedNames) {
|
||||
return entry.unqualifiedName.toString();
|
||||
}
|
||||
return entry.name.toString();
|
||||
}
|
||||
|
||||
template<class T, bool notnull>
|
||||
Void EnumInterpreterAsString<T, notnull>::fromInterpretation(const Void& interValue, EnumInterpreterError& error) {
|
||||
Void EnumInterpreterAsString<T, notnull>::fromInterpretation(const Void& interValue, bool useUnqualifiedNames, EnumInterpreterError& error) {
|
||||
typedef EnumObjectWrapper<T, EnumInterpreterAsString<T, notnull>> EnumOW;
|
||||
|
||||
if(interValue.getValueType() != String::Class::getType()) {
|
||||
@ -495,6 +519,9 @@ Void EnumInterpreterAsString<T, notnull>::fromInterpretation(const Void& interVa
|
||||
}
|
||||
|
||||
try {
|
||||
if(useUnqualifiedNames) {
|
||||
return EnumOW(EnumOW::getEntryByUnqualifiedName(interValue.template cast<String>()).value);
|
||||
}
|
||||
return EnumOW(EnumOW::getEntryByName(interValue.template cast<String>()).value);
|
||||
} catch (const std::runtime_error&) { // TODO - add a specific error for this.
|
||||
error = EnumInterpreterError::ENTRY_NOT_FOUND;
|
||||
@ -508,8 +535,8 @@ Type* EnumInterpreterAsString<T, notnull>::getInterpretationType() {
|
||||
}
|
||||
|
||||
template<class T, bool notnull>
|
||||
Void EnumInterpreterAsNumber<T, notnull>::toInterpretation(const Void& enumValue, EnumInterpreterError& error) {
|
||||
|
||||
Void EnumInterpreterAsNumber<T, notnull>::toInterpretation(const Void& enumValue, bool useUnqualifiedNames, EnumInterpreterError& error) {
|
||||
(void) useUnqualifiedNames;
|
||||
typedef EnumObjectWrapper<T, EnumInterpreterAsNumber<T, notnull>> EnumOW;
|
||||
typedef typename std::underlying_type<T>::type EnumUT;
|
||||
typedef typename ObjectWrapperByUnderlyingType<EnumUT>::ObjectWrapper UTOW;
|
||||
@ -533,7 +560,8 @@ Void EnumInterpreterAsNumber<T, notnull>::toInterpretation(const Void& enumValue
|
||||
}
|
||||
|
||||
template<class T, bool notnull>
|
||||
Void EnumInterpreterAsNumber<T, notnull>::fromInterpretation(const Void& interValue, EnumInterpreterError& error) {
|
||||
Void EnumInterpreterAsNumber<T, notnull>::fromInterpretation(const Void& interValue, bool useUnqualifiedNames, EnumInterpreterError& error) {
|
||||
(void) useUnqualifiedNames;
|
||||
typedef EnumObjectWrapper<T, EnumInterpreterAsNumber<T, notnull>> EnumOW;
|
||||
|
||||
typedef typename std::underlying_type<T>::type EnumUT;
|
||||
@ -586,19 +614,19 @@ namespace __class {
|
||||
return type::Void(std::make_shared<T>(), getType());
|
||||
}
|
||||
|
||||
type::Void toInterpretation(const type::Void& enumValue, EnumInterpreterError& error) const override {
|
||||
return Interpreter::toInterpretation(enumValue, error);
|
||||
type::Void toInterpretation(const type::Void& enumValue, bool useUnqualifiedNames, EnumInterpreterError& error) const override {
|
||||
return Interpreter::toInterpretation(enumValue, useUnqualifiedNames, error);
|
||||
}
|
||||
|
||||
type::Void fromInterpretation(const type::Void& interValue, EnumInterpreterError& error) const override {
|
||||
return Interpreter::fromInterpretation(interValue, error);
|
||||
type::Void fromInterpretation(const type::Void& interValue, bool useUnqualifiedNames, EnumInterpreterError& error) const override {
|
||||
return Interpreter::fromInterpretation(interValue, useUnqualifiedNames, error);
|
||||
}
|
||||
|
||||
type::Type* getInterpretationType() const override {
|
||||
return Interpreter::getInterpretationType();
|
||||
}
|
||||
|
||||
std::vector<type::Any> getInterpretedEnum() const override {
|
||||
std::vector<type::Any> getInterpretedEnum(bool useUnqualifiedNames) const override {
|
||||
|
||||
typedef type::EnumObjectWrapper<T, Interpreter> EnumOW;
|
||||
|
||||
@ -606,7 +634,7 @@ namespace __class {
|
||||
|
||||
for(const auto& e : EnumOW::getEntries()) {
|
||||
type::EnumInterpreterError error = type::EnumInterpreterError::OK;
|
||||
result.push_back(type::Any(toInterpretation(EnumOW(e.value), error)));
|
||||
result.push_back(type::Any(toInterpretation(EnumOW(e.value), useUnqualifiedNames, error)));
|
||||
if(error != type::EnumInterpreterError::OK) {
|
||||
throw std::runtime_error("[oatpp::data::type::__class::Enum<T, Interpreter>::getInterpretedEnum()]: Unknown error.");
|
||||
}
|
||||
|
@ -58,33 +58,48 @@ void* BaseObject::getBasePointer() const {
|
||||
|
||||
BaseObject::Property* BaseObject::Properties::pushBack(Property* property) {
|
||||
m_map.insert({property->name, property});
|
||||
m_unqualifiedMap.insert({property->unqualifiedName, property});
|
||||
m_list.push_back(property);
|
||||
return property;
|
||||
}
|
||||
|
||||
void BaseObject::Properties::pushFrontAll(Properties* properties) {
|
||||
m_map.insert(properties->m_map.begin(), properties->m_map.end());
|
||||
m_unqualifiedMap.insert(properties->m_unqualifiedMap.begin(), properties->m_unqualifiedMap.end());
|
||||
m_list.insert(m_list.begin(), properties->m_list.begin(), properties->m_list.end());
|
||||
}
|
||||
|
||||
const std::unordered_map<std::string, BaseObject::Property*>& BaseObject::Properties::getMap() const {
|
||||
return m_map;
|
||||
}
|
||||
|
||||
const std::unordered_map<std::string, BaseObject::Property*>& BaseObject::Properties::getUnqualifiedMap() const {
|
||||
return m_unqualifiedMap;
|
||||
}
|
||||
|
||||
const std::list<BaseObject::Property*>& BaseObject::Properties::getList() const {
|
||||
return m_list;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// BaseObject::Property
|
||||
|
||||
BaseObject::Property::Property(v_int64 pOffset, const char* pName, const Type* pType)
|
||||
BaseObject::Property::Property(v_int64 pOffset, std::string pName, std::string pUName, const Type* pType)
|
||||
: offset(pOffset)
|
||||
, name(pName)
|
||||
, name(std::move(pName))
|
||||
, unqualifiedName(std::move(pUName))
|
||||
, type(pType)
|
||||
{}
|
||||
|
||||
void BaseObject::Property::set(BaseObject* object, const Void& value) {
|
||||
void BaseObject::Property::set(BaseObject* object, const Void& value) const {
|
||||
object->set(offset, value);
|
||||
}
|
||||
|
||||
Void BaseObject::Property::get(BaseObject* object) {
|
||||
Void BaseObject::Property::get(BaseObject* object) const {
|
||||
return object->get(offset);
|
||||
}
|
||||
|
||||
Void& BaseObject::Property::getAsRef(BaseObject* object) {
|
||||
Void& BaseObject::Property::getAsRef(BaseObject* object) const {
|
||||
return object->getAsRef(offset);
|
||||
}
|
||||
|
||||
|
@ -124,14 +124,21 @@ public:
|
||||
* Constructor.
|
||||
* @param pOffset - memory offset of object field from object start address.
|
||||
* @param pName - name of the property.
|
||||
* @param pUName - unqualified name of the property. Name of the class field in the code.
|
||||
* @param pType - &l:Type; of the property.
|
||||
*/
|
||||
Property(v_int64 pOffset, const char* pName, const Type* pType);
|
||||
Property(v_int64 pOffset, std::string pName, std::string pUName, const Type* pType);
|
||||
|
||||
/**
|
||||
* Property name.
|
||||
*/
|
||||
const char* const name;
|
||||
const std::string name;
|
||||
|
||||
/**
|
||||
* Unqualified property name.
|
||||
* Name of the class field that is used in the code.
|
||||
*/
|
||||
const std::string unqualifiedName;
|
||||
|
||||
/**
|
||||
* Property type.
|
||||
@ -148,21 +155,21 @@ public:
|
||||
* @param object - object address.
|
||||
* @param value - value to set.
|
||||
*/
|
||||
void set(BaseObject* object, const Void& value);
|
||||
void set(BaseObject* object, const Void& value) const;
|
||||
|
||||
/**
|
||||
* Get value of object field mapped by this property.
|
||||
* @param object - object address.
|
||||
* @return - value of the field.
|
||||
*/
|
||||
Void get(BaseObject* object);
|
||||
Void get(BaseObject* object) const;
|
||||
|
||||
/**
|
||||
* Get reference to ObjectWrapper of the object field.
|
||||
* @param object - object address.
|
||||
* @return - reference to ObjectWrapper of the object field.
|
||||
*/
|
||||
Void& getAsRef(BaseObject* object);
|
||||
Void& getAsRef(BaseObject* object) const;
|
||||
|
||||
};
|
||||
|
||||
@ -172,6 +179,7 @@ public:
|
||||
class Properties {
|
||||
private:
|
||||
std::unordered_map<std::string, Property*> m_map;
|
||||
std::unordered_map<std::string, Property*> m_unqualifiedMap;
|
||||
std::list<Property*> m_list;
|
||||
public:
|
||||
|
||||
@ -191,17 +199,19 @@ public:
|
||||
* Get properties as unordered map for random access.
|
||||
* @return reference to std::unordered_map of std::string to &id:oatpp::data::type::BaseObject::Property;*.
|
||||
*/
|
||||
const std::unordered_map<std::string, Property*>& getMap() const {
|
||||
return m_map;
|
||||
}
|
||||
const std::unordered_map<std::string, Property*>& getMap() const;
|
||||
|
||||
/**
|
||||
* Get properties as unordered map for random access by unqualified names.
|
||||
* @return reference to std::unordered_map of std::string to &id:oatpp::data::type::BaseObject::Property;*.
|
||||
*/
|
||||
const std::unordered_map<std::string, Property*>& getUnqualifiedMap() const;
|
||||
|
||||
/**
|
||||
* Get properties in ordered way.
|
||||
* @return std::list of &id:oatpp::data::type::BaseObject::Property;*.
|
||||
*/
|
||||
const std::list<Property*>& getList() const {
|
||||
return m_list;
|
||||
}
|
||||
const std::list<Property*>& getList() const;
|
||||
|
||||
};
|
||||
|
||||
@ -425,6 +435,7 @@ private:
|
||||
public:
|
||||
typedef oatpp::data::type::Void Void;
|
||||
typedef oatpp::data::type::Any Any;
|
||||
typedef oatpp::data::type::Tree Tree;
|
||||
typedef oatpp::data::type::String String;
|
||||
typedef oatpp::data::type::Int8 Int8;
|
||||
typedef oatpp::data::type::UInt8 UInt8;
|
||||
|
@ -123,6 +123,27 @@ bool Tree::operator != (const Tree& other) const {
|
||||
return !operator == (other);
|
||||
}
|
||||
|
||||
mapping::Tree* Tree::operator->() {
|
||||
if(!m_ptr) {
|
||||
m_ptr = std::make_shared<mapping::Tree>();
|
||||
}
|
||||
return m_ptr.get();
|
||||
}
|
||||
|
||||
mapping::Tree* Tree::operator->() const {
|
||||
if(!m_ptr) {
|
||||
throw std::runtime_error("[oatpp::data::type::Tree::operator ->()]: null-pointer exception");
|
||||
}
|
||||
return m_ptr.get();
|
||||
}
|
||||
|
||||
mapping::Tree& Tree::operator*() {
|
||||
if(!m_ptr) {
|
||||
m_ptr = std::make_shared<mapping::Tree>();
|
||||
}
|
||||
return *m_ptr;
|
||||
}
|
||||
|
||||
const mapping::Tree& Tree::operator*() const {
|
||||
if(!m_ptr) {
|
||||
throw std::runtime_error("[oatpp::data::type::Tree::operator *()]: null-pointer exception");
|
||||
@ -130,12 +151,32 @@ const mapping::Tree& Tree::operator*() const {
|
||||
return *m_ptr;
|
||||
}
|
||||
|
||||
mapping::Tree& Tree::operator*() {
|
||||
mapping::Tree& Tree::operator [] (const String& key) {
|
||||
if(!m_ptr) {
|
||||
throw std::runtime_error("[oatpp::data::type::Tree::operator *()]: null-pointer exception");
|
||||
m_ptr = std::make_shared<mapping::Tree>();
|
||||
}
|
||||
return *m_ptr;
|
||||
return (*m_ptr)[key];
|
||||
}
|
||||
|
||||
const mapping::Tree& Tree::operator [] (const String& key) const {
|
||||
if(!m_ptr) {
|
||||
throw std::runtime_error("[oatpp::data::type::Tree::operator []]: null-pointer exception");
|
||||
}
|
||||
return (*m_ptr)[key];
|
||||
}
|
||||
|
||||
mapping::Tree& Tree::operator [] (v_uint64 index) {
|
||||
if(!m_ptr) {
|
||||
m_ptr = std::make_shared<mapping::Tree>();
|
||||
}
|
||||
return (*m_ptr)[index];
|
||||
}
|
||||
|
||||
const mapping::Tree& Tree::operator [] (v_uint64 index) const {
|
||||
if(!m_ptr) {
|
||||
throw std::runtime_error("[oatpp::data::type::Tree::operator []]: null-pointer exception");
|
||||
}
|
||||
return (*m_ptr)[index];
|
||||
}
|
||||
|
||||
}}}
|
||||
|
@ -26,6 +26,7 @@
|
||||
#define oatpp_data_type_Tree_hpp
|
||||
|
||||
#include "./Type.hpp"
|
||||
#include "./Primitive.hpp"
|
||||
|
||||
namespace oatpp { namespace data { namespace mapping {
|
||||
|
||||
@ -108,8 +109,17 @@ public:
|
||||
bool operator == (const Tree& other) const;
|
||||
bool operator != (const Tree& other) const;
|
||||
|
||||
const mapping::Tree& operator*() const;
|
||||
mapping::Tree* operator->();
|
||||
mapping::Tree* operator->() const;
|
||||
|
||||
mapping::Tree& operator*();
|
||||
const mapping::Tree& operator*() const;
|
||||
|
||||
mapping::Tree& operator [] (const String& key);
|
||||
const mapping::Tree& operator [] (const String& key) const;
|
||||
|
||||
mapping::Tree& operator [] (v_uint64 index);
|
||||
const mapping::Tree& operator [] (v_uint64 index) const;
|
||||
|
||||
};
|
||||
|
||||
|
@ -86,7 +86,7 @@ oatpp::Void ObjectMapper::read(utils::parser::Caret& caret, const data::type::Ty
|
||||
|
||||
/* if expected type is Tree (root element is Tree) - then we can just move deserialized tree */
|
||||
if(type == data::type::Tree::Class::getType()) {
|
||||
return oatpp::Tree(tree);
|
||||
return oatpp::Tree(std::move(tree));
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -383,7 +383,7 @@ struct ApiClient::TypeInterpretation<data::type::EnumObjectWrapper<T, I>> {
|
||||
static oatpp::String toString(const oatpp::String &typeName, const EnumOW ¶meter) {
|
||||
|
||||
data::type::EnumInterpreterError error = data::type::EnumInterpreterError::OK;
|
||||
const auto& value = I::toInterpretation(parameter, error);
|
||||
const auto& value = I::toInterpretation(parameter, false, error);
|
||||
|
||||
switch(error){
|
||||
case data::type::EnumInterpreterError::OK: break;
|
||||
|
@ -558,7 +558,7 @@ struct ApiController::TypeInterpretation <data::type::EnumObjectWrapper<T, I>> {
|
||||
const auto& parsedValue = ApiController::TypeInterpretation<UTOW>::fromString(typeName, text, success);
|
||||
if(success) {
|
||||
data::type::EnumInterpreterError error = data::type::EnumInterpreterError::OK;
|
||||
const auto& result = I::fromInterpretation(parsedValue, error);
|
||||
const auto& result = I::fromInterpretation(parsedValue, false, error);
|
||||
if(error == data::type::EnumInterpreterError::OK) {
|
||||
return result.template cast<EnumOW>();
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ add_executable(oatppAllTests
|
||||
oatpp/base/CommandLineArgumentsTest.hpp
|
||||
oatpp/data/buffer/ProcessorTest.cpp
|
||||
oatpp/data/buffer/ProcessorTest.hpp
|
||||
oatpp/data/mapping/ObjectRemapperTest.cpp
|
||||
oatpp/data/mapping/ObjectRemapperTest.hpp
|
||||
oatpp/data/mapping/ObjectToTreeMapperTest.cpp
|
||||
oatpp/data/mapping/ObjectToTreeMapperTest.hpp
|
||||
oatpp/data/mapping/TreeTest.cpp
|
||||
|
@ -57,6 +57,7 @@
|
||||
#include "oatpp/data/mapping/TreeTest.hpp"
|
||||
#include "oatpp/data/mapping/ObjectToTreeMapperTest.hpp"
|
||||
#include "oatpp/data/mapping/TreeToObjectMapperTest.hpp"
|
||||
#include "oatpp/data/mapping/ObjectRemapperTest.hpp"
|
||||
|
||||
#include "oatpp/data/share/LazyStringMapTest.hpp"
|
||||
#include "oatpp/data/share/StringTemplateTest.hpp"
|
||||
@ -117,6 +118,7 @@ void runTests() {
|
||||
OATPP_RUN_TEST(oatpp::data::mapping::TreeTest);
|
||||
OATPP_RUN_TEST(oatpp::data::mapping::ObjectToTreeMapperTest);
|
||||
OATPP_RUN_TEST(oatpp::data::mapping::TreeToObjectMapperTest);
|
||||
OATPP_RUN_TEST(oatpp::data::mapping::ObjectRemapperTest);
|
||||
|
||||
OATPP_RUN_TEST(oatpp::data::type::ObjectWrapperTest);
|
||||
OATPP_RUN_TEST(oatpp::data::type::TypeTest);
|
||||
@ -245,8 +247,6 @@ void runTests() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
224
test/oatpp/data/mapping/ObjectRemapperTest.cpp
Normal file
224
test/oatpp/data/mapping/ObjectRemapperTest.cpp
Normal file
@ -0,0 +1,224 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "ObjectRemapperTest.hpp"
|
||||
|
||||
#include "oatpp/data/mapping/ObjectRemapper.hpp"
|
||||
|
||||
#include "oatpp/macro/codegen.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace oatpp { namespace data { namespace mapping {
|
||||
|
||||
namespace {
|
||||
|
||||
#include OATPP_CODEGEN_BEGIN(DTO)
|
||||
|
||||
ENUM(TestEnum1, v_int32,
|
||||
VALUE(VALUE_1, 1, "value-1"),
|
||||
VALUE(VALUE_2, 2, "value-2")
|
||||
)
|
||||
|
||||
ENUM(TestEnum2, v_int32,
|
||||
VALUE(VALUE_1, 1, "other-value-1"),
|
||||
VALUE(VALUE_2, 2, "other-value-2")
|
||||
)
|
||||
|
||||
class TestDto1 : public oatpp::DTO {
|
||||
|
||||
DTO_INIT(TestDto1, DTO)
|
||||
|
||||
DTO_FIELD(String, field1);
|
||||
DTO_FIELD(String, field2, "field-2");
|
||||
|
||||
DTO_FIELD(Enum<TestEnum1>, enum1);
|
||||
DTO_FIELD(Enum<TestEnum1>, enum2, "enum-2");
|
||||
|
||||
DTO_FIELD(Int32 , i32);
|
||||
|
||||
};
|
||||
|
||||
class TestDto2 : public oatpp::DTO {
|
||||
|
||||
DTO_INIT(TestDto2, DTO)
|
||||
|
||||
DTO_FIELD(String, field1);
|
||||
DTO_FIELD(String, field2, "other-field-2");
|
||||
|
||||
DTO_FIELD(Enum<TestEnum2>, enum1);
|
||||
DTO_FIELD(Enum<TestEnum2>, enum2, "other-enum-2");
|
||||
|
||||
};
|
||||
|
||||
#include OATPP_CODEGEN_END(DTO)
|
||||
|
||||
}
|
||||
|
||||
void ObjectRemapperTest::onRun() {
|
||||
|
||||
ObjectRemapper remapper;
|
||||
|
||||
{
|
||||
|
||||
OATPP_LOGD(TAG, "Remap. useUnqualifiedFieldNames = false; useUnqualifiedEnumNames = true")
|
||||
|
||||
remapper.objectToTreeConfig().useUnqualifiedFieldNames = false;
|
||||
remapper.treeToObjectConfig().useUnqualifiedFieldNames = false;
|
||||
|
||||
remapper.objectToTreeConfig().useUnqualifiedEnumNames = true;
|
||||
remapper.treeToObjectConfig().useUnqualifiedEnumNames = true;
|
||||
|
||||
auto obj1 = TestDto1::createShared();
|
||||
obj1->field1 = "f1";
|
||||
obj1->field2 = "f2";
|
||||
obj1->enum1 = TestEnum1::VALUE_1;
|
||||
obj1->enum2 = TestEnum1::VALUE_2;
|
||||
|
||||
ErrorStack errorStack;
|
||||
auto obj2 = remapper.remap<oatpp::Object<TestDto2>>(obj1, errorStack);
|
||||
if(!errorStack.empty()) {
|
||||
std::cout << *errorStack.stacktrace() << std::endl;
|
||||
}
|
||||
|
||||
OATPP_ASSERT(obj2->field1 == "f1")
|
||||
OATPP_ASSERT(obj2->field2 == nullptr)
|
||||
|
||||
OATPP_ASSERT(obj2->enum1 == TestEnum2::VALUE_1)
|
||||
OATPP_ASSERT(obj2->enum2 == nullptr)
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
OATPP_LOGD(TAG, "Remap. useUnqualifiedFieldNames = true; useUnqualifiedEnumNames = true")
|
||||
|
||||
remapper.objectToTreeConfig().useUnqualifiedFieldNames = true;
|
||||
remapper.treeToObjectConfig().useUnqualifiedFieldNames = true;
|
||||
|
||||
remapper.objectToTreeConfig().useUnqualifiedEnumNames = true;
|
||||
remapper.treeToObjectConfig().useUnqualifiedEnumNames = true;
|
||||
|
||||
auto obj1 = TestDto1::createShared();
|
||||
obj1->field1 = "f1";
|
||||
obj1->field2 = "f2";
|
||||
obj1->enum1 = TestEnum1::VALUE_1;
|
||||
obj1->enum2 = TestEnum1::VALUE_2;
|
||||
|
||||
ErrorStack errorStack;
|
||||
auto obj2 = remapper.remap<oatpp::Object<TestDto2>>(obj1, errorStack);
|
||||
if(!errorStack.empty()) {
|
||||
std::cout << *errorStack.stacktrace() << std::endl;
|
||||
}
|
||||
|
||||
OATPP_ASSERT(obj2->field1 == "f1")
|
||||
OATPP_ASSERT(obj2->field2 == "f2")
|
||||
|
||||
OATPP_ASSERT(obj2->enum1 == TestEnum2::VALUE_1)
|
||||
OATPP_ASSERT(obj2->enum2 == TestEnum2::VALUE_2)
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
OATPP_LOGD(TAG, "Remap. Object to Vector")
|
||||
|
||||
remapper.objectToTreeConfig().useUnqualifiedFieldNames = false;
|
||||
remapper.treeToObjectConfig().useUnqualifiedFieldNames = false;
|
||||
|
||||
remapper.objectToTreeConfig().useUnqualifiedEnumNames = false;
|
||||
remapper.treeToObjectConfig().useUnqualifiedEnumNames = false;
|
||||
|
||||
auto obj1 = TestDto1::createShared();
|
||||
obj1->field1 = "f1";
|
||||
obj1->field2 = "f2";
|
||||
obj1->enum1 = TestEnum1::VALUE_1;
|
||||
obj1->enum2 = TestEnum1::VALUE_2;
|
||||
obj1->i32 = nullptr;
|
||||
|
||||
ErrorStack errorStack;
|
||||
auto vec = remapper.remap<oatpp::Vector<oatpp::String>>(obj1, errorStack);
|
||||
if(!errorStack.empty()) {
|
||||
std::cout << *errorStack.stacktrace() << std::endl;
|
||||
}
|
||||
OATPP_ASSERT(vec[0] == "f1")
|
||||
OATPP_ASSERT(vec[1] == "f2")
|
||||
OATPP_ASSERT(vec[2] == "value-1")
|
||||
OATPP_ASSERT(vec[3] == "value-2")
|
||||
OATPP_ASSERT(vec[4] == nullptr)
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
OATPP_LOGD(TAG, "Remap tree fragments")
|
||||
|
||||
Tree tree;
|
||||
tree.setVector(3);
|
||||
|
||||
tree[0]["field_1"] = "val1";
|
||||
tree[0]["field_2"] = "val2";
|
||||
|
||||
tree[1]["field_1"] = "val1.2";
|
||||
tree[1]["field_2"] = "val2.2";
|
||||
|
||||
tree[2]["field_1"] = "val1.3";
|
||||
tree[2]["field_2"] = "val2.3";
|
||||
|
||||
{
|
||||
auto map = remapper.remap<oatpp::UnorderedFields<String>>(tree[0]);
|
||||
OATPP_ASSERT(map->size() == 2)
|
||||
OATPP_ASSERT(map["field_1"] == "val1")
|
||||
OATPP_ASSERT(map["field_2"] == "val2")
|
||||
}
|
||||
|
||||
{
|
||||
auto map = remapper.remap<oatpp::UnorderedFields<String>>(tree[1]);
|
||||
OATPP_ASSERT(map->size() == 2)
|
||||
OATPP_ASSERT(map["field_1"] == "val1.2")
|
||||
OATPP_ASSERT(map["field_2"] == "val2.2")
|
||||
}
|
||||
|
||||
{
|
||||
auto map = remapper.remap<oatpp::UnorderedFields<String>>(tree[2]);
|
||||
OATPP_ASSERT(map->size() == 2)
|
||||
OATPP_ASSERT(map["field_1"] == "val1.3")
|
||||
OATPP_ASSERT(map["field_2"] == "val2.3")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
oatpp::Tree tree;
|
||||
OATPP_ASSERT(tree == nullptr)
|
||||
|
||||
OATPP_ASSERT(tree->isUndefined()) // implicitly initialized
|
||||
OATPP_ASSERT(tree != nullptr)
|
||||
|
||||
tree["hello"] = "world";
|
||||
std::cout << *tree->debugPrint() << std::endl;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}}}
|
40
test/oatpp/data/mapping/ObjectRemapperTest.hpp
Normal file
40
test/oatpp/data/mapping/ObjectRemapperTest.hpp
Normal file
@ -0,0 +1,40 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef oatpp_data_mapping_ObjectRemapperTest_hpp
|
||||
#define oatpp_data_mapping_ObjectRemapperTest_hpp
|
||||
|
||||
#include "oatpp-test/UnitTest.hpp"
|
||||
|
||||
namespace oatpp { namespace data { namespace mapping {
|
||||
|
||||
class ObjectRemapperTest : public oatpp::test::UnitTest {
|
||||
public:
|
||||
ObjectRemapperTest() : UnitTest("TEST[oatpp::data::mapping::ObjectRemapperTest]") {}
|
||||
void onRun() override;
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif /* oatpp_data_mapping_ObjectRemapperTest_hpp */
|
@ -36,27 +36,32 @@ namespace {
|
||||
|
||||
#include OATPP_CODEGEN_BEGIN(DTO)
|
||||
|
||||
ENUM(TestEnum, v_int32,
|
||||
VALUE(VALUE_1, 1, "value-1"),
|
||||
VALUE(VALUE_2, 2, "value-2")
|
||||
)
|
||||
|
||||
class TestDto1 : public oatpp::DTO {
|
||||
|
||||
DTO_INIT(TestDto1, DTO)
|
||||
|
||||
DTO_FIELD(String, str);
|
||||
DTO_FIELD(String, str, "str-q");
|
||||
|
||||
DTO_FIELD(Int8, i8);
|
||||
DTO_FIELD(UInt8, ui8);
|
||||
DTO_FIELD(Int8, i8, "i8-q");
|
||||
DTO_FIELD(UInt8, ui8, "ui8-q");
|
||||
|
||||
DTO_FIELD(Int16, i16);
|
||||
DTO_FIELD(UInt16, ui16);
|
||||
DTO_FIELD(Int16, i16, "i16-q");
|
||||
DTO_FIELD(UInt16, ui16, "ui16-q");
|
||||
|
||||
DTO_FIELD(Int32, i32);
|
||||
DTO_FIELD(UInt32, ui32);
|
||||
DTO_FIELD(Int32, i32, "i32-q");
|
||||
DTO_FIELD(UInt32, ui32, "ui32-q");
|
||||
|
||||
DTO_FIELD(Int64, i64);
|
||||
DTO_FIELD(UInt64, ui64);
|
||||
DTO_FIELD(Int64, i64, "i64-q");
|
||||
DTO_FIELD(UInt64, ui64, "ui64-q");
|
||||
|
||||
DTO_FIELD(Vector<oatpp::Object<TestDto1>>, vector);
|
||||
DTO_FIELD(UnorderedFields<oatpp::Object<TestDto1>>, map);
|
||||
DTO_FIELD(Fields<String>, pairs);
|
||||
DTO_FIELD(Vector<oatpp::Object<TestDto1>>, vector, "vector-q");
|
||||
DTO_FIELD(UnorderedFields<oatpp::Object<TestDto1>>, map, "map-q");
|
||||
DTO_FIELD(Fields<String>, pairs, "pairs-q");
|
||||
|
||||
};
|
||||
|
||||
@ -105,7 +110,79 @@ void ObjectToTreeMapperTest::onRun() {
|
||||
}
|
||||
|
||||
{
|
||||
OATPP_LOGD(TAG, "Map Object")
|
||||
OATPP_LOGD(TAG, "Map Object qualified")
|
||||
config.useUnqualifiedFieldNames = false;
|
||||
|
||||
Tree tree;
|
||||
ObjectToTreeMapper::State state;
|
||||
state.tree = &tree;
|
||||
state.config = &config;
|
||||
|
||||
auto obj = TestDto1::createShared();
|
||||
|
||||
obj->str = "hello object";
|
||||
|
||||
obj->i8 = -8;
|
||||
obj->ui8 = 8;
|
||||
obj->i16 = -16;
|
||||
obj->ui16 = 16;
|
||||
obj->i32 = -32;
|
||||
obj->ui32 = 32;
|
||||
obj->i64 = -64;
|
||||
obj->ui64 = 64;
|
||||
|
||||
obj->vector = {TestDto1::createShared(), TestDto1::createShared(), TestDto1::createShared()};
|
||||
obj->map = {{"key1", TestDto1::createShared()}, {"key2", TestDto1::createShared()}, {"key3", TestDto1::createShared()}};
|
||||
obj->pairs = {{"same-key", "value1"}, {"same-key", "value2"}, {"same-key", "value3"}};
|
||||
|
||||
obj->vector[0]->str = "vec-item-1";
|
||||
obj->vector[1]->str = "vec-item-2";
|
||||
obj->vector[2]->str = "vec-item-3";
|
||||
|
||||
obj->map["key1"]->i64 = 1;
|
||||
obj->map["key2"]->i64 = 2;
|
||||
obj->map["key3"]->i64 = 3;
|
||||
|
||||
mapper.map(state, obj);
|
||||
|
||||
OATPP_ASSERT(state.errorStack.empty())
|
||||
|
||||
std::cout << *tree.debugPrint() << std::endl;
|
||||
|
||||
OATPP_ASSERT(tree.getType() == Tree::Type::MAP)
|
||||
|
||||
OATPP_ASSERT(tree["str-q"].getString() == "hello object")
|
||||
OATPP_ASSERT(tree["i8-q"].getValue<v_int8>() == -8)
|
||||
OATPP_ASSERT(tree["ui8-q"].getValue<v_uint8>() == 8)
|
||||
OATPP_ASSERT(tree["i16-q"].getValue<v_int16>() == -16)
|
||||
OATPP_ASSERT(tree["ui16-q"].getValue<v_uint16>() == 16)
|
||||
OATPP_ASSERT(tree["i32-q"].getValue<v_int32>() == -32)
|
||||
OATPP_ASSERT(tree["ui32-q"].getValue<v_uint32>() == 32)
|
||||
OATPP_ASSERT(tree["i64-q"].getValue<v_int64>() == -64)
|
||||
OATPP_ASSERT(tree["ui64-q"].getValue<v_uint64>() == 64)
|
||||
|
||||
OATPP_ASSERT(tree["vector-q"].getVector().size() == 3)
|
||||
OATPP_ASSERT(tree["vector-q"][0]["str-q"].getString() == "vec-item-1")
|
||||
OATPP_ASSERT(tree["vector-q"][1]["str-q"].getString() == "vec-item-2")
|
||||
OATPP_ASSERT(tree["vector-q"][2]["str-q"].getString() == "vec-item-3")
|
||||
|
||||
OATPP_ASSERT(tree["map-q"].getMap().size() == 3)
|
||||
OATPP_ASSERT(tree["map-q"]["key1"]["i64-q"].getValue<v_int64>() == 1)
|
||||
OATPP_ASSERT(tree["map-q"]["key2"]["i64-q"].getValue<v_int64>() == 2)
|
||||
OATPP_ASSERT(tree["map-q"]["key3"]["i64-q"].getValue<v_int64>() == 3)
|
||||
|
||||
auto& pairs = tree["pairs-q"].getPairs();
|
||||
OATPP_ASSERT(pairs.size() == 3)
|
||||
OATPP_ASSERT(pairs[0].first == "same-key" && pairs[0].second.getString() == "value1")
|
||||
OATPP_ASSERT(pairs[1].first == "same-key" && pairs[1].second.getString() == "value2")
|
||||
OATPP_ASSERT(pairs[2].first == "same-key" && pairs[2].second.getString() == "value3")
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
OATPP_LOGD(TAG, "Map Object unqualified")
|
||||
config.useUnqualifiedFieldNames = true;
|
||||
|
||||
Tree tree;
|
||||
ObjectToTreeMapper::State state;
|
||||
state.tree = &tree;
|
||||
@ -172,6 +249,42 @@ void ObjectToTreeMapperTest::onRun() {
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
OATPP_LOGD(TAG, "Map Enum qualified")
|
||||
config.useUnqualifiedEnumNames = false;
|
||||
|
||||
Tree tree;
|
||||
ObjectToTreeMapper::State state;
|
||||
state.tree = &tree;
|
||||
state.config = &config;
|
||||
|
||||
oatpp::Enum<TestEnum> enumObj(TestEnum::VALUE_1);
|
||||
|
||||
mapper.map(state, enumObj);
|
||||
|
||||
std::cout << *tree.debugPrint() << std::endl;
|
||||
|
||||
OATPP_ASSERT(tree.getString() == "value-1");
|
||||
}
|
||||
|
||||
{
|
||||
OATPP_LOGD(TAG, "Map Enum Unqualified")
|
||||
config.useUnqualifiedEnumNames = true;
|
||||
|
||||
Tree tree;
|
||||
ObjectToTreeMapper::State state;
|
||||
state.tree = &tree;
|
||||
state.config = &config;
|
||||
|
||||
oatpp::Enum<TestEnum> enumObj = oatpp::Enum<TestEnum>::getEntryByUnqualifiedName("VALUE_2").value;
|
||||
|
||||
mapper.map(state, enumObj);
|
||||
|
||||
std::cout << *tree.debugPrint() << std::endl;
|
||||
|
||||
OATPP_ASSERT(tree.getString() == "VALUE_2");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}}}
|
||||
|
@ -36,6 +36,8 @@ namespace {
|
||||
template<typename T>
|
||||
void testTreeValue(T value) {
|
||||
|
||||
OATPP_LOGD("TEST", "Test value retrieval for '%s'", Tree::NodePrimitiveType<T>::name)
|
||||
|
||||
Tree node;
|
||||
|
||||
//node.setValue<T>(value);
|
||||
@ -70,6 +72,7 @@ void TreeTest::onRun() {
|
||||
testTreeValue<v_float64>(16);
|
||||
|
||||
{
|
||||
OATPP_LOGD(TAG, "Case 1")
|
||||
Tree node;
|
||||
oatpp::String original = "Hello World!";
|
||||
node.setString(original);
|
||||
@ -79,6 +82,7 @@ void TreeTest::onRun() {
|
||||
}
|
||||
|
||||
{
|
||||
OATPP_LOGD(TAG, "Case 2")
|
||||
Tree node1;
|
||||
Tree node2;
|
||||
|
||||
@ -93,6 +97,7 @@ void TreeTest::onRun() {
|
||||
}
|
||||
|
||||
{
|
||||
OATPP_LOGD(TAG, "Case 3")
|
||||
Tree node1;
|
||||
Tree node2;
|
||||
|
||||
@ -105,6 +110,7 @@ void TreeTest::onRun() {
|
||||
}
|
||||
|
||||
{
|
||||
OATPP_LOGD(TAG, "Case 4")
|
||||
std::vector<Tree> originalVector(10);
|
||||
for(v_uint32 i = 0; i < 10; i ++) {
|
||||
originalVector.at(i).setValue(i);
|
||||
@ -132,6 +138,7 @@ void TreeTest::onRun() {
|
||||
}
|
||||
|
||||
{
|
||||
OATPP_LOGD(TAG, "Case 5")
|
||||
TreeMap originalMap;
|
||||
for(v_uint32 i = 0; i < 10; i ++) {
|
||||
originalMap["node_" + utils::Conversion::int32ToStr(static_cast<v_int32>(i))].setValue(i);
|
||||
@ -156,6 +163,7 @@ void TreeTest::onRun() {
|
||||
}
|
||||
|
||||
{
|
||||
OATPP_LOGD(TAG, "Case 6")
|
||||
Tree article;
|
||||
oatpp::Tree ot;
|
||||
|
||||
@ -176,6 +184,120 @@ void TreeTest::onRun() {
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
OATPP_LOGD(TAG, "Attributes Case 1")
|
||||
OATPP_LOGD(TAG, "size of Tree::Attributes='%lu'", sizeof(Tree::Attributes))
|
||||
|
||||
Tree::Attributes attr;
|
||||
|
||||
attr["key1"] = "value1";
|
||||
attr["key1"] = "value1.2";
|
||||
attr["key2"] = "value2";
|
||||
|
||||
OATPP_ASSERT(attr.size() == 2)
|
||||
|
||||
OATPP_ASSERT(attr["key1"] == "value1.2")
|
||||
OATPP_ASSERT(attr["key2"] == "value2")
|
||||
OATPP_ASSERT(attr["key3"] == nullptr) // key3 added
|
||||
|
||||
OATPP_ASSERT(attr.size() == 3)
|
||||
|
||||
OATPP_ASSERT(attr[0].second.get() == "value1.2")
|
||||
OATPP_ASSERT(attr[1].second.get() == "value2")
|
||||
OATPP_ASSERT(attr[2].second.get() == nullptr)
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
OATPP_LOGD(TAG, "Attributes Case 2")
|
||||
|
||||
Tree::Attributes attr1;
|
||||
Tree::Attributes attr2;
|
||||
|
||||
attr1["key1"] = "value1";
|
||||
attr1["key2"] = "value2";
|
||||
attr1["key3"] = nullptr;
|
||||
|
||||
attr2["key1"] = "v1";
|
||||
attr2["key2"] = "v2";
|
||||
|
||||
attr2 = attr1;
|
||||
|
||||
attr1["key1"] = "1";
|
||||
attr1["key2"] = "2";
|
||||
attr1["key3"] = "3";
|
||||
|
||||
OATPP_ASSERT(attr1[0].second.get() == "1")
|
||||
OATPP_ASSERT(attr1[1].second.get() == "2")
|
||||
OATPP_ASSERT(attr1[2].second.get() == "3")
|
||||
|
||||
OATPP_ASSERT(attr1["key1"] == "1")
|
||||
OATPP_ASSERT(attr1["key2"] == "2")
|
||||
OATPP_ASSERT(attr1["key3"] == "3")
|
||||
|
||||
OATPP_ASSERT(attr2[0].second.get() == "value1")
|
||||
OATPP_ASSERT(attr2[1].second.get() == "value2")
|
||||
OATPP_ASSERT(attr2[2].second.get() == nullptr)
|
||||
|
||||
OATPP_ASSERT(attr2["key1"] == "value1")
|
||||
OATPP_ASSERT(attr2["key2"] == "value2")
|
||||
OATPP_ASSERT(attr2["key3"] == nullptr)
|
||||
|
||||
Tree::Attributes attr3;
|
||||
attr2 = attr3;
|
||||
|
||||
OATPP_ASSERT(attr2.empty())
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
OATPP_LOGD(TAG, "Attributes Case 3")
|
||||
|
||||
Tree tree1;
|
||||
Tree tree2;
|
||||
|
||||
tree1 = "hello";
|
||||
tree2 = "world";
|
||||
|
||||
tree1.attributes()["key1"] = "value1";
|
||||
tree1.attributes()["key2"] = "value2";
|
||||
tree1.attributes()["key3"] = nullptr;
|
||||
|
||||
tree2.attributes()["key1"] = "v1";
|
||||
tree2.attributes()["key2"] = "v2";
|
||||
|
||||
tree2 = tree1;
|
||||
|
||||
tree1.attributes()["key1"] = "1";
|
||||
tree1.attributes()["key2"] = "2";
|
||||
tree1.attributes()["key3"] = "3";
|
||||
|
||||
OATPP_ASSERT(tree1.attributes()[0].second.get() == "1")
|
||||
OATPP_ASSERT(tree1.attributes()[1].second.get() == "2")
|
||||
OATPP_ASSERT(tree1.attributes()[2].second.get() == "3")
|
||||
|
||||
OATPP_ASSERT(tree1.attributes()["key1"] == "1")
|
||||
OATPP_ASSERT(tree1.attributes()["key2"] == "2")
|
||||
OATPP_ASSERT(tree1.attributes()["key3"] == "3")
|
||||
|
||||
OATPP_ASSERT(tree2.attributes()[0].second.get() == "value1")
|
||||
OATPP_ASSERT(tree2.attributes()[1].second.get() == "value2")
|
||||
OATPP_ASSERT(tree2.attributes()[2].second.get() == nullptr)
|
||||
|
||||
OATPP_ASSERT(tree2.attributes()["key1"] == "value1")
|
||||
OATPP_ASSERT(tree2.attributes()["key2"] == "value2")
|
||||
OATPP_ASSERT(tree2.attributes()["key3"] == nullptr)
|
||||
|
||||
Tree tree3;
|
||||
tree2 = tree3;
|
||||
|
||||
OATPP_ASSERT(tree2.attributes().empty())
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}}}
|
||||
|
@ -38,27 +38,32 @@ namespace {
|
||||
|
||||
#include OATPP_CODEGEN_BEGIN(DTO)
|
||||
|
||||
ENUM(TestEnum, v_int32,
|
||||
VALUE(VALUE_1, 1, "value-1"),
|
||||
VALUE(VALUE_2, 2, "value-2")
|
||||
)
|
||||
|
||||
class TestDto1 : public oatpp::DTO {
|
||||
|
||||
DTO_INIT(TestDto1, DTO)
|
||||
|
||||
DTO_FIELD(String, str);
|
||||
DTO_FIELD(String, str, "str-q");
|
||||
|
||||
DTO_FIELD(Int8, i8);
|
||||
DTO_FIELD(UInt8, ui8);
|
||||
DTO_FIELD(Int8, i8, "i8-q");
|
||||
DTO_FIELD(UInt8, ui8, "ui8-q");
|
||||
|
||||
DTO_FIELD(Int16, i16);
|
||||
DTO_FIELD(UInt16, ui16);
|
||||
DTO_FIELD(Int16, i16, "i16-q");
|
||||
DTO_FIELD(UInt16, ui16, "ui16-q");
|
||||
|
||||
DTO_FIELD(Int32, i32);
|
||||
DTO_FIELD(UInt32, ui32);
|
||||
DTO_FIELD(Int32, i32, "i32-q");
|
||||
DTO_FIELD(UInt32, ui32, "ui32-q");
|
||||
|
||||
DTO_FIELD(Int64, i64);
|
||||
DTO_FIELD(UInt64, ui64);
|
||||
DTO_FIELD(Int64, i64, "i64-q");
|
||||
DTO_FIELD(UInt64, ui64, "ui64-q");
|
||||
|
||||
DTO_FIELD(Vector<oatpp::Object<TestDto1>>, vector);
|
||||
DTO_FIELD(UnorderedFields<oatpp::Object<TestDto1>>, map);
|
||||
DTO_FIELD(Fields<String>, pairs);
|
||||
DTO_FIELD(Vector<oatpp::Object<TestDto1>>, vector, "vector-q");
|
||||
DTO_FIELD(UnorderedFields<oatpp::Object<TestDto1>>, map, "map-q");
|
||||
DTO_FIELD(Fields<String>, pairs, "pairs-q");
|
||||
|
||||
};
|
||||
|
||||
@ -79,6 +84,86 @@ void TreeToObjectMapperTest::onRun() {
|
||||
ObjectToTreeMapper::Config reverseConfig;
|
||||
|
||||
{
|
||||
OATPP_LOGD(TAG, "Map Object qualified")
|
||||
config.useUnqualifiedFieldNames = false;
|
||||
|
||||
Tree tree;
|
||||
|
||||
tree["str-q"] = "Hello World!";
|
||||
tree["i8-q"] = -8;
|
||||
tree["ui8-q"] = 8;
|
||||
tree["i16-q"] = -16;
|
||||
tree["ui16-q"] = 16;
|
||||
tree["i32-q"] = -32;
|
||||
tree["ui32-q"] = 32;
|
||||
tree["i64-q"] = -64;
|
||||
tree["ui64-q"] = 64;
|
||||
|
||||
tree["vector-q"].setVector(3);
|
||||
tree["vector-q"][0]["str-q"] = "nested_1 (in vector)";
|
||||
tree["vector-q"][1]["str-q"] = "nested_2 (in vector)";
|
||||
tree["vector-q"][2]["str-q"] = "nested_3 (in vector)";
|
||||
|
||||
tree["map-q"]["nested_1"]["i32-q"] = 1;
|
||||
tree["map-q"]["nested_2"]["i32-q"] = 2;
|
||||
tree["map-q"]["nested_3"]["i32-q"] = 3;
|
||||
|
||||
auto& pairs = tree["pairs-q"].getPairs();
|
||||
pairs.push_back({"same-key", {}});
|
||||
pairs.push_back({"same-key", {}});
|
||||
pairs.push_back({"same-key", {}});
|
||||
|
||||
pairs[0].second = "value1";
|
||||
pairs[1].second = "value2";
|
||||
pairs[2].second = "value3";
|
||||
|
||||
TreeToObjectMapper::State state;
|
||||
state.config = &config;
|
||||
state.tree = &tree;
|
||||
|
||||
const auto& polymorph = mapper.map(state,oatpp::Object<TestDto1>::Class::getType());
|
||||
|
||||
if(state.errorStack.empty()) {
|
||||
auto json = jsonMapper.writeToString(polymorph);
|
||||
std::cout << *json << std::endl;
|
||||
} else {
|
||||
auto err = state.errorStack.stacktrace();
|
||||
std::cout << *err << std::endl;
|
||||
}
|
||||
|
||||
auto obj = polymorph.cast<oatpp::Object<TestDto1>>();
|
||||
|
||||
OATPP_ASSERT(obj->str == "Hello World!")
|
||||
OATPP_ASSERT(obj->i8 == -8)
|
||||
OATPP_ASSERT(obj->ui8 == 8)
|
||||
OATPP_ASSERT(obj->i16 == -16)
|
||||
OATPP_ASSERT(obj->ui16 == 16)
|
||||
OATPP_ASSERT(obj->i32 == -32)
|
||||
OATPP_ASSERT(obj->ui32 == 32)
|
||||
OATPP_ASSERT(obj->i64 == -64)
|
||||
OATPP_ASSERT(obj->ui64 == 64)
|
||||
|
||||
OATPP_ASSERT(obj->vector->size() == 3)
|
||||
OATPP_ASSERT(obj->vector[0]->str == "nested_1 (in vector)")
|
||||
OATPP_ASSERT(obj->vector[1]->str == "nested_2 (in vector)")
|
||||
OATPP_ASSERT(obj->vector[2]->str == "nested_3 (in vector)")
|
||||
|
||||
OATPP_ASSERT(obj->map->size() == 3)
|
||||
OATPP_ASSERT(obj->map["nested_1"]->i32 = 1)
|
||||
OATPP_ASSERT(obj->map["nested_2"]->i32 = 2)
|
||||
OATPP_ASSERT(obj->map["nested_3"]->i32 = 3)
|
||||
|
||||
OATPP_ASSERT(obj->pairs->size() == 3)
|
||||
OATPP_ASSERT(obj->pairs[0].first == "same-key" && obj->pairs[0].second == "value1")
|
||||
OATPP_ASSERT(obj->pairs[1].first == "same-key" && obj->pairs[1].second == "value2")
|
||||
OATPP_ASSERT(obj->pairs[2].first == "same-key" && obj->pairs[2].second == "value3")
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
OATPP_LOGD(TAG, "Map Object unqualified")
|
||||
config.useUnqualifiedFieldNames = true;
|
||||
|
||||
Tree tree;
|
||||
|
||||
tree["str"] = "Hello World!";
|
||||
@ -152,6 +237,52 @@ void TreeToObjectMapperTest::onRun() {
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
OATPP_LOGD(TAG, "Map Enum qualified")
|
||||
config.useUnqualifiedEnumNames = false;
|
||||
|
||||
Tree tree;
|
||||
|
||||
TreeToObjectMapper::State state;
|
||||
state.tree = &tree;
|
||||
state.config = &config;
|
||||
|
||||
tree = "value-2";
|
||||
|
||||
auto polymorph = mapper.map(state, oatpp::Enum<TestEnum>::Class::getType());
|
||||
|
||||
if(!state.errorStack.empty()) {
|
||||
auto err = state.errorStack.stacktrace();
|
||||
std::cout << *err << std::endl;
|
||||
}
|
||||
|
||||
OATPP_ASSERT(polymorph.getValueType() == oatpp::Enum<TestEnum>::Class::getType())
|
||||
OATPP_ASSERT(polymorph.cast<oatpp::Enum<TestEnum>>() == TestEnum::VALUE_2)
|
||||
}
|
||||
|
||||
{
|
||||
OATPP_LOGD(TAG, "Map Enum unqualified")
|
||||
config.useUnqualifiedEnumNames = true;
|
||||
|
||||
Tree tree;
|
||||
|
||||
TreeToObjectMapper::State state;
|
||||
state.tree = &tree;
|
||||
state.config = &config;
|
||||
|
||||
tree = "VALUE_2";
|
||||
|
||||
auto polymorph = mapper.map(state, oatpp::Enum<TestEnum>::Class::getType());
|
||||
|
||||
if(!state.errorStack.empty()) {
|
||||
auto err = state.errorStack.stacktrace();
|
||||
std::cout << *err << std::endl;
|
||||
}
|
||||
|
||||
OATPP_ASSERT(polymorph.getValueType() == oatpp::Enum<TestEnum>::Class::getType())
|
||||
OATPP_ASSERT(polymorph.cast<oatpp::Enum<TestEnum>>() == TestEnum::VALUE_2)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}}}
|
||||
|
@ -154,7 +154,7 @@ void EnumTest::onRun() {
|
||||
OATPP_ASSERT(pd2->notNull == true)
|
||||
|
||||
{
|
||||
auto interEnum = pd1->getInterpretedEnum();
|
||||
auto interEnum = pd1->getInterpretedEnum(false);
|
||||
OATPP_ASSERT(interEnum.size() == 3)
|
||||
OATPP_ASSERT(interEnum[0].getStoredType() == oatpp::String::Class::getType())
|
||||
}
|
||||
@ -163,16 +163,16 @@ void EnumTest::onRun() {
|
||||
}
|
||||
|
||||
{
|
||||
OATPP_LOGI(TAG, "Test Interpreter AsString...")
|
||||
OATPP_LOGI(TAG, "Test Interpreter AsString (Qualified)...")
|
||||
oatpp::data::type::EnumInterpreterError e = oatpp::data::type::EnumInterpreterError::OK;
|
||||
auto inter = oatpp::Enum<Enum2>::AsString::Interpreter::toInterpretation(oatpp::Enum<Enum2>::AsString(Enum2::NAME_1), e);
|
||||
auto inter = oatpp::Enum<Enum2>::AsString::Interpreter::toInterpretation(oatpp::Enum<Enum2>::AsString(Enum2::NAME_1), false, e);
|
||||
OATPP_ASSERT(inter.getValueType() == oatpp::String::Class::getType())
|
||||
OATPP_ASSERT(e == oatpp::data::type::EnumInterpreterError::OK)
|
||||
|
||||
auto interValue = inter.cast<oatpp::String>();
|
||||
OATPP_ASSERT(interValue == "name-1")
|
||||
|
||||
oatpp::Void voidValue = oatpp::Enum<Enum2>::AsString::Interpreter::fromInterpretation(interValue, e);
|
||||
oatpp::Void voidValue = oatpp::Enum<Enum2>::AsString::Interpreter::fromInterpretation(interValue, false, e);
|
||||
OATPP_ASSERT(voidValue.getValueType() == oatpp::Enum<Enum2>::AsString::Class::getType())
|
||||
OATPP_ASSERT(e == oatpp::data::type::EnumInterpreterError::OK)
|
||||
|
||||
@ -182,16 +182,54 @@ void EnumTest::onRun() {
|
||||
}
|
||||
|
||||
{
|
||||
OATPP_LOGI(TAG, "Test Interpreter AsNumber...")
|
||||
OATPP_LOGI(TAG, "Test Interpreter AsString (Unqualified)...")
|
||||
oatpp::data::type::EnumInterpreterError e = oatpp::data::type::EnumInterpreterError::OK;
|
||||
auto inter = oatpp::Enum<Enum2>::AsNumber::Interpreter::toInterpretation(oatpp::Enum<Enum2>::AsNumber(Enum2::NAME_1), e);
|
||||
auto inter = oatpp::Enum<Enum2>::AsString::Interpreter::toInterpretation(oatpp::Enum<Enum2>::AsString(Enum2::NAME_1), true, e);
|
||||
OATPP_ASSERT(inter.getValueType() == oatpp::String::Class::getType())
|
||||
OATPP_ASSERT(e == oatpp::data::type::EnumInterpreterError::OK)
|
||||
|
||||
auto interValue = inter.cast<oatpp::String>();
|
||||
OATPP_ASSERT(interValue == "NAME_1")
|
||||
|
||||
oatpp::Void voidValue = oatpp::Enum<Enum2>::AsString::Interpreter::fromInterpretation(interValue, true, e);
|
||||
OATPP_ASSERT(voidValue.getValueType() == oatpp::Enum<Enum2>::AsString::Class::getType())
|
||||
OATPP_ASSERT(e == oatpp::data::type::EnumInterpreterError::OK)
|
||||
|
||||
auto value = voidValue.cast<oatpp::Enum<Enum2>::AsString>();
|
||||
OATPP_ASSERT(value == Enum2::NAME_1)
|
||||
OATPP_LOGI(TAG, "OK")
|
||||
}
|
||||
|
||||
{
|
||||
OATPP_LOGI(TAG, "Test Interpreter AsNumber (Qualified)...")
|
||||
oatpp::data::type::EnumInterpreterError e = oatpp::data::type::EnumInterpreterError::OK;
|
||||
auto inter = oatpp::Enum<Enum2>::AsNumber::Interpreter::toInterpretation(oatpp::Enum<Enum2>::AsNumber(Enum2::NAME_1), false, e);
|
||||
OATPP_ASSERT(inter.getValueType() == oatpp::Int32::Class::getType())
|
||||
OATPP_ASSERT(e == oatpp::data::type::EnumInterpreterError::OK)
|
||||
|
||||
auto interValue = inter.cast<oatpp::Int32>();
|
||||
OATPP_ASSERT(interValue == static_cast<v_int32>(Enum2::NAME_1))
|
||||
|
||||
oatpp::Void voidValue = oatpp::Enum<Enum2>::AsNumber::Interpreter::fromInterpretation(interValue, e);
|
||||
oatpp::Void voidValue = oatpp::Enum<Enum2>::AsNumber::Interpreter::fromInterpretation(interValue, false, e);
|
||||
OATPP_ASSERT(voidValue.getValueType() == oatpp::Enum<Enum2>::AsNumber::Class::getType())
|
||||
OATPP_ASSERT(e == oatpp::data::type::EnumInterpreterError::OK)
|
||||
|
||||
auto value = voidValue.cast<oatpp::Enum<Enum2>::AsNumber>();
|
||||
OATPP_ASSERT(value == Enum2::NAME_1)
|
||||
OATPP_LOGI(TAG, "OK")
|
||||
}
|
||||
|
||||
{
|
||||
OATPP_LOGI(TAG, "Test Interpreter AsNumber (Unualified)...")
|
||||
oatpp::data::type::EnumInterpreterError e = oatpp::data::type::EnumInterpreterError::OK;
|
||||
auto inter = oatpp::Enum<Enum2>::AsNumber::Interpreter::toInterpretation(oatpp::Enum<Enum2>::AsNumber(Enum2::NAME_1), true, e);
|
||||
OATPP_ASSERT(inter.getValueType() == oatpp::Int32::Class::getType())
|
||||
OATPP_ASSERT(e == oatpp::data::type::EnumInterpreterError::OK)
|
||||
|
||||
auto interValue = inter.cast<oatpp::Int32>();
|
||||
OATPP_ASSERT(interValue == static_cast<v_int32>(Enum2::NAME_1))
|
||||
|
||||
oatpp::Void voidValue = oatpp::Enum<Enum2>::AsNumber::Interpreter::fromInterpretation(interValue, true, e);
|
||||
OATPP_ASSERT(voidValue.getValueType() == oatpp::Enum<Enum2>::AsNumber::Class::getType())
|
||||
OATPP_ASSERT(e == oatpp::data::type::EnumInterpreterError::OK)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user