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
61void InitRecordParser();
64struct CompositeBinaryParser : BufferParserBase<T> {
65 using BaseType = BufferParserBase<T>;
67 using IndexSequence =
typename RowType::IndexSequence;
69 using BaseType::BaseType;
71 void operator()(
FieldBuffer buffer,
const TypeBufferCategory& categories) {
72 if constexpr (!
traits::kIsMappedToUserType<T>) {
76 Integer field_count{0};
79 if (field_count != RowType::size) {
84 ReadTuple(buffer, categories, RowType::GetTuple(
this->value),
89 static constexpr std::size_t int_size =
sizeof(Integer);
92 void ReadField(
FieldBuffer& buffer,
const TypeBufferCategory& categories,
94 Integer field_type = 0;
96 auto elem_category = GetTypeBufferCategory(categories, field_type);
97 if (elem_category == BufferCategory::kNoParser) {
98 throw LogicError{
"Buffer category for oid " + std::to_string(field_type) +
101 buffer.ReadRaw(val, categories, elem_category);
103 template <
typename Tuple, std::size_t... Indexes>
104 void ReadTuple(
FieldBuffer& buffer,
const TypeBufferCategory& categories,
105 Tuple&& tuple, std::index_sequence<Indexes...>)
const {
106 (ReadField(buffer, categories,
107 std::get<Indexes>(std::forward<Tuple>(tuple))),
113struct CompositeBinaryFormatter : BufferFormatterBase<T> {
114 using BaseType = BufferFormatterBase<T>;
115 using PgMapping = CppToPg<T>;
117 using IndexSequence =
typename RowType::IndexSequence;
118 static constexpr std::size_t size = RowType::size;
120 using BaseType::BaseType;
122 template <
typename Buffer>
123 void operator()(
const UserTypes& types, Buffer& buffer)
const {
124 const auto& type_desc =
125 types.GetCompositeDescription(PgMapping::GetOid(types));
126 if (type_desc.Size() != size) {
127 throw CompositeSizeMismatch{type_desc.Size(), size,
128 compiler::GetTypeName<T>()};
131 io::WriteBuffer(types, buffer,
static_cast<Integer>(size));
132 WriteTuple(types, type_desc, buffer, RowType::GetTuple(
this->value),
137 template <
typename Buffer,
typename U>
140 Buffer& buffer,
const U& val)
const {
141 auto field_type = CppToPg<U>::GetOid(types);
142 const auto& field_desc = type_desc[index];
143 if (field_type != field_desc.type) {
144 if (io::MappedToSameType(
static_cast<PredefinedOids>(field_type),
145 static_cast<PredefinedOids>(
146 types.FindDomainBaseOid(field_desc.type)))) {
147 field_type = field_desc.type;
149 throw CompositeMemberTypeMismatch(
150 PgMapping::postgres_name.schema, PgMapping::postgres_name.name,
151 field_desc.name, field_desc.type, field_type);
154 io::WriteBuffer(types, buffer,
static_cast<Integer>(field_type));
155 io::WriteRawBinary(types, buffer, val, field_type);
157 template <
typename Buffer,
typename Tuple, std::size_t... Indexes>
160 Tuple&& tuple, std::index_sequence<Indexes...>)
const {
161 (WriteField(types, type_desc, Indexes, buffer,
162 std::get<Indexes>(std::forward<Tuple>(tuple))),
173template <
typename Tuple>
174struct AssertTupleHasParsers;
176template <
typename... Members>
177struct AssertTupleHasParsers<std::tuple<Members...>> : std::true_type {
178 static_assert((HasParser<std::decay_t<Members>>::value && ...),
179 "No parser for member. Probably you forgot to include "
180 "file with parser or to define your own. Please see page "
181 "`uPg: Supported data types` for more information");
184template <
typename Tuple>
185struct AssertTupleHasFormatters;
187template <
typename... Members>
188struct AssertTupleHasFormatters<std::tuple<Members...>> : std::true_type {
190 (HasFormatter<std::decay_t<Members>>::value && ...),
191 "No formatter for member. Probably you forgot to "
192 "include file with formatter or to define your own. Please see page "
193 "`uPg: Supported data types` for more information");
197constexpr bool AssertHasCompositeParsers() {
198 static_assert(kIsRowType<T>);
199 return AssertTupleHasParsers<
typename io::
RowType<T>::TupleType>::value;
203constexpr bool AssertHasCompositeFormatters() {
204 static_assert(kIsRowType<T>);
205 return AssertTupleHasFormatters<
typename io::
RowType<T>::TupleType>::value;