first failing test
Rafael Kitover [Mon, 28 Feb 2011 04:31:49 +0000 (23:31 -0500)]
lib/DBIx/Class/Optional/Dependencies.pm
lib/DBIx/Class/Storage/DBI/POE/EasyDBI.pm [new file with mode: 0644]
t/storage/poe_easydbi.t [new file with mode: 0644]

index 6f7c10d..185aca5 100644 (file)
@@ -24,6 +24,11 @@ my $replicated = {
   %$moose_basic,
 };
 
+my $poe_easydbi = {
+  'POE'                           => '0',
+  'POE::Component::EasyDBI'       => '0',
+};
+
 my $admin_basic = {
   %$moose_basic,
   %$json_any,
@@ -94,6 +99,19 @@ my $reqs = {
     },
   },
 
+  poe_easydbi => {
+    req => $poe_easydbi,
+    pod => {
+      title => 'Storage::DBI::POE::EasyDBI',
+      desc => 'Modules required for L<DBIx::Class::Storage::DBI::POE::EasyDBI>',
+    },
+  },
+
+  test_poe_easydbi => {
+    req => {
+      %$poe_easydbi,
+    },
+  },
 
   admin => {
     req => {
diff --git a/lib/DBIx/Class/Storage/DBI/POE/EasyDBI.pm b/lib/DBIx/Class/Storage/DBI/POE/EasyDBI.pm
new file mode 100644 (file)
index 0000000..ebf4b31
--- /dev/null
@@ -0,0 +1,102 @@
+package DBIx::Class::Storage::DBI::POE::EasyDBI;
+
+BEGIN {
+  use Carp::Clan qw/^DBIx::Class/;
+  use DBIx::Class;
+  croak('The following modules are required for Replication ' . DBIx::Class::Optional::Dependencies->req_missing_for ('poe_easydbi') )
+    unless DBIx::Class::Optional::Dependencies->req_ok_for ('poe_easydbi');
+}
+
+use strict;
+use warnings;
+use base qw/DBIx::Class::Storage::DBI/;
+use mro 'c3';
+use Carp::Clan qw/^DBIx::Class|^Try::Tiny/;
+use Sub::Name;
+use POE;
+use POE::Component::EasyDBI;
+use namespace::clean;
+
+__PACKAGE__->mk_group_accessors(simple => qw/
+  _normal_storage
+/);
+
+my @proxy_to_normal_storage = qw/
+  sql_maker_class sql_limit_dialect sql_quote_char sql_name_sep
+/;
+
+=head1 NAME
+
+DBIx::Class::Storage::DBI::POE::EasyDBI - Asynchronous Storage Driver Using
+L<POE::Component::EasyDBI>
+
+=head1 SYNOPSIS
+
+  my $schema = Schema::Class->clone;
+  $schema->storage_type('::DBI::POE::EasyDBI');
+  $schema->connection(...);
+
+=head1 DESCRIPTION
+
+This is a L<DBIx::Class> storage driver for asynchronous applications using
+L<POE::Component::EasyDBI>.
+
+It can be used with L<POE> or any other asynchronous framework that has a L<POE>
+adaptor or L<POE::Loop> for it. For L<AnyEvent>, for example, you can use
+L<AnyEvent::Impl::POE>.
+
+=head1 CAVEATS
+
+=head2 reentrancy
+
+The mechanism of supporting a synchronous API in an asynchronous system is
+similar to that used by L<LWP::UserAgent::POE>. It is reentrant, however, the
+most recent request must finish before ones already being waited on will
+complete (the rest of the application, that does not depend on L<DBIx::Class>
+still runs.) To keep your app responsive, I recommend avoiding long-running
+queries.
+
+=head2 transactions
+
+Transactions are not currently supported at all.
+
+=cut
+
+# make a normal storage for proxying some methods
+sub connect_info {
+  my $self = shift;
+  my ($info) = @_;
+
+  my $storage = DBIx::Class::Storage::DBI->new;
+  $storage->connect_info($info);
+  $storage->_determine_driver;
+
+  $self->_normal_storage($storage);
+
+  return $self->next::method(@_);
+}
+
+for my $method (@proxy_to_normal_storage) {
+  no strict 'refs';
+  no warnings 'redefine';
+
+  my $replaced = __PACKAGE__->can($method);
+
+  *{$method} = subname $method => sub {
+    my $self = shift;
+    return $self->_normal_storage->$replaced(@_);
+  };
+}
+
+1;
+
+=head1 AUTHOR
+
+See L<DBIx::Class/AUTHOR> and L<DBIx::Class/CONTRIBUTORS>.
+
+=head1 LICENSE
+
+You may distribute this code under the same terms as Perl itself.
+
+=cut
+# vim:sw=2 sts=2:
diff --git a/t/storage/poe_easydbi.t b/t/storage/poe_easydbi.t
new file mode 100644 (file)
index 0000000..4215252
--- /dev/null
@@ -0,0 +1,60 @@
+use strict;
+use warnings;
+
+use Test::More;
+use Test::Exception;
+
+BEGIN {
+  require DBIx::Class;
+  plan skip_all => 'Test needs ' . DBIx::Class::Optional::Dependencies->req_missing_for ('test_poe_easydbi')
+    unless DBIx::Class::Optional::Dependencies->req_ok_for ('test_poe_easydbi');
+}
+
+use lib qw(t/lib);
+use DBICTest;
+use POE;
+
+my $artist_num = -3;
+
+POE::Session->create(
+  inline_states => {
+    _start => sub {
+      $_[HEAP]{schema} = DBICTest->init_schema(
+        no_populate  => 1,
+        storage_type => '::DBI::POE::EasyDBI',
+      );
+      $_[KERNEL]->yield('do_creates');
+      $_[KERNEL]->yield('do_creates');
+    },
+    do_creates => sub {
+      my $ars = $_[HEAP]{schema}->resultset('Artist');
+
+      $artist_num += 3;
+
+      my $i = $artist_num;
+
+      $ars->create({ name => "Artist ".($i++) });
+      $ars->create({ name => "Artist ".($i++) });
+      $ars->create({ name => "Artist ".($i++) });
+
+      $_[KERNEL]->yield('creates_done');
+    },
+    creates_done => sub {
+      my $ars = $_[HEAP]{schema}->resultset('Artist');
+
+      return unless $ars->count == 6 && (not $_[HEAP]{creates_done_ran});
+
+      my $seq = join ',', map /(\d+)/, map $_->name, $ars->all;
+
+      isnt $seq, '0,1,2,3,4,5', 'records were not inserted synchronously';
+
+      $_[HEAP]{creates_done_ran} = 1;
+    },
+  },
+);
+
+$poe_kernel->run;
+
+done_testing;
+
+# vim:sw=2 sts=2: