diff --git a/pglab/ASyncDBConnection.cpp b/pglab/ASyncDBConnection.cpp index 42b9b62..3379423 100644 --- a/pglab/ASyncDBConnection.cpp +++ b/pglab/ASyncDBConnection.cpp @@ -4,19 +4,19 @@ using namespace boost::asio; -namespace { +//namespace { - class registerMetaTypes { - public: - registerMetaTypes() - { - qRegisterMetaType(); - qRegisterMetaType(); - } - } registerMetaTypes_instance; +// class registerMetaTypes { +// public: +// registerMetaTypes() +// { +// qRegisterMetaType(); +// qRegisterMetaType(); +// } +// } registerMetaTypes_instance; -} +//} ASyncDBConnection::ASyncDBConnection(boost::asio::io_service &ios) : m_asioSock(ios) @@ -87,7 +87,8 @@ void ASyncDBConnection::doStateCallback(State state) m_connection.setNoticeReceiver( [this](const PGresult *result) { processNotice(result); }); } - emit onStateChanged(state); + if (m_stateChangeReceiver) + m_stateChangeReceiver(state); } @@ -136,7 +137,7 @@ void ASyncDBConnection::async_query_handler(boost::system::error_code ec, std::s while ( ! finished && ! m_connection.isBusy()) { auto res = m_connection.getResult(); qint64 ms = m_timer.restart(); - on_result(res, ms); + on_result(res, ms); // do we really want to send null result to??? if (res == nullptr) { m_timer.invalidate(); doStateCallback(State::Connected); @@ -169,5 +170,16 @@ bool ASyncDBConnection::cancel() void ASyncDBConnection::processNotice(const PGresult *result) { Pgsql::ErrorDetails details = Pgsql::ErrorDetails::createErrorDetailsFromPGresult(result); - emit onNotice(details); + if (m_noticeReceiver) + m_noticeReceiver(details); +} + +void ASyncDBConnection::setStateChangeReceiver(StateChangeReceiver state_change_receiver) +{ + m_stateChangeReceiver = state_change_receiver; +} + +void ASyncDBConnection::setNoticeReceiver(NoticeReceiver notice_receiver) +{ + m_noticeReceiver = notice_receiver; } diff --git a/pglab/ASyncDBConnection.h b/pglab/ASyncDBConnection.h index 60543e9..c052965 100644 --- a/pglab/ASyncDBConnection.h +++ b/pglab/ASyncDBConnection.h @@ -1,14 +1,13 @@ #ifndef ASYNCDBCONNECTION_H #define ASYNCDBCONNECTION_H -#include - #include "Pgsql_Connection.h" #include "Pgsql_Params.h" #include "Pgsql_Result.h" #include "Expected.h" #include "ConnectionConfig.h" #include +#include #include #include #include @@ -16,10 +15,12 @@ /** \brief Class that handles asynchronous execution of queries. * * Queries are passed to this class with a routine to call on completion - * when the result is on that routine is called. + * when the result is received that routine is called. The asynchronous + * processing is done using boost::asio. + * + * You can cancel a running query but even then you have to wait for the result. */ -class ASyncDBConnection: public QObject { - Q_OBJECT +class ASyncDBConnection { public: enum class State { NotConnected, @@ -39,20 +40,36 @@ public: void setupConnection(const ConnectionConfig &config); void closeConnection(); - /** Sends command to the server. + /** \defgroup send These function send queries to the server. + * + * The query string can actually contain multiple queries. + * These functions report their results through a callback function. + * If the command gives multiple results on_result will be called for each result. + * + * \note when the io_service that was passed to the constructor is running + * on a different thread the callback also will be done on that thread. Forward + * the call to your own thread if needed. + * + * \note while you can pass multiple queries to a single send call it is not allowed to + * send new queries while not all results have been received. + */ - When the result is in on_result will be called directly within the thread. - - If the command gives multiple results on_result will be called for each result. - */ + /** \ingroup send + * \brief Function to send a command without parameters to the server. + */ bool send(const std::string &command, on_result_callback on_result); + /** \ingroup send + * \brief Function to send a a command with parameters to the server. + */ bool send(const std::string &command, Pgsql::Params params, on_result_callback on_result); bool cancel(); -signals: - void onStateChanged(ASyncDBConnection::State state); - void onNotice(Pgsql::ErrorDetails notice); + using StateChangeReceiver = std::function; + void setStateChangeReceiver(StateChangeReceiver state_change_receiver); + + using NoticeReceiver = std::function; + void setNoticeReceiver(NoticeReceiver notice_receiver); private: Pgsql::Connection m_connection; @@ -60,7 +77,9 @@ private: ConnectionConfig m_config; State m_state = State::NotConnected; Pgsql::Canceller m_canceller; - + StateChangeReceiver m_stateChangeReceiver; + NoticeReceiver m_noticeReceiver; + QElapsedTimer m_timer; void async_connect_handler(boost::system::error_code ec, std::size_t s); @@ -69,8 +88,4 @@ private: void processNotice(const PGresult *result); }; -Q_DECLARE_METATYPE(ASyncDBConnection::State); -Q_DECLARE_METATYPE(Pgsql::ErrorDetails); - - #endif // ASYNCDBCONNECTION_H diff --git a/pglab/DatabaseWindow.cpp b/pglab/DatabaseWindow.cpp index 4aab48e..adf32bb 100644 --- a/pglab/DatabaseWindow.cpp +++ b/pglab/DatabaseWindow.cpp @@ -11,8 +11,10 @@ DatabaseWindow::DatabaseWindow(QWidget *parent) : { ui->setupUi(this); - connect(&m_dbConnection, &ASyncDBConnection::onStateChanged, this, &DatabaseWindow::connectionStateChanged); - connect(&m_dbConnection, &ASyncDBConnection::onNotice, this, &DatabaseWindow::receiveNotice); + m_dbConnection.setStateChangeReceiver( + [this](auto s) { QueueTask([this, s]() { connectionStateChanged(s); }); }); + m_dbConnection.setNoticeReceiver( + [this](auto n) { QueueTask([this, n]() { receiveNotice(n); }); }); } DatabaseWindow::~DatabaseWindow() diff --git a/pglab/QueryTab.cpp b/pglab/QueryTab.cpp index 4df3363..5bab123 100644 --- a/pglab/QueryTab.cpp +++ b/pglab/QueryTab.cpp @@ -31,9 +31,11 @@ QueryTab::QueryTab(MainWindow *win, QWidget *parent) : { ui->setupUi(this); - connect(&m_dbConnection, &ASyncDBConnection::onStateChanged, this, &QueryTab::connectionStateChanged); - connect(&m_dbConnection, &ASyncDBConnection::onNotice, this, &QueryTab::receiveNotice); - + m_dbConnection.setStateChangeReceiver( + [this, win](auto s) { win->QueueTask([this, s]() { connectionStateChanged(s); }); }); + m_dbConnection.setNoticeReceiver( + [this, win](auto n) { win->QueueTask([this, n]() { receiveNotice(n); }); }); + QFont font; font.setFamily("Source Code Pro"); font.setFixedPitch(true);