userver: userver/ydb/io/list.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
list.hpp
1#pragma once
2
3#include <ydb-cpp-sdk/client/value/value.h>
4
5#include <iterator>
6#include <type_traits>
7#include <vector> // for InsertRow
8
9#if __cpp_lib_ranges >= 201911L
10#include <ranges>
11#endif
12
13#include <userver/utils/assert.hpp>
14#include <userver/utils/meta.hpp>
15
16#include <userver/ydb/io/traits.hpp>
17
18USERVER_NAMESPACE_BEGIN
19
20namespace ydb {
21
22namespace impl {
23
24template <typename T>
25class ParseItemsIterator final {
26 public:
27 using difference_type = std::ptrdiff_t;
28 using value_type = T;
29 using reference = T;
30 using iterator_category = std::input_iterator_tag;
31
32 ParseItemsIterator() = default;
33
34 ParseItemsIterator(NYdb::TValueParser& parser, const ParseContext& context)
35 : parser_(&parser), context_(&context) {
36 ++*this;
37 }
38
39 // Trivially copyable.
40 ParseItemsIterator(const ParseItemsIterator&) = default;
41 ParseItemsIterator& operator=(const ParseItemsIterator&) = default;
42
43 T operator*() const {
44 UASSERT(parser_ && context_);
45 return ydb::Parse<T>(*parser_, *context_);
46 }
47
48 ParseItemsIterator& operator++() {
49 UASSERT(parser_ && context_);
50 if (!parser_->TryNextListItem()) {
51 parser_ = nullptr;
52 }
53 return *this;
54 }
55
56 bool operator==(const ParseItemsIterator& other) const noexcept {
57 UASSERT(parser_ == nullptr || other.parser_ == nullptr);
58 return parser_ == other.parser_;
59 }
60
61 private:
62 NYdb::TValueParser* parser_{nullptr};
63 const ParseContext* context_{nullptr};
64};
65
66} // namespace impl
67
68/// @cond
69struct InsertColumn;
70using InsertRow = std::vector<InsertColumn>;
71/// @endcond
72
73template <typename T>
74struct ValueTraits<T, std::enable_if_t<meta::kIsRange<T> && !meta::kIsMap<T>>> {
75 using ValueType = meta::RangeValueType<T>;
76
77 static T Parse(NYdb::TValueParser& parser, const ParseContext& context) {
78 parser.OpenList();
79#if __cpp_lib_ranges_to_container >= 202202L
80 T result =
81 std::ranges::subrange{
82 impl::ParseItemsIterator<ValueType>{parser, context},
83 impl::ParseItemsIterator<ValueType>{},
84 } |
85 std::ranges::to<T>();
86#else
87 T result(impl::ParseItemsIterator<ValueType>{parser, context},
88 impl::ParseItemsIterator<ValueType>{});
89#endif
90 parser.CloseList();
91 return result;
92 }
93
94 template <typename Builder, typename U = const T&>
95 static void Write(NYdb::TValueBuilderBase<Builder>& builder, U&& value) {
96 bool list_opened = false;
97 for (auto&& item : value) {
98 if (!list_opened) {
99 builder.BeginList();
100 list_opened = true;
101 }
102 builder.AddListItem();
103 ydb::Write(builder, item);
104 }
105 if (list_opened) {
106 builder.EndList();
107 } else if constexpr (std::is_same_v<ValueType, InsertRow>) {
108 // Legacy behavior. Sometimes YDB will throw here due to insufficient type
109 // info.
110 builder.EmptyList();
111 } else {
112 builder.EmptyList(ValueTraits<ValueType>::MakeType());
113 }
114 }
115
116 static NYdb::TType MakeType() {
117 NYdb::TTypeBuilder builder;
118 builder.List(ValueTraits<ValueType>::MakeType());
119 return builder.Build();
120 }
121};
122
123} // namespace ydb
124
125USERVER_NAMESPACE_END