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