From: Peter Rabbitson Date: Thu, 4 Mar 2010 18:10:49 +0000 (+0000) Subject: Fix identity fiasco X-Git-Tag: v0.08121~87 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=dbsrgits%2FDBIx-Class.git;a=commitdiff_plain;h=cf85635700695fcf07a2383270c9c3d0ac1baa73 Fix identity fiasco --- diff --git a/Changes b/Changes index 33fdf83..cde661d 100644 --- a/Changes +++ b/Changes @@ -3,6 +3,7 @@ Revision history for DBIx::Class - Fix regression on not properly throwing when $obj->relationship is unresolvable - Add has_relationship method to row objects + - Fix regression in set_column on PK-less objects - Fix for SQLite to ignore the { for => ... } attribute 0.08120 2010-02-24 08:58:00 (UTC) diff --git a/lib/DBIx/Class/Row.pm b/lib/DBIx/Class/Row.pm index a397ceb..45cff9b 100644 --- a/lib/DBIx/Class/Row.pm +++ b/lib/DBIx/Class/Row.pm @@ -477,17 +477,18 @@ this method. sub update { my ($self, $upd) = @_; $self->throw_exception( "Not in database" ) unless $self->in_storage; - my $ident_cond = $self->ident_condition; - $self->throw_exception("Cannot safely update a row in a PK-less table") + + my $ident_cond = $self->{_orig_ident} || $self->ident_condition; + + $self->throw_exception('Unable to update a row with incomplete or no identity') if ! keys %$ident_cond; $self->set_inflated_columns($upd) if $upd; my %to_update = $self->get_dirty_columns; return $self unless keys %to_update; my $rows = $self->result_source->storage->update( - $self->result_source, \%to_update, - $self->{_orig_ident} || $ident_cond - ); + $self->result_source, \%to_update, $ident_cond + ); if ($rows == 0) { $self->throw_exception( "Can't update ${self}: row not found" ); } elsif ($rows > 1) { @@ -495,7 +496,7 @@ sub update { } $self->{_dirty_columns} = {}; $self->{related_resultsets} = {}; - undef $self->{_orig_ident}; + delete $self->{_orig_ident}; return $self; } @@ -544,17 +545,19 @@ sub delete { my $self = shift; if (ref $self) { $self->throw_exception( "Not in database" ) unless $self->in_storage; + my $ident_cond = $self->{_orig_ident} || $self->ident_condition; - $self->throw_exception("Cannot safely delete a row in a PK-less table") + $self->throw_exception('Unable to delete a row with incomplete or no identity') if ! keys %$ident_cond; - foreach my $column (keys %$ident_cond) { - $self->throw_exception("Can't delete the object unless it has loaded the primary keys") - unless exists $self->{_column_data}{$column}; - } + $self->result_source->storage->delete( - $self->result_source, $ident_cond); + $self->result_source, $ident_cond + ); + + delete $self->{_orig_ident}; $self->in_storage(undef); - } else { + } + else { $self->throw_exception("Can't do class delete without a ResultSource instance") unless $self->can('result_source_instance'); my $attrs = @_ > 1 && ref $_[$#_] eq 'HASH' ? { %{pop(@_)} } : {}; @@ -812,9 +815,10 @@ instead, see L. sub set_column { my ($self, $column, $new_value) = @_; - $self->{_orig_ident} ||= $self->ident_condition; - my $old_value = $self->get_column($column); + # if we can't get an ident condition on first try - mark the object as unidentifiable + $self->{_orig_ident} ||= (eval { $self->ident_condition }) || {}; + my $old_value = $self->get_column($column); $new_value = $self->store_column($column, $new_value); my $dirty; @@ -1297,7 +1301,12 @@ sub get_from_storage { $resultset = $resultset->search(undef, $attrs); } - return $resultset->find($self->{_orig_ident} || $self->ident_condition); + my $ident_cond = $self->{_orig_ident} || $self->ident_condition; + + $self->throw_exception('Unable to requery a row with incomplete or no identity') + if ! keys %$ident_cond; + + return $resultset->find($ident_cond); } =head2 discard_changes ($attrs) diff --git a/t/row/pkless.t b/t/row/pkless.t new file mode 100644 index 0000000..ac090de --- /dev/null +++ b/t/row/pkless.t @@ -0,0 +1,32 @@ +use strict; +use warnings; + +use Test::More; +use Test::Exception; + +use lib qw(t/lib); +use DBICTest; + +my $schema = DBICTest->init_schema(); + +my $rs = $schema->resultset('NoPrimaryKey'); + +my $row = $rs->create ({ foo => 1, bar => 1, baz => 1 }); + +lives_ok (sub { + $row->foo (2); +}, 'Set on pkless object works'); + +is ($row->foo, 2, 'Column updated in-object'); + +dies_ok (sub { + $row->update ({baz => 3}); +}, 'update() fails on pk-less object'); + +is ($row->foo, 2, 'Column not updated by failed update()'); + +dies_ok (sub { + $row->delete; +}, 'delete() fails on pk-less object'); + +done_testing;