From: Luke Saunders Date: Wed, 7 Jun 2006 23:31:44 +0000 (+0000) Subject: obscure prefetch problem fixed X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=4e4604937e2aa069e49a2fb8f3785d4562e319b3;p=dbsrgits%2FDBIx-Class-Historic.git obscure prefetch problem fixed --- diff --git a/lib/DBIx/Class/ResultSet.pm b/lib/DBIx/Class/ResultSet.pm index df1f51c..51bee33 100644 --- a/lib/DBIx/Class/ResultSet.pm +++ b/lib/DBIx/Class/ResultSet.pm @@ -754,13 +754,46 @@ sub _resolve { push(@{$attrs->{from}}, $source->resolve_join($p, $attrs->{alias})) unless $seen{$p}; } - #print "res pre: " . Dumper($p, $collapse); - my @prefetch = $source->resolve_prefetch( + + # we're about to resolve_join on the current class, so we need to bring + # the joins (which are from the original class) to the right level + # XXX the below alg is ridiculous + if ($attrs->{_live_join_stack}) { + STACK: foreach (@{$attrs->{_live_join_stack}}) { + if (ref $p eq 'HASH') { + if (exists $p->{$_}) { + $p = $p->{$_}; + } else { + $p = undef; + last STACK; + } + } elsif (ref $p eq 'ARRAY') { + foreach my $pe (@{$p}) { + if ($pe eq $_) { + $p = undef; + last STACK; + } + next unless(ref $pe eq 'HASH'); + next unless(exists $pe->{$_}); + $p = $pe->{$_}; + next STACK; + } + $p = undef; + last STACK; + } else { + $p = undef; + last STACK; + } + } + } + + if ($p) { + my @prefetch = $self->result_source->resolve_prefetch( $p, $attrs->{alias}, {}, \@pre_order, $collapse); - - #print "prefetch: " . Dumper(\@prefetch); - push(@{$attrs->{select}}, map { $_->[0] } @prefetch); - push(@{$attrs->{as}}, map { $_->[1] } @prefetch); + + push(@{$attrs->{select}}, map { $_->[0] } @prefetch); + push(@{$attrs->{as}}, map { $_->[1] } @prefetch); + } } push(@{$attrs->{order_by}}, @pre_order); } @@ -831,7 +864,6 @@ sub _construct_object { my ($self, @row) = @_; my @as = @{ $self->{_attrs}{as} }; - #print "row in: " . Dumper(\@row); my $info = $self->_collapse_result(\@as, \@row); my $new = $self->result_class->inflate_result($self->result_source, @$info); $new = $self->{_attrs}{record_filter}->($new) @@ -875,7 +907,6 @@ sub _collapse_result { } my @collapse; - #print "collapse: " . Dumper($self->{_attrs}->{collapse}); if (defined $prefix) { @collapse = map { m/^\Q${prefix}.\E(.+)$/ ? ($1) : () @@ -896,7 +927,6 @@ sub _collapse_result { my %co_check = map { ($_, $tree->[0]->{$_}); } @co_key; my (@final, @raw); - #print "les free: " . Dumper($tree->[0], \%co_check, \@co_key); while ( !(grep { !defined($tree->[0]->{$_}) || $co_check{$_} ne $tree->[0]->{$_} @@ -910,13 +940,6 @@ sub _collapse_result { # single empty result to indicate an empty prefetched has_many } - # get prefetch tree back to result_source level - # $self could be a related resultset - #if ($self->{attrs}->{_live_join_stack}) { - # foreach (@{$self->{attrs}->{_live_join_stack}}) { - # $info->[1] = $info->[1]->{$_}->[1] if(exists $info->[1]->{$_}); - #} - #} #print "final info: " . Dumper($info); return $info; } @@ -1586,22 +1609,25 @@ sub related_resultset { return $self->{related_resultsets}{$rel} ||= do { #warn "fetching related resultset for rel '$rel' " . $self->result_source->{name}; my $rel_obj = $self->result_source->relationship_info($rel); + #print Dumper($self->result_source->_relationships); $self->throw_exception( "search_related: result source '" . $self->result_source->name . "' has no such relationship ${rel}") unless $rel_obj; #die Dumper $self->{attrs}; - my $live_join_stack = $self->{attrs}->{_live_join_stack} || []; - push(@{$live_join_stack}, $rel); + my @live_join_stack = (exists $self->{attrs}->{_live_join_stack}) ? + @{$self->{attrs}->{_live_join_stack}}: + (); + push(@live_join_stack, $rel); my $rs = $self->result_source->schema->resultset($rel_obj->{class} )->search( undef, { select => undef, as => undef, _live_join => $rel, #the most recent - _live_join_stack => $live_join_stack, #the trail of rels + _live_join_stack => \@live_join_stack, #the trail of rels _parent_attrs => $self->{attrs}} - ); + ); # keep reference of the original resultset $rs->{_parent_rs} = ($self->{_parent_rs}) ? $self->{_parent_rs} : $self->result_source; diff --git a/t/90join_torture.t b/t/90join_torture.t index eee1e21..daf1c64 100644 --- a/t/90join_torture.t +++ b/t/90join_torture.t @@ -7,7 +7,7 @@ use DBICTest; my $schema = DBICTest->init_schema(); -plan tests => 11; +plan tests => 14; my @rs1a_results = $schema->resultset("Artist")->search_related('cds', {title => 'Forkful of bees'}, {order_by => 'title'}); is($rs1a_results[0]->title, 'Forkful of bees', "bare field conditions okay after search related"); @@ -21,7 +21,7 @@ my @artists2 = $rs2->search({ 'producer.name' => 'Matt S Trout' }); my @cds = $artists2[0]->cds; cmp_ok(scalar @cds, '==', 1, "condition based on inherited join okay"); -# this is wrong, should accept me.title really +#this is wrong, should accept me.title really my $rs3 = $rs2->search_related('cds'); cmp_ok($rs3->count, '==', 9, "Nine artists returned"); @@ -45,31 +45,31 @@ my $cd = $cds->search({'me.title' => 'Forkful of bees'}, { prefetch => 'tracks' my @tracks = $cd->tracks->all; is(scalar(@tracks), 3, 'right number of prefetched tracks after has many'); -# causes ambig col error due to order_by +#causes ambig col error due to order_by #my $tracks_rs = $cds->search_related('tracks', { 'tracks.position' => '2', 'disc.title' => 'Forkful of bees' }); #my $first_tracks_rs = $tracks_rs->first; my $related_rs = $schema->resultset("Artist")->search({ name => 'Caterwauler McCrae' })->search_related('cds', { year => '2001'})->search_related('tracks', { 'position' => '2' }); is($related_rs->first->trackid, '5', 'search related on search related okay'); -# causes ambig col error due to order_by +#causes ambig col error due to order_by #$related_rs->search({'cd.year' => '2001'}, {join => ['cd', 'cd']})->all; my $title = $schema->resultset("Artist")->search_related('twokeys')->search_related('cd')->search({'tracks.position' => '2'}, {join => 'tracks', order_by => 'tracks.trackid'})->next->title; is($title, 'Forkful of bees', 'search relateds with order by okay'); -# my $prod_rs = $schema->resultset("CD")->find(1)->other_producers; -# my $prod_rs2 = $prod_rs->search({ name => 'Matt S Trout' }, { prefetch => 'producer_to_cd', order_by => 'other_producer.name' }); -# my $prod_first = $prod_rs2->first; -# warn $prod_first->name; +my $prod_rs = $schema->resultset("CD")->find(1)->producers_sorted; +my $prod_rs2 = $prod_rs->search({ name => 'Matt S Trout' }); +my $prod_first = $prod_rs2->first; +is($prod_first->id, '1', 'somewhat pointless search on rel with order_by on it okay'); my $prod_map_rs = $schema->resultset("Artist")->find(1)->cds->search_related('cd_to_producer', {}, { join => 'producer', prefetch => 'producer' }); -use Data::Dumper; -warn $prod_map_rs->count; -print Dumper($prod_map_rs->{attrs}); -print Dumper($prod_map_rs->{_attrs}); -$prod_map_rs->first; +is($prod_map_rs->next->producer->producerid, '1', 'search related with prefetch okay'); +my $stupid = $schema->resultset("Artist")->search_related('artist_undirected_maps', {}, { prefetch => 'artist1' })->search_related('mapped_artists')->search_related('cds', {'cds.cdid' => '2'}, { prefetch => 'tracks' }); +#use Data::Dumper; warn Dumper($stupid->{attrs}); +my $cd_final = $schema->resultset("Artist")->search_related('artist_undirected_maps', {}, { prefetch => 'artist1' })->search_related('mapped_artists')->search_related('cds', {'cds.cdid' => '2'}, { prefetch => 'tracks' })->first; +is($cd_final->cdid, '2', 'bonkers search_related-with-join-midway okay'); 1; diff --git a/t/lib/DBICTest/Schema/CD.pm b/t/lib/DBICTest/Schema/CD.pm index d3ad8e8..7ba727c 100644 --- a/t/lib/DBICTest/Schema/CD.pm +++ b/t/lib/DBICTest/Schema/CD.pm @@ -40,7 +40,6 @@ __PACKAGE__->might_have( { proxy => [ qw/notes/ ] }, ); __PACKAGE__->many_to_many( producers => cd_to_producer => 'producer' ); -__PACKAGE__->many_to_many( other_producers => cd_to_producer => 'other_producer' ); __PACKAGE__->many_to_many( producers_sorted => cd_to_producer => 'producer', { order_by => 'producer.name' }, diff --git a/t/lib/DBICTest/Schema/CD_to_Producer.pm b/t/lib/DBICTest/Schema/CD_to_Producer.pm index b3a2b18..117a590 100644 --- a/t/lib/DBICTest/Schema/CD_to_Producer.pm +++ b/t/lib/DBICTest/Schema/CD_to_Producer.pm @@ -20,9 +20,4 @@ __PACKAGE__->belongs_to( { 'foreign.producerid' => 'self.producer' } ); -__PACKAGE__->belongs_to( - 'other_producer', 'DBICTest::Schema::Producer', - { 'foreign.producerid' => 'self.producer' } -); - 1; diff --git a/t/lib/DBICTest/Schema/Producer.pm b/t/lib/DBICTest/Schema/Producer.pm index 4deee65..036f9f2 100644 --- a/t/lib/DBICTest/Schema/Producer.pm +++ b/t/lib/DBICTest/Schema/Producer.pm @@ -17,9 +17,4 @@ __PACKAGE__->add_columns( __PACKAGE__->set_primary_key('producerid'); __PACKAGE__->add_unique_constraint(prod_name => [ qw/name/ ]); -__PACKAGE__->has_many( - producer_to_cd => 'DBICTest::Schema::CD_to_Producer' => 'producer' -); - - 1;