fixed boneheaded failure to properly propogate txn_do
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage / DBI / Replicated.pm
index 3bfbf60..a21c413 100644 (file)
@@ -230,6 +230,7 @@ has 'write_handler' => (
         sth
         deploy
         schema
+        reload_row
     /],
 );
 
@@ -374,6 +375,72 @@ sub all_storages {
        );
 }
 
+=head2 execute_reliably ($coderef, ?@args)
+
+Given a coderef, saves the current state of the L</read_handler>, forces it to
+use reliable storage (ie sets it to the master), executes a coderef and then
+restores the original state.
+
+Example:
+
+    my $reliably = sub {
+        my $name = shift @_;
+        $schema->resultset('User')->create({name=>$name});
+        my $user_rs = $schema->resultset('User')->find({name=>$name}); 
+        return $user_rs;
+    };
+
+    my $user_rs = $schema->storage->execute_reliably($reliably, 'John');
+
+Use this when you must be certain of your database state, such as when you just
+inserted something and need to get a resultset including it, etc.
+
+=cut
+
+sub execute_reliably {
+    my ($self, $coderef, @args) = @_;
+       
+    unless( ref $coderef eq 'CODE') {
+        $self->throw_exception('Second argument must be a coderef');
+    }
+
+    ##Get copy of master storage
+    my $master = $self->master;
+    
+    ##Get whatever the current read hander is
+    my $current = $self->read_handler;
+    
+    ##Set the read handler to master
+    $self->read_handler($master);
+    
+    ## do whatever the caller needs
+    my @result;
+    my $want_array = wantarray;
+    
+    eval {
+           if($want_array) {
+               @result = $coderef->(@args);
+           }
+           elsif(defined $want_array) {
+               ($result[0]) = ($coderef->(@args));
+           } else {
+               $coderef->(@args);
+           }           
+    };
+    
+    ##Reset to the original state
+    $self->read_handler($current); 
+    
+    ##Exception testing has to come last, otherwise you might leave the 
+    ##read_handler set to master.
+    
+    if($@) {
+        $self->throw_exception("coderef returned an error: $@");
+    } else {
+       return $want_array ? @result : $result[0];
+    }
+}
+
 =head2 set_reliable_storage
 
 Sets the current $schema to be 'reliable', that is all queries, both read and
@@ -404,6 +471,33 @@ sub set_balanced_storage {
     $schema->storage->read_handler($write_handler);
 }
 
+=head2 around: txn_do ($coderef)
+
+Overload to the txn_do method, which is delegated to whatever the
+L<write_handler> is set to.  We overload this in order to wrap in inside a
+L</execute_reliably> method.
+
+=cut
+
+around 'txn_do' => sub {
+    my($txn_do, $self, $coderef, @args) = @_;
+    $self->execute_reliably(sub {$self->$txn_do($coderef, @args)});    
+};
+
+=head2 reload_row ($row)
+
+Overload to the reload_row method so that the reloading is always directed to
+the master storage.
+
+=cut
+
+around 'reload_row' => sub {
+       my ($reload_row, $self, $row) = @_;
+       return $self->execute_reliably(sub {
+               return $self->$reload_row(shift);
+       }, $row);
+};
+
 =head2 connected
 
 Check that the master and at least one of the replicants is connected.
@@ -550,11 +644,12 @@ sub disconnect {
 
 =head1 AUTHOR
 
-Norbert Csongrádi <bert@cpan.org>
+    John Napiorkowski <john.napiorkowski@takkle.com>
 
-Peter Siklósi <einon@einon.hu>
+Based on code originated by:
 
-John Napiorkowski <john.napiorkowski@takkle.com>
+    Norbert Csongrádi <bert@cpan.org>
+    Peter Siklósi <einon@einon.hu>
 
 =head1 LICENSE