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) {
49 ReadTuple(buffer, categories, RowType::GetTuple(
this->value), IndexSequence{});
53 static constexpr std::size_t int_size =
sizeof(Integer);
56 void ReadField(
FieldBuffer& buffer,
const TypeBufferCategory& categories, U& val)
const {
57 Integer field_type = 0;
59 auto elem_category = GetTypeBufferCategory(categories, field_type);
60 if (elem_category == BufferCategory::kNoParser) {
61 throw LogicError{
"Buffer category for oid " + std::to_string(field_type) +
" is unknown"};
63 buffer.ReadRaw(val, categories, elem_category);
65 template <
typename Tuple, std::size_t... Indexes>
67 ReadTuple(
FieldBuffer& buffer,
const TypeBufferCategory& categories, Tuple&& tuple, std::index_sequence<Indexes...>)
69 (ReadField(buffer, categories, std::get<Indexes>(std::forward<Tuple>(tuple))), ...);
74struct CompositeBinaryFormatter : BufferFormatterBase<T> {
75 using BaseType = BufferFormatterBase<T>;
76 using PgMapping = CppToPg<T>;
78 using IndexSequence =
typename RowType::IndexSequence;
79 static constexpr std::size_t size = RowType::size;
81 using BaseType::BaseType;
83 template <
typename Buffer>
84 void operator()(
const UserTypes& types, Buffer& buffer)
const {
85 const auto oid = PgMapping::GetOid(types);
87 auto msg =
"Type '" + kPgUserTypeName<T>.ToString() +
88 "' was not created in database and because of that the '" +
compiler::GetTypeName<T>() +
89 "' could not be serialized. Forgot a migration or rolled it "
90 "after the service started?";
94 const auto& type_desc = types.GetCompositeDescription(oid);
95 if (type_desc.Size() != size) {
96 throw CompositeSizeMismatch{type_desc.Size(), size, compiler::GetTypeName<T>()};
99 io::WriteBuffer(types, buffer,
static_cast<Integer>(size));
100 WriteTuple(types, type_desc, buffer, RowType::GetTuple(
this->value), IndexSequence{});
104 template <
typename Buffer,
typename U>
112 auto field_type = CppToPg<U>::GetOid(types);
113 const auto& field_desc = type_desc[index];
114 if (field_type != field_desc.type) {
115 if (io::MappedToSameType(
116 static_cast<PredefinedOids>(field_type),
117 static_cast<PredefinedOids>(types.FindDomainBaseOid(field_desc.type))
119 field_type = field_desc.type;
121 throw CompositeMemberTypeMismatch(
122 PgMapping::postgres_name.schema,
123 PgMapping::postgres_name.name,
130 io::WriteBuffer(types, buffer,
static_cast<Integer>(field_type));
131 io::WriteRawBinary(types, buffer, val, field_type);
133 template <
typename Buffer,
typename Tuple, std::size_t... Indexes>
137 (WriteField(types, type_desc, Indexes, buffer, std::get<Indexes>(std::forward<Tuple>(tuple))), ...);
147template <
typename Tuple>
148struct AssertTupleHasParsers;
150template <
typename... Members>
151struct AssertTupleHasParsers<std::tuple<Members...>> : std::true_type {
153 (HasParser<std::decay_t<Members>>::value && ...),
154 "No parser for member. Probably you forgot to include "
155 "file with parser or to define your own. Please see page "
156 "`uPg: Supported data types` for more information"
160template <
typename Tuple>
161struct AssertTupleHasFormatters;
163template <
typename... Members>
164struct AssertTupleHasFormatters<std::tuple<Members...>> : std::true_type {
166 (HasFormatter<std::decay_t<Members>>::value && ...),
167 "No formatter for member. Probably you forgot to "
168 "include file with formatter or to define your own. Please see page "
169 "`uPg: Supported data types` for more information"
174constexpr bool AssertHasCompositeParsers() {
175 io::
traits::AssertIsValidRowType<T>();
176 return AssertTupleHasParsers<
typename io::
RowType<T>::TupleType>::value;
180constexpr bool AssertHasCompositeFormatters() {
181 io::
traits::AssertIsValidRowType<T>();
182 return AssertTupleHasFormatters<
typename io::
RowType<T>::TupleType>::value;