From: Peter Rabbitson Date: Mon, 11 Feb 2013 11:19:49 +0000 (+0100) Subject: And another collapser issue X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=a0726a33e1c8a66e531a021ffcc2b208afe2a3c8;p=dbsrgits%2FDBIx-Class-Historic.git And another collapser issue One can not infer definedness from the presence of a parent *unless* we have a 'belongs_to'-like relationship to that parent --- diff --git a/lib/DBIx/Class/ResultSource/RowParser.pm b/lib/DBIx/Class/ResultSource/RowParser.pm index cc4706c..d4b75f2 100644 --- a/lib/DBIx/Class/ResultSource/RowParser.pm +++ b/lib/DBIx/Class/ResultSource/RowParser.pm @@ -199,13 +199,14 @@ sub _resolve_collapse { } } - # if the parent is already defined, assume all of its related FKs are selected + # if the parent is already defined *AND* we have an inner reverse relationship + # (i.e. do not exist without it) , assume all of its related FKs are selected # (even if they in fact are NOT in the select list). Keep a record of what we # assumed, and if any such phantom-column becomes part of our own collapser, # throw everything assumed-from-parent away and replace with the collapser of # the parent (whatever it may be) my $assumed_from_parent; - unless ($args->{_parent_info}{underdefined}) { + if ( ! $args->{_parent_info}{underdefined} and ! $args->{_parent_info}{rev_rel_is_optional} ) { for my $col ( values %{$args->{_parent_info}{rel_condition} || {}} ) { next if exists $my_cols->{$col}; $my_cols->{$col} = { via_collapse => $args->{_parent_info}{collapse_on_idcols} }; @@ -228,7 +229,6 @@ sub _resolve_collapse { if $args->{_parent_info}{collapser_reusable}; } - # Still dont know how to collapse - try to resolve based on our columns (plus already inserted FK bridges) if ( ! $collapse_map->{-identifying_columns} @@ -381,8 +381,10 @@ sub _resolve_collapse { # If we got that far - we are collapsable - GREAT! Now go down all children # a second time, and fill in the rest - $collapse_map->{-is_optional} = 1 if $args->{_parent_info}{is_optional}; - + $collapse_map->{-identifying_columns} = [ __unique_numlist( + @{ $args->{_parent_info}{collapse_on_idcols}||[] }, + @{ $collapse_map->{-identifying_columns} }, + )]; my @id_sets; for my $rel (sort keys %$relinfo) { @@ -396,7 +398,14 @@ sub _resolve_collapse { rel_condition => $relinfo->{$rel}{fk_map}, - is_optional => $collapse_map->{-is_optional}, + is_optional => ! $relinfo->{$rel}{is_inner}, + + # if there is at least one *inner* reverse relationship which is HASH-based (equality only) + # we can safely assume that the child can not exist without us + rev_rel_is_optional => ( first + { ref $_->{cond} eq 'HASH' and ($_->{attrs}{join_type}||'') !~ /^left/i } + values %{ $self->reverse_relationship_info($rel) }, + ) ? 0 : 1, # if this is a 1:1 our own collapser can be used as a collapse-map # (regardless of left or not) diff --git a/lib/DBIx/Class/Row.pm b/lib/DBIx/Class/Row.pm index a17c3f7..3a4dda1 100644 --- a/lib/DBIx/Class/Row.pm +++ b/lib/DBIx/Class/Row.pm @@ -1187,7 +1187,7 @@ sub inflate_result { my @pre_vals; @pre_vals = (ref $prefetch->{$pre}[0] eq 'ARRAY') ? @{$prefetch->{$pre}} : $prefetch->{$pre} - if @{$prefetch->{$pre}}; + if @{$prefetch->{$pre}||[]}; my $pre_source = $source->related_source($pre); diff --git a/t/resultset/rowparser_internals.t b/t/resultset/rowparser_internals.t index 9d71d4c..a89897b 100644 --- a/t/resultset/rowparser_internals.t +++ b/t/resultset/rowparser_internals.t @@ -75,24 +75,24 @@ is_deeply ( -identifying_columns => [ 4, 5 ], single_track => { - -identifying_columns => [ 4, 5 ], + -identifying_columns => [ 1, 4, 5 ], -is_optional => 1, -is_single => 1, cd => { - -identifying_columns => [ 4, 5 ], + -identifying_columns => [ 1, 4, 5 ], -is_single => 1, artist => { - -identifying_columns => [ 4, 5 ], + -identifying_columns => [ 1, 4, 5 ], -is_single => 1, cds => { - -identifying_columns => [ 3, 4, 5 ], + -identifying_columns => [ 1, 3, 4, 5 ], -is_optional => 1, tracks => { - -identifying_columns => [ 0, 3, 4, 5 ], + -identifying_columns => [ 0, 1, 3, 4, 5 ], -is_optional => 1, }, }, @@ -117,7 +117,7 @@ is_same_src ( ) { $cur_row_ids{$_} = defined $cur_row_data->[$_] ? $cur_row_data->[$_] : "\0NULL\xFF$rows_pos\xFF$_\0" - for (0, 3, 4, 5); + for (0, 1, 3, 4, 5); # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2] $_[1] and $result_pos and unshift(@{$_[2]}, $cur_row_data) and last @@ -127,21 +127,21 @@ is_same_src ( $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} ||= [{ artist => $cur_row_data->[5], title => $cur_row_data->[4], year => $cur_row_data->[2] }]; # prefetch data of single_track (placed in root) - $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{single_track} ||= $collapse_idx[1]{$cur_row_ids{4}}{$cur_row_ids{5}}; + $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{single_track} ||= $collapse_idx[1]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}; # prefetch data of cd (placed in single_track) - $collapse_idx[1]{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{cd} ||= $collapse_idx[2]{$cur_row_ids{4}}{$cur_row_ids{5}}; + $collapse_idx[1]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{cd} ||= $collapse_idx[2]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}; # prefetch data of artist ( placed in single_track->cd) - $collapse_idx[2]{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{artist} ||= $collapse_idx[3]{$cur_row_ids{4}}{$cur_row_ids{5}} ||= [{ artistid => $cur_row_data->[1] }]; + $collapse_idx[2]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{artist} ||= $collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}} ||= [{ artistid => $cur_row_data->[1] }]; # prefetch data of cds (if available) - push @{$collapse_idx[3]{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{cds}}, $collapse_idx[4]{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} ||= [{ cdid => $cur_row_data->[3] }] - unless $collapse_idx[4]{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}; + push @{$collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{cds}}, $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} ||= [{ cdid => $cur_row_data->[3] }] + unless $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}; # prefetch data of tracks (if available) - push @{$collapse_idx[4]{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{tracks}}, $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} ||= [{ title => $cur_row_data->[0] }] - unless $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}; + push @{$collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{tracks}}, $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} ||= [{ title => $cur_row_data->[0] }] + unless $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}; $_[0][$result_pos++] = $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} if $is_new_res;