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