Skip to content

Commit f1260f2

Browse files
committed
Fixes
1 parent b49d32c commit f1260f2

File tree

2 files changed

+73
-24
lines changed

2 files changed

+73
-24
lines changed

universal/include/userver/formats/universal/common_containers.hpp

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -270,45 +270,65 @@ struct FieldConfig<std::unordered_map<std::string, Value>> {
270270
using Type = std::unordered_map<std::string, Value>;
271271
template <typename MainClass, auto I, typename Value2>
272272
inline constexpr Type Read(Value2&& value) const {
273-
if(!this->Additional) {
274-
throw std::runtime_error("Invalid Flags");
275-
}
276273
Type response;
277-
constexpr auto fields = boost::pfr::names_as_array<MainClass>();
278-
for(const auto& [name, value2] : userver::formats::common::Items(std::forward<Value2>(value))) {
279-
auto it = std::find(fields.begin(), fields.end(), name);
280-
if(it == fields.end()) {
281-
response.emplace(name, value2.template As<Value>());
274+
if(this->Additional) {
275+
constexpr auto fields = boost::pfr::names_as_array<MainClass>();
276+
for(const auto& [name, value] : userver::formats::common::Items(std::forward<Value2>(value))) {
277+
auto it = std::find(fields.begin(), fields.end(), name);
278+
if(it == fields.end()) {
279+
response.emplace(name, value.template As<Value>());
280+
}
282281
}
282+
return response;
283+
}
284+
constexpr auto fieldName = boost::pfr::get_name<I, MainClass>();
285+
for(const auto& [name, value] : userver::formats::common::Items(value[fieldName])) {
286+
response.emplace(name, value.template As<Value>());
283287
}
284288
return response;
285289
}
286290
template <typename MainClass, auto I, typename Value2>
287291
inline constexpr std::optional<Type> TryRead(Value2&& value) const {
288-
if(!this->Additional) {
289-
throw std::runtime_error("Invalid Flags");
290-
}
291292
Type response;
292-
constexpr auto fields = boost::pfr::names_as_array<MainClass>();
293-
constexpr auto name = boost::pfr::get_name<I, MainClass>();
294-
for(const auto& [name2, value2] : userver::formats::common::Items(std::forward<Value2>(value))) {
295-
if(std::find(fields.begin(), fields.end(), name2) == fields.end()) {
296-
auto New = parse::TryParse(value2, parse::To<Value>{});
297-
if(!New) {
298-
return std::nullopt;
299-
};
300-
response.emplace(name, *New);
293+
if(this->Additional) {
294+
constexpr auto fields = boost::pfr::names_as_array<MainClass>();
295+
for(const auto& [name, value] : userver::formats::common::Items(std::forward<Value2>(value))) {
296+
if(std::find(fields.begin(), fields.end(), name) == fields.end()) {
297+
auto New = parse::TryParse(value, parse::To<Value>{});
298+
if(!New) {
299+
return std::nullopt;
300+
}
301+
response.emplace(name, *New);
302+
}
303+
}
304+
return response;
305+
}
306+
constexpr auto fieldName = boost::pfr::get_name<I, MainClass>();
307+
for(const auto& [name, value] : userver::formats::common::Items(value[fieldName])) {
308+
auto New = parse::TryParse(value, parse::To<Value>{});
309+
if(!New) {
310+
return std::nullopt;
301311
}
312+
response.emplace(name, *New);
302313
}
303314
return response;
304315
}
305316
inline constexpr std::optional<std::string> Check(const Type&) const {
306317
return std::nullopt;
307318
}
308-
constexpr auto Write(const Type& value, std::string_view, const auto&, auto& builder) const {
319+
template <typename Builder>
320+
constexpr auto Write(const Type& value, std::string_view fieldName, const auto&, Builder& builder) const {
321+
if(this->Additional) {
322+
for(const auto& [name, value2] : value) {
323+
builder[name] = value2;
324+
};
325+
return;
326+
};
327+
Builder newBuilder;
309328
for(const auto& [name, value2] : value) {
310-
builder[name] = value2;
329+
newBuilder[name] = value2;
311330
};
331+
builder[static_cast<std::string>(fieldName)] = newBuilder.ExtractValue();
312332
};
313333
};
314334
template <typename Element>

universal/src/formats/json/universal_test.cpp

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ struct SomeStruct9 {
216216
std::optional<int> field1;
217217
inline constexpr bool operator==(const SomeStruct8& other) const {
218218
return this->field1 == other.field1;
219-
};
219+
}
220220
};
221221

222222
template <>
@@ -229,14 +229,43 @@ TEST(Parse, Nullable) {
229229
SomeStruct8{.field1 = std::nullopt});
230230
EXPECT_THROW(formats::json::FromString(R"({"field1":null})").As<SomeStruct9>(),
231231
formats::json::TypeMismatchException);
232-
};
232+
}
233+
233234
TEST(TryParse, Nullable) {
234235
EXPECT_EQ(formats::parse::TryParse(formats::json::FromString(R"({"field1":null})"), formats::parse::To<SomeStruct8>{}),
235236
SomeStruct8{.field1 = std::nullopt});
236237
EXPECT_EQ(formats::parse::TryParse(formats::json::FromString(R"({"field1":null})"), formats::parse::To<SomeStruct9>{}),
237238
std::nullopt);
239+
}
240+
241+
struct SomeStruct10 {
242+
std::unordered_map<std::string, int> map;
243+
inline bool operator==(const SomeStruct10& other) const {
244+
return this->map == other.map;
245+
}
238246
};
239247

248+
template <>
249+
inline constexpr auto formats::universal::kSerialization<SomeStruct10> =
250+
SerializationConfig<SomeStruct10>();
251+
252+
TEST(Parse, Map) {
253+
const auto json = formats::json::FromString(R"({"map":{"1":1,"2":2}})");
254+
SomeStruct10 valid;
255+
valid.map.emplace("1", 1);
256+
valid.map.emplace("2", 2);
257+
EXPECT_EQ(json.As<SomeStruct10>(), valid);
258+
}
259+
TEST(Serialize, Map) {
260+
const auto valid = formats::json::FromString(R"({"map":{"1":1,"2":2}})");
261+
SomeStruct10 value;
262+
value.map.emplace("1", 1);
263+
value.map.emplace("2", 2);
264+
const auto json = formats::json::ValueBuilder(value).ExtractValue();
265+
EXPECT_EQ(json, valid);
266+
}
267+
268+
240269

241270
USERVER_NAMESPACE_END
242271
#endif

0 commit comments

Comments
 (0)