OZO 「お象」
Boost.Asio and libpq based asynchronous PostgreSQL unofficial header-only C++17 client library.
recv.h
1 #pragma once
2 
3 #include <ozo/result.h>
4 #include <ozo/error.h>
5 #include <ozo/type_traits.h>
6 #include <ozo/io/size_of.h>
7 #include <ozo/core/concept.h>
8 #include <ozo/detail/endian.h>
9 #include <ozo/detail/float.h>
10 #include <ozo/io/istream.h>
11 #include <ozo/io/type_traits.h>
12 #include <boost/core/demangle.hpp>
13 #include <boost/hana/for_each.hpp>
14 #include <boost/hana/members.hpp>
15 #include <boost/hana/size.hpp>
16 
17 namespace ozo {
18 template <int... I>
19 constexpr std::tuple<boost::mpl::int_<I>...>
20 make_mpl_index_sequence(std::integer_sequence<int, I...>) {
21  return {};
22 }
23 
24 template <int N>
25 constexpr auto make_index_sequence(boost::mpl::int_<N>) {
26  return make_mpl_index_sequence(
27  std::make_integer_sequence<int, N>{}
28  );
29 }
30 
31 template <typename Adt, typename Index>
32 constexpr decltype(auto) member_name(const Adt&, const Index&) {
33  return fusion::extension::struct_member_name<Adt, Index::value>::call();
34 }
35 
36 template <typename Adt, typename Index>
37 constexpr decltype(auto) member_value(Adt&& v, const Index&) {
38  return fusion::at<Index>(std::forward<Adt>(v));
39 }
40 
75 template <typename Out, typename = std::void_t<>>
76 struct recv_impl {
77  static_assert(HasDefinition<Out>, "type Out must be defined as PostgreSQL type");
78 
88  template <typename OidMap>
89  static istream& apply(istream& in, size_type size, const OidMap&, Out& out) {
90  auto& real_out = [&] {
91  if constexpr (StrongTypedef<Out>) {
92  return std::ref(static_cast<typename Out::base_type&>(out));
93  } else {
94  return std::ref(static_cast<Out&>(out));
95  }
96  }().get();
97 
98  static_assert(
99  Writable<decltype(real_out)> || !Readable<decltype(real_out)>,
100  "Out type object can't be received. Probably it is read only type"
101  " or it is an adapted struct with read only field."
102  );
103 
104  static_assert(
105  Writable<decltype(real_out)>,
106  "Out type object can't be received. Probably it is not an arithmetic"
107  " or doesn't have non const data and size methods "
108  " or it is a struct with field which can't be received."
109  );
110 
111  if constexpr (DynamicSize<Out>) {
112  static_assert(Resizable<decltype(real_out)>,
113  "Out type object has dynamic size but doesn't have resize method."
114  );
115  real_out.resize(size);
116  } else if (size != size_of(real_out)) {
118  "data size " + std::to_string(size)
119  + " does not match type size " + std::to_string(size_of(real_out)));
120  }
121  return read(in, real_out);
122  }
123 };
124 
125 namespace detail {
126 
127 template <typename T, typename = std::void_t<>>
128 struct recv_impl_dispatcher { using type = recv_impl<std::decay_t<T>>; };
129 
130 template <typename T>
131 using get_recv_impl = typename recv_impl_dispatcher<unwrap_type<T>>::type;
132 
133 template <typename OidMap, typename Oid, typename Out>
134 inline istream& recv(istream& in, [[maybe_unused]] Oid oid, size_type size, const OidMap& oids, Out& out) {
135  static_assert(std::is_same_v<Oid, oid_t>||std::is_same_v<Oid, null_oid_t>,
136  "oid must be oid_t or null_oid_t type");
137 
138  if constexpr (Nullable<Out>) {
139  if (size == null_state_size) {
140  reset_nullable(out);
141  return in;
142  }
143  }
144 
145  if constexpr (!std::is_same_v<Oid, null_oid_t>) {
146  if (!accepts_oid(oids, out, oid)) {
147  throw system_error(error::oid_type_mismatch, "unexpected oid "
148  + std::to_string(oid) + " for type "
149  + boost::core::demangle(typeid(unwrap_type<Out>).name()));
150  }
151  }
152 
153  if constexpr (Nullable<Out>) {
154  init_nullable(out);
155  } else if (size == null_state_size) {
156  throw std::invalid_argument("unexpected null for type "
157  + boost::core::demangle(typeid(out).name()));
158  }
159 
160  return detail::get_recv_impl<Out>::apply(in, size, oids, ozo::unwrap(out));
161 }
162 
163 template <typename OidMap, typename Oid, typename Out>
164 inline istream& recv_data_frame(istream& in, Oid oid, const OidMap& oids, Out& out) {
165  size_type size = 0;
166  read(in, size);
167  return recv(in, oid, size, oids, out);
168 }
169 
170 } // namespace detail
171 
199 template <typename OidMap, typename Out>
200 inline istream& recv(istream& in, oid_t oid, size_type size, const OidMap& oids, Out& out) {
201  return detail::recv(in, oid, size, oids, out);
202 }
203 
220 template <typename OidMap, typename Out>
221 inline istream& recv_data_frame(istream& in, const OidMap& oids, Out& out) {
222  return detail::recv_data_frame(in, null_oid, oids, out);
223 }
224 
241 template <typename OidMap, typename Out>
242 inline istream& recv_frame(istream& in, const OidMap& oids, Out& out) {
243  oid_t oid = null_oid;
244  read(in, oid);
245  return detail::recv_data_frame(in, oid, oids, out);
246 }
247 
248 template <typename T, typename OidMap, typename Out>
249 void recv(const value<T>& in, const OidMap& oids, Out& out) {
250  istream s(in.data(), in.size());
251  recv(s, in.oid(), (in.is_null() ? null_state_size : in.size()), oids, out);
252 }
253 
254 template <typename T, typename OidMap, typename Out>
255 Require<!FusionSequence<Out> && !FusionAdaptedStruct<Out> && !HanaStruct<Out>>
256 recv_row(const row<T>& in, const OidMap& oid_map, Out& out) {
257  if (std::size(in) != 1) {
258  throw std::range_error("row size " + std::to_string(std::size(in))
259  + " does not equal 1 for single column result");
260  }
261 
262  recv(*(in.begin()), oid_map, out);
263 }
264 
265 template <typename T, typename OidMap, typename Out>
266 Require<FusionSequence<Out> && !FusionAdaptedStruct<Out> && !HanaStruct<Out>>
267 recv_row(const row<T>& in, const OidMap& oid_map, Out& out) {
268 
269  if (static_cast<std::size_t>(fusion::size(out)) != std::size(in)) {
270  throw std::range_error("row size " + std::to_string(std::size(in))
271  + " does not match sequence " + boost::core::demangle(typeid(out).name())
272  + " size " + std::to_string(fusion::size(out)));
273  }
274 
275  auto i = in.begin();
276  fusion::for_each(out, [&](auto& item) {
277  recv(*i, oid_map, item);
278  ++i;
279  });
280 }
281 
282 template <typename T, typename OidMap, typename Out>
283 Require<FusionAdaptedStruct<Out> && !HanaStruct<Out>>
284 recv_row(const row<T>& in, const OidMap& oid_map, Out& out) {
285 
286  if (static_cast<std::size_t>(fusion::size(out)) != std::size(in)) {
287  throw std::range_error("row size " + std::to_string(std::size(in))
288  + " does not match structure " + boost::core::demangle(typeid(out).name())
289  + " size " + std::to_string(fusion::size(out)));
290  }
291 
292  fusion::for_each(make_index_sequence(fusion::size(out)), [&](auto idx) {
293  auto i = in.find(member_name(out, idx));
294  if (i == in.end()) {
295  throw std::range_error(std::string("row does not contain \"")
296  + member_name(out, idx) + "\" column for "
297  + boost::core::demangle(typeid(out).name()));
298  } else {
299  recv(*i, oid_map, member_value(out, idx));
300  }
301  });
302 }
303 
304 template <typename T, typename OidMap, typename Out>
305 Require<HanaStruct<Out>>
306 recv_row(const row<T>& in, const OidMap& oid_map, Out& out) {
307 
308  const auto keys = hana::keys(out);
309  const auto size = size_type(hana::value(hana::size(keys)));
310  if (size != std::size(in)) {
311  throw std::range_error("row size " + std::to_string(std::size(in))
312  + " does not match structure " + boost::core::demangle(typeid(out).name())
313  + " size " + std::to_string(size));
314  }
315 
316  hana::for_each(keys, [&](auto key) {
317  auto i = in.find(hana::to<const char*>(key));
318  if (i == in.end()) {
319  throw std::range_error(std::string("row does not contain \"")
320  + hana::to<const char*>(key) + "\" column for "
321  + boost::core::demangle(typeid(out).name()));
322  } else {
323  recv(*i, oid_map, hana::at_key(out, key));
324  }
325  });
326 }
327 
328 template <typename T, typename OidMap, typename Out>
329 Require<ForwardIterator<Out>, Out>
330 recv_result(const basic_result<T>& in, const OidMap& oid_map, Out out) {
331  for (auto row : in) {
332  recv_row(row, oid_map, *out++);
333  }
334  return out;
335 }
336 
337 template <typename T, typename OidMap, typename Out>
338 Require<InsertIterator<Out>, Out>
339 recv_result(const basic_result<T>& in, const OidMap& oid_map, Out out) {
340  for (auto row : in) {
341  typename Out::container_type::value_type v{};
342  recv_row(row, oid_map, v);
343  *out++ = std::move(v);
344  }
345  return out;
346 }
347 
348 template <typename T, typename OidMap>
349 basic_result<T>& recv_result(basic_result<T>& in, const OidMap&, basic_result<T>& out) {
350  out = std::move(in);
351  return out;
352 }
353 
354 template <typename T, typename OidMap, typename Out>
355 basic_result<T>& recv_result(basic_result<T>& in, const OidMap& oid_map, std::reference_wrapper<Out> out) {
356  return recv_result(in, oid_map, out.get());
357 }
358 
359 } // namespace ozo
ozo::unwrap
constexpr decltype(auto) unwrap(T &&v) noexcept(noexcept(unwrap_impl< std::decay_t< T >>::apply(std::forward< T >(v))))
Unwraps argument underlying value or forwards the argument.
Definition: unwrap.h:57
ozo::recv_impl
Defines how to receive an object from an input stream.
Definition: recv.h:76
HasDefinition
Condition indicates if type has corresponding type traits for PostgreSQL.
ozo::size_of
constexpr size_type size_of(const T &v)
Returns size of object binary representation in bytes.
Definition: size_of.h:105
ozo::recv_impl::apply
static istream & apply(istream &in, size_type size, const OidMap &, Out &out)
Implementation of deserialization object from a stream.
Definition: recv.h:89
ozo::null_oid
constexpr null_oid_t null_oid
Constant for empty OID.
Definition: type_traits.h:95
ozo::system_error
boost::system::system_error system_error
Error code contaning exception of the library.
Definition: error.h:45
ozo::recv
istream & recv(istream &in, oid_t oid, size_type size, const OidMap &oids, Out &out)
Receive object from an input stream and control incoming oid.
Definition: recv.h:200
ozo::OidMap
constexpr auto OidMap
Map of C++ types to corresponding PostgreSQL types OIDs.
Definition: type_traits.h:534
ozo::recv_frame
istream & recv_frame(istream &in, const OidMap &oids, Out &out)
Receive full frame of an object from an input stream.
Definition: recv.h:242
ozo::recv_data_frame
istream & recv_data_frame(istream &in, const OidMap &oids, Out &out)
Receive data frame of an object from an input stream.
Definition: recv.h:221
ozo::error::oid_type_mismatch
@ oid_type_mismatch
no conversion possible from oid to user-supplied type - the type what user expected is not the same a...
Definition: error.h:81
ozo::size_type
std::int32_t size_type
PostgreSQL size type.
Definition: type_traits.h:265
ozo::accepts_oid
bool accepts_oid(const OidMap &map, const T &, oid_t oid) noexcept
Definition: type_traits.h:656
ozo::oid_t
::Oid oid_t
PostgreSQL OID type - object identifier.
Definition: type_traits.h:70
ozo::error::bad_object_size
@ bad_object_size
an object size received does not equal to the expected
Definition: error.h:93