X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FResultSet.pm;h=ed2d1449e1b24272a950d567b1efbe89b1499a34;hb=f1952f5c69e092d9ce416586f29942f8c2f66bce;hp=c17ca808203144453894bb4989a0c21297012988;hpb=1f279bcfdaa31b01fbf1c974012a483b209b75f7;p=dbsrgits%2FDBIx-Class.git diff --git a/lib/DBIx/Class/ResultSet.pm b/lib/DBIx/Class/ResultSet.pm index c17ca80..ed2d144 100644 --- a/lib/DBIx/Class/ResultSet.pm +++ b/lib/DBIx/Class/ResultSet.pm @@ -661,7 +661,6 @@ sub cursor { my ($self) = @_; my $attrs = $self->_resolved_attrs_copy; - $attrs->{_virtual_order_by} = $self->_gen_virtual_order; return $self->{cursor} ||= $self->result_source->storage->select($attrs->{from}, $attrs->{select}, @@ -714,7 +713,6 @@ sub single { } my $attrs = $self->_resolved_attrs_copy; - $attrs->{_virtual_order_by} = $self->_gen_virtual_order; if ($where) { if (defined $attrs->{where}) { @@ -742,15 +740,6 @@ sub single { return (@data ? ($self->_construct_object(@data))[0] : undef); } -# _gen_virtual_order -# -# This is a horrble hack, but seems like the best we can do at this point -# Some limit emulations (Top) require an ordered resultset in order to -# function at all. So supply a PK order to be used if necessary - -sub _gen_virtual_order { - return [ shift->result_source->primary_columns ]; -} # _is_unique_query # @@ -1329,7 +1318,7 @@ sub _rs_update_delete { my $subrs = (ref $self)->new($rsrc, $attrs); - return $self->result_source->storage->subq_update_delete($subrs, $op, $values); + return $self->result_source->storage->_subq_update_delete($subrs, $op, $values); } else { return $rsrc->storage->$op( @@ -1936,7 +1925,22 @@ B: This feature is still experimental. =cut -sub as_query { return shift->cursor->as_query(@_) } +sub as_query { + my $self = shift; + + my $attrs = $self->_resolved_attrs_copy; + + # For future use: + # + # in list ctx: + # my ($sql, \@bind, \%dbi_bind_attrs) = _select_args_to_query (...) + # $sql also has no wrapping parenthesis in list ctx + # + my $sqlbind = $self->result_source->storage + ->_select_args_to_query ($attrs->{from}, $attrs->{select}, $attrs->{where}, $attrs); + + return $sqlbind; +} =head2 find_or_new @@ -1977,8 +1981,10 @@ sub find_or_new { my $self = shift; my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {}); my $hash = ref $_[0] eq 'HASH' ? shift : {@_}; - my $exists = $self->find($hash, $attrs); - return defined $exists ? $exists : $self->new_result($hash); + if (keys %$hash and my $row = $self->find($hash, $attrs) ) { + return $row; + } + return $self->new_result($hash); } =head2 create @@ -2108,8 +2114,10 @@ sub find_or_create { my $self = shift; my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {}); my $hash = ref $_[0] eq 'HASH' ? shift : {@_}; - my $exists = $self->find($hash, $attrs); - return defined $exists ? $exists : $self->create($hash); + if (keys %$hash and my $row = $self->find($hash, $attrs) ) { + return $row; + } + return $self->create($hash); } =head2 update_or_create @@ -2434,10 +2442,17 @@ sub _resolve_from { my $source = $self->result_source; my $attrs = $self->{attrs}; - my $from = $attrs->{from} - || [ { $attrs->{alias} => $source->from } ]; + my $from = [ @{ + $attrs->{from} + || + [{ + -source_handle => $source->handle, + -alias => $attrs->{alias}, + $attrs->{alias} => $source->from, + }] + }]; - my $seen = $attrs->{seen_join} || {}; + my $seen = { %{$attrs->{seen_join} || {} } }; # we need to take the prefetch the attrs into account before we # ->_resolve_join as otherwise they get lost - captainL @@ -2540,7 +2555,11 @@ sub _resolved_attrs { push( @{ $attrs->{as} }, @$adds ); } - $attrs->{from} ||= [ { $self->{attrs}{alias} => $source->from } ]; + $attrs->{from} ||= [ { + -source_handle => $source->handle, + -alias => $self->{attrs}{alias}, + $self->{attrs}{alias} => $source->from, + } ]; if ( exists $attrs->{join} || exists $attrs->{prefetch} ) { my $join = delete $attrs->{join} || {}; @@ -2571,20 +2590,30 @@ sub _resolved_attrs { $attrs->{order_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 ]; + + my $collapse = $attrs->{collapse} || {}; + if ( my $prefetch = delete $attrs->{prefetch} ) { $prefetch = $self->_merge_attr( {}, $prefetch ); - my @pre_order; - foreach my $p ( ref $prefetch eq 'ARRAY' ? @$prefetch : ($prefetch) ) { - - # bring joins back to level of current class - my $join_map = $self->_joinpath_aliases ($attrs->{from}, $attrs->{seen_join}); - my @prefetch = - $source->_resolve_prefetch( $p, $alias, $join_map, \@pre_order, $collapse ); - push( @{ $attrs->{select} }, map { $_->[0] } @prefetch ); - push( @{ $attrs->{as} }, map { $_->[1] } @prefetch ); - } - push( @{ $attrs->{order_by} }, @pre_order ); + + my $prefetch_ordering = []; + + my $join_map = $self->_joinpath_aliases ($attrs->{from}, $attrs->{seen_join}); + + my @prefetch = + $source->_resolve_prefetch( $prefetch, $alias, $join_map, $prefetch_ordering, $collapse ); + + push( @{ $attrs->{select} }, map { $_->[0] } @prefetch ); + push( @{ $attrs->{as} }, map { $_->[1] } @prefetch ); + + push( @{ $attrs->{order_by} }, @$prefetch_ordering ); } if (delete $attrs->{distinct}) { @@ -2613,7 +2642,7 @@ sub _joinpath_aliases { my $p = $paths; $p = $p->{$_} ||= {} for @{$j->[0]{-join_path}}; - push @{$p->{-join_aliases} }, $j->[0]{-join_alias}; + push @{$p->{-join_aliases} }, $j->[0]{-alias}; } return $paths; @@ -3266,9 +3295,21 @@ with a father in the person table, we could explicitly use C: # SELECT child.* FROM person child # INNER JOIN person father ON child.father_id = father.id -If you need to express really complex joins or you need a subselect, you +You can select from a subquery by passing a resultset to from as follows. + + $schema->resultset('Artist')->search( + undef, + { alias => 'artist2', + from => [ { artist2 => $artist_rs->as_query } ], + } ); + + # and you'll get sql like this.. + # SELECT artist2.artistid, artist2.name, artist2.rank, artist2.charfield FROM + # ( SELECT me.artistid, me.name, me.rank, me.charfield FROM artists me ) artist2 + +If you need to express really complex joins, you can supply literal SQL to C via a scalar reference. In this case -the contents of the scalar will replace the table name asscoiated with the +the contents of the scalar will replace the table name associated with the resultsource. WARNING: This technique might very well not work as expected on chained