X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FRow.pm;h=ac12eadbbfbf6fe23c20db208fc10ef6d7ca4a56;hb=72c2540d9f7d45625853abc5d1782020fedc3887;hp=6685ad9df4268507b251f7fda95fe7a85be758b1;hpb=eed5492fecb339252aaad11adb22651e5bd06d7b;p=dbsrgits%2FDBIx-Class.git diff --git a/lib/DBIx/Class/Row.pm b/lib/DBIx/Class/Row.pm index 6685ad9..ac12ead 100644 --- a/lib/DBIx/Class/Row.pm +++ b/lib/DBIx/Class/Row.pm @@ -22,6 +22,8 @@ BEGIN { use namespace::clean; +__PACKAGE__->mk_group_accessors ( simple => [ in_storage => '_in_storage' ] ); + =head1 NAME DBIx::Class::Row - Basic row methods @@ -122,13 +124,13 @@ with NULL as the default, and save yourself a SELECT. ## tests! sub __new_related_find_or_new_helper { - my ($self, $relname, $data) = @_; + my ($self, $relname, $values) = @_; my $rsrc = $self->result_source; # create a mock-object so all new/set_column component overrides will run: my $rel_rs = $rsrc->related_source($relname)->resultset; - my $new_rel_obj = $rel_rs->new_result($data); + my $new_rel_obj = $rel_rs->new_result($values); my $proc_data = { $new_rel_obj->get_columns }; if ($self->__their_pk_needs_us($relname)) { @@ -160,9 +162,9 @@ sub __new_related_find_or_new_helper { sub __their_pk_needs_us { # this should maybe be in resultsource. my ($self, $relname) = @_; - my $source = $self->result_source; - my $reverse = $source->reverse_relationship_info($relname); - my $rel_source = $source->related_source($relname); + my $rsrc = $self->result_source; + my $reverse = $rsrc->reverse_relationship_info($relname); + my $rel_source = $rsrc->related_source($relname); my $us = { $self->get_columns }; foreach my $key (keys %$reverse) { # if their primary key depends on us, then we have to @@ -176,18 +178,18 @@ sub new { my ($class, $attrs) = @_; $class = ref $class if ref $class; - my $new = bless { _column_data => {} }, $class; + my $new = bless { _column_data => {}, _in_storage => 0 }, $class; if ($attrs) { $new->throw_exception("attrs must be a hashref") unless ref($attrs) eq 'HASH'; - my $source = delete $attrs->{-result_source}; + my $rsrc = delete $attrs->{-result_source}; if ( my $h = delete $attrs->{-source_handle} ) { - $source ||= $h->resolve; + $rsrc ||= $h->resolve; } - $new->result_source($source) if $source; + $new->result_source($rsrc) if $rsrc; if (my $col_from_rel = delete $attrs->{-cols_from_relations}) { @{$new->{_ignore_at_insert}={}}{@$col_from_rel} = (); @@ -199,8 +201,8 @@ sub new { if (ref $attrs->{$key}) { ## Can we extract this lot to use with update(_or .. ) ? $new->throw_exception("Can't do multi-create without result source") - unless $source; - my $info = $source->relationship_info($key); + unless $rsrc; + my $info = $rsrc->relationship_info($key); my $acc_type = $info->{attrs}{accessor} || ''; if ($acc_type eq 'single') { my $rel_obj = delete $attrs->{$key}; @@ -334,11 +336,11 @@ one, see L for more details. sub insert { my ($self) = @_; return $self if $self->in_storage; - my $source = $self->result_source; + my $rsrc = $self->result_source; $self->throw_exception("No result_source set on this object; can't insert") - unless $source; + unless $rsrc; - my $storage = $source->storage; + my $storage = $rsrc->storage; my $rollback_guard; @@ -354,7 +356,7 @@ sub insert { if (! $self->{_rel_in_storage}{$relname}) { next unless (blessed $rel_obj && $rel_obj->isa('DBIx::Class::Row')); - next unless $source->_pk_depends_on( + next unless $rsrc->_pk_depends_on( $relname, { $rel_obj->get_columns } ); @@ -400,7 +402,7 @@ sub insert { # (autoinc primary columns and any retrieve_on_insert columns) my %current_rowdata = $self->get_columns; my $returned_cols = $storage->insert( - $source, + $rsrc, { %current_rowdata }, # what to insert, copy because the storage *will* change it ); @@ -424,7 +426,7 @@ sub insert { $self->{related_resultsets} = {}; foreach my $relname (keys %related_stuff) { - next unless $source->has_relationship ($relname); + next unless $rsrc->has_relationship ($relname); my @cands = ref $related_stuff{$relname} eq 'ARRAY' ? @{$related_stuff{$relname}} @@ -433,7 +435,7 @@ sub insert { if (@cands && blessed $cands[0] && $cands[0]->isa('DBIx::Class::Row') ) { - my $reverse = $source->reverse_relationship_info($relname); + my $reverse = $rsrc->reverse_relationship_info($relname); foreach my $obj (@cands) { $obj->set_from_related($_, $self) for keys %$reverse; if ($self->__their_pk_needs_us($relname)) { @@ -480,13 +482,6 @@ are used. Creating a result object using L, or calling L on one, sets it to false. -=cut - -sub in_storage { - my ($self, $val) = @_; - $self->{_in_storage} = $val if @_ > 1; - return $self->{_in_storage} ? 1 : 0; -} =head2 update @@ -619,7 +614,7 @@ sub delete { ); delete $self->{_column_data_in_storage}; - $self->in_storage(undef); + $self->in_storage(0); } else { my $rsrc = try { $self->result_source_instance } @@ -773,6 +768,7 @@ Marks a column as having been changed regardless of whether it has really changed. =cut + sub make_column_dirty { my ($self, $column) = @_; @@ -905,20 +901,20 @@ sub set_column { # # FIXME - this is a quick *largely incorrect* hack, pending a more # serious rework during the merge of single and filter rels - my $rels = $self->result_source->{_relationships}; - for my $rel (keys %$rels) { + my $relnames = $self->result_source->{_relationships}; + for my $relname (keys %$relnames) { - my $acc = $rels->{$rel}{attrs}{accessor} || ''; + my $acc = $relnames->{$relname}{attrs}{accessor} || ''; - if ( $acc eq 'single' and $rels->{$rel}{attrs}{fk_columns}{$column} ) { - delete $self->{related_resultsets}{$rel}; - delete $self->{_relationship_data}{$rel}; - #delete $self->{_inflated_column}{$rel}; + if ( $acc eq 'single' and $relnames->{$relname}{attrs}{fk_columns}{$column} ) { + delete $self->{related_resultsets}{$relname}; + delete $self->{_relationship_data}{$relname}; + #delete $self->{_inflated_column}{$relname}; } - elsif ( $acc eq 'filter' and $rel eq $column) { - delete $self->{related_resultsets}{$rel}; - #delete $self->{_relationship_data}{$rel}; - delete $self->{_inflated_column}{$rel}; + elsif ( $acc eq 'filter' and $relname eq $column) { + delete $self->{related_resultsets}{$relname}; + #delete $self->{_relationship_data}{$relname}; + delete $self->{_inflated_column}{$relname}; } } @@ -987,10 +983,8 @@ Works as L. =cut sub set_columns { - my ($self,$data) = @_; - foreach my $col (keys %$data) { - $self->set_column($col,$data->{$col}); - } + my ($self, $values) = @_; + $self->set_column( $_, $values->{$_} ) for keys %$values; return $self; } @@ -1034,9 +1028,9 @@ sub set_inflated_columns { my $info = $self->relationship_info($key); my $acc_type = $info->{attrs}{accessor} || ''; if ($acc_type eq 'single') { - my $rel = delete $upd->{$key}; - $self->set_from_related($key => $rel); - $self->{_relationship_data}{$key} = $rel; + my $rel_obj = delete $upd->{$key}; + $self->set_from_related($key => $rel_obj); + $self->{_relationship_data}{$key} = $rel_obj; } elsif ($acc_type eq 'multi') { $self->throw_exception( @@ -1099,19 +1093,19 @@ sub copy { # Its possible we'll have 2 relations to the same Source. We need to make # sure we don't try to insert the same row twice else we'll violate unique # constraints - my $rels_copied = {}; + my $relnames_copied = {}; - foreach my $rel ($self->result_source->relationships) { - my $rel_info = $self->result_source->relationship_info($rel); + foreach my $relname ($self->result_source->relationships) { + my $rel_info = $self->result_source->relationship_info($relname); next unless $rel_info->{attrs}{cascade_copy}; my $resolved = $self->result_source->_resolve_condition( - $rel_info->{cond}, $rel, $new, $rel + $rel_info->{cond}, $relname, $new, $relname ); - my $copied = $rels_copied->{ $rel_info->{source} } ||= {}; - foreach my $related ($self->search_related($rel)) { + my $copied = $relnames_copied->{ $rel_info->{source} } ||= {}; + foreach my $related ($self->search_related($relname)) { my $id_str = join("\0", $related->id); next if $copied->{$id_str}; $copied->{$id_str} = 1; @@ -1179,78 +1173,58 @@ L, see L. =cut sub inflate_result { - my ($class, $source, $me, $prefetch) = @_; - - $source = $source->resolve - if $source->isa('DBIx::Class::ResultSourceHandle'); + my ($class, $rsrc, $me, $prefetch) = @_; my $new = bless - { _column_data => $me, _result_source => $source }, + { _column_data => $me, _result_source => $rsrc }, ref $class || $class ; - foreach my $pre (keys %{$prefetch||{}}) { - - my (@pre_vals, $is_multi); - if (ref $prefetch->{$pre}[0] eq 'ARRAY') { - $is_multi = 1; - @pre_vals = @{$prefetch->{$pre}}; - } - else { - @pre_vals = $prefetch->{$pre}; - } - - my $pre_source = try { - $source->related_source($pre) - } - catch { - $class->throw_exception(sprintf + if ($prefetch) { + for my $relname ( keys %$prefetch ) { - "Can't inflate manual prefetch into non-existent relationship '%s' from '%s', " - . "check the inflation specification (columns/as) ending in '%s.%s'.", + my @rel_objects; + if ( + $prefetch->{$relname} + and + @{$prefetch->{$relname}} + and + ref($prefetch->{$relname}) ne $DBIx::Class::ResultSource::RowParser::Util::null_branch_class + ) { + my $rel_rsrc = try { + $rsrc->related_source($relname) + } catch { + my $err = sprintf + "Inflation into non-existent relationship '%s' of '%s' requested", + $relname, + $rsrc->source_name, + ; + if (my ($colname) = sort { length($a) <=> length ($b) } keys %{$prefetch->{$relname}[0] || {}} ) { + $err .= sprintf ", check the inflation specification (columns/as) ending in '...%s.%s'", + $relname, + $colname, + } - $pre, - $source->source_name, - $pre, - (keys %{$pre_vals[0][0]})[0] || 'something.something...', - ); - }; + $rsrc->throw_exception($err); + }; - my $accessor = $source->relationship_info($pre)->{attrs}{accessor} - or $class->throw_exception("No accessor type declared for prefetched $pre"); + @rel_objects = map { + $rel_rsrc->result_class->inflate_result( $rel_rsrc, @$_ ) + } ( ref $prefetch->{$relname}[0] eq 'ARRAY' ? @{$prefetch->{$relname}} : $prefetch->{$relname} ); + } - if (! $is_multi and $accessor eq 'multi') { - $class->throw_exception("Manual prefetch (via select/columns) not supported with accessor 'multi'"); - } + my $accessor = $rsrc->relationship_info($relname)->{attrs}{accessor} + or $class->throw_exception("No accessor type declared for prefetched relationship '$relname'"); - my @pre_objects; - for my $me_pref (@pre_vals) { - - # FIXME - this should not be necessary - # 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; - } - } - next unless $has_def; - - push @pre_objects, $pre_source->result_class->inflate_result( - $pre_source, @$me_pref - ); - } + if ($accessor eq 'single') { + $new->{_relationship_data}{$relname} = $rel_objects[0]; + } + elsif ($accessor eq 'filter') { + $new->{_inflated_column}{$relname} = $rel_objects[0]; + } - if ($accessor eq 'single') { - $new->{_relationship_data}{$pre} = $pre_objects[0]; - } - elsif ($accessor eq 'filter') { - $new->{_inflated_column}{$pre} = $pre_objects[0]; + $new->related_resultset($relname)->set_cache(\@rel_objects); } - - $new->related_resultset($pre)->set_cache(\@pre_objects); } $new->in_storage (1);