X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=dbsrgits%2FDBIx-Class.git;a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FResultSet.pm;h=13cfa03a46ee00101fc68757a9747d8a6bb1bc69;hp=5ec88d0d5d9e875fe06debcb1d01bed9dead24d2;hb=fcf32d045;hpb=0077982b2edc8273ab4b6ea59921177667008cb3 diff --git a/lib/DBIx/Class/ResultSet.pm b/lib/DBIx/Class/ResultSet.pm index 5ec88d0..13cfa03 100644 --- a/lib/DBIx/Class/ResultSet.pm +++ b/lib/DBIx/Class/ResultSet.pm @@ -1358,18 +1358,21 @@ sub _construct_objects { } } else { - ($self->{_row_parser} ||= eval sprintf 'sub { %s }', $rsrc->_mk_row_parser({ + $self->{_row_parser} ||= eval sprintf 'sub { %s }', $rsrc->_mk_row_parser({ inflate_map => $infmap, selection => $attrs->{select}, collapse => $attrs->{collapse}, - }) or die $@)->($rows, $fetch_all ? () : ( + premultiplied => $attrs->{_main_source_premultiplied}, + }) or die $@; + + # modify $rows in-place, shrinking/extending as necessary + $self->{_row_parser}->($rows, $fetch_all ? () : ( # FIXME SUBOPTIMAL - we can do better, cursor->next/all (well diff. methods) should return a ref sub { my @r = $cursor->next or return; \@r }, # how the collapser gets more rows ($self->{stashed_rows} = []), # where does it stuff excess - )); # modify $rows in-place, shrinking/extending as necessary + )); $_ = $inflator->($res_class, $rsrc, @$_) for @$rows; - } # CDBI compat stuff @@ -3446,30 +3449,57 @@ sub _resolved_attrs { push @{ $attrs->{as} }, (map { $_->[1] } @prefetch); } - $attrs->{_single_object_inflation} = ! List::Util::first { $_ =~ /\./ } @{$attrs->{as}}; + if ( ! List::Util::first { $_ =~ /\./ } @{$attrs->{as}} ) { + $attrs->{_single_object_inflation} = 1; + $attrs->{collapse} = 0; + } # run through the resulting joinstructure (starting from our current slot) # and unset collapse if proven unnesessary - if ($attrs->{collapse} && ref $attrs->{from} eq 'ARRAY') { + # + # also while we are at it find out if the current root source has + # been premultiplied by previous related_source chaining + # + # this allows to predict whether a root object with all other relation + # data set to NULL is in fact unique + if ($attrs->{collapse}) { - if (@{$attrs->{from}} > 1) { + if (ref $attrs->{from} eq 'ARRAY') { - # find where our table-spec starts and consider only things after us - my @fromlist = @{$attrs->{from}}; - while (@fromlist) { - my $t = shift @fromlist; - $t = $t->[0] if ref $t eq 'ARRAY'; #me vs join from-spec mismatch - last if ($t->{-alias} && $t->{-alias} eq $alias); + if (@{$attrs->{from}} <= 1) { + # no joins - no collapse + $attrs->{collapse} = 0; } + else { + # find where our table-spec starts + my @fromlist = @{$attrs->{from}}; + while (@fromlist) { + my $t = shift @fromlist; + + my $is_multi; + # me vs join from-spec distinction - a ref means non-root + if (ref $t eq 'ARRAY') { + $t = $t->[0]; + $is_multi ||= ! $t->{-is_single}; + } + last if ($t->{-alias} && $t->{-alias} eq $alias); + $attrs->{_main_source_premultiplied} ||= $is_multi; + } - for (@fromlist) { - $attrs->{collapse} = ! $_->[0]{-is_single} - and last; + # no non-singles remaining, nor any premultiplication - nothing to collapse + if ( + ! $attrs->{_main_source_premultiplied} + and + ! List::Util::first { ! $_->[0]{-is_single} } @fromlist + ) { + $attrs->{collapse} = 0; + } } } + else { - # no joins - no collapse - $attrs->{collapse} = 0; + # if we can not analyze the from - err on the side of safety + $attrs->{_main_source_premultiplied} = 1; } } @@ -3604,7 +3634,7 @@ sub _merge_joinpref_attr { $seen_keys->{$import_key} = 1; # don't merge the same key twice } - return $orig; + return @$orig ? $orig : (); } {