userver: userver/formats/bson/value.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.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/formats/bson/value.hpp
4/// @brief @copybrief formats::bson::Value
5
6#include <chrono>
7#include <cstddef>
8#include <cstdint>
9#include <string>
10
11#include <userver/formats/bson/exception.hpp>
12#include <userver/formats/bson/iterator.hpp>
13#include <userver/formats/bson/types.hpp>
14#include <userver/formats/common/items.hpp>
15#include <userver/formats/common/meta.hpp>
16#include <userver/formats/parse/common.hpp>
17#include <userver/formats/parse/common_containers.hpp>
18
19USERVER_NAMESPACE_BEGIN
20
21namespace formats::bson {
22namespace impl {
23class BsonBuilder;
24class ValueImpl;
25} // namespace impl
26
27class Document;
28class ValueBuilder;
29
30/// @brief Non-mutable BSON value representation.
31///
32/// Class provides non mutable access BSON value. For modification and
33/// construction of new BSON values use formats::bson::ValueBuilder.
34///
35/// ## Example usage:
36///
37/// @snippet formats/bson/value_test.cpp Sample formats::bson::Value usage
38///
39/// @see @ref scripts/docs/en/userver/formats.md
40class Value {
41 public:
43
44 using const_iterator =
45 Iterator<const Value, common::IteratorDirection::kForward>;
46 using const_reverse_iterator =
47 Iterator<const Value, common::IteratorDirection::kReverse>;
48 using Exception = formats::bson::BsonException;
49 using ParseException = formats::bson::ParseException;
50 using ExceptionWithPath = formats::bson::ExceptionWithPath;
51 using Builder = ValueBuilder;
52
53 /// @brief Selectors for duplicate fields parsing behavior
54 /// @see SetDuplicateFieldsPolicy
55 enum class DuplicateFieldsPolicy { kForbid, kUseFirst, kUseLast };
56
57 /// Constructs a `null` value
59
60 Value(const Value&) = default;
61 Value(Value&&) noexcept = default;
62 Value& operator=(const Value&) & = default;
63 Value& operator=(Value&&) & noexcept = default;
64
65 template <class T>
66 Value& operator=(T&&) && {
67 static_assert(!sizeof(T),
68 "You're assigning to a temporary formats::bson::Value! Use "
69 "formats::bson::ValueBuilder for data modifications.");
70 return *this;
71 }
72
73 /// @cond
74 /// Constructor from implementation, internal use only
75 explicit Value(impl::ValueImplPtr);
76 /// @endcond
77
78 /// @brief Retrieves document field by name
79 /// @param name field name
80 /// @throws TypeMismatchException if value is not a missing value, a document,
81 /// or `null`
82 Value operator[](const std::string& name) const;
83
84 /// @brief Retrieves array element by index
85 /// @param index element index
86 /// @throws TypeMismatchException if value is not an array or `null`
87 /// @throws OutOfBoundsException if index is invalid for the array
88 Value operator[](uint32_t index) const;
89
90 /// @brief Checks whether the document has a field
91 /// @param name field name
92 /// @throws TypeMismatchExcepiton if value is not a document or `null`
93 bool HasMember(const std::string& name) const;
94
95 /// @brief Returns an iterator to the first array element/document field
96 /// @throws TypeMismatchException if value is not a document, array or `null`
97 const_iterator begin() const;
98
99 /// @brief Returns an iterator following the last array element/document field
100 /// @throws TypeMismatchException if value is not a document, array or `null`
101 const_iterator end() const;
102
103 /// @brief Returns a reversed iterator to the last array element
104 /// @throws TypeMismatchException if value is not an array or `null`
105 const_reverse_iterator rbegin() const;
106
107 /// @brief Returns a reversed iterator following the first array element
108 /// @throws TypeMismatchException if value is not an array or `null`
109 const_reverse_iterator rend() const;
110
111 /// @brief Returns whether the document/array is empty
112 /// @throws TypeMismatchException if value is not a document, array or `null`
113 /// @note Returns `true` for `null`.
114 bool IsEmpty() const;
115
116 /// @brief Returns the number of elements in a document/array
117 /// @throws TypeMismatchException if value is not a document, array or `null`
118 /// @note May require linear time before the first element access.
119 /// @note Returns 0 for `null`.
120 uint32_t GetSize() const;
121
122 /// Returns value path in a document
123 std::string GetPath() const;
124
125 bool operator==(const Value&) const;
126 bool operator!=(const Value&) const;
127
128 /// @brief Checks whether the selected element exists
129 /// @note MemberMissingException is throws on nonexisting element access
130 bool IsMissing() const;
131
132 /// @name Type checking
133 /// @{
134 bool IsArray() const;
135 bool IsDocument() const;
136 bool IsNull() const;
137 bool IsBool() const;
138 bool IsInt32() const;
139 bool IsInt64() const;
140 bool IsDouble() const;
141 bool IsString() const;
142 bool IsDateTime() const;
143 bool IsOid() const;
144 bool IsBinary() const;
145 bool IsDecimal128() const;
146 bool IsMinKey() const;
147 bool IsMaxKey() const;
148 bool IsTimestamp() const;
149
150 bool IsObject() const { return IsDocument(); }
151 /// @}
152
153 // clang-format off
154
155 /// Extracts the specified type with strict type checks
156 ///
157 /// ## Example usage:
158 ///
159 /// @snippet formats/bson/value_test.cpp Sample formats::bson::Value::As<T>() usage
160 ///
161 /// @see @ref scripts/docs/en/userver/formats.md
162
163 // clang-format on
164
165 template <typename T>
166 auto As() const {
167 static_assert(
168 formats::common::impl::kHasParse<Value, T>,
169 "There is no `Parse(const Value&, formats::parse::To<T>)` in namespace "
170 "of `T` or `formats::parse`. "
171 "Probably you have not provided a `Parse` function overload.");
172
173 return Parse(*this, formats::parse::To<T>{});
174 }
175
176 /// Extracts the specified type with strict type checks, or constructs the
177 /// default value when the field is not present
178 template <typename T, typename First, typename... Rest>
179 auto As(First&& default_arg, Rest&&... more_default_args) const {
180 if (IsMissing() || IsNull()) {
181 // intended raw ctor call, sometimes casts
182 // NOLINTNEXTLINE(google-readability-casting)
183 return decltype(As<T>())(std::forward<First>(default_arg),
184 std::forward<Rest>(more_default_args)...);
185 }
186 return As<T>();
187 }
188
189 /// @brief Returns value of *this converted to T or T() if this->IsMissing().
190 /// @throw Anything derived from std::exception.
191 /// @note Use as `value.As<T>({})`
192 template <typename T>
193 auto As(DefaultConstructed) const {
194 return (IsMissing() || IsNull()) ? decltype(As<T>())() : As<T>();
195 }
196
197 /// @brief Extracts the specified type with relaxed type checks.
198 /// For example, `true` may be converted to 1.0.
199 template <typename T>
200 T ConvertTo() const {
201 if constexpr (formats::common::impl::kHasConvert<Value, T>) {
202 return Convert(*this, formats::parse::To<T>{});
203 } else if constexpr (formats::common::impl::kHasParse<Value, T>) {
204 return Parse(*this, formats::parse::To<T>{});
205 } else {
206 static_assert(
207 !sizeof(T),
208 "There is no `Convert(const Value&, formats::parse::To<T>)` or"
209 "`Parse(const Value&, formats::parse::To<T>)`"
210 "in namespace of `T` or `formats::parse`. "
211 "Probably you have not provided a `Convert` function overload.");
212 }
213 }
214
215 /// Extracts the specified type with strict type checks, or constructs the
216 /// default value when the field is not present
217 template <typename T, typename First, typename... Rest>
218 T ConvertTo(First&& default_arg, Rest&&... more_default_args) const {
219 if (IsMissing() || IsNull()) {
220 // NOLINTNEXTLINE(google-readability-casting)
221 return T(std::forward<First>(default_arg),
222 std::forward<Rest>(more_default_args)...);
223 }
224 return ConvertTo<T>();
225 }
226
227 /// @brief Changes parsing behavior when duplicate fields are encountered.
228 /// Should not be used normally.
229 /// @details Should be called before the first field access. Only affects
230 /// documents. Default policy is to throw an exception when duplicate fields
231 /// are encountered.
232 /// @warning At most one value will be read, all others will be discarded and
233 /// cannot be serialized back!
235
236 /// Throws a MemberMissingException if the selected element does not exist
237 void CheckNotMissing() const;
238
239 /// @brief Throws a TypeMismatchException if the selected element
240 /// is not an array or null
241 void CheckArrayOrNull() const;
242
243 /// @brief Throws a TypeMismatchException if the selected element
244 /// is not a document or null
246
247 /// @cond
248 /// Same, for parsing capabilities
249 void CheckObjectOrNull() const { CheckDocumentOrNull(); }
250
251 /// @brief Returns an array as its internal representation (BSON document),
252 /// internal use only
253 Document GetInternalArrayDocument() const;
254 /// @endcond
255
256 protected:
257 const impl::BsonHolder& GetBson() const;
258
259 private:
260 friend class ValueBuilder;
261 friend class impl::BsonBuilder;
262
263 friend bool Parse(const Value& value, parse::To<bool>);
264 friend int64_t Parse(const Value& value, parse::To<int64_t>);
265 friend uint64_t Parse(const Value& value, parse::To<uint64_t>);
266 friend double Parse(const Value& value, parse::To<double>);
267 friend std::string Parse(const Value& value, parse::To<std::string>);
268 friend std::chrono::system_clock::time_point Parse(
269 const Value& value, parse::To<std::chrono::system_clock::time_point>);
270 friend Oid Parse(const Value& value, parse::To<Oid>);
271 friend Binary Parse(const Value& value, parse::To<Binary>);
272 friend Decimal128 Parse(const Value& value, parse::To<Decimal128>);
273 friend Timestamp Parse(const Value& value, parse::To<Timestamp>);
274 friend Document Parse(const Value& value, parse::To<Document>);
275
276 impl::ValueImplPtr impl_;
277};
278
279/// @cond
280bool Parse(const Value& value, parse::To<bool>);
281
282int64_t Parse(const Value& value, parse::To<int64_t>);
283
284uint64_t Parse(const Value& value, parse::To<uint64_t>);
285
286double Parse(const Value& value, parse::To<double>);
287
288std::string Parse(const Value& value, parse::To<std::string>);
289
290std::chrono::system_clock::time_point Parse(
291 const Value& value, parse::To<std::chrono::system_clock::time_point>);
292
293Oid Parse(const Value& value, parse::To<Oid>);
294
295Binary Parse(const Value& value, parse::To<Binary>);
296
297Decimal128 Parse(const Value& value, parse::To<Decimal128>);
298
299Timestamp Parse(const Value& value, parse::To<Timestamp>);
300
301Document Parse(const Value& value, parse::To<Document>);
302
303template <>
304bool Value::ConvertTo<bool>() const;
305
306template <>
307int64_t Value::ConvertTo<int64_t>() const;
308
309template <>
310uint64_t Value::ConvertTo<uint64_t>() const;
311
312template <>
313double Value::ConvertTo<double>() const;
314
315template <>
316std::string Value::ConvertTo<std::string>() const;
317/// @endcond
318
319/// @brief Wrapper for handy python-like iteration over a map
320///
321/// @code
322/// for (const auto& [name, value]: Items(map)) ...
323/// @endcode
324using formats::common::Items;
325
326} // namespace formats::bson
327
328/// Although we provide user defined literals, please beware that
329/// 'using namespace ABC' may contradict code style of your company.
330namespace formats::literals {
331
332bson::Value operator"" _bson(const char* str, std::size_t len);
333
334} // namespace formats::literals
335
336USERVER_NAMESPACE_END