6#include <initializer_list>
13#include <userver/storages/postgres/field.hpp>
14#include <userver/storages/postgres/io/supported_types.hpp>
16#include <userver/logging/log.hpp>
18USERVER_NAMESPACE_BEGIN
23template <
typename T,
typename ExtractionTag>
29 RowDescription(detail::ResultWrapperPtr res) : res_{std::move(res)} {}
37 detail::ResultWrapperPtr res_;
49 using size_type = std::size_t;
53 using value_type =
Field;
54 using reference =
Field;
55 using pointer = const_iterator;
58 size_type RowIndex()
const {
return row_index_; }
68 const_iterator cbegin()
const;
69 const_iterator begin()
const {
return cbegin(); }
70 const_iterator cend()
const;
71 const_iterator end()
const {
return cend(); }
75 const_reverse_iterator crbegin()
const;
76 const_reverse_iterator rbegin()
const {
return crbegin(); }
77 const_reverse_iterator crend()
const;
78 const_reverse_iterator rend()
const {
return crend(); }
87 reference
operator[](
const std::string& name)
const;
110 template <
typename T>
111 void To(T&& val)
const;
115 template <
typename T>
121 template <
typename T>
125 template <
typename... T>
126 void To(T&&... val)
const;
138 template <
typename T,
typename... Y>
143 template <
typename T>
152 template <
typename T>
160 template <
typename... T>
161 void To(
const std::initializer_list<std::string>& names, T&&... val)
const;
162 template <
typename... T>
163 std::tuple<T...> As(
const std::initializer_list<std::string>& names)
const;
167 template <
typename... T>
168 void To(
const std::initializer_list<size_type>& indexes, T&&... val)
const;
169 template <
typename... T>
170 std::tuple<T...> As(
const std::initializer_list<size_type>& indexes)
const;
173 size_type IndexOfName(
const std::string&)
const;
175 FieldView GetFieldView(size_type index)
const;
180 template <
typename T,
typename Tag>
181 friend class TypedResultSet;
185 Row(detail::ResultWrapperPtr res, size_type row) : res_{std::move(res)}, row_index_{row} {}
189 bool IsValid()
const;
190 int Compare(
const Row& rhs)
const;
191 std::ptrdiff_t Distance(
const Row& rhs)
const;
192 Row& Advance(std::ptrdiff_t);
195 detail::ResultWrapperPtr res_;
196 size_type row_index_{0};
202 ConstRowIterator() =
default;
207 ConstRowIterator(detail::ResultWrapperPtr res, size_type row) : ConstDataIterator(std::move(res), row) {}
214 ReverseConstRowIterator() =
default;
219 ReverseConstRowIterator(detail::ResultWrapperPtr res, size_type row) : ConstDataIterator(std::move(res), row) {}
225struct IsOptionalFromOptional : std::false_type {};
228struct IsOptionalFromOptional<std::optional<std::optional<T>>> : std::true_type {};
231struct IsOneVariant : std::false_type {};
234struct IsOneVariant<std::variant<T>> : std::true_type {};
236template <
typename... Args>
237constexpr void AssertSaneTypeToDeserialize() {
239 !(IsOptionalFromOptional<std::remove_const_t<std::remove_reference_t<Args>>>::value || ...),
240 "Attempt to get an optional<optional<T>> was detected. Such "
241 "optional-from-optional types are very error prone, obfuscate code and "
242 "are ambiguous to deserialize. Change the type to just optional<T>"
245 !(IsOneVariant<std::remove_const_t<std::remove_reference_t<Args>>>::value || ...),
246 "Attempt to get an variant<T> was detected. Such variant from one type "
247 "obfuscates code. Change the type to just T"
253template <
typename IndexTuple,
typename... T>
254struct RowDataExtractorBase;
256template <std::size_t... Indexes,
typename... T>
257struct RowDataExtractorBase<std::index_sequence<Indexes...>, T...> {
258 static void ExtractValues(
const Row& row, T&&... val) {
259 static_assert(
sizeof...(Indexes) ==
sizeof...(T));
261 std::size_t field_index = 0;
262 const auto perform = [&](
auto&& arg) { row.GetFieldView(field_index++).To(std::forward<
decltype(arg)>(arg)); };
263 (perform(std::forward<T>(val)), ...);
265 static void ExtractTuple(
const Row& row, std::tuple<T...>& val) {
266 static_assert(
sizeof...(Indexes) ==
sizeof...(T));
268 std::size_t field_index = 0;
269 const auto perform = [&](
auto& arg) { row.GetFieldView(field_index++).To(arg); };
270 (perform(std::get<Indexes>(val)), ...);
272 static void ExtractTuple(
const Row& row, std::tuple<T...>&& val) {
273 static_assert(
sizeof...(Indexes) ==
sizeof...(T));
275 std::size_t field_index = 0;
276 const auto perform = [&](
auto& arg) { row.GetFieldView(field_index++).To(arg); };
277 (perform(std::get<Indexes>(val)), ...);
280 static void ExtractValues(
const Row& row,
const std::initializer_list<std::string>& names, T&&... val) {
281 (row
[*(names.begin() +
Indexes)
].To(std::forward<T>(val)), ...);
283 static void ExtractTuple(
const Row& row,
const std::initializer_list<std::string>& names, std::tuple<T...>& val) {
284 std::tuple<T...> tmp{row
[*(names.begin() +
Indexes)
].
template As<T>()...};
288 static void ExtractValues(
const Row& row,
const std::initializer_list<std::size_t>& indexes, T&&... val) {
289 (row
[*(indexes.begin() +
Indexes)
].To(std::forward<T>(val)), ...);
291 static void ExtractTuple(
const Row& row,
const std::initializer_list<std::size_t>& indexes, std::tuple<T...>& val) {
292 std::tuple<T...> tmp{row
[*(indexes.begin() +
Indexes)
].
template As<T>()...};
297template <
typename... T>
298struct RowDataExtractor : RowDataExtractorBase<std::index_sequence_for<T...>, T...> {};
301struct TupleDataExtractor;
302template <
typename... T>
303struct TupleDataExtractor<std::tuple<T...>> : RowDataExtractorBase<std::index_sequence_for<T...>, T...> {};
306template <
typename RowType>
307constexpr void AssertRowTypeIsMappedToPgOrIsCompositeType() {
310 io::
traits::kIsMappedToPg<RowType> || io::
traits::kIsCompositeType<RowType>,
311 "Row type must be mapped to pg type(CppToUserPg) or one of the "
313 "1. primitive type. "
315 "3. Aggregation type. See std::aggregation. "
316 "4. Has a Introspect method that makes the std::tuple from your "
318 "For more info see `uPg: Typed PostgreSQL results` chapter in docs."
326 To(std::forward<T>(val), kFieldTag);
331 detail::AssertSaneTypeToDeserialize<T>();
333 using ValueType = std::decay_t<T>;
334 io::
traits::AssertIsValidRowType<ValueType>();
335 using RowType = io::
RowType<ValueType>;
336 using TupleType =
typename RowType::TupleType;
337 constexpr auto tuple_size = RowType::size;
338 if (tuple_size >
Size()) {
340 }
else if (tuple_size <
Size()) {
346 detail::TupleDataExtractor<TupleType>::ExtractTuple(*
this, RowType::GetTuple(std::forward<T>(val)));
351 detail::AssertSaneTypeToDeserialize<T>();
352 using ValueType = std::decay_t<T>;
353 detail::AssertRowTypeIsMappedToPgOrIsCompositeType<ValueType>();
361 (*
this)
[0
].To(std::forward<T>(val));
364template <
typename... T>
366 detail::AssertSaneTypeToDeserialize<T...>();
367 if (
sizeof...(T) >
Size()) {
370 detail::RowDataExtractor<T...>::ExtractValues(*
this, std::forward<T>(val)...);
373template <
typename T,
typename... Y>
375 if constexpr (
sizeof...(Y) > 0) {
376 std::tuple<T, Y...> res;
380 return As<T>(kFieldTag);
384template <
typename... T>
385void Row::
To(
const std::initializer_list<std::string>& names, T&&... val)
const {
386 detail::AssertSaneTypeToDeserialize<T...>();
387 if (
sizeof...(T) != names.size()) {
390 detail::RowDataExtractor<T...>::ExtractValues(*
this, names, std::forward<T>(val)...);
385void Row::
To(
const std::initializer_list<std::string>& names, T&&... val)
const {
…}
393template <
typename... T>
394std::tuple<T...>
Row::As(
const std::initializer_list<std::string>& names)
const {
395 if (
sizeof...(T) != names.size()) {
398 std::tuple<T...> res;
399 detail::RowDataExtractor<T...>::ExtractTuple(*
this, names, res);
403template <
typename... T>
404void Row::
To(
const std::initializer_list<size_type>& indexes, T&&... val)
const {
405 detail::AssertSaneTypeToDeserialize<T...>();
406 if (
sizeof...(T) != indexes.size()) {
409 detail::RowDataExtractor<T...>::ExtractValues(*
this, indexes, std::forward<T>(val)...);
404void Row::
To(
const std::initializer_list<size_type>& indexes, T&&... val)
const {
…}
412template <
typename... T>
413std::tuple<T...>
Row::As(
const std::initializer_list<size_type>& indexes)
const {
414 if (
sizeof...(T) != indexes.size()) {
417 std::tuple<T...> res;
418 detail::RowDataExtractor<T...>::ExtractTuple(*
this, indexes, res);