X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FResultSet.pm;h=ed1cdc0315b826cb778995be43862070188e0b9d;hb=35f61d278b515761c2dc3ac94059724a74e29793;hp=64dfe605296f1c70e80cbc6d180842afc3661d92;hpb=f7f14dc88220135c2faf05ea6c4ea122690b52c7;p=dbsrgits%2FDBIx-Class.git diff --git a/lib/DBIx/Class/ResultSet.pm b/lib/DBIx/Class/ResultSet.pm index 64dfe60..ed1cdc0 100644 --- a/lib/DBIx/Class/ResultSet.pm +++ b/lib/DBIx/Class/ResultSet.pm @@ -1279,8 +1279,15 @@ sub _count_subq_rs { $sub_attrs->{from}, $sub_attrs->{alias} ); + # this is so that ordering can be thrown away in things like Top limit + $sub_attrs->{-for_count_only} = 1; + + my $sub_rs = $rsrc->resultset_class->new ($rsrc, $sub_attrs); + $attrs->{from} = [{ - count_subq => $rsrc->resultset_class->new ($rsrc, $sub_attrs )->as_query + -alias => 'count_subq', + -source_handle => $rsrc->handle, + count_subq => $sub_rs->as_query, }]; # the subquery replaces this @@ -1308,9 +1315,12 @@ sub _count_subq_rs { sub _switch_to_inner_join_if_needed { my ($self, $from, $alias) = @_; + # subqueries and other oddness is naturally not supported return $from if ( ref $from ne 'ARRAY' || + @$from <= 1 + || ref $from->[0] ne 'HASH' || ! $from->[0]{-alias} @@ -1318,10 +1328,6 @@ sub _switch_to_inner_join_if_needed { $from->[0]{-alias} eq $alias ); - # this would be the case with a subquery - we'll never find - # the target as it is not in the parseable part of {from} - return $from if @$from == 1; - my $switch_branch; JOINSCAN: for my $j (@{$from}[1 .. $#$from]) { @@ -2226,12 +2232,15 @@ store. If the appropriate relationships are set up, foreign key fields can also be passed an object representing the foreign row, and the value will be set to its primary key. -To create related objects, pass a hashref for the value if the related -item is a foreign key relationship (L), -and use the name of the relationship as the key. (NOT the name of the field, -necessarily). For C and C relationships, pass an arrayref -of hashrefs containing the data for each of the rows to create in the foreign -tables, again using the relationship name as the key. +To create related objects, pass a hashref of related-object column values +B. If the relationship is of type C +(L) - pass an arrayref of hashrefs. +The process will correctly identify columns holding foreign keys, and will +transparrently populate them from the keys of the corresponding relation. +This can be applied recursively, and will work correctly for a structure +with an arbitrary depth and width, as long as the relationships actually +exists and the correct column data has been supplied. + Instead of hashrefs of plain related data (key/value pairs), you may also pass new or inserted objects. New objects (not inserted yet, see @@ -2655,6 +2664,11 @@ sub current_source_alias { # in order to properly resolve prefetch aliases (any alias # with a relation_chain_depth less than the depth of the # current prefetch is not considered) +# +# The increments happen in 1/2s to make it easier to correlate the +# join depth with the join path. An integer means a relationship +# specified via a search_related, whereas a fraction means an added +# join/prefetch via attributes sub _chain_relationship { my ($self, $rel) = @_; my $source = $self->result_source; @@ -2671,16 +2685,25 @@ sub _chain_relationship { }]; my $seen = { %{$attrs->{seen_join} || {} } }; + my $jpath = ($attrs->{seen_join} && keys %{$attrs->{seen_join}}) + ? $from->[-1][0]{-join_path} + : []; + # we need to take the prefetch the attrs into account before we # ->_resolve_join as otherwise they get lost - captainL my $merged = $self->_merge_attr( $attrs->{join}, $attrs->{prefetch} ); - my @requested_joins = $source->_resolve_join($merged, $attrs->{alias}, $seen); + my @requested_joins = $source->_resolve_join( + $merged, + $attrs->{alias}, + $seen, + $jpath, + ); push @$from, @requested_joins; - ++$seen->{-relation_chain_depth}; + $seen->{-relation_chain_depth} += 0.5; # if $self already had a join/prefetch specified on it, the requested # $rel might very well be already included. What we do in this case @@ -2692,7 +2715,7 @@ sub _chain_relationship { # we consider the last one thus reverse for my $j (reverse @requested_joins) { if ($rel eq $j->[0]{-join_path}[-1]) { - $j->[0]{-relation_chain_depth}++; + $j->[0]{-relation_chain_depth} += 0.5; $already_joined++; last; } @@ -2702,17 +2725,22 @@ sub _chain_relationship { # for my $j (reverse @$from) { # next unless ref $j eq 'ARRAY'; # if ($j->[0]{-join_path} && $j->[0]{-join_path}[-1] eq $rel) { -# $j->[0]{-relation_chain_depth}++; +# $j->[0]{-relation_chain_depth} += 0.5; # $already_joined++; # last; # } # } unless ($already_joined) { - push @$from, $source->_resolve_join($rel, $attrs->{alias}, $seen); + push @$from, $source->_resolve_join( + $rel, + $attrs->{alias}, + $seen, + $jpath, + ); } - ++$seen->{-relation_chain_depth}; + $seen->{-relation_chain_depth} += 0.5; return ($from,$seen); } @@ -2824,16 +2852,22 @@ sub _resolved_attrs { [ @{ $attrs->{from} }, $source->_resolve_join( - $join, $alias, { %{ $attrs->{seen_join} || {} } } + $join, + $alias, + { %{ $attrs->{seen_join} || {} } }, + ($attrs->{seen_join} && keys %{$attrs->{seen_join}}) + ? $attrs->{from}[-1][0]{-join_path} + : [] + , ) ]; } - if ( $attrs->{order_by} ) { + if ( defined $attrs->{order_by} ) { $attrs->{order_by} = ( ref( $attrs->{order_by} ) eq 'ARRAY' ? [ @{ $attrs->{order_by} } ] - : [ $attrs->{order_by} ] + : [ $attrs->{order_by} || () ] ); } @@ -2841,14 +2875,6 @@ sub _resolved_attrs { $attrs->{group_by} = [ $attrs->{group_by} ]; } - # If the order_by is otherwise empty - we will use this for TOP limit - # emulation and the like. - # Although this is needed only if the order_by is not defined, it is - # actually cheaper to just populate this rather than properly examining - # order_by (stuf like [ {} ] and the like) - $attrs->{_virtual_order_by} = [ $self->result_source->primary_columns ]; - - $attrs->{collapse} ||= {}; if ( my $prefetch = delete $attrs->{prefetch} ) { $prefetch = $self->_merge_attr( {}, $prefetch ); @@ -2864,7 +2890,7 @@ sub _resolved_attrs { push @{ $attrs->{select} }, @{$attrs->{prefetch_select}}; push @{ $attrs->{as} }, (map { $_->[1] } @prefetch); - push( @{ $attrs->{order_by} }, @$prefetch_ordering ); + push( @{$attrs->{order_by}}, @$prefetch_ordering ); $attrs->{_collapse_order_by} = \@$prefetch_ordering; } @@ -2877,8 +2903,11 @@ sub _resolved_attrs { # even though it doesn't make much sense, this is what pre 081xx has # been doing if (my $page = delete $attrs->{page}) { - $attrs->{offset} = ($attrs->{rows} * ($page - 1)) + - ($attrs->{offset} || 0); + $attrs->{offset} = + ($attrs->{rows} * ($page - 1)) + + + ($attrs->{offset} || 0) + ; } return $self->{_attrs} = $attrs; @@ -2890,13 +2919,21 @@ sub _joinpath_aliases { my $paths = {}; return $paths unless ref $fromspec eq 'ARRAY'; + my $cur_depth = $seen->{-relation_chain_depth} || 0; + + if (int ($cur_depth) != $cur_depth) { + $self->throw_exception ("-relation_chain_depth is not an integer, something went horribly wrong ($cur_depth)"); + } + for my $j (@$fromspec) { next if ref $j ne 'ARRAY'; - next if $j->[0]{-relation_chain_depth} < ( $seen->{-relation_chain_depth} || 0); + next if $j->[0]{-relation_chain_depth} < $cur_depth; + + my $jpath = $j->[0]{-join_path}; my $p = $paths; - $p = $p->{$_} ||= {} for @{$j->[0]{-join_path}}; + $p = $p->{$_} ||= {} for @{$jpath}[$cur_depth .. $#$jpath]; push @{$p->{-join_aliases} }, $j->[0]{-alias}; } @@ -3053,10 +3090,15 @@ These are in no particular order: =back -Which column(s) to order the results by. If a single column name, or -an arrayref of names is supplied, the argument is passed through -directly to SQL. The hashref syntax allows for connection-agnostic -specification of ordering direction: +Which column(s) to order the results by. + +[The full list of suitable values is documented in +L; the following is a summary of +common options.] + +If a single column name, or an arrayref of names is supplied, the +argument is passed through directly to SQL. The hashref syntax allows +for connection-agnostic specification of ordering direction: For descending order: