Added documentation for from => $rs->as_query
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage / DBI / Replicated.pm
index 549bc76..259cdc5 100644 (file)
@@ -11,6 +11,7 @@ BEGIN {
     MooseX::AttributeHelpers => '0.12',
     MooseX::Types => '0.10',
     namespace::clean => '0.11',
+    Hash::Merge => '0.11'
   );
        
   my @didnt_load;
@@ -33,6 +34,7 @@ use DBIx::Class::Storage::DBI::Replicated::Types 'BalancerClassNamePart';
 use MooseX::Types::Moose qw/ClassName HashRef Object/;
 use Scalar::Util 'reftype';
 use Carp::Clan qw/^DBIx::Class/;
+use Hash::Merge 'merge';
 
 use namespace::clean -except => 'meta';
 
@@ -110,6 +112,7 @@ Replicated Storage has additional requirements not currently part of L<DBIx::Cla
   MooseX::AttributeHelpers => 0.12 
   MooseX::Types => 0.10
   namespace::clean => 0.11
+  Hash::Merge => 0.11
   
 You will need to install these modules manually via CPAN or make them part of the
 Makefile for your distribution.
@@ -139,9 +142,8 @@ to: L<DBIx::Class::Storage::DBI::Replicated::Pool>.
 =cut
 
 has 'pool_type' => (
-  is=>'ro',
+  is=>'rw',
   isa=>ClassName,
-  required=>1,
   default=>'DBIx::Class::Storage::DBI::Replicated::Pool',
   handles=>{
     'create_pool' => 'new',
@@ -156,10 +158,9 @@ See L<DBIx::Class::Storage::Replicated::Pool> for available arguments.
 =cut
 
 has 'pool_args' => (
-  is=>'ro',
+  is=>'rw',
   isa=>HashRef,
   lazy=>1,
-  required=>1,
   default=>sub { {} },
 );
 
@@ -172,7 +173,7 @@ choose how to spread the query load across each replicant in the pool.
 =cut
 
 has 'balancer_type' => (
-  is=>'ro',
+  is=>'rw',
   isa=>BalancerClassNamePart,
   coerce=>1,
   required=>1,
@@ -190,7 +191,7 @@ See L<DBIx::Class::Storage::Replicated::Balancer> for available arguments.
 =cut
 
 has 'balancer_args' => (
-  is=>'ro',
+  is=>'rw',
   isa=>HashRef,
   lazy=>1,
   required=>1,
@@ -223,7 +224,7 @@ is a class that takes a pool (<DBIx::Class::Storage::DBI::Replicated::Pool>)
 =cut
 
 has 'balancer' => (
-  is=>'ro',
+  is=>'rw',
   isa=>'DBIx::Class::Storage::DBI::Replicated::Balancer',
   lazy_build=>1,
   handles=>[qw/auto_validate_every/],
@@ -277,7 +278,6 @@ has 'write_handler' => (
   is=>'ro',
   isa=>Object,
   lazy_build=>1,
-  lazy_build=>1,
   handles=>[qw/   
     on_connect_do
     on_disconnect_do       
@@ -316,23 +316,62 @@ has _master_connect_info_opts =>
 =head2 around: connect_info
 
 Preserve master's C<connect_info> options (for merging with replicants.)
+Also set any Replicated related options from connect_info, such as
+C<pool_type>, C<pool_args>, C<balancer_type> and C<balancer_args>.
 
 =cut
 
 around connect_info => sub {
   my ($next, $self, $info, @extra) = @_;
 
+  my $wantarray = wantarray;
+
   my %opts;
   for my $arg (@$info) {
     next unless (reftype($arg)||'') eq 'HASH';
-    %opts = (%opts, %$arg);
+    %opts = %{ merge($arg, \%opts) };
   }
-
   delete $opts{dsn};
 
+  if (@opts{qw/pool_type pool_args/}) {
+    $self->pool_type(delete $opts{pool_type})
+      if $opts{pool_type};
+
+    $self->pool_args(
+      merge((delete $opts{pool_args} || {}), $self->pool_args)
+    );
+
+    $self->pool($self->_build_pool)
+       if $self->pool;
+  }
+
+  if (@opts{qw/balancer_type balancer_args/}) {
+    $self->balancer_type(delete $opts{balancer_type})
+      if $opts{balancer_type};
+
+    $self->balancer_args(
+      merge((delete $opts{balancer_args} || {}), $self->balancer_args)
+    );
+
+    $self->balancer($self->_build_balancer)
+       if $self->balancer;
+  }
+
   $self->_master_connect_info_opts(\%opts);
 
-  $self->$next($info, @extra);
+  my (@res, $res);
+  if ($wantarray) {
+    @res = $self->$next($info, @extra);
+  } else {
+    $res = $self->$next($info, @extra);
+  }
+
+  # May have to reapply role if master will be reblessed to a more specific
+  # driver.
+  $self->master->_determine_driver;
+  DBIx::Class::Storage::DBI::Replicated::WithDSN->meta->apply($self->master);
+
+  $wantarray ? @res : $res;
 };
 
 =head1 METHODS
@@ -365,7 +404,9 @@ Lazy builder for the L</master> attribute.
 
 sub _build_master {
   my $self = shift @_;
-  DBIx::Class::Storage::DBI->new($self->schema);
+  my $master = DBIx::Class::Storage::DBI->new($self->schema);
+  DBIx::Class::Storage::DBI::Replicated::WithDSN->meta->apply($master);
+  $master
 }
 
 =head2 _build_pool
@@ -442,11 +483,21 @@ around connect_replicants => sub {
     $r->[$i] = {} unless $r->[$i];
 
 # merge if two hashes
-    my %opts = map %$_, @$r[$i .. $#{$r}];
+    my @hashes = @$r[$i .. $#{$r}];
+
+    croak "invalid connect_info options"
+      if (grep { reftype($_) eq 'HASH' } @hashes) != @hashes;
+
+    croak "too many hashrefs in connect_info"
+      if @hashes > 2;
+
+    my %opts = %{ merge(reverse @hashes) };
+
+# delete them
     splice @$r, $i+1, ($#{$r} - $i), ();
 
 # merge with master
-    %opts = (%{ $self->_master_connect_info_opts }, %opts);
+    %opts = %{ merge(\%opts, $self->_master_connect_info_opts) };
 
 # update
     $r->[$i] = \%opts;