taocpp / taopq

C++ client library for PostgreSQL
Boost Software License 1.0
265 stars 40 forks source link

Support for LISTEN/NOTIFY ? #46

Closed bog-dan-ro closed 3 years ago

bog-dan-ro commented 3 years ago

Are there any plans to support PostgreSQL LISTEN/NOTIFY ?

d-frey commented 3 years ago

Should be mostly implemented. Please test and let me know if anything is missing.

(yeah, documentation is still missing, will work on it with the rest of the missing documentation as time permits)

bog-dan-ro commented 3 years ago

WOW, thanks a lot!

I have a few ideas to make the API a bit more useful:

  1. add the handler functor to the listen member functions (e.g. conn.listen("channel", [](const char* channelName, const char* payload){///...});
  2. optionally add a poor man's event loop to handle external notifications? I.e. create another thread which will monitor socket and will process the notifications.
d-frey commented 3 years ago

For 1. you could write your own dispatcher easily:

void handle_foo( const char* payload )
{
   // ...
}

struct
{
   std::map< std::string, std::function< void( const char* payload ) >, std::less<> > dispatcher;

   void operator()( const tao::pq::notification& n )
   {
      const auto it = dispatcher.find( n.channel_name() );
      if( it != dispatcher.end() ) {
         it->second( n.payload() );
      }
   }

} handle_notification;

// later, do this:

connection->set_notification_handler( std::ref( handle_notification ) );
handle_notification.dispatcher[ "FOO" ] = &handle_foo;

Of course, there are other options to implement that. The handler-class should have set/reset-methods for the channels, etc. But you could also have a list of handlers per channel, not just a single handler. But then how do you delete the handlers for a channel, etc. I'm not sure what a generic solution should look like. Thoughts?

bog-dan-ro commented 2 years ago

But then how do you delete the handlers for a channel, etc. I'm not sure what a generic solution should look like. Thoughts?

You already added reset_notification_handler it just needs a channel parameter :)

Another idea is to pass an empty functor to set listener e.g. conn.listen("channel",{});.

But as you said it, people can implement their own dispatchers.

d-frey commented 2 years ago

But then how do you delete the handlers for a channel, etc. I'm not sure what a generic solution should look like. Thoughts?

You already added reset_notification_handler it just needs a channel parameter :)

The sentence you quoted was preceded by "But you could also have a list of handlers per channel, not just a single handler." In that context it's not just a channel name to identify the handler to delete.

But as you said it, people can implement their own dispatchers.

I'm not against a more convenient interface, I just need to balance it properly. I am still considering your ideas, I just don't want to rush it.