#ifndef _QTL_ASYNC_H_ #define _QTL_ASYNC_H_ #include #include #include #include namespace qtl { #ifdef _WIN32 typedef SOCKET socket_type; #else typedef int socket_type; #endif namespace detail { template struct async_fetch_helper : public std::enable_shared_from_this> { async_fetch_helper(const Values& values, const RowHandler& row_handler, const FinishHandler& finish_handler) : m_values(values), m_row_handler(row_handler), m_finish_handler(finish_handler), m_auto_close_command(true) { } template void start(const std::shared_ptr& command) { auto self = this->shared_from_this(); command->fetch(std::forward(m_values), [this, command]() { return qtl::detail::apply(std::forward(m_row_handler), std::forward(m_values)); }, [self, command](const Exception& e) { if (e || self->m_auto_close_command) { command->close([self, command, e](const Exception& new_e) { self->m_finish_handler(e ? e : new_e); }); } else { self->m_finish_handler(e); } }); } void auto_close_command(bool auto_close) { m_auto_close_command = auto_close; } private: Values m_values; RowHandler m_row_handler; FinishHandler m_finish_handler; bool m_auto_close_command; }; template inline std::shared_ptr> make_fetch_helper(const Values& values, const RowHandler& row_handler, const FinishHandler& cpmplete_handler) { return std::make_shared>(values, row_handler, cpmplete_handler); } template inline void async_fetch_command(const std::shared_ptr& command, FinishHandler&& finish_handler, RowHandler&& row_handler) { auto values=make_values(row_handler); typedef decltype(values) values_type; auto helper = make_fetch_helper(std::forward(values), std::forward(row_handler), std::forward(finish_handler)); helper->auto_close_command(false); helper->template start(command); } template inline void async_fetch_command(const std::shared_ptr& command, FinishHandler&& finish_handler, RowHandler&& row_handler, OtherHandler&&... other) { async_fetch_command(command, [command, finish_handler, other...](const Exception& e) mutable { if (e) { finish_handler(e); } else { command->next_result([=](const Exception& e) mutable { if (e) finish_handler(e); else async_fetch_command(command, std::forward(finish_handler), std::forward(other)...); }); } }, std::forward(row_handler)); } } struct event { enum io_flags { ef_read = 0x1, ef_write = 0x2, ef_exception = 0x4, ef_timeout =0x8, ev_all = ef_read | ef_write | ef_exception }; virtual ~event() { } virtual void set_io_handler(int flags, long timeout, std::function&&) = 0; virtual void remove() = 0; virtual bool is_busying() = 0; }; template class async_connection { public: template bool bind(EventLoop& ev) { T* pThis = static_cast(this); if(m_event_handler) { if(m_event_handler->is_busying()) return false; unbind(); } m_event_handler = ev.add(pThis); return m_event_handler!=nullptr; } qtl::event* event() const { return m_event_handler; } bool unbind() { if(m_event_handler) { if(m_event_handler->is_busying()) return false; m_event_handler->remove(); m_event_handler=nullptr; } return true; } /* ResultHandler defines as: void handler(const exception_type& e, uint64_t affected=0); Copies will be made of the handler as required. If an error occurred, value of affected is undefined. Note: parameter affected must has default value. */ template void execute(ResultHandler handler, const char* query_text, size_t text_length, const Params& params) { T* pThis = static_cast(this); pThis->open_command(query_text, text_length, [handler, params](const typename T::exception_type& e, std::shared_ptr& command) mutable { if(e) { command->close([command, e, handler](const typename T::exception_type& ae) mutable { handler(e ? e : ae, 0); }); return; } command->execute(params, [command, handler](const typename T::exception_type& e, uint64_t affected) mutable { command->close([command, handler, e, affected](const typename T::exception_type& ae) mutable { handler(e ? e : ae, affected); }); }); }); } template void execute(ResultHandler handler, const char* query_text, const Params& params) { return execute(std::forward(handler), query_text, strlen(query_text), params); } template void execute(ResultHandler handler, const std::string& query_text, const Params& params) { return execute(std::forward(handler), query_text.data(), query_text.length(), params); } template void execute_direct(ResultHandler handler, const char* query_text, size_t text_length, const Params&... params) { execute(std::forward(handler), query_text, text_length, std::forward_as_tuple(params...)); } template void execute_direct(ResultHandler handler, const char* query_text, const Params&... params) { execute(std::forward(handler), query_text, std::forward_as_tuple(params...)); } template void execute_direct(ResultHandler handler, const std::string& query_text, const Params&... params) { execute(std::forward(handler), query_text, query_text, std::forward_as_tuple(params...)); } /* ResultHandler defines as: void handler(const exception_type& e, uint64_t insert_id=0); Copies will be made of the handler as required. If an error occurred, value of insert_id is undefined. If the command is not insert statement, value of insert_id is zero. Note: parameter insert_id must has default value. */ template void insert(ResultHandler handler, const char* query_text, size_t text_length, const Params& params) { T* pThis = static_cast(this); pThis->open_command(query_text, text_length, [handler, params](const typename T::exception_type& e, std::shared_ptr& command) { if(e) { command->close([command, e, handler](const typename T::exception_type& ae) mutable { handler(e ? e : ae, 0); }); } else { command->execute(params, [command, handler](const typename T::exception_type& e, uint64_t affected) { auto insert_id = 0; if(!e && affected>0) insert_id = command->insert_id(); command->close([command, handler, e, insert_id](const typename T::exception_type& ae) mutable { handler(e ? e : ae, insert_id); }); }); } }); } template void insert(ResultHandler&& handler, const char* query_text, const Params& params) { insert(std::forward(handler), query_text, strlen(query_text), params); } template void insert(ResultHandler&& handler, const std::string& query_text, const Params& params) { insert(std::forward(handler), query_text.data(), query_text.length(), params); } template void insert_direct(ResultHandler&& handler, const char* query_text, size_t text_length, const Params&... params) { insert(std::forward(handler), query_text, text_length, std::forward_as_tuple(params...)); } template void insert_direct(ResultHandler&& handler, const char* query_text, const Params&... params) { insert(std::forward(handler), query_text, strlen(query_text), std::forward_as_tuple(params...)); } template void insert_direct(ResultHandler&& handler, const std::string& query_text, const Params&... params) { insert(std::forward(handler), query_text.data(), query_text.length(), std::forward_as_tuple(params...)); } /* RowHandler defines as: void row_handler(const Values& values); FinishHandler defines as: void finish_handler(const exception_type& e); If a row is fetched, the row handler is called. If an error occurred or the operation is completed, the result handler is called. */ template void query_explicit(const char* query_text, size_t text_length, const Params& params, Values&& values, RowHandler&& row_handler, FinishHandler&& finish_handler) { T* pThis = static_cast(this); pThis->open_command(query_text, text_length, [values, row_handler, finish_handler, params](const typename T::exception_type& e, const std::shared_ptr& command) mutable { if(e) { finish_handler(e); } else { command->execute(params, [command, values, row_handler, finish_handler](const typename T::exception_type& e, uint64_t affected) mutable { auto helper=detail::make_fetch_helper(values, row_handler, finish_handler); helper->template start(command); }); } }); } template void query_explicit(const char* query_text, const Params& params, Values&& values, RowHandler&& row_handler, FinishHandler&& finish_handler) { query_explicit(query_text, strlen(query_text), params, std::forward(values), std::forward(row_handler), std::forward(finish_handler)); } template void query_explicit(const std::string& query_text, const Params& params, Values&& values, RowHandler&& row_handler, FinishHandler&& finish_handler) { query_explicit(query_text.data(), query_text.size(), params, std::forward(values), std::forward(row_handler), std::forward(finish_handler)); } template void query_explicit(const char* query_text, size_t text_length, Values&& values, RowHandler&& row_handler, FinishHandler&& finish_handler) { query_explicit(query_text, text_length, std::make_tuple(), std::forward(values), std::forward(row_handler), std::forward(finish_handler)); } template void query_explicit(const char* query_text, Values&& values, RowHandler&& row_handler, FinishHandler&& finish_handler) { query_explicit(query_text, strlen(query_text), std::make_tuple(), std::forward(values), std::forward(row_handler), std::forward(finish_handler)); } template void query_explicit(const std::string& query_text, Values&& values, RowHandler&& row_handler, FinishHandler&& finish_handler) { query_explicit(query_text, std::make_tuple(), std::forward(values), std::forward(row_handler), std::forward(finish_handler)); } template void query(const char* query_text, size_t text_length, const Params& params, RowHandler&& row_handler, FinishHandler&& finish_handler) { query_explicit(query_text, text_length, params, detail::make_values(row_handler), std::forward(row_handler), std::forward(finish_handler)); } template void query(const char* query_text, const Params& params, RowHandler&& row_handler, FinishHandler&& finish_handler) { query_explicit(query_text, params, detail::make_values(row_handler), std::forward(row_handler), std::forward(finish_handler)); } template void query(const std::string& query_text, const Params& params, RowHandler&& row_handler, FinishHandler&& finish_handler) { query_explicit(query_text, params, detail::make_values(row_handler), std::forward(row_handler), std::forward(finish_handler)); } template void query(const char* query_text, size_t text_length, RowHandler&& row_handler, FinishHandler&& finish_handler) { query_explicit(query_text, text_length, detail::make_values(row_handler), std::forward(row_handler), std::forward(finish_handler)); } template void query(const char* query_text, RowHandler&& row_handler, FinishHandler&& finish_handler) { query_explicit(query_text, detail::make_values(row_handler), std::forward(row_handler), std::forward(finish_handler)); } template void query(const std::string& query_text, RowHandler&& row_handler, FinishHandler&& finish_handler) { query_explicit(query_text, detail::make_values(row_handler), std::forward(row_handler), std::forward(finish_handler)); } template void query_multi_with_params(const char* query_text, size_t text_length, const Params& params, FinishHandler&& finish_handler, RowHandlers&&... row_handlers) { T* pThis = static_cast(this); pThis->open_command(query_text, text_length, [params, finish_handler, row_handlers...](const typename T::exception_type& e, const std::shared_ptr& command) mutable { if (e) { finish_handler(e); } else { command->execute(params, [=](const typename T::exception_type& e, uint64_t affected) mutable { if (e) finish_handler(e); else qtl::detail::async_fetch_command(command, std::forward(finish_handler), std::forward(row_handlers)...); }); } }); } template void query_multi_with_params(const char* query_text, const Params& params, FinishHandler&& finish_handler, RowHandlers&&... row_handlers) { query_multi_with_params(query_text, strlen(query_text), params, std::forward(finish_handler), std::forward(row_handlers)...); } template void query_multi_with_params(const std::string& query_text, const Params& params, FinishHandler&& finish_handler, RowHandlers&&... row_handlers) { query_multi_with_params(query_text.data(), query_text.size(), params, std::forward(finish_handler), std::forward(row_handlers)...); } template void query_multi(const char* query_text, size_t text_length, FinishHandler&& finish_handler, RowHandlers&&... row_handlers) { query_multi_with_params, FinishHandler, RowHandlers...>(query_text, text_length, std::make_tuple(), std::forward(finish_handler), std::forward(row_handlers)...); } template void query_multi(const char* query_text, FinishHandler&& finish_handler, RowHandlers&&... row_handlers) { query_multi_with_params, FinishHandler, RowHandlers...>(query_text, strlen(query_text), std::make_tuple(), std::forward(finish_handler), std::forward(row_handlers)...); } template void query_multi(const std::string& query_text, FinishHandler&& finish_handler, RowHandlers&&... row_handlers) { query_multi_with_params, FinishHandler, RowHandlers...>(query_text.data(), query_text.size(), std::make_tuple(), std::forward(finish_handler), std::forward(row_handlers)...); } protected: qtl::event* m_event_handler { nullptr }; }; } #endif //_QTL_ASYNC_H_