Fix very subtle but deadly bug in single()
[dbsrgits/DBIx-Class.git] / t / search / preserve_original_rs.t
1 use strict;
2 use warnings;
3
4 use Test::More;
5 use Test::Exception;
6
7 use lib qw(t/lib);
8 use DBICTest;
9 use DBIC::SqlMakerTest;
10 use DBIC::DebugObj;
11
12 use Storable qw/dclone/;
13
14 my $schema = DBICTest->init_schema();
15
16 # A search() with prefetch seems to pollute an already joined resultset
17 # in a way that offsets future joins (adapted from a test case by Debolaz)
18 {
19   my ($cd_rs, $attrs);
20
21   # test a real-life case - rs is obtained by an implicit m2m join
22   $cd_rs = $schema->resultset ('Producer')->first->cds;
23   $attrs = dclone( $cd_rs->{attrs} );
24
25   $cd_rs->search ({})->all;
26   is_deeply (dclone($cd_rs->{attrs}), $attrs, 'Resultset attributes preserved after a simple search');
27
28   lives_ok (sub {
29     $cd_rs->search ({'artist.artistid' => 1}, { prefetch => 'artist' })->all;
30     is_deeply (dclone($cd_rs->{attrs}), $attrs, 'Resultset attributes preserved after search with prefetch');
31   }, 'first prefetching search ok');
32
33   lives_ok (sub {
34     $cd_rs->search ({'artist.artistid' => 1}, { prefetch => 'artist' })->all;
35     is_deeply (dclone($cd_rs->{attrs}), $attrs, 'Resultset attributes preserved after another search with prefetch')
36   }, 'second prefetching search ok');
37
38
39   # test a regular rs with an empty seen_join injected - it should still work!
40   $cd_rs = $schema->resultset ('CD');
41   $cd_rs->{attrs}{seen_join}  = {};
42   $attrs = dclone( $cd_rs->{attrs} );
43
44   $cd_rs->search ({})->all;
45   is_deeply (dclone($cd_rs->{attrs}), $attrs, 'Resultset attributes preserved after a simple search');
46
47   lives_ok (sub {
48     $cd_rs->search ({'artist.artistid' => 1}, { prefetch => 'artist' })->all;
49     is_deeply (dclone($cd_rs->{attrs}), $attrs, 'Resultset attributes preserved after search with prefetch');
50   }, 'first prefetching search ok');
51
52   lives_ok (sub {
53     $cd_rs->search ({'artist.artistid' => 1}, { prefetch => 'artist' })->all;
54     is_deeply (dclone($cd_rs->{attrs}), $attrs, 'Resultset attributes preserved after another search with prefetch')
55   }, 'second prefetching search ok');
56 }
57
58 # Also test search_related, but now that we have as_query simply compare before and after
59 my $artist = $schema->resultset ('Artist')->first;
60 my %q;
61
62 $q{a2a}{rs} = $artist->search_related ('artwork_to_artist');
63 $q{a2a}{query} = $q{a2a}{rs}->as_query;
64
65 $q{artw}{rs} = $q{a2a}{rs}->search_related ('artwork',
66   { },
67   { join => ['cd', 'artwork_to_artist'] },
68 );
69 $q{artw}{query} = $q{artw}{rs}->as_query;
70
71 $q{cd}{rs} = $q{artw}{rs}->search_related ('cd', {}, { join => [ 'artist', 'tracks' ] } );
72 $q{cd}{query} = $q{cd}{rs}->as_query;
73
74 $q{artw_back}{rs} = $q{cd}{rs}->search_related ('artwork',
75   {}, { join => { artwork_to_artist => 'artist' } }
76 )->search_related ('artwork_to_artist', {}, { join => 'artist' });
77 $q{artw_back}{query} = $q{artw_back}{rs}->as_query;
78
79 for my $s (qw/a2a artw cd artw_back/) {
80   my $rs = $q{$s}{rs};
81
82   lives_ok ( sub { $rs->first }, "first() on $s does not throw an exception" );
83
84   lives_ok ( sub { $rs->count }, "count() on $s does not throw an exception" );
85
86   is_same_sql_bind ($rs->as_query, $q{$s}{query}, "$s resultset unmodified (as_query matches)" );
87 }
88
89 # ensure nothing pollutes the attrs of an existing rs
90 {
91   my $fresh = $schema->resultset('CD');
92
93   isa_ok ($fresh->find(1), 'DBICTest::CD' );
94   isa_ok ($fresh->single({ cdid => 1}), 'DBICTest::CD' );
95   isa_ok ($fresh->search({ cdid => 1})->next, 'DBICTest::CD' );
96   is ($fresh->count({ cdid => 1}), 1 );
97   is ($fresh->count_rs({ cdid => 1})->next, 1 );
98
99   ok (! exists $fresh->{_attrs}{_sqlmaker_select_args}, 'select args did not leak through' );
100 }
101
102 done_testing;