6#include <initializer_list>
13#include <userver/storages/postgres/field.hpp>
14#include <userver/storages/postgres/io/supported_types.hpp>
15#include <userver/utils/zstring_view.hpp>
17#include <userver/logging/log.hpp>
19USERVER_NAMESPACE_BEGIN
24template <
typename T,
typename ExtractionTag>
30 RowDescription(detail::ResultWrapperPtr res)
31 : res_{std::move(res)}
40 detail::ResultWrapperPtr res_;
52 using size_type = std::size_t;
56 using value_type =
Field;
57 using reference =
Field;
58 using pointer = const_iterator;
61 size_type RowIndex()
const {
return row_index_; }
71 const_iterator cbegin()
const;
72 const_iterator begin()
const {
return cbegin(); }
73 const_iterator cend()
const;
74 const_iterator end()
const {
return cend(); }
78 const_reverse_iterator crbegin()
const;
79 const_reverse_iterator rbegin()
const {
return crbegin(); }
80 const_reverse_iterator crend()
const;
81 const_reverse_iterator rend()
const {
return crend(); }
113 template <
typename T>
114 void To(T&& val)
const;
118 template <
typename T>
124 template <
typename T>
128 template <
typename... T>
129 void To(T&&... val)
const;
141 template <
typename T,
typename... Y>
146 template <
typename T>
155 template <
typename T>
163 template <
typename... T>
164 void To(
const std::initializer_list<USERVER_NAMESPACE::utils::
zstring_view>& names, T&&... val)
const;
165 template <
typename... T>
166 std::tuple<T...> As(
const std::initializer_list<USERVER_NAMESPACE::utils::
zstring_view>& names)
const;
170 template <
typename... T>
171 void To(
const std::initializer_list<size_type>& indexes, T&&... val)
const;
172 template <
typename... T>
173 std::tuple<T...> As(
const std::initializer_list<size_type>& indexes)
const;
176 size_type IndexOfName(USERVER_NAMESPACE::utils::
zstring_view)
const;
178 FieldView GetFieldView(size_type index)
const;
183 template <
typename T,
typename Tag>
184 friend class TypedResultSet;
188 Row(detail::ResultWrapperPtr res, size_type row)
189 : res_{std::move(res)},
195 bool IsValid()
const;
196 int Compare(
const Row& rhs)
const;
197 std::ptrdiff_t Distance(
const Row& rhs)
const;
198 Row& Advance(std::ptrdiff_t);
201 detail::ResultWrapperPtr res_;
202 size_type row_index_{0};
208 ConstRowIterator() =
default;
213 ConstRowIterator(detail::ResultWrapperPtr res, size_type row)
214 : ConstDataIterator(std::move(res), row)
222 ReverseConstRowIterator() =
default;
227 ReverseConstRowIterator(detail::ResultWrapperPtr res, size_type row)
228 : ConstDataIterator(std::move(res), row)
235struct IsOptionalFromOptional : std::false_type {};
238struct IsOptionalFromOptional<std::optional<std::optional<T>>> : std::true_type {};
241struct IsOneVariant : std::false_type {};
244struct IsOneVariant<std::variant<T>> : std::true_type {};
246template <
typename... Args>
247constexpr void AssertSaneTypeToDeserialize() {
249 !(IsOptionalFromOptional<std::remove_const_t<std::remove_reference_t<Args>>>::value || ...),
250 "Attempt to get an optional<optional<T>> was detected. Such "
251 "optional-from-optional types are very error prone, obfuscate code and "
252 "are ambiguous to deserialize. Change the type to just optional<T>"
255 !(IsOneVariant<std::remove_const_t<std::remove_reference_t<Args>>>::value || ...),
256 "Attempt to get an variant<T> was detected. Such variant from one type "
257 "obfuscates code. Change the type to just T"
263template <
typename IndexTuple,
typename... T>
264struct RowDataExtractorBase;
266template <std::size_t... Indexes,
typename... T>
267struct RowDataExtractorBase<std::index_sequence<Indexes...>, T...> {
268 static void ExtractValues(
const Row& row, T&&... val) {
269 static_assert(
sizeof...(Indexes) ==
sizeof...(T));
271 std::size_t field_index = 0;
272 const auto perform = [&](
auto&& arg) { row.GetFieldView(field_index++).To(std::forward<
decltype(arg)>(arg)); };
273 (perform(std::forward<T>(val)), ...);
275 static void ExtractTuple(
const Row& row, std::tuple<T...>& val) {
276 static_assert(
sizeof...(Indexes) ==
sizeof...(T));
278 std::size_t field_index = 0;
279 const auto perform = [&](
auto& arg) { row.GetFieldView(field_index++).To(arg); };
280 (perform(std::get<Indexes>(val)), ...);
282 static void ExtractTuple(
const Row& row, std::tuple<T...>&& val) {
283 static_assert(
sizeof...(Indexes) ==
sizeof...(T));
285 std::size_t field_index = 0;
286 const auto perform = [&](
auto& arg) { row.GetFieldView(field_index++).To(arg); };
287 (perform(std::get<Indexes>(val)), ...);
290 static void ExtractValues(
292 const std::initializer_list<USERVER_NAMESPACE::utils::
zstring_view>& names,
295 (row
[*(names.begin() +
Indexes)
].To(std::forward<T>(val)), ...);
297 static void ExtractTuple(
299 const std::initializer_list<USERVER_NAMESPACE::utils::
zstring_view>& names,
300 std::tuple<T...>& val
302 std::tuple<T...> tmp{row
[*(names.begin() +
Indexes)
].
template As<T>()...};
306 static void ExtractValues(
const Row& row,
const std::initializer_list<std::size_t>& indexes, T&&... val) {
307 (row
[*(indexes.begin() +
Indexes)
].To(std::forward<T>(val)), ...);
309 static void ExtractTuple(
const Row& row,
const std::initializer_list<std::size_t>& indexes, std::tuple<T...>& val) {
310 std::tuple<T...> tmp{row
[*(indexes.begin() +
Indexes)
].
template As<T>()...};
315template <
typename... T>
316struct RowDataExtractor : RowDataExtractorBase<std::index_sequence_for<T...>, T...> {};
319struct TupleDataExtractor;
320template <
typename... T>
321struct TupleDataExtractor<std::tuple<T...>> : RowDataExtractorBase<std::index_sequence_for<T...>, T...> {};
324template <
typename RowType>
325constexpr void AssertRowTypeIsMappedToPgOrIsCompositeType() {
328 io::
traits::kIsMappedToPg<RowType> || io::
traits::kIsCompositeType<RowType>,
329 "Row type must be mapped to pg type(CppToUserPg) or one of the "
331 "1. primitive type. "
333 "3. Aggregation type. See std::aggregation. "
334 "4. Has a Introspect method that makes the std::tuple from your "
336 "For more info see `uPg: Typed PostgreSQL results` chapter in docs."
344 To(std::forward<T>(val), kFieldTag);
349 detail::AssertSaneTypeToDeserialize<T>();
351 using ValueType = std::decay_t<T>;
352 io::
traits::AssertIsValidRowType<ValueType>();
353 using RowType = io::
RowType<ValueType>;
354 using TupleType =
typename RowType::TupleType;
355 constexpr auto tuple_size = RowType::size;
356 if (tuple_size >
Size()) {
358 }
else if (tuple_size <
Size()) {
360 <<
"Row size is greater that the number of data members in "
365 detail::TupleDataExtractor<TupleType>::ExtractTuple(*
this, RowType::GetTuple(std::forward<T>(val)));
370 detail::AssertSaneTypeToDeserialize<T>();
371 using ValueType = std::decay_t<T>;
372 detail::AssertRowTypeIsMappedToPgOrIsCompositeType<ValueType>();
380 (*
this)
[0
].To(std::forward<T>(val));
383template <
typename... T>
385 detail::AssertSaneTypeToDeserialize<T...>();
386 if (
sizeof...(T) >
Size()) {
389 detail::RowDataExtractor<T...>::ExtractValues(*
this, std::forward<T>(val)...);
392template <
typename T,
typename... Y>
394 if constexpr (
sizeof...(Y) > 0) {
395 std::tuple<T, Y...> res;
399 return As<T>(kFieldTag);
403template <
typename... T>
404void Row::
To(
const std::initializer_list<USERVER_NAMESPACE::utils::
zstring_view>& names, T&&... val)
const {
405 detail::AssertSaneTypeToDeserialize<T...>();
406 if (
sizeof...(T) != names.size()) {
409 detail::RowDataExtractor<T...>::ExtractValues(*
this, names, std::forward<T>(val)...);
412template <
typename... T>
413std::tuple<T...>
Row::As(
const std::initializer_list<USERVER_NAMESPACE::utils::
zstring_view>& names)
const {
414 if (
sizeof...(T) != names.size()) {
417 std::tuple<T...> res;
418 detail::RowDataExtractor<T...>::ExtractTuple(*
this, names, res);
422template <
typename... T>
423void Row::
To(
const std::initializer_list<size_type>& indexes, T&&... val)
const {
424 detail::AssertSaneTypeToDeserialize<T...>();
425 if (
sizeof...(T) != indexes.size()) {
428 detail::RowDataExtractor<T...>::ExtractValues(*
this, indexes, std::forward<T>(val)...);
431template <
typename... T>
432std::tuple<T...>
Row::As(
const std::initializer_list<size_type>& indexes)
const {
433 if (
sizeof...(T) != indexes.size()) {
436 std::tuple<T...> res;
437 detail::RowDataExtractor<T...>::ExtractTuple(*
this, indexes, res);