userver: userver/formats/json/value_builder.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
value_builder.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/formats/json/value_builder.hpp
4/// @brief @copybrief formats::json::ValueBuilder
5
6#include <chrono>
7#include <string_view>
8#include <vector>
9
10#include <userver/formats/common/meta.hpp>
11#include <userver/formats/common/transfer_tag.hpp>
12#include <userver/formats/json/impl/mutable_value_wrapper.hpp>
13#include <userver/formats/json/value.hpp>
14#include <userver/utils/strong_typedef.hpp>
15
16USERVER_NAMESPACE_BEGIN
17
18namespace formats::json {
19
20// clang-format off
21
22/// @ingroup userver_universal userver_containers userver_formats
23///
24/// @brief Builder for JSON.
25///
26/// Class provides methods for building JSON. For read only access to the
27/// existing JSON values use formats::json::Value.
28///
29/// ## Example usage:
30///
31/// @snippet formats/json/value_builder_test.cpp Sample formats::json::ValueBuilder usage
32///
33/// ## Customization example:
34///
35/// @snippet formats/json/value_builder_test.cpp Sample Customization formats::json::ValueBuilder usage
36///
37/// @see @ref scripts/docs/en/userver/formats.md
38
39// clang-format on
40
41class ValueBuilder final {
42 public:
43 struct IterTraits {
44 using ValueType = formats::json::ValueBuilder;
45 using Reference = formats::json::ValueBuilder&;
46 using Pointer = formats::json::ValueBuilder*;
47 using ContainerType = impl::MutableValueWrapper;
48 };
49
50 using iterator = Iterator<IterTraits>;
51
52 /// Constructs a ValueBuilder that holds kNull
53 ValueBuilder() noexcept = default;
54
55 /// Constructs a valueBuilder that holds default value for provided `type`.
57
58 /// @brief Transfers the `ValueBuilder` object
59 /// @see formats::common::TransferTag for the transfer semantics
60 ValueBuilder(common::TransferTag, ValueBuilder&&) noexcept;
61
62 ValueBuilder(const ValueBuilder& other);
63 // NOLINTNEXTLINE(performance-noexcept-move-constructor)
64 ValueBuilder(ValueBuilder&& other);
65 ValueBuilder& operator=(const ValueBuilder& other);
66 // NOLINTNEXTLINE(performance-noexcept-move-constructor)
67 ValueBuilder& operator=(ValueBuilder&& other);
68
69 ValueBuilder(const formats::json::Value& other);
70 ValueBuilder(formats::json::Value&& other);
71
72 /// Converting constructors.
73 ValueBuilder(bool t);
74 ValueBuilder(const char* str);
75 ValueBuilder(const std::string& str);
76 ValueBuilder(std::string_view str);
77 ValueBuilder(int t);
78 ValueBuilder(unsigned int t);
79 ValueBuilder(uint64_t t);
80 ValueBuilder(int64_t t);
81 ValueBuilder(float t);
82 ValueBuilder(double t);
83
84 /// Universal constructor using Serialize
85 template <typename T>
86 ValueBuilder(const T& t) : ValueBuilder(DoSerialize(t)) {}
87
88 /// @brief Access member by key for modification.
89 /// @throw `TypeMismatchException` if not object or null value.
90 ValueBuilder operator[](std::string key);
91 /// @brief Access array member by index for modification.
92 /// @throw `TypeMismatchException` if not an array value.
93 /// @throw `OutOfBoundsException` if index is greater than size.
94 ValueBuilder operator[](std::size_t index);
95 /// @brief Access member by key for modification.
96 /// @throw `TypeMismatchException` if not object or null value.
97 template <
98 typename Tag, utils::StrongTypedefOps Ops,
99 typename Enable = std::enable_if_t<utils::IsStrongTypedefLoggable(Ops)>>
100 ValueBuilder operator[](utils::StrongTypedef<Tag, std::string, Ops> key);
101
102 /// @brief Emplaces new member w/o a check whether the key already exists.
103 /// @warning May create invalid JSON with duplicate key.
104 /// @throw `TypeMismatchException` if not object or null value.
105 void EmplaceNocheck(std::string_view key, ValueBuilder value);
106
107 /// @brief Remove key from object. If key is missing nothing happens.
108 /// @throw `TypeMismatchException` if value is not an object.
109 void Remove(std::string_view key);
110
111 iterator begin();
112 iterator end();
113
114 /// @brief Returns whether the array or object is empty.
115 /// @throw `TypeMismatchException` if not an array or an object.
116 bool IsEmpty() const;
117
118 /// @brief Returns true if *this holds a Null (Type::kNull).
119 bool IsNull() const noexcept;
120
121 /// @brief Returns true if *this is convertible to bool.
122 bool IsBool() const noexcept;
123
124 /// @brief Returns true if *this is convertible to int.
125 bool IsInt() const noexcept;
126
127 /// @brief Returns true if *this is convertible to int64_t.
128 bool IsInt64() const noexcept;
129
130 /// @brief Returns true if *this is convertible to uint64_t.
131 bool IsUInt64() const noexcept;
132
133 /// @brief Returns true if *this is convertible to double.
134 bool IsDouble() const noexcept;
135
136 /// @brief Returns true if *this is convertible to std::string.
137 bool IsString() const noexcept;
138
139 /// @brief Returns true if *this is an array (Type::kArray).
140 bool IsArray() const noexcept;
141
142 /// @brief Returns true if *this holds a map (Type::kObject).
143 bool IsObject() const noexcept;
144
145 /// @brief Returns array size or object members count.
146 /// @throw `TypeMismatchException` if not an array or an object.
147 std::size_t GetSize() const;
148
149 /// @brief Returns true if value holds a `key`.
150 /// @throw `TypeMismatchException` if `*this` is not a map or null.
151 bool HasMember(std::string_view key) const;
152
153 /// @brief Returns full path to this value.
154 std::string GetPath() const;
155
156 /// @brief Resize the array value or convert null value
157 /// into an array of requested size.
158 /// @throw `TypeMismatchException` if not an array or null.
159 void Resize(std::size_t size);
160
161 /// @brief Add element into the last position of array.
162 /// @throw `TypeMismatchException` if not an array or null.
163 void PushBack(ValueBuilder&& bld);
164
165 /// @brief Take out the resulting `Value` object.
166 /// After calling this method the object is in unspecified
167 /// (but valid - possibly null) state.
168 /// @throw `JsonException` if called not from the root builder.
169 formats::json::Value ExtractValue();
170
171 private:
172 class EmplaceEnabler {};
173
174 public:
175 /// @cond
176 ValueBuilder(EmplaceEnabler, impl::MutableValueWrapper) noexcept;
177 /// @endcond
178
179 private:
180 enum class CheckMemberExists { kYes, kNo };
181
182 explicit ValueBuilder(impl::MutableValueWrapper) noexcept;
183
184 static void Copy(impl::Value& to, const ValueBuilder& from);
185 static void Move(impl::Value& to, ValueBuilder&& from);
186
187 impl::Value& AddMember(std::string_view key, CheckMemberExists);
188
189 template <typename T>
190 static Value DoSerialize(const T& t);
191
192 impl::MutableValueWrapper value_;
193
194 friend class Iterator<IterTraits, common::IteratorDirection::kForward>;
195 friend class Iterator<IterTraits, common::IteratorDirection::kReverse>;
196};
197
198template <typename T>
199Value ValueBuilder::DoSerialize(const T& t) {
200 static_assert(
201 formats::common::impl::kHasSerialize<Value, T>,
202 "There is no `Serialize(const T&, formats::serialize::To<json::Value>)` "
203 "in namespace of `T` or `formats::serizalize`. "
204 ""
205 "Probably you forgot to include the "
206 "<userver/formats/serialize/common_containers.hpp> header "
207 "or one of the <formats/json/serialize_*.hpp> headers or you "
208 "have not provided a `Serialize` function overload.");
209
210 return Serialize(t, formats::serialize::To<Value>());
211}
212
213template <typename T>
214std::enable_if_t<std::is_integral<T>::value && sizeof(T) <= sizeof(int64_t),
215 Value>
216Serialize(T value, formats::serialize::To<Value>) {
217 using Type = std::conditional_t<std::is_signed<T>::value, int64_t, uint64_t>;
218 return json::ValueBuilder(static_cast<Type>(value)).ExtractValue();
219}
220
221json::Value Serialize(std::chrono::system_clock::time_point tp,
222 formats::serialize::To<Value>);
223
224template <typename Tag, utils::StrongTypedefOps Ops, typename Enable>
225ValueBuilder ValueBuilder::operator[](
226 utils::StrongTypedef<Tag, std::string, Ops> key) {
227 return (*this)[std::move(key.GetUnderlying())];
228}
229
230/// Optimized maps of StrongTypedefs serialization for JSON
231template <typename T>
234 Value>
236 json::ValueBuilder builder(formats::common::Type::kObject);
237 for (const auto& [key, value] : value) {
238 builder.EmplaceNocheck(key.GetUnderlying(), value);
239 }
240 return builder.ExtractValue();
241}
242
243/// Optimized maps serialization for JSON
244template <typename T>
246 std::is_convertible_v<typename T::key_type, std::string>,
247 Value>
249 json::ValueBuilder builder(formats::common::Type::kObject);
250 for (const auto& [key, value] : value) {
251 builder.EmplaceNocheck(key, value);
252 }
253 return builder.ExtractValue();
254}
255
256} // namespace formats::json
257
258USERVER_NAMESPACE_END