OZO 「お象」
Boost.Asio and libpq based asynchronous PostgreSQL unofficial header-only C++17 client library.
connection.h
1 #pragma once
2 
3 #include <ozo/error.h>
4 #include <ozo/type_traits.h>
5 #include <ozo/asio.h>
6 #include <ozo/core/concept.h>
7 #include <ozo/core/recursive.h>
8 #include <ozo/core/none.h>
9 #include <ozo/deadline.h>
10 #include <ozo/pg/handle.h>
11 
12 #include <ozo/detail/bind.h>
13 #include <ozo/detail/functional.h>
14 
15 #include <boost/asio/dispatch.hpp>
16 #include <boost/asio/posix/stream_descriptor.hpp>
17 
18 namespace ozo {
19 
31 using no_statistics = ozo::none_t;
32 
33 template <typename T>
34 struct unwrap_connection_impl : unwrap_recursive_impl<T> {};
74 template <typename T>
75 inline constexpr decltype(auto) unwrap_connection(T&& conn) noexcept {
76  return detail::apply<unwrap_connection_impl>(std::forward<T>(conn));
77 }
78 
92 template <typename OidMap, typename Statistics>
93 class connection {
94 public:
95  using native_handle_type = ozo::pg::conn::pointer;
96  using oid_map_type = OidMap;
97  using error_context_type = std::string;
98  using executor_type = io_context::executor_type;
99 
106  connection(io_context& io, Statistics statistics);
107 
119  native_handle_type native_handle() const noexcept { return handle_.get(); }
120 
127  oid_map_type& oid_map() noexcept { return oid_map_;}
133  const oid_map_type& oid_map() const noexcept { return oid_map_;}
134 
135  template <typename Key, typename Value>
136  void update_statistics(const Key&, const Value&) noexcept {
137  static_assert(std::is_void_v<Key>, "update_statistics is not supperted");
138  }
139  const Statistics& statistics() const noexcept { return statistics_;}
140 
146  const error_context_type& get_error_context() const noexcept { return error_context_; }
153  void set_error_context(error_context_type v = error_context_type{}) { error_context_ = std::move(v); }
154 
160  executor_type get_executor() const noexcept { return io_->get_executor(); }
161 
174  error_code assign(ozo::pg::conn&& handle);
175 
187  ozo::pg::conn release();
188 
199  template <typename WaitHandler>
200  void async_wait_write(WaitHandler&& handler);
201 
212  template <typename WaitHandler>
213  void async_wait_read(WaitHandler&& handler);
214 
225  error_code close() noexcept;
226 
233  void cancel() noexcept;
234 
243  bool is_bad() const noexcept;
244 
253  operator bool () const noexcept { return !is_bad();}
254 
261  bool is_open() const noexcept { return native_handle() != nullptr;}
262 
263  ~connection();
264 private:
265  using stream_type = asio::posix::stream_descriptor;
266 
267  ozo::pg::conn handle_;
268  io_context* io_ = nullptr;
269  stream_type socket_;
270  oid_map_type oid_map_;
271  Statistics statistics_;
272  error_context_type error_context_;
273 };
274 
282 template <typename, typename = std::void_t<>>
283 struct is_connection : std::false_type {};
284 
285 template <typename ...Ts>
286 struct is_connection<connection<Ts...>> : std::true_type {};
287 
337 template <typename T>
339 inline constexpr auto Connection = is_connection<std::decay_t<decltype(unwrap_connection(std::declval<T>()))>>::value;
341 
347 
357 template <typename Connection>
358 inline auto get_native_handle(const Connection& conn) noexcept;
359 
368 template <typename Connection>
369 inline auto get_executor(const Connection& conn) noexcept;
370 
379 template <typename T>
380 inline bool connection_bad(const T& conn) noexcept;
381 
390 template <typename Connection>
391 inline bool connection_good(const Connection& conn) noexcept {
392  return !connection_bad(conn);
393 }
394 
404 template <typename Connection>
405 inline std::string_view error_message(const Connection& conn);
406 
415 template <typename Connection>
416 inline const auto& get_error_context(const Connection& conn);
417 
429 template <typename Connection>
430 inline std::string_view get_database(const Connection& conn);
431 
443 template <typename Connection>
444 inline std::string_view get_host(const Connection& conn);
445 
457 template <typename Connection>
458 inline std::string_view get_port(const Connection& conn);
459 
471 template <typename Connection>
472 inline std::string_view get_user(const Connection& conn) ;
473 
485 template <typename Connection>
486 inline std::string_view get_password(const Connection& conn);
488 
494 namespace detail {
495 
496 template <typename ConnectionProvider, typename = std::void_t<>>
497 struct get_connection_type_default {};
498 
499 template <typename ConnectionProvider>
500 struct get_connection_type_default<ConnectionProvider,
501  std::void_t<typename ConnectionProvider::connection_type>> {
502  using type = typename ConnectionProvider::connection_type;
503 };
504 
505 template <typename T>
506 struct get_connection_type_default<T, Require<ozo::Connection<T>>> {
507  using type = T;
508 };
509 
510 } // namespace detail
511 
551 template <typename ConnectionProvider>
553 #ifdef OZO_DOCUMENTATION
554 {
555  using type = <implementation defined>;
556 };
557 #else
558  : detail::get_connection_type_default<ConnectionProvider>{};
559 #endif
560 
571 template <typename T>
573 
574 template <typename T>
575 using handler_signature = void (error_code, connection_type<T>);
576 
577 namespace detail {
578 
579 struct call_async_get_connection {
580  template <typename Provider, typename TimeConstraint, typename Handler>
581  static constexpr auto apply(Provider&& p, TimeConstraint t, Handler&& h) ->
582  decltype(p.async_get_connection(t, std::forward<Handler>(h))) {
583  static_assert(ozo::TimeConstraint<TimeConstraint>, "should model TimeConstraint concept");
584  return p.async_get_connection(t, std::forward<Handler>(h));
585  }
586 };
587 
588 struct forward_connection {
589  template <typename Conn, typename TimeConstraint, typename Handler>
590  static constexpr void apply(Conn&& c, TimeConstraint, Handler&& h) {
591  static_assert(ozo::TimeConstraint<TimeConstraint>, "should model TimeConstraint concept");
592  unwrap_connection(c).set_error_context();
593  auto ex = unwrap_connection(c).get_executor();
594  asio::dispatch(ex, detail::bind(std::forward<Handler>(h), error_code{}, std::forward<Conn>(c)));
595  }
596 };
597 
598 } // namespace detail
599 
600 template <typename Provider, typename TimeConstraint>
601 struct async_get_connection_impl : std::conditional_t<Connection<Provider>,
602  detail::forward_connection,
603  detail::call_async_get_connection
604 > {};
605 
606 namespace detail {
607 
608 template <typename Source, typename TimeTraits, typename = std::void_t<>>
609 struct connection_source_supports_time_traits : std::false_type {};
610 
611 template <typename Source, typename TimeTraits>
612 struct connection_source_supports_time_traits<Source, TimeTraits, std::void_t<decltype(
613  std::declval<Source&>()(
614  std::declval<io_context&>(),
615  std::declval<TimeTraits>(),
616  std::declval<handler_signature<Source>>()
617  )
618 )>> : std::true_type {};
619 
620 template <typename T>
621 using connection_source_defined = std::conjunction<
622  typename connection_source_supports_time_traits<T, time_traits::time_point>::type,
623  typename connection_source_supports_time_traits<T, time_traits::duration>::type,
624  typename connection_source_supports_time_traits<T, none_t>::type
625 >;
626 } // namespace detail
627 
628 template <typename T>
629 using is_connection_source = typename detail::connection_source_defined<T>::type;
630 
631 template <typename T>
632 struct connection_source_traits {
633  using type = connection_source_traits;
634  using connection_type = typename get_connection_type<std::decay_t<T>>::type;
635 };
636 
671 template <typename T>
673 inline constexpr auto ConnectionSource = is_connection_source<std::decay_t<T>>::value;
675 
676 template <typename Provider, typename TimeConstraint, typename Handler>
677 constexpr auto async_get_connection(Provider&& p, TimeConstraint t, Handler&& h) ->
678  decltype(async_get_connection_impl<std::decay_t<Provider>, TimeConstraint>::
679  apply(std::forward<Provider>(p), t, std::forward<Handler>(h))) {
680  static_assert(ozo::TimeConstraint<TimeConstraint>, "should model TimeConstraint concept");
681  return async_get_connection_impl<std::decay_t<Provider>, TimeConstraint>::
682  apply(std::forward<Provider>(p), t, std::forward<Handler>(h));
683 }
684 
685 namespace detail {
686 template <typename Provider, typename TimeConstraint, typename = std::void_t<>>
687 struct connection_provider_supports_time_constraint : std::false_type {};
688 
689 template <typename Provider, typename TimeConstraint>
690 struct connection_provider_supports_time_constraint<Provider, TimeConstraint, std::void_t<decltype(
691  async_get_connection(
692  std::declval<Provider&>(),
693  std::declval<TimeConstraint>(),
694  std::declval<handler_signature<Provider>>()
695  )
696 )>> : std::true_type {};
697 
698 template <typename T>
699 using async_get_connection_defined = std::conjunction<
700  typename connection_provider_supports_time_constraint<T, none_t>::type,
701  typename connection_provider_supports_time_constraint<T, time_traits::duration>::type,
702  typename connection_provider_supports_time_constraint<T, time_traits::time_point>::type
703 >;
704 
705 } // namespace detail
706 
707 template <typename T>
708 using is_connection_provider = typename detail::async_get_connection_defined<T>::type;
709 
710 template <typename T>
711 struct connection_provider_traits {
712  using type = connection_provider_traits;
713  using connection_type = typename get_connection_type<std::decay_t<T>>::type;
714 };
715 
751 template <typename T>
753 inline constexpr auto ConnectionProvider = is_connection_provider<std::decay_t<T>>::value;
755 
756 #ifdef OZO_DOCUMENTATION
757 
797 template <typename T, typename TimeConstraint, typename CompletionToken>
798 decltype(auto) get_connection(T&& provider, TimeConstraint time_constraint, CompletionToken&& token);
799 
812 template <typename T, typename CompletionToken>
813 decltype(auto) get_connection(T&& provider, CompletionToken&& token);
814 #else
815 template <typename Initiator>
816 struct get_connection_op : base_async_operation <get_connection_op<Initiator>, Initiator> {
817  using base = typename get_connection_op::base;
818  using base::base;
819 
820  template <typename T, typename TimeConstraint, typename CompletionToken>
821  decltype(auto) operator() (T&& provider, TimeConstraint t, CompletionToken&& token) const {
822  static_assert(ConnectionProvider<T>, "T is not a ConnectionProvider concept");
823  static_assert(ozo::TimeConstraint<TimeConstraint>, "should model TimeConstraint concept");
824  return async_initiate<CompletionToken, handler_signature<T>>(
825  get_operation_initiator(*this), token, std::forward<T>(provider), t
826  );
827  }
828 
829  template <typename T, typename CompletionToken>
830  decltype(auto) operator() (T&& provider, CompletionToken&& token) const {
831  return (*this)(std::forward<T>(provider), none, std::forward<CompletionToken>(token));
832  }
833 
834  template <typename OtherInitiator>
835  constexpr static auto rebind_initiator(const OtherInitiator& other) {
836  return get_connection_op<OtherInitiator>{other};
837  }
838 };
839 
840 namespace detail {
841 struct initiate_async_get_connection {
842  template <typename Provider, typename Handler, typename TimeConstraint>
843  constexpr void operator()(Handler&& h, Provider&& p, TimeConstraint t) const {
844  async_get_connection( std::forward<Provider>(p), t, std::forward<Handler>(h));
845  }
846 };
847 } // namespace detail
848 
849 inline constexpr get_connection_op<detail::initiate_async_get_connection> get_connection;
850 #endif
851 
852 
866 template <typename Connection>
867 inline error_code close_connection(Connection&& conn);
868 
890 template <typename Connection>
891 inline auto defer_close_connection(Connection* conn) {
892  static_assert(ozo::Connection<Connection>, "argument should model Connection");
893 
894  auto do_close = [] (auto conn_ptr) {
895  if (!is_null_recursive(*conn_ptr)) {
896  close_connection(*conn_ptr);
897  }
898  };
899 
900  return std::unique_ptr<Connection, decltype(do_close)>{conn, do_close};
901 }
902 
903 } // namespace ozo
904 
905 #include <ozo/impl/connection.h>
ozo::connection::set_error_context
void set_error_context(error_context_type v=error_context_type{})
Definition: connection.h:153
ozo::connection::release
ozo::pg::conn release()
Definition: connection.h:54
ozo::error_code
boost::system::error_code error_code
Error code representation of the library.
Definition: error.h:38
ozo::connection::oid_map
oid_map_type & oid_map() noexcept
Definition: connection.h:127
ozo::connection::close
error_code close() noexcept
Definition: connection.h:75
ozo::error_message
std::string_view error_message(const Connection &conn)
Get native libpq error message.
Definition: connection.h:97
ozo::connection::cancel
void cancel() noexcept
Definition: connection.h:81
ozo::get_executor
auto get_executor(const Connection &conn) noexcept
Get the executor associated with the object.
Definition: connection.h:130
ozo::connection::error_context_type
std::string error_context_type
Additional error context which could provide context depended information for errors.
Definition: connection.h:97
ozo::unwrap_connection
constexpr decltype(auto) unwrap_connection(T &&conn) noexcept
Unwrap connection if wrapped with Nullable.
Definition: connection.h:75
ozo::defer_close_connection
auto defer_close_connection(Connection *conn)
Close connection to the database when leaving the scope.
Definition: connection.h:891
ozo::OidMap
constexpr auto OidMap
Map of C++ types to corresponding PostgreSQL types OIDs.
Definition: type_traits.h:534
ozo::connection::oid_map_type
OidMap oid_map_type
Oid map of types that are used with the connection.
Definition: connection.h:96
ozo::get_native_handle
auto get_native_handle(const Connection &conn) noexcept
Get native connection handle object.
Definition: connection.h:118
ozo::connection::native_handle
native_handle_type native_handle() const noexcept
Definition: connection.h:119
ozo::connection::async_wait_write
void async_wait_write(WaitHandler &&handler)
Definition: connection.h:64
ozo::get_port
std::string_view get_port(const Connection &conn)
Get the port connected of the active connection.
Definition: connection.h:154
ozo::connection::get_executor
executor_type get_executor() const noexcept
Definition: connection.h:160
ConnectionProvider
Connection provider concept
ozo::connection::assign
error_code assign(ozo::pg::conn &&handle)
Definition: connection.h:39
ozo::none
constexpr auto none
None object.
Definition: none.h:27
ozo::connection::is_bad
bool is_bad() const noexcept
Definition: connection.h:87
ozo::get_database
std::string_view get_database(const Connection &conn)
Get the database name of the active connection.
Definition: connection.h:142
ozo::connection::native_handle_type
ozo::pg::conn::pointer native_handle_type
Native connection handle type.
Definition: connection.h:95
ozo::close_connection
error_code close_connection(Connection &&conn)
Close connection to the database immediately.
Definition: connection.h:106
ozo::is_null_recursive
constexpr bool is_null_recursive(T &&v) noexcept
Indicates if one of unwrapped values is in null state.
Definition: recursive.h:78
ozo::connection
Default model for Connection concept.
Definition: connection.h:93
ozo::connection::executor_type
io_context::executor_type executor_type
The type of the executor associated with the object.
Definition: connection.h:98
ozo::Require
Type Require
Concept requirement emulation.
Definition: concept.h:54
ozo::get_operation_initiator
constexpr auto get_operation_initiator(const Operation &op)
Get asynchronous operation initiator.
Definition: asio.h:166
ozo::connection::async_wait_read
void async_wait_read(WaitHandler &&handler)
Definition: connection.h:70
CompletionToken
Completion token concept.
ConnectionSource
Connection source concept
ozo::is_connection
Connection indicator.
Definition: connection.h:283
ozo::get_connection_type
Connection type getter
Definition: connection.h:554
ozo::get_host
std::string_view get_host(const Connection &conn)
Get the host connected of the active connection.
Definition: connection.h:148
Handler
Handler concept.
ozo::connection_type
typename get_connection_type< std::decay_t< T > >::type connection_type
The connection object type that ConnectionProvider or ConnectionSource provide.
Definition: connection.h:572
ozo::connection_good
bool connection_good(const Connection &conn) noexcept
Indicates if connection state is not bad.
Definition: connection.h:391
ozo::get_password
std::string_view get_password(const Connection &conn)
Get the password of the active connection.
Definition: connection.h:166
Connection
Database connection concept.
ozo::none_t
None type None type modelling void as ordinary type. This type is callable with return type void.
Definition: none.h:13
ozo::get_user
std::string_view get_user(const Connection &conn)
Get the user name of the active connection.
Definition: connection.h:160
ozo::connection::is_open
bool is_open() const noexcept
Definition: connection.h:261
ozo::base_async_operation
Base class for async operations.
Definition: asio.h:236
ozo::connection::oid_map
const oid_map_type & oid_map() const noexcept
Definition: connection.h:133
ozo::connection_bad
bool connection_bad(const T &conn) noexcept
Determine whether the connection is in bad state.
ozo::connection::connection
connection(io_context &io, Statistics statistics)
Definition: connection.h:35
ozo::get_connection
decltype(auto) get_connection(T &&provider, CompletionToken &&token)
Get a connection from connection provider.
ozo::get_error_context
const auto & get_error_context(const Connection &conn)
Get additional error context.
Definition: connection.h:124
ozo::connection::get_error_context
const error_context_type & get_error_context() const noexcept
Definition: connection.h:146