userver: userver/formats/bson/value.hpp Source File
Loading...
Searching...
No Matches
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 {
41public:
43
44 using const_iterator = Iterator<const Value, common::IteratorDirection::kForward>;
45 using const_reverse_iterator = Iterator<const Value, common::IteratorDirection::kReverse>;
46 using Exception = formats::bson::BsonException;
47 using ParseException = formats::bson::ParseException;
48 using ExceptionWithPath = formats::bson::ExceptionWithPath;
49 using Builder = ValueBuilder;
50
51 /// @brief Selectors for duplicate fields parsing behavior
52 /// @see SetDuplicateFieldsPolicy
53 enum class DuplicateFieldsPolicy { kForbid, kUseFirst, kUseLast };
54
55 /// Constructs a `null` value
57
58 Value(const Value&) = default;
59 Value(Value&&) noexcept = default;
60 Value& operator=(const Value&) & = default;
61 Value& operator=(Value&&) & noexcept = default;
62
63 template <class T>
64 Value& operator=(T&&) && {
65 static_assert(
66 !sizeof(T),
67 "You're assigning to a temporary formats::bson::Value! Use "
68 "formats::bson::ValueBuilder for data modifications."
69 );
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
174 return Parse(*this, formats::parse::To<T>{});
175 }
176
177 /// Extracts the specified type with strict type checks, or constructs the
178 /// default value when the field is not present
179 template <typename T, typename First, typename... Rest>
180 auto As(First&& default_arg, Rest&&... more_default_args) const {
181 if (IsMissing() || IsNull()) {
182 // intended raw ctor call, sometimes casts
183 // NOLINTNEXTLINE(google-readability-casting)
184 return decltype(As<T>())(std::forward<First>(default_arg), 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
216 /// Extracts the specified type with strict type checks, or constructs the
217 /// default value when the field is not present
218 template <typename T, typename First, typename... Rest>
219 T ConvertTo(First&& default_arg, Rest&&... more_default_args) const {
220 if (IsMissing() || IsNull()) {
221 // NOLINTNEXTLINE(google-readability-casting)
222 return T(std::forward<First>(default_arg), 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
256protected:
257 const impl::BsonHolder& GetBson() const;
258
259private:
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
269 Parse(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(const Value& value, parse::To<std::chrono::system_clock::time_point>);
291
292Oid Parse(const Value& value, parse::To<Oid>);
293
294Binary Parse(const Value& value, parse::To<Binary>);
295
296Decimal128 Parse(const Value& value, parse::To<Decimal128>);
297
298Timestamp Parse(const Value& value, parse::To<Timestamp>);
299
300Document Parse(const Value& value, parse::To<Document>);
301
302template <>
303bool Value::ConvertTo<bool>() const;
304
305template <>
306int64_t Value::ConvertTo<int64_t>() const;
307
308template <>
309uint64_t Value::ConvertTo<uint64_t>() const;
310
311template <>
312double Value::ConvertTo<double>() const;
313
314template <>
315std::string Value::ConvertTo<std::string>() const;
316/// @endcond
317
318/// @brief Wrapper for handy python-like iteration over a map
319///
320/// @code
321/// for (const auto& [name, value]: Items(map)) ...
322/// @endcode
323using formats::common::Items;
324
325} // namespace formats::bson
326
327/// Although we provide user defined literals, please beware that
328/// 'using namespace ABC' may contradict code style of your company.
329namespace formats::literals {
330
331bson::Value operator"" _bson(const char* str, std::size_t len);
332
333} // namespace formats::literals
334
335USERVER_NAMESPACE_END