Anyway next patch: reset in_storage property in case row gone away
from db, test it also

On Sun, Apr 13, 2008 at 3:32 PM, Vladimir Timofeev <[EMAIL PROTECTED]> wrote:
> On Sun, Apr 13, 2008 at 5:15 AM, Jonathan Rockway <[EMAIL PROTECTED]> wrote:
>  > * On Sat, Apr 12 2008, Vladimir Timofeev wrote:
>  >
>  >  > +    my $hash_ref = $rs->find({
>  >
>  > > +        map { $_ => $self->get_column($_) } $self->primary_columns,
>  >  > +    }, $attrs);
>  >  > +
>  >  > +    $self->set_columns($hash_ref);
>  >  > +    delete $self->{_dirty_columns};
>  >
>  >  Is this the only way to do this?  There is an irritating race condition
>  >  where the record can go away between initially fetching it and then
>  >  refreshing it.  I don't know if much can be done about that (other than
>  >  caching the initial state in the row object), but it might be exception
>  >  worthy instead of the current code's strategy of just set_columns-ing
>  >  nothing (and then erasing the dirty bit).
>  May be simple set in_storage to false and don't touch any data?
>  Exception will thrown by near update method call.
>  Any suggestions?
>
>
>  >
>  >  Also, I object to a variable named $hash_ref :P
>  ;-) thanks, this should be renamed in next patch
>
>
>
>  >
>  >  Regards,
>  >  Jonathan Rockway
>  >
>  >  --
>  >  print just => another => perl => hacker => if $,=$"
>  >
>  >
>  >
>  >  _______________________________________________
>  >  List: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/dbix-class
>  >  IRC: irc.perl.org#dbix-class
>  >  SVN: http://dev.catalyst.perl.org/repos/bast/DBIx-Class/
>  >  Searchable Archive: http://www.grokbase.com/group/[EMAIL PROTECTED]
>  >
>
Index: t/reload_columns.t
===================================================================
--- t/reload_columns.t	(revision 0)
+++ t/reload_columns.t	(revision 0)
@@ -0,0 +1,48 @@
+use strict;
+use warnings;  
+
+use Test::More;
+use lib qw(t/lib);
+use DBICTest;
+
+plan tests => 8;
+
+my $schema = DBICTest->init_schema();
+
+$schema->class('CD')->mk_group_accessors(simple => qw/external_data/);
+Class::C3->reinitialize;
+
+my $cd = $schema->resultset("CD")->find(3);
+my $orig_title = $cd->title;
+$cd->title('some strange other title');
+$cd->reload_columns;
+is( $cd->title, $orig_title, 'reload_columns should refresh data from db');
+
+# what if object removed from db while we holding it?
+$cd = $schema->resultset("CD")->find(3);
+$schema->resultset("CD")->find(3)->delete;
+ok( $cd->in_storage, 'we think object in storage, but it is deleted');
+$cd->title('some strange other title');
+$cd->reload_columns;
+is( $cd->title, 'some strange other title', 'in that case our columns data should not be touched');
+ok( ! $cd->in_storage, 'now in_storage false');
+
+$schema = DBICTest->init_schema();
+
+# external accessors test
+$cd = $schema->resultset("CD")->find(3);
+$cd->external_data('some value');
+is( $cd->external_data, 'some value', 'custom created accessor can store data');
+$cd->reload_columns;
+is( $cd->external_data, 'some value', 'reload_columns should not touch custom accessors');
+
+# attrs test (we need eval, because sqlite dosn't support FOR UPDATE syntax)
+my @storage_trace = ();
+$schema->storage->debugcb(sub { push @storage_trace, { op => $_[0], info => $_[1] } });
+$schema->storage->debug(1);
+
+$cd = $schema->resultset("CD")->find(3);
+eval { $cd->reload_columns({for => 'update'}) };
+
+is( scalar(@storage_trace), 2, 'we got debug trace info for both statements');
+like( $storage_trace[1]->{info}, qr/FOR UPDATE/, 'reload_columns process attrs');
Index: lib/DBIx/Class/PK.pm
===================================================================
--- lib/DBIx/Class/PK.pm	(revision 4271)
+++ lib/DBIx/Class/PK.pm	(working copy)
@@ -2,6 +2,7 @@
 
 use strict;
 use warnings;
+use DBIx::Class::ResultClass::HashRefInflator;
 
 use base qw/DBIx::Class::Row/;
 
@@ -57,6 +58,36 @@
   return $self;
 }
 
+=head2 reload_columns
+
+    $row->reload_columns(\%attrs?)
+
+Reloads from storage. Reset in_storage property in case row was removed from db.
+
+It's using HashRefInflator to load columns for fast.
+
+=cut
+
+sub reload_columns {
+    my ($self, $attrs) = @_;
+    return unless $self->in_storage;
+
+    my $rs = $self->result_source->resultset;
+    $rs->result_class('DBIx::Class::ResultClass::HashRefInflator');
+
+    my $column_data = $rs->find({
+        map { $_ => $self->get_column($_) } $self->primary_columns,
+    }, $attrs);
+    
+    unless ($column_data) {
+        $self->in_storage(0);
+        return;
+    }
+
+    $self->set_columns($column_data);
+    delete $self->{_dirty_columns};
+}
+
 =head2 id
 
 Returns the primary key(s) for a row. Can't be called as
Index: lib/DBIx/Class/Row.pm
===================================================================
--- lib/DBIx/Class/Row.pm	(revision 4271)
+++ lib/DBIx/Class/Row.pm	(working copy)
@@ -798,6 +798,14 @@
 changes made since the row was last read from storage. Actually
 implemented in L<DBIx::Class::PK>
 
+=head2 reload_columns
+
+    $row->reload_columns(\%attrs?)
+
+Reloads from storage. Reset in_storage property in case row was removed from db.
+
+Actually in L<DBIx::Class::PK>
+
 =cut
 
 1;
_______________________________________________
List: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/dbix-class
IRC: irc.perl.org#dbix-class
SVN: http://dev.catalyst.perl.org/repos/bast/DBIx-Class/
Searchable Archive: http://www.grokbase.com/group/[EMAIL PROTECTED]

Reply via email to