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 {
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 auto 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 auto 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 decltype(As<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>
192 auto As(DefaultConstructed) const {
193 return (IsMissing() || IsNull()) ? decltype(As<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 friend bool Parse(const Value& value, parse::To<bool>);
263 friend int64_t Parse(const Value& value, parse::To<int64_t>);
264 friend uint64_t Parse(const Value& value, parse::To<uint64_t>);
265 friend double Parse(const Value& value, parse::To<double>);
266 friend std::string Parse(const Value& value, parse::To<std::string>);
267 friend std::chrono::system_clock::time_point Parse(
268 const Value& value, parse::To<std::chrono::system_clock::time_point>);
269 friend Oid Parse(const Value& value, parse::To<Oid>);
270 friend Binary Parse(const Value& value, parse::To<Binary>);
271 friend Decimal128 Parse(const Value& value, parse::To<Decimal128>);
272 friend Timestamp Parse(const Value& value, parse::To<Timestamp>);
273 friend Document Parse(const Value& value, parse::To<Document>);
274
275 impl::ValueImplPtr impl_;
276};
277
278/// @cond
279bool Parse(const Value& value, parse::To<bool>);
280
281int64_t Parse(const Value& value, parse::To<int64_t>);
282
283uint64_t Parse(const Value& value, parse::To<uint64_t>);
284
285double Parse(const Value& value, parse::To<double>);
286
287std::string Parse(const Value& value, parse::To<std::string>);
288
289std::chrono::system_clock::time_point Parse(
290 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