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;
354 Field(detail::ResultWrapperPtr res, size_type row, size_type col)
355 : res_{std::move(res)}, row_index_{row}, field_index_{col} {}
359 bool IsValid()
const;
360 int Compare(
const Field& rhs)
const;
361 std::ptrdiff_t Distance(
const Field& rhs)
const;
362 Field& Advance(std::ptrdiff_t);
366 detail::ResultWrapperPtr res_;
367 size_type row_index_;
368 size_type field_index_;
377 ConstFieldIterator(detail::ResultWrapperPtr res, size_type row, size_type col)
378 : ConstDataIterator(std::move(res), row, col) {}
387 ReverseConstFieldIterator(detail::ResultWrapperPtr res, size_type row,
389 : ConstDataIterator(std::move(res), row, col) {}
401 using size_type = std::size_t;
405 using value_type =
Field;
406 using reference =
Field;
407 using pointer = const_iterator;
410 size_type RowIndex()
const {
return row_index_; }
420 const_iterator cbegin()
const;
421 const_iterator begin()
const {
return cbegin(); }
422 const_iterator cend()
const;
423 const_iterator end()
const {
return cend(); }
427 const_reverse_iterator crbegin()
const;
428 const_reverse_iterator rbegin()
const {
return crbegin(); }
429 const_reverse_iterator crend()
const;
430 const_reverse_iterator rend()
const {
return crend(); }
439 reference
operator[](
const std::string& name)
const;
462 template <
typename T>
463 void To(T&& val)
const;
467 template <
typename T>
473 template <
typename T>
477 template <
typename... T>
478 void To(T&&... val)
const;
490 template <
typename T,
typename... Y>
495 template <
typename T>
504 template <
typename T>
512 template <
typename... T>
513 void To(
const std::initializer_list<std::string>& names, T&&... val)
const;
514 template <
typename... T>
515 std::tuple<T...> As(
const std::initializer_list<std::string>& names)
const;
519 template <
typename... T>
520 void To(
const std::initializer_list<size_type>& indexes, T&&... val)
const;
521 template <
typename... T>
522 std::tuple<T...> As(
const std::initializer_list<size_type>& indexes)
const;
525 size_type IndexOfName(
const std::string&)
const;
527 FieldView GetFieldView(size_type index)
const;
532 Row(detail::ResultWrapperPtr res, size_type row)
533 : res_{std::move(res)}, row_index_{row} {}
537 bool IsValid()
const;
538 int Compare(
const Row& rhs)
const;
539 std::ptrdiff_t Distance(
const Row& rhs)
const;
540 Row& Advance(std::ptrdiff_t);
543 detail::ResultWrapperPtr res_;
544 size_type row_index_;
553 ConstRowIterator(detail::ResultWrapperPtr res, size_type row)
554 : ConstDataIterator(std::move(res), row) {}
563 ReverseConstRowIterator(detail::ResultWrapperPtr res, size_type row)
564 : ConstDataIterator(std::move(res), row) {}
582 using size_type = std::size_t;
583 using difference_type = std::ptrdiff_t;
584 static constexpr size_type npos = std::numeric_limits<size_type>::max();
591 using value_type =
Row;
592 using reference = value_type;
593 using pointer = const_iterator;
596 explicit ResultSet(std::shared_ptr<detail::ResultWrapper> pimpl)
597 : pimpl_{std::move(pimpl)} {}
601 bool IsEmpty()
const {
return Size() == 0; }
603 size_type RowsAffected()
const;
604 std::string CommandStatus()
const;
610 const_iterator cbegin()
const&;
611 const_iterator begin()
const& {
return cbegin(); }
612 const_iterator cend()
const&;
613 const_iterator end()
const& {
return cend(); }
616 const_iterator cbegin()
const&& =
delete;
617 const_iterator begin()
const&& =
delete;
618 const_iterator cend()
const&& =
delete;
619 const_iterator end()
const&& =
delete;
623 const_reverse_iterator crbegin()
const&;
624 const_reverse_iterator rbegin()
const& {
return crbegin(); }
625 const_reverse_iterator crend()
const&;
626 const_reverse_iterator rend()
const& {
return crend(); }
628 const_reverse_iterator crbegin()
const&& =
delete;
629 const_reverse_iterator rbegin()
const&& =
delete;
630 const_reverse_iterator crend()
const&& =
delete;
631 const_reverse_iterator rend()
const&& =
delete;
634 reference Front()
const&;
635 reference Back()
const&;
637 reference Front()
const&& =
delete;
638 reference Back()
const&& =
delete;
644 reference operator[](size_type index)
const&& =
delete;
650 size_type FieldCount()
const;
660 template <
typename T>
662 template <
typename T>
663 auto AsSetOf(
RowTag)
const;
664 template <
typename T>
669 template <
typename Container>
671 template <
typename Container>
672 Container AsContainer(
RowTag)
const;
677 template <
typename T>
679 template <
typename T>
680 auto AsSingleRow(
RowTag)
const;
681 template <
typename T>
688 template <
typename T>
690 template <
typename T>
691 std::optional<T> AsOptionalSingleRow(
RowTag)
const;
692 template <
typename T>
693 std::optional<T> AsOptionalSingleRow(
FieldTag)
const;
696 friend class detail::ConnectionImpl;
697 void FillBufferCategories(
const UserTypes& types);
698 void SetBufferCategoriesFrom(
const ResultSet&);
700 template <
typename T,
typename Tag>
701 friend class TypedResultSet;
702 friend class ConnectionImpl;
704 std::shared_ptr<detail::ResultWrapper> pimpl_;
710struct IsOptionalFromOptional : std::false_type {};
713struct IsOptionalFromOptional<std::optional<std::optional<T>>>
717struct IsOneVariant : std::false_type {};
720struct IsOneVariant<std::variant<T>> : std::true_type {};
722template <
typename... Args>
723constexpr void AssertSaneTypeToDeserialize() {
725 !(IsOptionalFromOptional<
726 std::remove_const_t<std::remove_reference_t<Args>>>::value ||
728 "Attempt to get an optional<optional<T>> was detected. Such "
729 "optional-from-optional types are very error prone, obfuscate code and "
730 "are ambiguous to deserialize. Change the type to just optional<T>");
733 std::remove_const_t<std::remove_reference_t<Args>>>::value ||
735 "Attempt to get an variant<T> was detected. Such variant from one type "
736 "obfuscates code. Change the type to just T");
741template <
typename IndexTuple,
typename... T>
742struct RowDataExtractorBase;
744template <std::size_t... Indexes,
typename... T>
745struct RowDataExtractorBase<std::index_sequence<Indexes...>, T...> {
746 static void ExtractValues(
const Row& row, T&&... val) {
747 static_assert(
sizeof...(Indexes) ==
sizeof...(T));
749 std::size_t field_index = 0;
750 const auto perform = [&](
auto&& arg) {
751 row.GetFieldView(field_index++).To(std::forward<
decltype(arg)>(arg));
753 (perform(std::forward<T>(val)), ...);
755 static void ExtractTuple(
const Row& row, std::tuple<T...>& val) {
756 static_assert(
sizeof...(Indexes) ==
sizeof...(T));
758 std::size_t field_index = 0;
759 const auto perform = [&](
auto& arg) {
760 row.GetFieldView(field_index++).To(arg);
762 (perform(std::get<Indexes>(val)), ...);
764 static void ExtractTuple(
const Row& row, std::tuple<T...>&& val) {
765 static_assert(
sizeof...(Indexes) ==
sizeof...(T));
767 std::size_t field_index = 0;
768 const auto perform = [&](
auto& arg) {
769 row.GetFieldView(field_index++).To(arg);
771 (perform(std::get<Indexes>(val)), ...);
774 static void ExtractValues(
const Row& row,
775 const std::initializer_list<std::string>& names,
777 (row[*(names.begin() + Indexes)].To(std::forward<T>(val)), ...);
779 static void ExtractTuple(
const Row& row,
780 const std::initializer_list<std::string>& names,
781 std::tuple<T...>& val) {
782 std::tuple<T...> tmp{row[*(names.begin() + Indexes)].
template As<T>()...};
786 static void ExtractValues(
const Row& row,
787 const std::initializer_list<std::size_t>& indexes,
789 (row[*(indexes.begin() + Indexes)].To(std::forward<T>(val)), ...);
791 static void ExtractTuple(
const Row& row,
792 const std::initializer_list<std::size_t>& indexes,
793 std::tuple<T...>& val) {
794 std::tuple<T...> tmp{row[*(indexes.begin() + Indexes)].
template As<T>()...};
799template <
typename... T>
800struct RowDataExtractor
801 : RowDataExtractorBase<std::index_sequence_for<T...>, T...> {};
804struct TupleDataExtractor;
805template <
typename... T>
806struct TupleDataExtractor<std::tuple<T...>>
807 : RowDataExtractorBase<std::index_sequence_for<T...>, T...> {};
810template <
typename RowType>
811constexpr void AssertRowTypeIsMappedToPgOrIsCompositeType() {
814 io::
traits::kIsMappedToPg<RowType> ||
815 io::
traits::kIsCompositeType<RowType>,
816 "Row type must be mapped to pg type(CppToUserPg) or one of the "
818 "1. primitive type. "
820 "3. Aggregation type. See std::aggregation. "
821 "4. Has a Introspect method that makes the std::tuple from your "
823 "For more info see `uPg: Typed PostgreSQL results` chapter in docs.");
830 To(std::forward<T>(val), kFieldTag);
835 detail::AssertSaneTypeToDeserialize<T>();
837 using ValueType = std::decay_t<T>;
838 io::traits::AssertIsValidRowType<ValueType>();
839 using RowType = io::RowType<ValueType>;
840 using TupleType =
typename RowType::TupleType;
841 constexpr auto tuple_size = RowType::size;
842 if (tuple_size > Size()) {
843 throw InvalidTupleSizeRequested(Size(), tuple_size);
844 }
else if (tuple_size < Size()) {
846 <<
"Row size is greater that the number of data members in "
851 detail::TupleDataExtractor<TupleType>::ExtractTuple(
852 *
this, RowType::GetTuple(std::forward<T>(val)));
857 detail::AssertSaneTypeToDeserialize<T>();
858 using ValueType = std::decay_t<T>;
859 detail::AssertRowTypeIsMappedToPgOrIsCompositeType<ValueType>();
867 (*
this)
[0
].To(std::forward<T>(val));
870template <
typename... T>
872 detail::AssertSaneTypeToDeserialize<T...>();
873 if (
sizeof...(T) >
Size()) {
876 detail::RowDataExtractor<T...>::ExtractValues(*
this, std::forward<T>(val)...);
879template <
typename T,
typename... Y>
881 if constexpr (
sizeof...(Y) > 0) {
882 std::tuple<T, Y...> res;
886 return As<T>(kFieldTag);
890template <
typename... T>
891void Row::
To(
const std::initializer_list<std::string>& names,
893 detail::AssertSaneTypeToDeserialize<T...>();
894 if (
sizeof...(T) != names.size()) {
895 throw FieldTupleMismatch(names.size(),
sizeof...(T));
897 detail::RowDataExtractor<T...>::ExtractValues(*
this, names,
898 std::forward<T>(val)...);
901template <
typename... T>
902std::tuple<T...>
Row::As(
903 const std::initializer_list<std::string>& names)
const {
904 if (
sizeof...(T) != names.size()) {
905 throw FieldTupleMismatch(names.size(),
sizeof...(T));
907 std::tuple<T...> res;
908 detail::RowDataExtractor<T...>::ExtractTuple(*
this, names, res);
912template <
typename... T>
913void Row::
To(
const std::initializer_list<size_type>& indexes,
915 detail::AssertSaneTypeToDeserialize<T...>();
916 if (
sizeof...(T) != indexes.size()) {
917 throw FieldTupleMismatch(indexes.size(),
sizeof...(T));
919 detail::RowDataExtractor<T...>::ExtractValues(*
this, indexes,
920 std::forward<T>(val)...);
923template <
typename... T>
924std::tuple<T...>
Row::As(
925 const std::initializer_list<size_type>& indexes)
const {
926 if (
sizeof...(T) != indexes.size()) {
927 throw FieldTupleMismatch(indexes.size(),
sizeof...(T));
929 std::tuple<T...> res;
930 detail::RowDataExtractor<T...>::ExtractTuple(*
this, indexes, res);
936 return AsSetOf<T>(kFieldTag);
941 detail::AssertSaneTypeToDeserialize<T>();
942 using ValueType = std::decay_t<T>;
943 io::traits::AssertIsValidRowType<ValueType>();
944 return TypedResultSet<T,
RowTag>{*
this};
949 detail::AssertSaneTypeToDeserialize<T>();
950 using ValueType = std::decay_t<T>;
951 detail::AssertRowTypeIsMappedToPgOrIsCompositeType<ValueType>();
952 if (FieldCount() > 1) {
956 return TypedResultSet<T,
FieldTag>{*
this};
959template <
typename Container>
961 detail::AssertSaneTypeToDeserialize<Container>();
962 using ValueType =
typename Container::value_type;
964 if constexpr (
io::
traits::kCanReserve<Container>) {
967 auto res = AsSetOf<ValueType>();
969 auto inserter =
io::
traits::Inserter(c);
970 auto row_it = res.begin();
971 for (std::size_t i = 0; i < res.Size(); ++i, ++row_it, ++inserter) {
978template <
typename Container>
980 detail::AssertSaneTypeToDeserialize<Container>();
981 using ValueType =
typename Container::value_type;
983 if constexpr (
io::
traits::kCanReserve<Container>) {
986 auto res = AsSetOf<ValueType>(kRowTag);
988 auto inserter =
io::
traits::Inserter(c);
989 auto row_it = res.begin();
990 for (std::size_t i = 0; i < res.Size(); ++i, ++row_it, ++inserter) {
999 return AsSingleRow<T>(kFieldTag);
1002template <
typename T>
1004 detail::AssertSaneTypeToDeserialize<T>();
1008 return Front().As<T>(kRowTag);
1011template <
typename T>
1013 detail::AssertSaneTypeToDeserialize<T>();
1017 return Front().As<T>(kFieldTag);
1020template <
typename T>
1022 return AsOptionalSingleRow<T>(kFieldTag);
1025template <
typename T>
1027 return IsEmpty() ? std::nullopt : std::optional<T>{AsSingleRow<T>(kRowTag)};
1030template <
typename T>
1032 return IsEmpty() ? std::nullopt : std::optional<T>{AsSingleRow<T>(kFieldTag)};
1037USERVER_NAMESPACE_END
1039#include <userver/storages/postgres/typed_result_set.hpp>