7#include <boost/pfr/core.hpp> 
   10#include <userver/compiler/demangle.hpp> 
   12#include <userver/storages/postgres/exceptions.hpp> 
   13#include <userver/storages/postgres/io/buffer_io_base.hpp> 
   14#include <userver/storages/postgres/io/field_buffer.hpp> 
   15#include <userver/storages/postgres/io/row_types.hpp> 
   16#include <userver/storages/postgres/io/traits.hpp> 
   17#include <userver/storages/postgres/io/type_mapping.hpp> 
   18#include <userver/storages/postgres/io/type_traits.hpp> 
   19#include <userver/storages/postgres/io/user_types.hpp> 
   21USERVER_NAMESPACE_BEGIN
 
   27void InitRecordParser();
 
   30struct CompositeBinaryParser : BufferParserBase<T> {
 
   31  using BaseType = BufferParserBase<T>;
 
   33  using IndexSequence = 
typename RowType::IndexSequence;
 
   35  using BaseType::BaseType;
 
   37  void operator()(
FieldBuffer buffer, 
const TypeBufferCategory& categories) {
 
   38    if constexpr (!
traits::kIsMappedToUserType<T>) {
 
   42    Integer field_count{0};
 
   45    if (field_count != RowType::size) {
 
   50    ReadTuple(buffer, categories, RowType::GetTuple(
this->value),
 
   55  static constexpr std::size_t int_size = 
sizeof(Integer);
 
   58  void ReadField(
FieldBuffer& buffer, 
const TypeBufferCategory& categories,
 
   60    Integer field_type = 0;
 
   62    auto elem_category = GetTypeBufferCategory(categories, field_type);
 
   63    if (elem_category == BufferCategory::kNoParser) {
 
   64      throw LogicError{
"Buffer category for oid " + std::to_string(field_type) +
 
   67    buffer.ReadRaw(val, categories, elem_category);
 
   69  template <
typename Tuple, std::size_t... Indexes>
 
   70  void ReadTuple(
FieldBuffer& buffer, 
const TypeBufferCategory& categories,
 
   71                 Tuple&& tuple, std::index_sequence<Indexes...>) 
const {
 
   72    (ReadField(buffer, categories,
 
   73               std::get<Indexes>(std::forward<Tuple>(tuple))),
 
   79struct CompositeBinaryFormatter : BufferFormatterBase<T> {
 
   80  using BaseType = BufferFormatterBase<T>;
 
   81  using PgMapping = CppToPg<T>;
 
   83  using IndexSequence = 
typename RowType::IndexSequence;
 
   84  static constexpr std::size_t size = RowType::size;
 
   86  using BaseType::BaseType;
 
   88  template <
typename Buffer>
 
   89  void operator()(
const UserTypes& types, Buffer& buffer) 
const {
 
   90    const auto& type_desc =
 
   91        types.GetCompositeDescription(PgMapping::GetOid(types));
 
   92    if (type_desc.Size() != size) {
 
   93      throw CompositeSizeMismatch{type_desc.Size(), size,
 
   94                                  compiler::GetTypeName<T>()};
 
   97    io::WriteBuffer(types, buffer, 
static_cast<Integer>(size));
 
   98    WriteTuple(types, type_desc, buffer, RowType::GetTuple(
this->value),
 
  103  template <
typename Buffer, 
typename U>
 
  106                  Buffer& buffer, 
const U& val) 
const {
 
  107    auto field_type = CppToPg<U>::GetOid(types);
 
  108    const auto& field_desc = type_desc[index];
 
  109    if (field_type != field_desc.type) {
 
  110      if (io::MappedToSameType(
static_cast<PredefinedOids>(field_type),
 
  111                               static_cast<PredefinedOids>(
 
  112                                   types.FindDomainBaseOid(field_desc.type)))) {
 
  113        field_type = field_desc.type;
 
  115        throw CompositeMemberTypeMismatch(
 
  116            PgMapping::postgres_name.schema, PgMapping::postgres_name.name,
 
  117            field_desc.name, field_desc.type, field_type);
 
  120    io::WriteBuffer(types, buffer, 
static_cast<Integer>(field_type));
 
  121    io::WriteRawBinary(types, buffer, val, field_type);
 
  123  template <
typename Buffer, 
typename Tuple, std::size_t... Indexes>
 
  126                  Tuple&& tuple, std::index_sequence<Indexes...>) 
const {
 
  127    (WriteField(types, type_desc, Indexes, buffer,
 
  128                std::get<Indexes>(std::forward<Tuple>(tuple))),
 
  139template <
typename Tuple>
 
  140struct AssertTupleHasParsers;
 
  142template <
typename... Members>
 
  143struct AssertTupleHasParsers<std::tuple<Members...>> : std::true_type {
 
  144  static_assert((HasParser<std::decay_t<Members>>::value && ...),
 
  145                "No parser for member. Probably you forgot to include " 
  146                "file with parser or to define your own. Please see page " 
  147                "`uPg: Supported data types` for more information");
 
  150template <
typename Tuple>
 
  151struct AssertTupleHasFormatters;
 
  153template <
typename... Members>
 
  154struct AssertTupleHasFormatters<std::tuple<Members...>> : std::true_type {
 
  156      (HasFormatter<std::decay_t<Members>>::value && ...),
 
  157      "No formatter for member. Probably you forgot to " 
  158      "include file with formatter or to define your own. Please see page " 
  159      "`uPg: Supported data types` for more information");
 
  163constexpr bool AssertHasCompositeParsers() {
 
  164  io::
traits::AssertIsValidRowType<T>();
 
  165  return AssertTupleHasParsers<
typename io::
RowType<T>::TupleType>::value;
 
  169constexpr bool AssertHasCompositeFormatters() {
 
  170  io::
traits::AssertIsValidRowType<T>();
 
  171  return AssertTupleHasFormatters<
typename io::
RowType<T>::TupleType>::value;