63e431aa9deb8732224d146441ea56283c942fc1
[dbsrgits/DBIx-Class.git] / t / prefetch / incomplete.t
1 use strict;
2 use warnings;
3
4 use Test::More;
5 use Test::Deep;
6 use Test::Exception;
7 use lib qw(t/lib);
8 use DBICTest ':DiffSQL';
9
10 my $schema = DBICTest->init_schema();
11
12 lives_ok(sub {
13   # while cds.* will be selected anyway (prefetch implies it)
14   # only the requested me.name column will be fetched.
15
16   # reference sql with select => [...]
17   #   SELECT me.name, cds.title, cds.cdid, cds.artist, cds.title, cds.year, cds.genreid, cds.single_track FROM ...
18
19   my $rs = $schema->resultset('Artist')->search(
20     { 'cds.title' => { '!=', 'Generic Manufactured Singles' } },
21     {
22       prefetch => [ qw/ cds / ],
23       order_by => [ { -desc => 'me.name' }, 'cds.title' ],
24       select => [qw/ me.name cds.title / ],
25     },
26   );
27
28   is ($rs->count, 2, 'Correct number of collapsed artists');
29   my ($we_are_goth) = $rs->all;
30   is ($we_are_goth->name, 'We Are Goth', 'Correct first artist');
31   is ($we_are_goth->cds->count, 1, 'Correct number of CDs for first artist');
32   is ($we_are_goth->cds->first->title, 'Come Be Depressed With Us', 'Correct cd for artist');
33 }, 'explicit prefetch on a keyless object works');
34
35 lives_ok ( sub {
36
37   my $rs = $schema->resultset('CD')->search(
38     {},
39     {
40       order_by => [ { -desc => 'me.year' } ],
41     }
42   );
43   my $years = [qw/ 2001 2001 1999 1998 1997/];
44
45   cmp_deeply (
46     [ $rs->search->get_column('me.year')->all ],
47     $years,
48     'Expected years (at least one duplicate)',
49   );
50
51   my @cds_and_tracks;
52   for my $cd ($rs->all) {
53     my $data = { year => $cd->year, cdid => $cd->cdid };
54     for my $tr ($cd->tracks->all) {
55       push @{$data->{tracks}}, { $tr->get_columns };
56     }
57     @{$data->{tracks}} = sort { $a->{trackid} <=> $b->{trackid} } @{$data->{tracks}};
58     push @cds_and_tracks, $data;
59   }
60
61   my $pref_rs = $rs->search ({}, { columns => [qw/year cdid/], prefetch => 'tracks' });
62
63   my @pref_cds_and_tracks;
64   for my $cd ($pref_rs->all) {
65     my $data = { $cd->get_columns };
66     for my $tr ($cd->tracks->all) {
67       push @{$data->{tracks}}, { $tr->get_columns };
68     }
69     @{$data->{tracks}} = sort { $a->{trackid} <=> $b->{trackid} } @{$data->{tracks}};
70     push @pref_cds_and_tracks, $data;
71   }
72
73   cmp_deeply (
74     \@pref_cds_and_tracks,
75     \@cds_and_tracks,
76     'Correct collapsing on non-unique primary object'
77   );
78
79   cmp_deeply (
80     $pref_rs->search ({}, { order_by => [ { -desc => 'me.year' }, 'trackid' ] })->all_hri,
81     \@cds_and_tracks,
82     'Correct HRI collapsing on non-unique primary object'
83   );
84
85 }, 'weird collapse lives');
86
87
88 lives_ok(sub {
89   # test implicit prefetch as well
90
91   my $rs = $schema->resultset('CD')->search(
92     { title => 'Generic Manufactured Singles' },
93     {
94       join=> 'artist',
95       select => [qw/ me.title artist.name / ],
96     }
97   );
98
99   my $cd = $rs->next;
100   is ($cd->title, 'Generic Manufactured Singles', 'CD title prefetched correctly');
101   isa_ok ($cd->artist, 'DBICTest::Artist');
102   is ($cd->artist->name, 'Random Boy Band', 'Artist object has correct name');
103
104 }, 'implicit keyless prefetch works');
105
106 # sane error
107 throws_ok(
108   sub {
109     $schema->resultset('Track')->search({}, { join => { cd => 'artist' }, '+columns' => 'artist.name' } )->next;
110   },
111   qr|\QInflation into non-existent relationship 'artist' of 'Track' requested, check the inflation specification (columns/as) ending in '...artist.name'|,
112   'Sensible error message on mis-specified "as"',
113 );
114
115 # check complex limiting prefetch without the join-able columns
116 {
117   my $pref_rs = $schema->resultset('Owners')->search({}, {
118     rows => 3,
119     offset => 1,
120     order_by => 'name',
121     columns => 'name',  # only the owner name, still prefetch all the books
122     prefetch => 'books',
123   });
124
125   is_same_sql_bind(
126     $pref_rs->as_query,
127     '(
128       SELECT me.name, books.id, books.source, books.owner, books.title, books.price
129         FROM (
130           SELECT me.name, me.id
131             FROM owners me
132           ORDER BY name
133           LIMIT ?
134           OFFSET ?
135         ) me
136         LEFT JOIN books books
137           ON books.owner = me.id
138       ORDER BY name
139     )',
140     [ [ { sqlt_datatype => "integer" } => 3 ], [ { sqlt_datatype => "integer" } => 1 ] ],
141     'Expected SQL on complex limited prefetch with non-selected join condition',
142   );
143
144   is_deeply (
145     $pref_rs->all_hri,
146     [ {
147       name => "Waltham",
148       books => [ {
149         id => 3,
150         owner => 2,
151         price => 65,
152         source => "Library",
153         title => "Best Recipe Cookbook",
154       } ],
155     } ],
156     'Expected result on complex limited prefetch with non-selected join condition'
157   );
158
159   my $empty_ordered_pref_rs = $pref_rs->search({}, {
160     columns => [],  # nothing, we only prefetch the book data
161     order_by => 'me.name',
162   });
163   my $empty_ordered_pref_hri = [ {
164     books => [ {
165       id => 3,
166       owner => 2,
167       price => 65,
168       source => "Library",
169       title => "Best Recipe Cookbook",
170     } ],
171   } ];
172
173   is_same_sql_bind(
174     $empty_ordered_pref_rs->as_query,
175     '(
176       SELECT books.id, books.source, books.owner, books.title, books.price
177         FROM (
178           SELECT me.id, me.name
179             FROM owners me
180           ORDER BY me.name
181           LIMIT ?
182           OFFSET ?
183         ) me
184         LEFT JOIN books books
185           ON books.owner = me.id
186       ORDER BY me.name
187     )',
188     [ [ { sqlt_datatype => "integer" } => 3 ], [ { sqlt_datatype => "integer" } => 1 ] ],
189     'Expected SQL on *ordered* complex limited prefetch with non-selected root data',
190   );
191
192   is_deeply (
193     $empty_ordered_pref_rs->all_hri,
194     $empty_ordered_pref_hri,
195     'Expected result on *ordered* complex limited prefetch with non-selected root data'
196   );
197
198   $empty_ordered_pref_rs = $empty_ordered_pref_rs->search({}, {
199     order_by => [ \ 'LENGTH(me.name)', \ 'RANDOM()' ],
200   });
201
202   is_same_sql_bind(
203     $empty_ordered_pref_rs->as_query,
204     '(
205       SELECT books.id, books.source, books.owner, books.title, books.price
206         FROM (
207           SELECT me.id, me.name
208             FROM owners me
209           ORDER BY LENGTH(me.name), RANDOM()
210           LIMIT ?
211           OFFSET ?
212         ) me
213         LEFT JOIN books books
214           ON books.owner = me.id
215       ORDER BY LENGTH(me.name), RANDOM()
216     )',
217     [ [ { sqlt_datatype => "integer" } => 3 ], [ { sqlt_datatype => "integer" } => 1 ] ],
218     'Expected SQL on *function-ordered* complex limited prefetch with non-selected root data',
219   );
220
221   is_deeply (
222     $empty_ordered_pref_rs->all_hri,
223     $empty_ordered_pref_hri,
224     'Expected result on *function-ordered* complex limited prefetch with non-selected root data'
225   );
226 }
227
228
229 done_testing;