From: Arthur Axel "fREW" Schmidt Date: Sun, 7 Feb 2010 20:07:03 +0000 (+0000) Subject: add as_subselect_rs X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=e4bb67275eafae2905d88eb061f1e5a7dca21d18;p=dbsrgits%2FDBIx-Class-Historic.git add as_subselect_rs --- diff --git a/lib/DBIx/Class/ResultSet.pm b/lib/DBIx/Class/ResultSet.pm index c0c758f..206569a 100644 --- a/lib/DBIx/Class/ResultSet.pm +++ b/lib/DBIx/Class/ResultSet.pm @@ -2502,7 +2502,7 @@ sub related_resultset { ->relname_to_table_alias($rel, $join_count); # since this is search_related, and we already slid the select window inwards - # (the select/as attrs were deleted in the beginning), we need to flip all + # (the select/as attrs were deleted in the beginning), we need to flip all # left joins to inner, so we get the expected results # read the comment on top of the actual function to see what this does $attrs->{from} = $rsrc->schema->storage->_straight_join_to_node ($attrs->{from}, $alias); @@ -2588,6 +2588,56 @@ sub current_source_alias { return ($self->{attrs} || {})->{alias} || 'me'; } +=head2 as_subselect_rs + +=over 4 + +=item Arguments: none + +=item Return Value: $resultset + +=back + +Act as a barrier to SQL symbols. The resultset provided will be made into a +"virtual view" by including it as a subquery within the from clause. From this +point on, any joined tables are inaccessible to ->search on the resultset (as if +it were simply where-filtered without joins). For example: + + my $rs = $schema->resultset('Bar')->search({'x.name' => 'abc'},{ join => 'x' }); + + # 'x' now pollutes the query namespace + + # So the following works as expected + my $ok_rs = $rs->search({'x.other' => 1}); + + # But this doesn't: instead of finding a 'Bar' related to two x rows (abc and + # def) we look for one row with contradictory terms and join in another table + # (aliased 'x_2') which we never use + my $broken_rs = $rs->search({'x.name' => 'def'}); + + my $rs2 = $rs->as_subselect_rs; + + # doesn't work - 'x' is no longer accessible in $rs2, having been sealed away + my $not_joined_rs = $rs2->search({'x.other' => 1}); + + # works as expected: finds a 'table' row related to two x rows (abc and def) + my $correctly_joined_rs = $rs2->search({'x.name' => 'def'}); + +=cut + +sub as_subselect_rs { + my $self = shift; + + return $self->result_source->resultset->search( undef, { + alias => 'me', + from => [{ + me => $self->as_query, + -alias => $self->current_source_alias, + -source_handle => $self->result_source->handle, + }] + }); +} + # This code is called by search_related, and makes sure there # is clear separation between the joins before, during, and # after the relationship. This information is needed later diff --git a/t/resultset/as_subselect_rs.t b/t/resultset/as_subselect_rs.t new file mode 100644 index 0000000..c143d11 --- /dev/null +++ b/t/resultset/as_subselect_rs.t @@ -0,0 +1,25 @@ +use strict; +use warnings; + +use Test::More; +use Test::Exception; + +use lib qw(t/lib); +use DBICTest; +use DBIC::SqlMakerTest; + +my $schema = DBICTest->init_schema(); + +my $new_rs = $schema->resultset('Artist')->search({ + 'artwork_to_artist.artist_id' => 1 +}, { + join => 'artwork_to_artist' +}); +lives_ok { $new_rs->count } 'regular search works'; +lives_ok { $new_rs->search({ 'artwork_to_artist.artwork_cd_id' => 1})->count } + '... and chaining off that using join works'; +lives_ok { $new_rs->search({ 'artwork_to_artist.artwork_cd_id' => 1})->as_subselect_rs->count } + '... and chaining off the virtual view works'; +dies_ok { $new_rs->as_subselect_rs->search({'artwork_to_artist.artwork_cd_id'=> 1})->count } + q{... but chaining off of a virtual view using join doesn't work}; +done_testing;