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::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