On Thu, Sep 08, 2011 at 01:19:17PM +0100, Andrew Ford wrote: > Hi Tim > > Sorry for mailing you directly, but I don't know whether my emails > are getting through to the dbi-users mailing list,
[CC'd to dbi-users] > and I would quite like to get this module onto CPAN and would like some > feedback as to > whether "the expert" thinks it is a bad idea. I think it would be a > useful addition to the testing > armoury, but then I am obviously biased. The general idea is certainly useful. I'd like to generalise it though. There's a conceptual similarity with PSGI/Plack middlewares that I'd like to build on. Specifically, rather than creating a new transport, I'd like to see DBD/Gofer/Transport/Base.pm extended to call one or more 'Gofer client middlewares' just before it calls transmit_request_by_transport(). The calling code could be something like: + my $mw = $self->middleware; my $transmit_sub = sub { my $response = eval { ... - $self->transmit_request_by_transport($request) + $mw->($self, $request); } ... } The middleware attribute would default to: sub { shift->transmit_request_by_transport(@_) } new middleware layer would be added by doing: my $mw = $self->middleware; $self->middleware( sub { my ($self, $request) = @_; ...do something with $request... my $response = $mw->($self, $request); ...do something with $response... return $response; } ); [This is all off-the-top-of-my-head, and I'm not very familar with Plack internals so I may well be missing important issues.] Then we just need a way to add middlewares via the environment. I'd be delighted if you would work up a patch to add that to the DBI. Your module could then use this mechanism. If you wanted to release it to CPAN then a name like DBDx::GoferMiddleware::FOO would be good. (Note the DBDx not DBIx since this is client-side. We may well end up with server-side gofer middlewares as well.) Tim. > I have attached the current version of the module file with some > documentation from my intial post > included below (I've changed my mind about the attribute naming and > currently am going for > transform=modulename and method=methodname for the module/method that > implements the transformation). I > will of course add unit tests and everything that goes with a proper CPAN > release, but I would be > grateful for some quick feedback. > > Regards > Andrew > > -------- Original Message -------- > > Subject: Idea for a Gofer transport for translating SQL - primarily > intended for testing > Date: Thu, 08 Sep 2011 11:16:41 +0100 > From: Andrew Ford [1]<a.f...@ford-mason.co.uk> > To: [2]dbi-users@perl.org > > I have a software system that I have to test that uses a very large > database accessed exclusively with > stored procedures. It is a pain setting up a test database for simple > unit tests of the Perl code (I am > not trying to test the stored procedures). > > What I want is to be able to do is set up a simple database (SQLite) > quickly to use instead, but of > course there is the issue of the stored procedures being database-specific > - but then for testing > purposes most of the stored procedures could be represented by simple SQL > statements. > > What I have done as a proof of concept is to take the > DBD::Gofer::Transport::null and create a new > module that maps the stored procedures into simple SQL statements and then > executes them in-process > against the test database > > The code is pretty simple and included below. Currently it has a map of > stored procedure > transformations hard-coded in the code and assumes ODBC style stored > procedure call syntax, but I was > thinking of allowing a mapping module to be specified as an attribute in > the DSN so that the DSN would > be specified like: > > > dbi:Gofer:transport=adaptor;mapper=My::Mapping::Module;dsn=dbi:SQLite:test.db > > Overriding the system's DSN then causes the system to use my test > database, transparently doing the > appropriate mappings. > > I would appreciate any comments, suggestions, and thoughts as to whether > this would be a useful addition > to CPAN. > > The immediate issue that I see is: what would the interface to the mapping > module be (probably the > module should provide a single function that takes a request object and > either modifies it or returns a > new request object). > > Andrew > > current proof-of-concept code: > > package DBD::Gofer::Transport::adaptor; > > use strict; > use warnings; > > use DBI::Gofer::Execute; > > use base qw(DBD::Gofer::Transport::Base); > > __PACKAGE__->mk_accessors( qw( pending_response transmit_count ) ); > > # Lookup table for stored procedure transformations > > my %stored_proc_transform > = ( > fetch_user => 'select * from user where email = ?', > # ... > ); > > my $executor = DBI::Gofer::Execute->new(); > > sub transmit_request_by_transport { > my ($self, $request) = @_; > > # Intercept 'do' and 'prepare' methods > > if ( exists $request->{dbh_method_call} > and ref $request->{dbh_method_call} eq 'ARRAY' > and @{$request->{dbh_method_call}} > 2 > and ( $request->{dbh_method_call}[1] eq 'do' > or $request->{dbh_method_call}[1] eq 'prepare')) > { > > # The SQL statement is held in the third element of the method > call slot - check > # for stored procedure calls and look and see if there is a > transformation > # defined. The transformation may be a simple string > replacement or a code ref to > # a function that performs more complex transformations. > > my $orig_sql = $request->{dbh_method_call}[2]; > > if ($orig_sql =~ m{ ^ \s* [{] \s* call \s+ (\w+) \s* [\(] ( .* ) > [\)] \s* [}] \s* $ }isx) { > my ($sp, $placeholders) = ($1, $2); > > my $xformed_sql = $stored_proc_transform{$sp}; > if (ref $xformed_sql eq 'CODE') { > $xformed_sql = $xformed_sql->($request, $orig_sql, $sp, > $placeholders); > } > $request->{dbh_method_call}->[2] = $xformed_sql; > } > } > > my $response = $executor->execute_request( $request ); > > # put response 'on the shelf' ready for receive_response() > $self->pending_response( $response ); > > return undef; > } > > sub receive_response_by_transport { return shift->pending_response; } > > 1; > > References > > Visible links > 1. mailto:a.f...@ford-mason.co.uk > 2. mailto:dbi-users@perl.org