ap / DBIx-Connector

Fast, safe DBI connection and transaction management
https://metacpan.org/release/DBIx-Connector
40 stars 14 forks source link

Execute a callback before attempting DBI->connect #21

Closed rwstauner closed 12 years ago

rwstauner commented 12 years ago

Separating this idea from #19, accepting a coderef that DBIx::Connector would call before calling DBI->connect could be a handy feature.

After reading DBI docs and code I found that this effect can be achieved with something like:

DBIx::Connector->new('dbi:SQLite:dbname=:memory:', '', '',
    { dbi_connect_method => sub { do_something; shift->connect(@_) } }) 

but that seems a bit hackish and slightly cumbersome: Each time you have to remember to also do the shift->connect(@_) part. Also passing a coderef as dbi_connect_method is undocumented, and making a separate sub or class each time would be even more cumbersome.

What do you think? Or perhaps do you have any other pearls of wisdom I've overlooked again? :-)

Thanks!

theory commented 12 years ago

Why wouldn't you just execute said code before calling DBIx::Connector->new?

Otherwise, I recommend using connect_cached and the accompanying connect_cached.new and connect_cached.reused callbacks, which are called before connecting.

If you can't use connect_cached, maybe ask @timbunce if dbi_connect_method could be officially blessed for this purpose in the docs?

rwstauner commented 12 years ago

I was thinking about doing something for preparing the connection.

Some example situations I've run into:

I've since changed the java thing to be run by a daemon that tries to handle keeping java running so that the dbi-using code isn't concerned with it. It recently occurred to me that perhaps one solution for the ssh tunnel could be setting up a dbi proxy server that would manage that (aside from the other possibility of merely running a separate process to manage it).

I also didn't realize that connect_cached.new actually fired before the connect rather than after, so that would work. Since I'd definitely like to minimize the goofy cases like these, I'll go that route.

I have one other old project that sets up subclasses and uses connect_cached. I've been scheming about how to replace some of that code with DBIx::Connector. Combining connect_cached.new with RootClass looks like everything should be doable through DBIx::Connector, so thank you very much!

{ package MYDBI; package MYDBI::db; our @ISA = qw(DBI::db);
  sub connected { print STDERR "hi mom!"; } package MYDBI::st; our @ISA = qw(DBI::st); };
$INC{"MYDBI.pm"} = 1;
my $dbc = DBIx::Connector->new('dbi:SQLite:dbname=:memory:', '', '', {
    dbi_connect_method => "connect_cached",
    Callbacks => { "connect_cached.new" => sub { print STDERR "CONNECTING"; } },
    RootClass => "MYDBI",
});

I apologize again for bothering you with these questions, but I really appreciate your showing me how to achieve the same effect through existing interfaces. Thanks for the help, and for DBIx::Connector which I'm looking forward to using more... but don't worry, I think I'm done asking you for things about it :-)

theory commented 12 years ago

Bah! I just realized that you can't use the connect_cached.* callbacks with DBIx::Connector, because it calls connect. @timbunce is there any other way to get a callback in before the actual connection code? As Randy noted, dbi_connect_method is not documented. Maybe it could be? Or some other callback name could be created to support it?

rwstauner commented 12 years ago

Setting dbi_connect_method to connect_cached (or any other function name) as in the example in my last comment is documented:

The C<dbi_connect_method> attribute can be used to specify which driver
method should be called to establish the connection. The only useful
values are 'connect', 'connect_cached', or some specialized case like
'Apache::DBI::connect' (which is automatically the default when running
within Apache).

However the docs say nothing about using an anonymous coderef as in my first comment.

theory commented 12 years ago

Oh, so not complete undocumented, and you can coerce into using connect_cached. That's kind of cool. Would be nice to document it as available for callbacks, too. If, of course, it is.

timbunce commented 12 years ago

I'll take a doc patch to officially bless using a code ref for dbi_connect_method (asuming it work, I've not tried/looked).

For this use case perhaps DBIx::Connector->new could take an extra argument, or notice a dbix_connect_foo => ... in the DBI connect attributes. Either way, DBIx::Connector->new could take that argument and turn it into a dbi_connectmethod code ref that calls the supplied code ref and then does shift->connect(@);

theory commented 12 years ago

Meh. I have steered clear of adding parameters to DBIx::Connector->new. Only those supported by DBI->connect are allowed. There are a couple of other things one can change in the DBIx::Connector object, but only via accessors. And although it does muck with a few DBI params, it does not change their meaning at all.