mirror of
https://github.com/oatpp/oatpp.git
synced 2025-04-12 18:50:22 +08:00
Tree: better mapping to/from object
This commit is contained in:
parent
a29c664581
commit
b9d78cce64
src/oatpp/data/mapping
test
@ -161,7 +161,7 @@ void ObjectToTreeMapper::mapCollection(const ObjectToTreeMapper* mapper, State&
|
||||
auto iterator = dispatcher->beginIteration(polymorph);
|
||||
|
||||
state.tree->setVector(0);
|
||||
auto& vector = state.tree->getVector();
|
||||
TreeChildrenOperator childrenOperator(*state.tree);
|
||||
v_int64 index = 0;
|
||||
|
||||
while (!iterator->finished()) {
|
||||
@ -170,10 +170,8 @@ void ObjectToTreeMapper::mapCollection(const ObjectToTreeMapper* mapper, State&
|
||||
|
||||
if(value || state.config->includeNullFields || state.config->alwaysIncludeNullCollectionElements) {
|
||||
|
||||
vector.emplace_back();
|
||||
|
||||
State nestedState;
|
||||
nestedState.tree = &vector[vector.size() - 1];
|
||||
nestedState.tree = childrenOperator.putItem({});
|
||||
nestedState.config = state.config;
|
||||
|
||||
mapper->map(nestedState, value);
|
||||
@ -212,8 +210,15 @@ void ObjectToTreeMapper::mapMap(const ObjectToTreeMapper* mapper, State& state,
|
||||
|
||||
auto iterator = dispatcher->beginIteration(polymorph);
|
||||
|
||||
state.tree->setMap({});
|
||||
auto& map = state.tree->getMap();
|
||||
if(polymorph.getValueType()->classId == data::type::__class::AbstractUnorderedMap::CLASS_ID) {
|
||||
state.tree->setMap({});
|
||||
} else if(polymorph.getValueType()->classId == data::type::__class::AbstractPairList::CLASS_ID) {
|
||||
state.tree->setPairs({});
|
||||
} else {
|
||||
state.errorStack.push("[oatpp::data::mapping::ObjectToTreeMapper::mapMap()]: Invalid polymorph type");
|
||||
}
|
||||
|
||||
TreeChildrenOperator childrenOperator(*state.tree);
|
||||
|
||||
while (!iterator->finished()) {
|
||||
const auto& value = iterator->getValue();
|
||||
@ -223,7 +228,7 @@ void ObjectToTreeMapper::mapMap(const ObjectToTreeMapper* mapper, State& state,
|
||||
const auto& key = oatpp::String(std::static_pointer_cast<std::string>(untypedKey.getPtr()));
|
||||
|
||||
State nestedState;
|
||||
nestedState.tree = &map[key];
|
||||
nestedState.tree = childrenOperator.putPair(key, {});
|
||||
nestedState.config = state.config;
|
||||
|
||||
mapper->map(nestedState, value);
|
||||
@ -255,7 +260,7 @@ void ObjectToTreeMapper::mapObject(const ObjectToTreeMapper* mapper, State& stat
|
||||
auto object = static_cast<oatpp::BaseObject*>(polymorph.get());
|
||||
|
||||
state.tree->setMap({});
|
||||
auto& map = state.tree->getMap();
|
||||
TreeChildrenOperator childrenOperator(*state.tree);
|
||||
|
||||
for (auto const& field : fields) {
|
||||
|
||||
@ -277,7 +282,7 @@ void ObjectToTreeMapper::mapObject(const ObjectToTreeMapper* mapper, State& stat
|
||||
if (value || state.config->includeNullFields || (field->info.required && state.config->alwaysIncludeRequired)) {
|
||||
|
||||
State nestedState;
|
||||
nestedState.tree = &map[oatpp::String(field->name)];
|
||||
nestedState.tree = childrenOperator.putPair(oatpp::String(field->name), {});
|
||||
nestedState.config = state.config;
|
||||
|
||||
mapper->map(nestedState, value);
|
||||
|
@ -784,33 +784,23 @@ TreeChildrenOperator::TreeChildrenOperator(Tree& tree)
|
||||
: TreeChildrenOperator(const_cast<const Tree&>(tree))
|
||||
{
|
||||
m_const = false;
|
||||
if(tree.getType() == Tree::Type::VECTOR) {
|
||||
m_vector = std::addressof(tree.getVector());
|
||||
} else if(tree.getType() == Tree::Type::MAP) {
|
||||
m_map = std::addressof(tree.getMap());
|
||||
} else if(tree.getType() == Tree::Type::PAIRS) {
|
||||
m_pairs = std::addressof(tree.getPairs());
|
||||
}
|
||||
}
|
||||
|
||||
TreeChildrenOperator::TreeChildrenOperator(const Tree& tree)
|
||||
: m_vector(nullptr)
|
||||
, m_map(nullptr)
|
||||
, m_pairs(nullptr)
|
||||
, c_vector(nullptr)
|
||||
, c_map(nullptr)
|
||||
, c_pairs(nullptr)
|
||||
{
|
||||
m_const = true;
|
||||
if(tree.getType() == Tree::Type::VECTOR) {
|
||||
m_type = VECTOR;
|
||||
c_vector = std::addressof(tree.getVector());
|
||||
m_vector = std::addressof(tree.getVector());
|
||||
} else if(tree.getType() == Tree::Type::MAP) {
|
||||
m_type = MAP;
|
||||
c_map = std::addressof(tree.getMap());
|
||||
m_map = std::addressof(tree.getMap());
|
||||
} else if(tree.getType() == Tree::Type::PAIRS) {
|
||||
m_type = PAIRS;
|
||||
c_pairs = std::addressof(tree.getPairs());
|
||||
m_pairs = std::addressof(tree.getPairs());
|
||||
} else {
|
||||
throw std::runtime_error("[oatpp::data::mapping::TreeChildrenOperator::TreeChildrenOperator()]: Node type is NOT suppoerted");
|
||||
}
|
||||
@ -823,11 +813,11 @@ std::pair<type::String, Tree*> TreeChildrenOperator::getPair(v_uint64 index) {
|
||||
switch (m_type) {
|
||||
case VECTOR: break;
|
||||
case MAP: {
|
||||
const auto& p = (*m_map)[index];
|
||||
const auto& p = (*const_cast<TreeMap*>(m_map))[index];
|
||||
return {p.first, std::addressof(p.second.get())};
|
||||
}
|
||||
case PAIRS: {
|
||||
auto& p = m_pairs->at(index);
|
||||
auto& p = const_cast<std::vector<std::pair<type::String, Tree>>*>(m_pairs)->at(index);
|
||||
return {p.first, &p.second};
|
||||
}
|
||||
default:
|
||||
@ -840,11 +830,11 @@ std::pair<type::String, const Tree*> TreeChildrenOperator::getPair(v_uint64 inde
|
||||
switch (m_type) {
|
||||
case VECTOR: break;
|
||||
case MAP: {
|
||||
const auto& p = (*c_map)[index];
|
||||
const auto& p = (*m_map)[index];
|
||||
return {p.first, std::addressof(p.second.get())};
|
||||
}
|
||||
case PAIRS: {
|
||||
auto& p = (*c_pairs)[index];
|
||||
auto& p = (*m_pairs)[index];
|
||||
return {p.first, &p.second};
|
||||
}
|
||||
default:
|
||||
@ -858,9 +848,9 @@ Tree* TreeChildrenOperator::getItem(v_uint64 index) {
|
||||
throw std::runtime_error("[oatpp::data::mapping::TreeChildrenOperator::getItem()]: Can't operate on CONST tree node");
|
||||
}
|
||||
switch (m_type) {
|
||||
case VECTOR: return std::addressof(m_vector->at(index));
|
||||
case MAP: return std::addressof((*m_map)[index].second.get());
|
||||
case PAIRS: return &m_pairs->at(index).second;
|
||||
case VECTOR: return std::addressof(const_cast<std::vector<Tree>*>(m_vector)->at(index));
|
||||
case MAP: return std::addressof((*const_cast<TreeMap*>(m_map))[index].second.get());
|
||||
case PAIRS: return &const_cast<std::vector<std::pair<type::String, Tree>>*>(m_pairs)->at(index).second;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -869,20 +859,102 @@ Tree* TreeChildrenOperator::getItem(v_uint64 index) {
|
||||
|
||||
const Tree* TreeChildrenOperator::getItem(v_uint64 index) const {
|
||||
switch (m_type) {
|
||||
case VECTOR: return std::addressof(c_vector->at(index));
|
||||
case MAP: return std::addressof((*c_map)[index].second.get());
|
||||
case PAIRS: return &c_pairs->at(index).second;
|
||||
case VECTOR: return std::addressof(m_vector->at(index));
|
||||
case MAP: return std::addressof((*m_map)[index].second.get());
|
||||
case PAIRS: return &m_pairs->at(index).second;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
throw std::runtime_error("[oatpp::data::mapping::TreeChildrenOperator::getItem()]: Invalid operator type");
|
||||
}
|
||||
|
||||
Tree* TreeChildrenOperator::putPair(const type::String& key, const Tree& tree) {
|
||||
if(m_const) {
|
||||
throw std::runtime_error("[oatpp::data::mapping::TreeChildrenOperator::putPair()]: Can't operate on CONST tree node");
|
||||
}
|
||||
switch (m_type) {
|
||||
case VECTOR: break;
|
||||
case MAP: {
|
||||
auto& node = (*const_cast<TreeMap*>(m_map))[key];
|
||||
node = tree;
|
||||
return std::addressof(node);
|
||||
}
|
||||
case PAIRS: {
|
||||
auto& pairs = *const_cast<std::vector<std::pair<type::String, Tree>>*>(m_pairs);
|
||||
pairs.emplace_back(key, tree);
|
||||
auto& p = pairs.at(pairs.size() - 1);
|
||||
return std::addressof(p.second);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
throw std::runtime_error("[oatpp::data::mapping::TreeChildrenOperator::putPair()]: Node type doesn't support pairs");
|
||||
}
|
||||
|
||||
Tree* TreeChildrenOperator::putPair(const type::String& key, Tree&& tree) {
|
||||
if(m_const) {
|
||||
throw std::runtime_error("[oatpp::data::mapping::TreeChildrenOperator::putPair()]: Can't operate on CONST tree node");
|
||||
}
|
||||
switch (m_type) {
|
||||
case VECTOR: break;
|
||||
case MAP: {
|
||||
auto& node = (*const_cast<TreeMap*>(m_map))[key];
|
||||
node = std::forward<Tree>(tree);
|
||||
return std::addressof(node);
|
||||
}
|
||||
case PAIRS: {
|
||||
auto& pairs = *const_cast<std::vector<std::pair<type::String, Tree>>*>(m_pairs);
|
||||
pairs.emplace_back(key, std::forward<Tree>(tree));
|
||||
auto& p = pairs.at(pairs.size() - 1);
|
||||
return std::addressof(p.second);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
throw std::runtime_error("[oatpp::data::mapping::TreeChildrenOperator::putPair()]: Node type doesn't support pairs");
|
||||
}
|
||||
|
||||
Tree* TreeChildrenOperator::putItem(const Tree& tree) {
|
||||
if(m_const) {
|
||||
throw std::runtime_error("[oatpp::data::mapping::TreeChildrenOperator::putItem()]: Can't operate on CONST tree node");
|
||||
}
|
||||
switch (m_type) {
|
||||
case VECTOR: {
|
||||
auto& vector = *const_cast<std::vector<Tree>*>(m_vector);
|
||||
vector.push_back(tree);
|
||||
return std::addressof(vector.at(vector.size() - 1));
|
||||
}
|
||||
case MAP:
|
||||
case PAIRS:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
throw std::runtime_error("[oatpp::data::mapping::TreeChildrenOperator::putItem()]: Invalid iterator type");
|
||||
}
|
||||
|
||||
Tree* TreeChildrenOperator::putItem(Tree&& tree) {
|
||||
if(m_const) {
|
||||
throw std::runtime_error("[oatpp::data::mapping::TreeChildrenOperator::putItem()]: Can't operate on CONST tree node");
|
||||
}
|
||||
switch (m_type) {
|
||||
case VECTOR: {
|
||||
auto& vector = *const_cast<std::vector<Tree>*>(m_vector);
|
||||
vector.emplace_back(std::forward<Tree>(tree));
|
||||
return std::addressof(vector.at(vector.size() - 1));
|
||||
}
|
||||
case MAP:
|
||||
case PAIRS:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
throw std::runtime_error("[oatpp::data::mapping::TreeChildrenOperator::putItem()]: Invalid iterator type");
|
||||
}
|
||||
|
||||
v_uint64 TreeChildrenOperator::size() const {
|
||||
switch (m_type) {
|
||||
case VECTOR: return c_vector->size();
|
||||
case MAP: return c_map->size();
|
||||
case PAIRS: return c_pairs->size();
|
||||
case VECTOR: return m_vector->size();
|
||||
case MAP: return m_map->size();
|
||||
case PAIRS: return m_pairs->size();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -268,20 +268,16 @@ private:
|
||||
PAIRS
|
||||
};
|
||||
private:
|
||||
std::vector<Tree>* m_vector;
|
||||
TreeMap* m_map;
|
||||
std::vector<std::pair<type::String, Tree>>* m_pairs;
|
||||
private:
|
||||
const std::vector<Tree>* c_vector;
|
||||
const TreeMap* c_map;
|
||||
const std::vector<std::pair<type::String, Tree>>* c_pairs;
|
||||
const std::vector<Tree>* m_vector;
|
||||
const TreeMap* m_map;
|
||||
const std::vector<std::pair<type::String, Tree>>* m_pairs;
|
||||
private:
|
||||
bool m_const;
|
||||
IteratorType m_type;
|
||||
public:
|
||||
|
||||
TreeChildrenOperator(Tree& tree);
|
||||
TreeChildrenOperator(const Tree& tree);
|
||||
explicit TreeChildrenOperator(Tree& tree);
|
||||
explicit TreeChildrenOperator(const Tree& tree);
|
||||
|
||||
std::pair<type::String, Tree*> getPair(v_uint64 index);
|
||||
std::pair<type::String, const Tree*> getPair(v_uint64 index) const;
|
||||
@ -289,6 +285,12 @@ public:
|
||||
Tree* getItem(v_uint64 index);
|
||||
const Tree* getItem(v_uint64 index) const;
|
||||
|
||||
Tree* putPair(const type::String& key, const Tree& tree);
|
||||
Tree* putPair(const type::String& key, Tree&& tree);
|
||||
|
||||
Tree* putItem(const Tree& tree);
|
||||
Tree* putItem(Tree&& tree);
|
||||
|
||||
v_uint64 size() const;
|
||||
|
||||
};
|
||||
|
@ -8,6 +8,8 @@ add_executable(oatppAllTests
|
||||
oatpp/base/CommandLineArgumentsTest.hpp
|
||||
oatpp/data/buffer/ProcessorTest.cpp
|
||||
oatpp/data/buffer/ProcessorTest.hpp
|
||||
oatpp/data/mapping/ObjectToTreeMapperTest.cpp
|
||||
oatpp/data/mapping/ObjectToTreeMapperTest.hpp
|
||||
oatpp/data/mapping/TreeTest.cpp
|
||||
oatpp/data/mapping/TreeTest.hpp
|
||||
oatpp/data/mapping/TreeToObjectMapperTest.cpp
|
||||
|
@ -55,6 +55,7 @@
|
||||
#include "oatpp/data/stream/BufferStreamTest.hpp"
|
||||
|
||||
#include "oatpp/data/mapping/TreeTest.hpp"
|
||||
#include "oatpp/data/mapping/ObjectToTreeMapperTest.hpp"
|
||||
#include "oatpp/data/mapping/TreeToObjectMapperTest.hpp"
|
||||
|
||||
#include "oatpp/data/share/LazyStringMapTest.hpp"
|
||||
@ -115,9 +116,10 @@ void runTests() {
|
||||
// OATPP_RUN_TEST(oatpp::data::stream::BufferStreamTest);
|
||||
//
|
||||
|
||||
OATPP_RUN_TEST(oatpp::data::mapping::TreeTest);
|
||||
//OATPP_RUN_TEST(oatpp::data::mapping::TreeTest);
|
||||
|
||||
OATPP_RUN_TEST(oatpp::data::mapping::TreeToObjectMapperTest);
|
||||
OATPP_RUN_TEST(oatpp::data::mapping::ObjectToTreeMapperTest);
|
||||
//OATPP_RUN_TEST(oatpp::data::mapping::TreeToObjectMapperTest);
|
||||
|
||||
//
|
||||
//
|
||||
|
33
test/oatpp/data/mapping/ObjectToTreeMapperTest.cpp
Normal file
33
test/oatpp/data/mapping/ObjectToTreeMapperTest.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* 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 "ObjectToTreeMapperTest.hpp"
|
||||
|
||||
namespace oatpp { namespace data { namespace mapping {
|
||||
|
||||
void ObjectToTreeMapperTest::onRun() {
|
||||
|
||||
}
|
||||
|
||||
}}}
|
40
test/oatpp/data/mapping/ObjectToTreeMapperTest.hpp
Normal file
40
test/oatpp/data/mapping/ObjectToTreeMapperTest.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_ObjectToTreeMapperTest_hpp
|
||||
#define oatpp_data_mapping_ObjectToTreeMapperTest_hpp
|
||||
|
||||
#include "oatpp-test/UnitTest.hpp"
|
||||
|
||||
namespace oatpp { namespace data { namespace mapping {
|
||||
|
||||
class ObjectToTreeMapperTest : public oatpp::test::UnitTest {
|
||||
public:
|
||||
ObjectToTreeMapperTest() : UnitTest("TEST[oatpp::data::mapping::ObjectToTreeMapperTest]") {}
|
||||
void onRun() override;
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif /* oatpp_data_mapping_ObjectToTreeMapperTest_hpp */
|
@ -330,7 +330,7 @@ void DTOMapperTest::onRun(){
|
||||
oatpp::String result;
|
||||
try {
|
||||
result = mapper.writeToString(test2);
|
||||
} catch(std::runtime_error& e) {
|
||||
} catch(std::runtime_error&) {
|
||||
OATPP_LOGV(TAG, "Test2::field_string is required!")
|
||||
}
|
||||
OATPP_ASSERT(result == nullptr)
|
||||
@ -340,7 +340,7 @@ void DTOMapperTest::onRun(){
|
||||
auto test3 = Test3::createShared();
|
||||
try {
|
||||
auto result = mapper.writeToString(test3);
|
||||
} catch(std::runtime_error& e) {
|
||||
} catch(std::runtime_error&) {
|
||||
OATPP_ASSERT(false)
|
||||
}
|
||||
}
|
||||
@ -352,7 +352,7 @@ void DTOMapperTest::onRun(){
|
||||
oatpp::String result;
|
||||
try {
|
||||
result = mapper.writeToString(test4);
|
||||
} catch(std::runtime_error& e) {
|
||||
} catch(std::runtime_error&) {
|
||||
OATPP_LOGV(TAG, "TestChild1::name is required!")
|
||||
}
|
||||
OATPP_ASSERT(result == nullptr)
|
||||
@ -364,7 +364,7 @@ void DTOMapperTest::onRun(){
|
||||
test5->child = TestChild2::createShared();
|
||||
try {
|
||||
auto result = mapper.writeToString(test5);
|
||||
} catch(std::runtime_error& e) {
|
||||
} catch(std::runtime_error&) {
|
||||
OATPP_ASSERT(false)
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user