1+ #if __cplusplus >= 202002L
12#pragma once
23#include < userver/formats/universal/universal.hpp>
34#include < userver/formats/common/items.hpp>
@@ -11,31 +12,35 @@ template <typename T>
1112struct Max : public impl ::Param<T> {
1213 inline constexpr Max (const T& value) :
1314 impl::Param<T>(value) {}
14- inline constexpr std::string Check (const T& value) const {
15- return value <= this ->value ? " " : this ->Error (value);
15+ inline constexpr std::optional<std::string> Check (const T& value) const {
16+ if (value <= this ->value ) {
17+ return std::nullopt ;
18+ }
19+ return this ->Error (value);
1620 }
1721 template <typename Value>
18- inline constexpr std::enable_if_t <meta::kIsRange <Value>, std::string>
22+ inline constexpr std::enable_if_t <meta::kIsRange <Value>, std::optional<std:: string> >
1923 Check (const Value& value) const {
2024 for (const auto & element : value) {
2125 if (element > this ->value ) {
2226 return this ->Error (element);
2327 }
2428 }
25- return " " ;
29+ return std:: nullopt ;
2630 }
2731 inline constexpr std::string Error (const T& value) const {
2832 return std::format (" {} > {}" , value, this ->value );
2933 }
3034};
3135
36+
3237struct MinElements : public impl ::Param<std::size_t > {
3338 inline constexpr MinElements (const std::size_t & value) :
3439 impl::Param<std::size_t>(value) {}
3540 template <typename Value>
36- inline constexpr std::string Check (const Value& value) const {
41+ inline constexpr std::optional<std:: string> Check (const Value& value) const {
3742 if (value.size () >= this ->value ) {
38- return " " ;
43+ return std:: nullopt ;
3944 }
4045 return this ->Error (value);
4146 }
@@ -49,18 +54,21 @@ template <typename T>
4954struct Min : public impl ::Param<T> {
5055 inline constexpr Min (const T& value) :
5156 impl::Param<T>(value) {}
52- inline constexpr std::string Check (const T& value) const {
53- return value >= this ->value ? " " : this ->Error (value);
57+ inline constexpr std::optional<std::string> Check (const T& value) const {
58+ if (value >= this ->value ) {
59+ return std::nullopt ;
60+ }
61+ return this ->Error (value);
5462 };
5563 template <typename Value>
56- inline constexpr std::enable_if_t <meta::kIsRange <Value>, std::string>
64+ inline constexpr std::enable_if_t <meta::kIsRange <Value>, std::optional<std:: string> >
5765 Check (const Value& value) const {
5866 for (const auto & element : value) {
5967 if (element < this ->value ) {
6068 return this ->Error (element);
6169 }
6270 }
63- return " " ;
71+ return std:: nullopt ;
6472 }
6573 inline constexpr auto Error (const T& value) const {
6674 return std::format (" {} < {}" , value, this ->value );
@@ -77,8 +85,11 @@ static const utils::regex kRegex(Pattern);
7785struct Pattern : public impl ::EmptyCheck, public impl::Param<const utils::regex*> {
7886 constexpr inline Pattern (const utils::regex& regex) :
7987 impl::Param<const utils::regex*>(®ex) {}
80- constexpr inline std::string Check (std::string_view str) const {
81- return utils::regex_match (str, *this ->value ) ? " " : this ->Error (str);
88+ constexpr inline std::optional<std::string> Check (std::string_view str) const {
89+ if (utils::regex_match (str, *this ->value )) {
90+ return std::nullopt ;
91+ }
92+ return this ->Error (str);
8293 }
8394 constexpr inline std::string Error (std::string_view) const {
8495 return " Error" ;
@@ -90,8 +101,8 @@ struct Additional : public impl::EmptyCheck, public impl::Param<bool> {
90101};
91102template <>
92103struct FieldConfig <int > {
93- std::optional<Max<int >> Maximum;
94- std::optional<Min<int >> Minimum;
104+ std::optional<Max<int >> Maximum = std:: nullopt ;
105+ std::optional<Min<int >> Minimum = std:: nullopt ;
95106 template <typename MainClass, auto I, typename Value>
96107 constexpr int Read (Value&& value) const {
97108 constexpr auto name = boost::pfr::get_name<I, MainClass>();
@@ -105,48 +116,74 @@ struct FieldConfig<int> {
105116 constexpr auto Write (const int & value, std::string_view fieldName, const auto &, auto & builder) const {
106117 builder[static_cast <std::string>(fieldName)] = value;
107118 };
108- inline constexpr std::string_view Check (const int &) const {
109- return " " ;
119+ inline constexpr std::optional<std::string> Check (const int &) const {
120+ return std:: nullopt ;
110121 }
111122
112123};
113124template <>
114125struct FieldConfig <std::optional<std::string>> {
115- std::optional<Pattern> Pattern;
116- std::optional<Default<std::string>> Default;
126+ std::optional<Pattern> Pattern = std::nullopt ;
127+ std::optional<Default<std::string_view>> Default = std::nullopt ;
128+ bool Required = false ;
129+ bool Nullable = false ;
117130 template <typename MainClass, auto I, typename Value>
118131 constexpr std::optional<std::string> Read (Value&& value) const {
119132 constexpr auto name = boost::pfr::get_name<I, MainClass>();
120- if (! value. HasMember (name) ) {
133+ if (value[name]. IsMissing () && this -> Required ) {
121134 return std::nullopt ;
122135 };
123- return value[name].template As <std::string>();
136+ if (!value[name].IsMissing ()) {
137+ if (this ->Nullable ) {
138+ return value[name].template As <std::optional<std::string>>();
139+ };
140+ return value[name].template As <std::string>();
141+ };
142+ if (this ->Default ) {
143+ return static_cast <std::string>(this ->Default ->value );
144+ };
145+ return std::nullopt ;
124146 };
125147 template <typename MainClass, auto I, typename Value>
126148 constexpr std::optional<std::optional<std::string>> TryRead (Value&& value) const {
127149 constexpr auto name = boost::pfr::get_name<I, MainClass>();
128- auto response = parse::TryParse (value[name], parse::To<std::string>{});
129- if (response) {
130- return response;
131- }
150+ if (value[name].IsMissing () && this ->Required ) {
151+ return std::nullopt ;
152+ };
153+
154+ if (this ->Nullable ) {
155+ auto response = parse::TryParse (value[name], parse::To<std::optional<std::string>>{});
156+ if (response) {
157+ return response;
158+ }
159+ } else {
160+ auto response = parse::TryParse (value[name], parse::To<std::string>{});
161+ if (response) {
162+ return response;
163+ };
164+ };
132165 if (this ->Default ) {
133- return this ->Default ->value ;
166+ return static_cast <std::string>( this ->Default ->value ) ;
134167 }
135- return std:: nullopt ;
168+ return {{}} ;
136169 }
137170 constexpr auto Write (const std::optional<std::string>& value, std::string_view fieldName, const auto &, auto & builder) const {
138171 if (value) {
139172 builder[static_cast <std::string>(fieldName)] = *value;
173+ return ;
174+ };
175+ if (this ->Default ) {
176+ builder[static_cast <std::string>(fieldName)] = this ->Default ->value ;
140177 };
141178 };
142- inline constexpr std::string_view Check (const std::string &) const {
143- return " " ;
179+ inline constexpr std::optional<std::string> Check (const auto &) const {
180+ return std:: nullopt ;
144181 }
145182
146183};
147184template <>
148185struct FieldConfig <std::string> {
149- std::optional<Pattern> Pattern;
186+ std::optional<Pattern> Pattern = std:: nullopt ;
150187 template <typename MainClass, auto I, typename Value>
151188 constexpr std::string Read (Value&& value) const {
152189 constexpr auto name = boost::pfr::get_name<I, MainClass>();
@@ -160,21 +197,29 @@ struct FieldConfig<std::string> {
160197 constexpr auto Write (std::string_view value, std::string_view fieldName, const auto &, auto & builder) const {
161198 builder[static_cast <std::string>(fieldName)] = value;
162199 };
163- inline constexpr std::string_view Check (std::string_view) const {
164- return " " ;
200+ inline constexpr std::optional<std::string> Check (std::string_view) const {
201+ return std:: nullopt ;
165202 }
166203
167204};
168205
169206template <>
170207struct FieldConfig <std::optional<int >> {
171- std::optional<Max<int >> Maximum;
172- std::optional<Min<int >> Minimum;
173- std::optional<Default<int >> Default;
208+ std::optional<Max<int >> Maximum = std::nullopt ;
209+ std::optional<Min<int >> Minimum = std::nullopt ;
210+ std::optional<Default<int >> Default = std::nullopt ;
211+ bool Required = false ;
212+ bool Nullable = false ;
174213 template <typename MainClass, auto I, typename Value>
175214 constexpr std::optional<int > Read (Value&& value) const {
176215 constexpr auto name = boost::pfr::get_name<I, MainClass>();
177- if (value.HasMember (name)) {
216+ if (value[name].IsMissing () && this ->Required ) {
217+ return std::nullopt ;
218+ };
219+ if (!value[name].IsMissing ()) {
220+ if (this ->Nullable ) {
221+ return value[name].template As <std::optional<int >>();
222+ };
178223 return value[name].template As <int >();
179224 }
180225 if (this ->Default ) {
@@ -185,10 +230,20 @@ struct FieldConfig<std::optional<int>> {
185230 template <typename MainClass, auto I, typename Value>
186231 constexpr std::optional<std::optional<int >> TryRead (Value&& value) const {
187232 constexpr auto name = boost::pfr::get_name<I, MainClass>();
188- auto response = parse::TryParse (value[name], parse::To<int >{});
189- if (response) {
190- return response;
191- }
233+ if (this ->Nullable ) {
234+ auto response = parse::TryParse (value[name], parse::To<std::optional<int >>{});
235+ if (response) {
236+ return response;
237+ }
238+ } else {
239+ if (value[name].IsNull ()) {
240+ return std::nullopt ;
241+ };
242+ auto response = parse::TryParse (value[name], parse::To<int >{});
243+ if (response) {
244+ return response;
245+ };
246+ };
192247 if (this ->Default ) {
193248 return this ->Default ->value ;
194249 }
@@ -204,21 +259,21 @@ struct FieldConfig<std::optional<int>> {
204259 }
205260 }
206261
207- inline constexpr std::string_view Check (const std::optional<int >&) const {
208- return " " ;
262+ inline constexpr std::optional<std::string> Check (const std::optional<int >&) const {
263+ return std:: nullopt ;
209264 }
210265
211266};
212267template <typename Value>
213268struct FieldConfig <std::unordered_map<std::string, Value>> {
214- std::optional<Additional> Additional;
215- using kType = std::unordered_map<std::string, Value>;
269+ std::optional<Additional> Additional = std:: nullopt ;
270+ using Type = std::unordered_map<std::string, Value>;
216271 template <typename MainClass, auto I, typename Value2>
217- inline constexpr kType Read (Value2&& value) const {
272+ inline constexpr Type Read (Value2&& value) const {
218273 if (!this ->Additional ) {
219274 throw std::runtime_error (" Invalid Flags" );
220275 }
221- kType response;
276+ Type response;
222277 constexpr auto fields = boost::pfr::names_as_array<MainClass>();
223278 for (const auto & [name, value2] : userver::formats::common::Items (std::forward<Value2>(value))) {
224279 auto it = std::find (fields.begin (), fields.end (), name);
@@ -229,11 +284,11 @@ struct FieldConfig<std::unordered_map<std::string, Value>> {
229284 return response;
230285 }
231286 template <typename MainClass, auto I, typename Value2>
232- inline constexpr std::optional<kType > TryRead (Value2&& value) const {
287+ inline constexpr std::optional<Type > TryRead (Value2&& value) const {
233288 if (!this ->Additional ) {
234289 throw std::runtime_error (" Invalid Flags" );
235290 }
236- kType response;
291+ Type response;
237292 constexpr auto fields = boost::pfr::names_as_array<MainClass>();
238293 constexpr auto name = boost::pfr::get_name<I, MainClass>();
239294 for (const auto & [name2, value2] : userver::formats::common::Items (std::forward<Value2>(value))) {
@@ -247,19 +302,19 @@ struct FieldConfig<std::unordered_map<std::string, Value>> {
247302 }
248303 return response;
249304 }
250- inline constexpr std::string_view Check (const kType &) const {
251- return " " ;
305+ inline constexpr std::optional<std::string> Check (const Type &) const {
306+ return std:: nullopt ;
252307 }
253- constexpr auto Write (const kType & value, std::string_view, const auto &, auto & builder) const {
308+ constexpr auto Write (const Type & value, std::string_view, const auto &, auto & builder) const {
254309 for (const auto & [name, value2] : value) {
255310 builder[name] = value2;
256311 };
257312 };
258313};
259314template <typename Element>
260315struct FieldConfig <std::vector<Element>> {
261- std::optional<MinElements> MinimalElements;
262- FieldConfig<Element> Items;
316+ std::optional<MinElements> MinimalElements = std:: nullopt ;
317+ FieldConfig<Element> Items = {} ;
263318 template <typename MainClass, auto I, typename Value>
264319 inline constexpr auto Read (Value&& value) const {
265320 constexpr auto name = boost::pfr::get_name<I, MainClass>();
@@ -283,14 +338,22 @@ struct FieldConfig<std::vector<Element>> {
283338 }
284339 return response;
285340 }
286- inline constexpr std::string Check (const std::vector<Element>& obj) const {
287- std::string error;
341+ inline constexpr std::optional<std:: string> Check (const std::vector<Element>& obj) const {
342+ std::optional<std:: string> error = std:: nullopt ;
288343 for (const auto & element : obj) {
289- error += impl::UniversalCheckField (element, this ->Items );
344+ auto add = impl::UniversalCheckField (element, this ->Items );
345+ if (add) {
346+ if (!error) {
347+ error = *add;
348+ continue ;
349+ };
350+ *error += *add;
351+ }
290352 }
291353 return error;
292354 }
293355
294356};
295357} // namespace formats::universal
296358USERVER_NAMESPACE_END
359+ #endif
0 commit comments