Subject: | PATCH: Add DBIx::Simple::Connector |
Juerd,
As we discussed by email some time ago, attached is a patch which supplies DBIx::Simple::Connector, including code, tests and docs.
I added _clear_cache() to DBIx::Simple as you asked, and it was also necessary to create internal calls in DBIx::Simple to reference 'dbh()' instead of {dbh}.
Subject: | dbix_simple_connector.diff |
Fri Oct 4 11:35:57 EDT 2013 Mark Stosberg <mark@summersault.com>
* Implement DBIx::Simple::Connector.
To implement this, some required changes were made to DBIx::Simple as well:
- Use $self->dbh internally instead of $self->{dbh}
- Add $self->_clear_cache();
diff -rN -u old-rt-9160-DBIx-Simple/Changes new-rt-9160-DBIx-Simple/Changes
--- old-rt-9160-DBIx-Simple/Changes 2013-10-04 11:37:58.000000000 -0400
+++ new-rt-9160-DBIx-Simple/Changes 2013-10-04 11:37:58.000000000 -0400
@@ -3,6 +3,17 @@
Incompatible changes are marked with "!!". Incompatibility with and changes in
"undocumented features" are not always specifically mentioned here.
+1.40 Sat Oct 5 12:00 2013
+ - DBIx::Simple::Connector has been added to the distribution for
+ built-in integration with DBIx::Connector. DBIx::Connector helps with
+ making connections persistent, automatically reconnecting and
+ avoiding pinging the database so much to test if the connection is
+ up. (Mark Stosberg)
+
+ - Internally, we now maximally call $self->dbh instead of $self->{dbh},
+ allowing sub-classes the flexibility to implement their own dbh() method.
+ (Mark Stosberg)
+
1.35 Tue Jan 4 23:48 2010
!! - RaiseError is now enabled by default, as announced three years ago.
Set PERL_DBIX_SIMPLE_NO_RAISEERROR=1 to get the old behavior.
diff -rN -u old-rt-9160-DBIx-Simple/lib/DBIx/Simple/Connector.pm new-rt-9160-DBIx-Simple/lib/DBIx/Simple/Connector.pm
--- old-rt-9160-DBIx-Simple/lib/DBIx/Simple/Connector.pm 1969-12-31 19:00:00.000000000 -0500
+++ new-rt-9160-DBIx-Simple/lib/DBIx/Simple/Connector.pm 2013-10-04 11:37:58.000000000 -0400
@@ -0,0 +1,84 @@
+use 5.006;
+use strict;
+
+$DBIx::Simple::Connector::VERSION = '1.40';
+
+my $no_raiseerror = $ENV{PERL_DBIX_SIMPLE_NO_RAISEERROR};
+
+package DBIx::Simple::Connector;
+use base 'DBIx::Simple';
+use DBIx::Connector;
+use Data::Dumper;
+
+sub connect {
+ my ($class, @arguments) = @_;
+ my $self = {
+ lc_columns => 1,
+ result_class => 'DBIx::Simple::Result',
+ dont_disconnect => 1,
+ };
+
+ if (defined $arguments[0] and UNIVERSAL::isa($arguments[0], 'DBIx::Connector')) {
+ $self->{conn} = shift @arguments;
+ Carp::carp("Additional arguments for $class->connect are ignored") if @arguments;
+ } else {
+ $arguments[3]->{PrintError} = 0
+ unless defined $arguments[3] and exists $arguments[3]{PrintError};
+ $arguments[3]->{RaiseError} = 1
+ unless $no_raiseerror
+ or defined $arguments[3] and exists $arguments[3]{RaiseError};
+ $self->{conn} = DBIx::Connector->new(@arguments);
+ }
+
+ return undef unless $self->{conn};
+ bless $self, $class;
+ $self->{dbd} = $self->{conn}->dbh->{Driver}->{Name};
+
+ return $self;
+}
+
+sub dbh {
+ my $self = shift;
+
+ # If the database handle has changed, invalidate our statement handle caches.
+ my $new_dbh = $self->{conn}->dbh;
+ if (defined $self->{old_dbh} and "$self->{old_dbh}" ne "$new_dbh") {
+ $self->_clear_cache;
+ }
+
+ $self->{old_dbh} = "$new_dbh";
+ return $new_dbh;
+}
+
+
+
+1;
+
+=head1 NAME
+
+DBIx::Simple::Connector - Initialize DBIx::Simple with a DBIx::Connector object
+
+=head1 SYNOPSIS
+
+ my $db = DBIx::Simple::Connector->new( DBIx::Connector->new(...) );
+
+ my $db = DBIx::Simple::Connector->new($dsn, $username, $password, \%args);
+
+=head1 DESCRIPTION
+
+Works just like L<DBIx::Simple>, but accepts a DBIx::Connector object as argument to C<new()>
+instead of a raw database handle.
+
+Alternately, arguments to C<new()> will be passed to DBIx::Connector to make a database connection.
+
+=head1 AUTHORS
+
+Mark Stosberg <mark@stosberg.com> and Juerd Waalboer <#####@juerd.nl> <http://juerd.nl/>
+
+=head1 SEE ALSO
+
+L<DBIx::Simple>
+
+L<DBIx::Connector>
+
+=cut
diff -rN -u old-rt-9160-DBIx-Simple/lib/DBIx/Simple.pm new-rt-9160-DBIx-Simple/lib/DBIx/Simple.pm
--- old-rt-9160-DBIx-Simple/lib/DBIx/Simple.pm 2013-10-04 11:37:58.000000000 -0400
+++ new-rt-9160-DBIx-Simple/lib/DBIx/Simple.pm 2013-10-04 11:37:58.000000000 -0400
@@ -3,7 +3,7 @@
use DBI;
use Carp ();
-$DBIx::Simple::VERSION = '1.35';
+$DBIx::Simple::VERSION = '1.40';
$Carp::Internal{$_} = 1
for qw(DBIx::Simple DBIx::Simple::Result DBIx::Simple::DeadObject);
@@ -34,6 +34,14 @@
bless $hash2, $tempref;
}
+# Used by DBIx::Simple::Connector
+sub _clear_cache {
+ my $self = shift;
+ delete $statements{$self};
+ delete $old_statements{$self};
+}
+
+
### constructor
sub connect {
@@ -83,7 +91,7 @@
sub error {
my ($self) = @_;
- return 'DBI error: ' . (ref $self ? $self->{dbh}->errstr : $DBI::errstr);
+ return 'DBI error: ' . (ref $self ? $self->dbh->errstr : $DBI::errstr);
}
sub dbh { $_[0]->{dbh} }
@@ -121,7 +129,7 @@
unless ($self->{dont_disconnect}) {
# Conditional, because destruction order is not guaranteed
# during global destruction.
- $self->{dbh}->disconnect() if defined $self->{dbh};
+ $self->dbh->disconnect() if defined $self->dbh;
}
_swap(
@@ -150,7 +158,7 @@
$st = splice(@$old, $i, 1)->[1];
$sth = $st->{sth};
} else {
- eval { $sth = $self->{dbh}->prepare($query) } or do {
+ eval { $sth = $self->dbh->prepare($query) } or do {
if ($@) {
$@ =~ s/ at \S+ line \d+\.\n\z//;
Carp::croak($@);
@@ -184,11 +192,11 @@
return bless { st => $st, lc_columns => $self->{lc_columns} }, $self->{result_class};
}
-sub begin_work { $_[0]->{dbh}->begin_work }
+sub begin_work { $_[0]->dbh->begin_work }
sub begin { $_[0]->begin_work }
-sub commit { $_[0]->{dbh}->commit }
-sub rollback { $_[0]->{dbh}->rollback }
-sub func { shift->{dbh}->func(@_) }
+sub commit { $_[0]->dbh->commit }
+sub rollback { $_[0]->dbh->rollback }
+sub func { shift->dbh->func(@_) }
sub last_insert_id {
my ($self) = @_;
@@ -198,7 +206,7 @@
"--this is only $self->{dbi_version}, stopped"
);
- return shift->{dbh}->last_insert_id(@_);
+ return shift->dbh->last_insert_id(@_);
}
sub disconnect {
@@ -601,6 +609,11 @@
$result = $db->query(...)
+=head2 DBIx::Simple + DBIx::Connector
+
+ $db = DBIx::Simple::Connector->new($conn);
+ $db = DBIx::Simple::Connector->new($dsn,$username,$password,\%args);
+
=head2 DBIx::SImple + SQL::Interp
$result = $db->iquery(...)
@@ -1009,6 +1022,23 @@
=back
+=head2 DBIx::Simple::Connector
+
+L<DBIx::Simple::Connector> allows you to initialize DBIx::Simple with a
+L<DBIx::Connector> object instead of a direct database handle, and otherwise
+works the same. Benefits include helping you automatically re-connect to the
+database if the connection is dropped, and potentially avoiding re-checking if
+the database handle is working by issuing issuing a "ping" call before every
+query.
+
+Connecting to a database can be expensive; you don't want your application to
+re-connect every time you need to run a query. The efficient thing to do is to
+hang on to a database handle to maintain a connection to the database in order
+to minimize that overhead. DBIx::Connector lets you do that without having to
+worry about dropped or corrupted connections.
+
+See L<DBIx::Simple::Connector> and L<DBIx::Connector> for further details.
+
=head2 Object construction
DBIx::Simple has basic support for returning results as objects. The actual
diff -rN -u old-rt-9160-DBIx-Simple/t/sqlite.t new-rt-9160-DBIx-Simple/t/sqlite.t
--- old-rt-9160-DBIx-Simple/t/sqlite.t 2013-10-04 11:37:58.000000000 -0400
+++ new-rt-9160-DBIx-Simple/t/sqlite.t 2013-10-04 11:37:58.000000000 -0400
@@ -7,7 +7,6 @@
eval { DBD::SQLite->VERSION >= 1 }
or plan skip_all => 'DBD::SQLite >= 1.00 required';
- plan tests => 57;
use_ok('DBIx::Simple');
}
@@ -119,4 +118,34 @@
is_deeply(scalar $db->query($q)->objects('Mock', 42, 21), [ 1 ]); # wantarray true
}
+SKIP: {
+ eval { require DBIx::Connector } or skip "DBIx::Connector required", 1;
+ use DBIx::Simple::Connector;
+ {
+ my $dsc = DBIx::Simple::Connector->connect('dbi:SQLite:dbname=:memory:');
+ ok($dsc->query('CREATE TABLE connector_1 (FOO, bar, baz)'),
+ 'DBIx::Simple::Connector, with DSN');
+ $dsc->disconnect();
+ }
+ {
+ my $conn = DBIx::Connector->new('dbi:SQLite:dbname=:memory:');
+ my $dsc = DBIx::Simple::Connector->connect($conn);
+ ok($dsc->query('CREATE TABLE connector_1 (FOO, bar, baz)'),
+ 'DBIx::Simple::Connector, with existing DBIx::Connector object');
+
+ my $old_dbh = $dsc->dbh;
+
+ # Simulate a DB disconnection.
+ $conn->{_dbh} = undef;
+
+ ok($dsc->query('CREATE TABLE connector_1 (FOO, bar, baz)'),
+ 'DBIx::Simple::Connector, automatically reconnects');
+
+ isnt($old_dbh,$dsc->dbh, "The database handle was indeed updated.");
+ $dsc->disconnect();
+ }
+}
+
ok($db->disconnect);
+
+done_testing();