6#include <initializer_list>
15#include <fmt/format.h>
17#include <userver/storages/postgres/exceptions.hpp>
18#include <userver/storages/postgres/io/supported_types.hpp>
19#include <userver/storages/postgres/postgres_fwd.hpp>
21#include <userver/storages/postgres/detail/const_data_iterator.hpp>
23#include <userver/compiler/demangle.hpp>
24#include <userver/logging/log.hpp>
26USERVER_NAMESPACE_BEGIN
212 RowDescription(detail::ResultWrapperPtr res) : res_{std::move(res)} {}
220 detail::ResultWrapperPtr res_;
225template <
typename T,
typename ExtractionTag>
228class FieldView
final {
230 using size_type = std::size_t;
232 FieldView(
const detail::ResultWrapper& res, size_type row_index,
233 size_type field_index)
234 : res_{res}, row_index_{row_index}, field_index_{field_index} {}
236 template <
typename T>
237 size_type To(T&& val)
const {
238 using ValueType =
typename std::decay<T>::type;
239 auto fb = GetBuffer();
240 return ReadNullable(fb, std::forward<T>(val),
246 std::string_view Name()
const;
247 const io::TypeBufferCategory& GetTypeBufferCategories()
const;
249 template <
typename T>
251 std::true_type)
const {
252 using ValueType =
typename std::decay<T>::type;
255 NullSetter::SetNull(val);
257 Read(fb, std::forward<T>(val));
262 template <
typename T>
263 size_type ReadNullable(
const io::
FieldBuffer& buffer, T&& val,
264 std::false_type)
const {
265 if (buffer.is_null) {
266 throw FieldValueIsNull{field_index_, Name(), val};
268 Read(buffer, std::forward<T>(val));
270 return buffer.length;
273 template <
typename T>
275 using ValueType =
typename std::decay<T>::type;
276 io::
traits::CheckParser<ValueType>();
278 io::ReadBuffer(buffer, std::forward<T>(val), GetTypeBufferCategories());
281 fmt::format(
" (ResultSet error while reading field #{} name `{}`)",
282 field_index_, Name()));
287 const detail::ResultWrapper& res_;
288 const size_type row_index_;
289 const size_type field_index_;
295 using size_type = std::size_t;
297 size_type RowIndex()
const {
return row_index_; }
298 size_type FieldIndex()
const {
return field_index_; }
306 Oid GetTypeOid()
const;
316 template <
typename T>
317 size_type
To(T&& val)
const {
318 return FieldView{*res_, row_index_, field_index_}.To(std::forward<T>(val));
323 template <
typename T>
324 void Coalesce(T& val,
const T& default_val)
const {
334 template <
typename T>
335 typename std::decay<T>::
type As()
const {
343 template <
typename T>
345 if (IsNull())
return default_val;
349 const io::TypeBufferCategory& GetTypeBufferCategories()
const;
356 Field(detail::ResultWrapperPtr res, size_type row, size_type col)
357 : res_{std::move(res)}, row_index_{row}, field_index_{col} {}
361 bool IsValid()
const;
362 int Compare(
const Field& rhs)
const;
363 std::ptrdiff_t Distance(
const Field& rhs)
const;
364 Field& Advance(std::ptrdiff_t);
368 detail::ResultWrapperPtr res_;
369 size_type row_index_{0};
370 size_type field_index_{0};
378 ConstFieldIterator() =
default;
383 ConstFieldIterator(detail::ResultWrapperPtr res, size_type row, size_type col)
384 : ConstDataIterator(std::move(res), row, col) {}
392 ReverseConstFieldIterator() =
default;
397 ReverseConstFieldIterator(detail::ResultWrapperPtr res, size_type row,
399 : ConstDataIterator(std::move(res), row, col) {}
411 using size_type = std::size_t;
415 using value_type =
Field;
416 using reference =
Field;
417 using pointer = const_iterator;
420 size_type RowIndex()
const {
return row_index_; }
430 const_iterator cbegin()
const;
431 const_iterator begin()
const {
return cbegin(); }
432 const_iterator cend()
const;
433 const_iterator end()
const {
return cend(); }
437 const_reverse_iterator crbegin()
const;
438 const_reverse_iterator rbegin()
const {
return crbegin(); }
439 const_reverse_iterator crend()
const;
440 const_reverse_iterator rend()
const {
return crend(); }
449 reference
operator[](
const std::string& name)
const;
472 template <
typename T>
473 void To(T&& val)
const;
477 template <
typename T>
483 template <
typename T>
487 template <
typename... T>
488 void To(T&&... val)
const;
500 template <
typename T,
typename... Y>
505 template <
typename T>
514 template <
typename T>
522 template <
typename... T>
523 void To(
const std::initializer_list<std::string>& names, T&&... val)
const;
524 template <
typename... T>
525 std::tuple<T...> As(
const std::initializer_list<std::string>& names)
const;
529 template <
typename... T>
530 void To(
const std::initializer_list<size_type>& indexes, T&&... val)
const;
531 template <
typename... T>
532 std::tuple<T...> As(
const std::initializer_list<size_type>& indexes)
const;
535 size_type IndexOfName(
const std::string&)
const;
537 FieldView GetFieldView(size_type index)
const;
544 Row(detail::ResultWrapperPtr res, size_type row)
545 : res_{std::move(res)}, row_index_{row} {}
549 bool IsValid()
const;
550 int Compare(
const Row& rhs)
const;
551 std::ptrdiff_t Distance(
const Row& rhs)
const;
552 Row& Advance(std::ptrdiff_t);
555 detail::ResultWrapperPtr res_;
556 size_type row_index_{0};
564 ConstRowIterator() =
default;
569 ConstRowIterator(detail::ResultWrapperPtr res, size_type row)
570 : ConstDataIterator(std::move(res), row) {}
578 ReverseConstRowIterator() =
default;
583 ReverseConstRowIterator(detail::ResultWrapperPtr res, size_type row)
584 : ConstDataIterator(std::move(res), row) {}
602 using size_type = std::size_t;
603 using difference_type = std::ptrdiff_t;
604 static constexpr size_type npos = std::numeric_limits<size_type>::max();
611 using value_type =
Row;
612 using reference = value_type;
613 using pointer = const_iterator;
616 explicit ResultSet(std::shared_ptr<detail::ResultWrapper> pimpl)
617 : pimpl_{std::move(pimpl)} {}
621 bool IsEmpty()
const {
return Size() == 0; }
623 size_type RowsAffected()
const;
624 std::string CommandStatus()
const;
630 const_iterator cbegin()
const&;
631 const_iterator begin()
const& {
return cbegin(); }
632 const_iterator cend()
const&;
633 const_iterator end()
const& {
return cend(); }
636 const_iterator cbegin()
const&& =
delete;
637 const_iterator begin()
const&& =
delete;
638 const_iterator cend()
const&& =
delete;
639 const_iterator end()
const&& =
delete;
643 const_reverse_iterator crbegin()
const&;
644 const_reverse_iterator rbegin()
const& {
return crbegin(); }
645 const_reverse_iterator crend()
const&;
646 const_reverse_iterator rend()
const& {
return crend(); }
648 const_reverse_iterator crbegin()
const&& =
delete;
649 const_reverse_iterator rbegin()
const&& =
delete;
650 const_reverse_iterator crend()
const&& =
delete;
651 const_reverse_iterator rend()
const&& =
delete;
654 reference Front()
const&;
655 reference Back()
const&;
657 reference Front()
const&& =
delete;
658 reference Back()
const&& =
delete;
664 reference operator[](size_type index)
const&& =
delete;
670 size_type FieldCount()
const;
680 template <
typename T>
682 template <
typename T>
683 auto AsSetOf(
RowTag)
const;
684 template <
typename T>
689 template <
typename Container>
691 template <
typename Container>
692 Container AsContainer(
RowTag)
const;
697 template <
typename T>
699 template <
typename T>
700 auto AsSingleRow(
RowTag)
const;
701 template <
typename T>
708 template <
typename T>
710 template <
typename T>
711 std::optional<T> AsOptionalSingleRow(
RowTag)
const;
712 template <
typename T>
713 std::optional<T> AsOptionalSingleRow(
FieldTag)
const;
716 friend class detail::ConnectionImpl;
717 void FillBufferCategories(
const UserTypes& types);
718 void SetBufferCategoriesFrom(
const ResultSet&);
720 template <
typename T,
typename Tag>
721 friend class TypedResultSet;
722 friend class ConnectionImpl;
724 std::shared_ptr<detail::ResultWrapper> pimpl_;
730struct IsOptionalFromOptional : std::false_type {};
733struct IsOptionalFromOptional<std::optional<std::optional<T>>>
737struct IsOneVariant : std::false_type {};
740struct IsOneVariant<std::variant<T>> : std::true_type {};
742template <
typename... Args>
743constexpr void AssertSaneTypeToDeserialize() {
745 !(IsOptionalFromOptional<
746 std::remove_const_t<std::remove_reference_t<Args>>>::value ||
748 "Attempt to get an optional<optional<T>> was detected. Such "
749 "optional-from-optional types are very error prone, obfuscate code and "
750 "are ambiguous to deserialize. Change the type to just optional<T>");
753 std::remove_const_t<std::remove_reference_t<Args>>>::value ||
755 "Attempt to get an variant<T> was detected. Such variant from one type "
756 "obfuscates code. Change the type to just T");
761template <
typename IndexTuple,
typename... T>
762struct RowDataExtractorBase;
764template <std::size_t... Indexes,
typename... T>
765struct RowDataExtractorBase<std::index_sequence<Indexes...>, T...> {
766 static void ExtractValues(
const Row& row, T&&... val) {
767 static_assert(
sizeof...(Indexes) ==
sizeof...(T));
769 std::size_t field_index = 0;
770 const auto perform = [&](
auto&& arg) {
771 row.GetFieldView(field_index++).To(std::forward<
decltype(arg)>(arg));
773 (perform(std::forward<T>(val)), ...);
775 static void ExtractTuple(
const Row& row, std::tuple<T...>& val) {
776 static_assert(
sizeof...(Indexes) ==
sizeof...(T));
778 std::size_t field_index = 0;
779 const auto perform = [&](
auto& arg) {
780 row.GetFieldView(field_index++).To(arg);
782 (perform(std::get<Indexes>(val)), ...);
784 static void ExtractTuple(
const Row& row, std::tuple<T...>&& val) {
785 static_assert(
sizeof...(Indexes) ==
sizeof...(T));
787 std::size_t field_index = 0;
788 const auto perform = [&](
auto& arg) {
789 row.GetFieldView(field_index++).To(arg);
791 (perform(std::get<Indexes>(val)), ...);
794 static void ExtractValues(
const Row& row,
795 const std::initializer_list<std::string>& names,
797 (row[*(names.begin() + Indexes)].To(std::forward<T>(val)), ...);
799 static void ExtractTuple(
const Row& row,
800 const std::initializer_list<std::string>& names,
801 std::tuple<T...>& val) {
802 std::tuple<T...> tmp{row[*(names.begin() + Indexes)].
template As<T>()...};
806 static void ExtractValues(
const Row& row,
807 const std::initializer_list<std::size_t>& indexes,
809 (row[*(indexes.begin() + Indexes)].To(std::forward<T>(val)), ...);
811 static void ExtractTuple(
const Row& row,
812 const std::initializer_list<std::size_t>& indexes,
813 std::tuple<T...>& val) {
814 std::tuple<T...> tmp{row[*(indexes.begin() + Indexes)].
template As<T>()...};
819template <
typename... T>
820struct RowDataExtractor
821 : RowDataExtractorBase<std::index_sequence_for<T...>, T...> {};
824struct TupleDataExtractor;
825template <
typename... T>
826struct TupleDataExtractor<std::tuple<T...>>
827 : RowDataExtractorBase<std::index_sequence_for<T...>, T...> {};
830template <
typename RowType>
831constexpr void AssertRowTypeIsMappedToPgOrIsCompositeType() {
834 io::
traits::kIsMappedToPg<RowType> ||
835 io::
traits::kIsCompositeType<RowType>,
836 "Row type must be mapped to pg type(CppToUserPg) or one of the "
838 "1. primitive type. "
840 "3. Aggregation type. See std::aggregation. "
841 "4. Has a Introspect method that makes the std::tuple from your "
843 "For more info see `uPg: Typed PostgreSQL results` chapter in docs.");
850 To(std::forward<T>(val), kFieldTag);
855 detail::AssertSaneTypeToDeserialize<T>();
857 using ValueType = std::decay_t<T>;
858 io::traits::AssertIsValidRowType<ValueType>();
859 using RowType = io::RowType<ValueType>;
860 using TupleType =
typename RowType::TupleType;
861 constexpr auto tuple_size = RowType::size;
862 if (tuple_size > Size()) {
863 throw InvalidTupleSizeRequested(Size(), tuple_size);
864 }
else if (tuple_size < Size()) {
866 <<
"Row size is greater that the number of data members in "
871 detail::TupleDataExtractor<TupleType>::ExtractTuple(
872 *
this, RowType::GetTuple(std::forward<T>(val)));
877 detail::AssertSaneTypeToDeserialize<T>();
878 using ValueType = std::decay_t<T>;
879 detail::AssertRowTypeIsMappedToPgOrIsCompositeType<ValueType>();
887 (*
this)
[0
].To(std::forward<T>(val));
890template <
typename... T>
892 detail::AssertSaneTypeToDeserialize<T...>();
893 if (
sizeof...(T) >
Size()) {
896 detail::RowDataExtractor<T...>::ExtractValues(*
this, std::forward<T>(val)...);
899template <
typename T,
typename... Y>
901 if constexpr (
sizeof...(Y) > 0) {
902 std::tuple<T, Y...> res;
906 return As<T>(kFieldTag);
910template <
typename... T>
911void Row::
To(
const std::initializer_list<std::string>& names,
913 detail::AssertSaneTypeToDeserialize<T...>();
914 if (
sizeof...(T) != names.size()) {
915 throw FieldTupleMismatch(names.size(),
sizeof...(T));
917 detail::RowDataExtractor<T...>::ExtractValues(*
this, names,
918 std::forward<T>(val)...);
921template <
typename... T>
922std::tuple<T...>
Row::As(
923 const std::initializer_list<std::string>& names)
const {
924 if (
sizeof...(T) != names.size()) {
925 throw FieldTupleMismatch(names.size(),
sizeof...(T));
927 std::tuple<T...> res;
928 detail::RowDataExtractor<T...>::ExtractTuple(*
this, names, res);
932template <
typename... T>
933void Row::
To(
const std::initializer_list<size_type>& indexes,
935 detail::AssertSaneTypeToDeserialize<T...>();
936 if (
sizeof...(T) != indexes.size()) {
937 throw FieldTupleMismatch(indexes.size(),
sizeof...(T));
939 detail::RowDataExtractor<T...>::ExtractValues(*
this, indexes,
940 std::forward<T>(val)...);
943template <
typename... T>
944std::tuple<T...>
Row::As(
945 const std::initializer_list<size_type>& indexes)
const {
946 if (
sizeof...(T) != indexes.size()) {
947 throw FieldTupleMismatch(indexes.size(),
sizeof...(T));
949 std::tuple<T...> res;
950 detail::RowDataExtractor<T...>::ExtractTuple(*
this, indexes, res);
956 return AsSetOf<T>(kFieldTag);
961 detail::AssertSaneTypeToDeserialize<T>();
962 using ValueType = std::decay_t<T>;
963 io::traits::AssertIsValidRowType<ValueType>();
964 return TypedResultSet<T,
RowTag>{*
this};
969 detail::AssertSaneTypeToDeserialize<T>();
970 using ValueType = std::decay_t<T>;
971 detail::AssertRowTypeIsMappedToPgOrIsCompositeType<ValueType>();
972 if (FieldCount() > 1) {
976 return TypedResultSet<T,
FieldTag>{*
this};
979template <
typename Container>
981 detail::AssertSaneTypeToDeserialize<Container>();
982 using ValueType =
typename Container::value_type;
984 if constexpr (
io::
traits::kCanReserve<Container>) {
987 auto res = AsSetOf<ValueType>();
989 auto inserter =
io::
traits::Inserter(c);
990 auto row_it = res.begin();
991 for (std::size_t i = 0; i < res.Size(); ++i, ++row_it, ++inserter) {
998template <
typename Container>
1000 detail::AssertSaneTypeToDeserialize<Container>();
1001 using ValueType =
typename Container::value_type;
1003 if constexpr (
io::
traits::kCanReserve<Container>) {
1006 auto res = AsSetOf<ValueType>(kRowTag);
1008 auto inserter =
io::
traits::Inserter(c);
1009 auto row_it = res.begin();
1010 for (std::size_t i = 0; i < res.Size(); ++i, ++row_it, ++inserter) {
1011 *inserter = *row_it;
1017template <
typename T>
1019 return AsSingleRow<T>(kFieldTag);
1022template <
typename T>
1024 detail::AssertSaneTypeToDeserialize<T>();
1028 return Front().As<T>(kRowTag);
1031template <
typename T>
1033 detail::AssertSaneTypeToDeserialize<T>();
1037 return Front().As<T>(kFieldTag);
1040template <
typename T>
1042 return AsOptionalSingleRow<T>(kFieldTag);
1045template <
typename T>
1047 return IsEmpty() ? std::nullopt : std::optional<T>{AsSingleRow<T>(kRowTag)};
1050template <
typename T>
1052 return IsEmpty() ? std::nullopt : std::optional<T>{AsSingleRow<T>(kFieldTag)};
1057USERVER_NAMESPACE_END
1059#include <userver/storages/postgres/typed_result_set.hpp>