Retire DBIC/SqlMakerTest.pm now that SQLA::Test provides the same function
[dbsrgits/DBIx-Class.git] / t / prefetch / with_limit.t
CommitLineData
a04af85f 1# Test to ensure we get a consistent result set wether or not we use the
2# prefetch option in combination rows (LIMIT).
3use strict;
4use warnings;
5
6use Test::More;
61fd5dfc 7use Test::Exception;
a04af85f 8use lib qw(t/lib);
a5a7bb73 9use DBICTest ':DiffSQL';
fcb7fcbb 10use DBIx::Class::SQLMaker::LimitDialects;
11
12my $ROWS = DBIx::Class::SQLMaker::LimitDialects->__rows_bindtype;
a04af85f 13
a04af85f 14my $schema = DBICTest->init_schema();
51a296b4 15
16
a04af85f 17my $no_prefetch = $schema->resultset('Artist')->search(
51a296b4 18 [ # search deliberately contrived
19 { 'artwork.cd_id' => undef },
20 { 'tracks.title' => { '!=' => 'blah-blah-1234568' }}
21 ],
96faafb4 22 { rows => 3, join => { cds => [qw/artwork tracks/] },
23 }
24);
25
26my $use_prefetch = $no_prefetch->search(
27 {},
25cac750 28 {
c9d29bb2 29 select => ['me.artistid', 'me.name'],
30 as => ['artistid', 'name'],
25cac750 31 prefetch => 'cds',
51a296b4 32 order_by => { -desc => 'name' },
25cac750 33 }
a04af85f 34);
35
f7f53a89 36# add an extra +select to make sure it does not throw things off
36fd7f07 37# we also expect it to appear in both selectors, as we can not know
38# for sure which part of the query it applies to (may be order_by,
39# maybe something else)
40#
41# we use a reference to the same array in bind vals, because
42# is_deeply picks up this difference too (not sure if bug or
43# feature)
36fd7f07 44$use_prefetch = $use_prefetch->search({}, {
f7f53a89 45 '+columns' => { monkeywrench => \[ 'me.artistid + ?', [ \ 'inTEger' => 1 ] ] },
36fd7f07 46});
47
0e773352 48my $bind_int_resolved = sub { [ { sqlt_datatype => 'inTEger' } => 1 ] };
49my $bind_vc_resolved = sub { [
50 { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'tracks.title' }
51 => 'blah-blah-1234568'
52] };
36fd7f07 53is_same_sql_bind (
54 $use_prefetch->as_query,
55 '(
f7f53a89 56 SELECT me.artistid + ?,
57 me.artistid, me.name,
58 cds.cdid, cds.artist, cds.title, cds.year, cds.genreid, cds.single_track
36fd7f07 59 FROM (
f7f53a89 60 SELECT me.artistid + ?,
61 me.artistid, me.name
36fd7f07 62 FROM artist me
63 LEFT JOIN cd cds
64 ON cds.artist = me.artistid
65 LEFT JOIN cd_artwork artwork
66 ON artwork.cd_id = cds.cdid
67 LEFT JOIN track tracks
68 ON tracks.cd = cds.cdid
69 WHERE artwork.cd_id IS NULL
70 OR tracks.title != ?
f7f53a89 71 GROUP BY me.artistid + ?, me.artistid, me.name
fcb7fcbb 72 ORDER BY name DESC LIMIT ?
36fd7f07 73 ) me
74 LEFT JOIN cd cds
75 ON cds.artist = me.artistid
76 LEFT JOIN cd_artwork artwork
77 ON artwork.cd_id = cds.cdid
78 LEFT JOIN track tracks
79 ON tracks.cd = cds.cdid
80 WHERE artwork.cd_id IS NULL
81 OR tracks.title != ?
908aa1bb 82 ORDER BY name DESC
36fd7f07 83 )',
84 [
0e773352 85 $bind_int_resolved->(), # outer select
86 $bind_int_resolved->(), # inner select
87 $bind_vc_resolved->(), # inner where
88 $bind_int_resolved->(), # inner group_by
fcb7fcbb 89 [ $ROWS => 3 ],
0e773352 90 $bind_vc_resolved->(), # outer where
36fd7f07 91 ],
92 'Expected SQL on complex limited prefetch'
93);
94
a04af85f 95is($no_prefetch->count, $use_prefetch->count, '$no_prefetch->count == $use_prefetch->count');
5624ba1f 96is(
9117ccfb 97 scalar ($no_prefetch->all),
98 scalar ($use_prefetch->all),
99 "Amount of returned rows is right"
5624ba1f 100);
101
9117ccfb 102my $artist_many_cds = $schema->resultset('Artist')->search ( {}, {
103 join => 'cds',
104 group_by => 'me.artistid',
105 having => \ 'count(cds.cdid) > 1',
106})->first;
107
108
5624ba1f 109$no_prefetch = $schema->resultset('Artist')->search(
9117ccfb 110 { artistid => $artist_many_cds->id },
5624ba1f 111 { rows => 1 }
112);
113
61fd5dfc 114$use_prefetch = $no_prefetch->search ({}, { prefetch => 'cds' });
5624ba1f 115
61fd5dfc 116my $normal_artist = $no_prefetch->single;
117my $prefetch_artist = $use_prefetch->find({ name => $artist_many_cds->name });
118my $prefetch2_artist = $use_prefetch->first;
5624ba1f 119
120is(
121 $prefetch_artist->cds->count,
122 $normal_artist->cds->count,
61fd5dfc 123 "Count of child rel with prefetch + rows => 1 is right (find)"
124);
125is(
126 $prefetch2_artist->cds->count,
127 $normal_artist->cds->count,
128 "Count of child rel with prefetch + rows => 1 is right (first)"
5624ba1f 129);
61fd5dfc 130
9117ccfb 131is (
132 scalar ($prefetch_artist->cds->all),
133 scalar ($normal_artist->cds->all),
61fd5dfc 134 "Amount of child rel rows with prefetch + rows => 1 is right (find)"
135);
136is (
137 scalar ($prefetch2_artist->cds->all),
138 scalar ($normal_artist->cds->all),
139 "Amount of child rel rows with prefetch + rows => 1 is right (first)"
140);
141
142throws_ok (
143 sub { $use_prefetch->single },
5b309063 144 qr/\Qsingle() can not be used on resultsets collapsing a has_many/,
61fd5dfc 145 'single() with multiprefetch is illegal',
9117ccfb 146);
01c781fe 147
14e26c5f 148throws_ok (
149 sub {
150 $use_prefetch->search(
151 {'tracks.title' => { '!=' => 'foo' }},
152 { order_by => \ 'some oddball literal sql', join => { cds => 'tracks' } }
153 )->next
9736be65 154 }, qr/Unable to programatically derive a required group_by from the supplied order_by criteria/,
155);
14e26c5f 156
09707a31 157my $artist = $use_prefetch->search({'cds.title' => $artist_many_cds->cds->first->title })->next;
01c781fe 158is($artist->cds->count, 1, "count on search limiting prefetched has_many");
159
a3683eae 160# try with double limit
161my $artist2 = $use_prefetch->search({'cds.title' => { '!=' => $artist_many_cds->cds->first->title } })->slice (0,0)->next;
162is($artist2->cds->count, 2, "count on search limiting prefetched has_many");
163
53c29913 164# make sure 1:1 joins do not force a subquery (no point to exercise the optimizer, if at all available)
165# get cd's that have any tracks and their artists
166my $single_prefetch_rs = $schema->resultset ('CD')->search (
167 { 'me.year' => 2010, 'artist.name' => 'foo' },
168 { prefetch => ['tracks', 'artist'], rows => 15 },
169);
170is_same_sql_bind (
171 $single_prefetch_rs->as_query,
172 '(
173 SELECT
174 me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track,
3d98c75e 175 tracks.trackid, tracks.cd, tracks.position, tracks.title, tracks.last_updated_on, tracks.last_updated_at,
53c29913 176 artist.artistid, artist.name, artist.rank, artist.charfield
177 FROM (
178 SELECT
179 me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track
180 FROM cd me
181 JOIN artist artist ON artist.artistid = me.artist
182 WHERE ( ( artist.name = ? AND me.year = ? ) )
fcb7fcbb 183 LIMIT ?
53c29913 184 ) me
185 LEFT JOIN track tracks
186 ON tracks.cd = me.cdid
187 JOIN artist artist
188 ON artist.artistid = me.artist
189 WHERE ( ( artist.name = ? AND me.year = ? ) )
53c29913 190 )',
fcb7fcbb 191 [
192 [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'artist.name' } => 'foo' ],
193 [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'me.year' } => 2010 ],
194 [ $ROWS => 15 ],
195 [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'artist.name' } => 'foo' ],
196 [ { sqlt_datatype => 'varchar', sqlt_size => 100, dbic_colname => 'me.year' } => 2010 ],
197 ],
53c29913 198 'No grouping of non-multiplying resultsets',
199);
200
eb58c082 201my $many_one_many_rs = $schema->resultset('CD')->search({}, {
202 prefetch => { tracks => { lyrics => 'lyric_versions' } },
203 rows => 2,
204 order_by => ['lyrics.track_id'],
205});
206
207is_same_sql_bind(
208 $many_one_many_rs->as_query,
209 '(
210 SELECT me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track,
211 tracks.trackid, tracks.cd, tracks.position, tracks.title, tracks.last_updated_on, tracks.last_updated_at,
212 lyrics.lyric_id, lyrics.track_id, lyric_versions.id, lyric_versions.lyric_id, lyric_versions.text
213 FROM (
214 SELECT me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track
215 FROM cd me
216 LEFT JOIN track tracks
217 ON tracks.cd = me.cdid
218 LEFT JOIN lyrics lyrics
219 ON lyrics.track_id = tracks.trackid
220 GROUP BY me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track
221 ORDER BY MIN(lyrics.track_id)
222 LIMIT ?
223 ) me
224 LEFT JOIN track tracks
225 ON tracks.cd = me.cdid
226 LEFT JOIN lyrics lyrics
227 ON lyrics.track_id = tracks.trackid
228 LEFT JOIN lyric_versions lyric_versions
229 ON lyric_versions.lyric_id = lyrics.lyric_id
230 ORDER BY lyrics.track_id
231 )',
232 [
233 [ { sqlt_datatype => 'integer' } => 2 ]
234 ],
235 'Correct SQL on indirectly multiplied orderer',
236);
237
238my $cond_on_multi_ord_by_single = $schema->resultset('CD')->search(
239 {
240 'tracks.position' => { '!=', 1 },
241 },
242 {
243 prefetch => [qw( tracks artist )],
244 order_by => 'artist.name',
245 rows => 1,
246 },
247);
248
249is_same_sql_bind(
250 $cond_on_multi_ord_by_single->as_query,
251 '(
252 SELECT me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track,
253 tracks.trackid, tracks.cd, tracks.position, tracks.title, tracks.last_updated_on, tracks.last_updated_at,
254 artist.artistid, artist.name, artist.rank, artist.charfield
255 FROM (
256 SELECT me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track
257 FROM cd me
258 LEFT JOIN track tracks
259 ON tracks.cd = me.cdid
260 JOIN artist artist
261 ON artist.artistid = me.artist
262 WHERE tracks.position != ?
263 GROUP BY me.cdid, me.artist, me.title, me.year, me.genreid, me.single_track, artist.name
264 ORDER BY artist.name
265 LIMIT ?
266 ) me
267 LEFT JOIN track tracks
268 ON tracks.cd = me.cdid
269 JOIN artist artist
270 ON artist.artistid = me.artist
271 WHERE tracks.position != ?
272 ORDER BY artist.name
273 )',
274 [
275 [ { dbic_colname => "tracks.position", sqlt_datatype => "int" }
276 => 1
277 ],
278 [ { sqlt_datatype => "integer" }
279 => 1
280 ],
281 [ { dbic_colname => "tracks.position", sqlt_datatype => "int" }
282 => 1
283 ],
284 ],
285 'Correct SQl on prefetch with limit of restricting multi ordered by a single'
286);
287
c9d29bb2 288done_testing;