X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FRow.pm;h=158c215d9aed0cf198c0ba52926afc3eb469927e;hb=bbd107cf7ae1e53547ce63b710716d88adb73013;hp=de61ac0e73db7a1a00a38963c760acc73b7e1cb2;hpb=b6d347e0d659aa1d4262b07d0930a449a2ff1862;p=dbsrgits%2FDBIx-Class.git diff --git a/lib/DBIx/Class/Row.pm b/lib/DBIx/Class/Row.pm index de61ac0..158c215 100644 --- a/lib/DBIx/Class/Row.pm +++ b/lib/DBIx/Class/Row.pm @@ -787,7 +787,10 @@ sub set_column { $self->store_column($column, $new_value); my $dirty; - if (defined $old_value xor defined $new_value) { + if (!$self->in_storage) { # no point tracking dirtyness on uninserted data + $dirty = 1; + } + elsif (defined $old_value xor defined $new_value) { $dirty = 1; } elsif (not defined $old_value) { # both undef @@ -799,8 +802,8 @@ sub set_column { else { # do a numeric comparison if datatype allows it my $colinfo = $self->column_info ($column); - # cache for speed - if (not defined $colinfo->{is_numeric}) { + # cache for speed (the object may *not* have a resultsource instance) + if (not defined $colinfo->{is_numeric} && $self->_source_handle) { $colinfo->{is_numeric} = $self->result_source->schema->storage->is_datatype_numeric ($colinfo->{data_type}) ? 1 @@ -1050,7 +1053,6 @@ sub inflate_result { my $new = { _source_handle => $source_handle, _column_data => $me, - _in_storage => 1 }; bless $new, (ref $class || $class); @@ -1062,14 +1064,25 @@ sub inflate_result { unless $pre_source; if (ref($pre_val->[0]) eq 'ARRAY') { # multi my @pre_objects; - foreach my $pre_rec (@$pre_val) { - unless ($pre_source->primary_columns == grep { exists $pre_rec->[0]{$_} - and defined $pre_rec->[0]{$_} } $pre_source->primary_columns) { - next; + + for my $me_pref (@$pre_val) { + + # the collapser currently *could* return bogus elements with all + # columns set to undef + my $has_def; + for (values %{$me_pref->[0]}) { + if (defined $_) { + $has_def++; + last; + } } - push(@pre_objects, $pre_source->result_class->inflate_result( - $pre_source, @{$pre_rec})); + next unless $has_def; + + push @pre_objects, $pre_source->result_class->inflate_result( + $pre_source, @$me_pref + ); } + $new->related_resultset($pre)->set_cache(\@pre_objects); } elsif (defined $pre_val->[0]) { my $fetched; @@ -1087,11 +1100,13 @@ sub inflate_result { } elsif ($accessor eq 'filter') { $new->{_inflated_column}{$pre} = $fetched; } else { - $class->throw_exception("Prefetch not supported with accessor '$accessor'"); + $class->throw_exception("Implicit prefetch (via select/columns) not supported with accessor '$accessor'"); } $new->related_resultset($pre)->set_cache([ $fetched ]); } } + + $new->in_storage (1); return $new; } @@ -1262,12 +1277,51 @@ sub get_from_storage { my $resultset = $self->result_source->resultset; if(defined $attrs) { - $resultset = $resultset->search(undef, $attrs); + $resultset = $resultset->search(undef, $attrs); } return $resultset->find($self->{_orig_ident} || $self->ident_condition); } +=head2 discard_changes ($attrs) + +Re-selects the row from the database, losing any changes that had +been made. + +This method can also be used to refresh from storage, retrieving any +changes made since the row was last read from storage. + +$attrs is expected to be a hashref of attributes suitable for passing as the +second argument to $resultset->search($cond, $attrs); + +=cut + +sub discard_changes { + my ($self, $attrs) = @_; + delete $self->{_dirty_columns}; + return unless $self->in_storage; # Don't reload if we aren't real! + + # add a replication default to read from the master only + $attrs = { force_pool => 'master', %{$attrs||{}} }; + + if( my $current_storage = $self->get_from_storage($attrs)) { + + # Set $self to the current. + %$self = %$current_storage; + + # Avoid a possible infinite loop with + # sub DESTROY { $_[0]->discard_changes } + bless $current_storage, 'Do::Not::Exist'; + + return $self; + } + else { + $self->in_storage(0); + return $self; + } +} + + =head2 throw_exception See L. @@ -1317,6 +1371,13 @@ This method can also be used to refresh from storage, retrieving any changes made since the row was last read from storage. Actually implemented in L +Note: If you are using L as your +storage, please kept in mind that if you L on a row that you +just updated or created, you should wrap the entire bit inside a transaction. +Otherwise you run the risk that you insert or update to the master database +but read from a replicant database that has not yet been updated from the +master. This will result in unexpected results. + =cut 1;