e6bedc2b148b136e0d1c20458a4967b7bb3acb75
[dbsrgits/DBIx-Class.git] / t / resultset / inflate_result_api.t
1 use strict;
2 use warnings;
3 no warnings 'exiting';
4
5 use Test::More;
6 use Test::Deep;
7 use lib qw(t/lib);
8 use DBICTest;
9
10 my $schema = DBICTest->init_schema(no_populate => 1);
11
12 $schema->resultset('Artist')->create({ name => 'JMJ', cds => [{
13   title => 'Magnetic Fields',
14   year => 1981,
15   genre => { name => 'electro' },
16   tracks => [
17     { title => 'm1' },
18     { title => 'm2' },
19     { title => 'm3' },
20     { title => 'm4' },
21   ],
22 } ] });
23
24 $schema->resultset('CD')->create({
25   title => 'Equinoxe',
26   year => 1978,
27   artist => { name => 'JMJ' },
28   genre => { name => 'electro' },
29   tracks => [
30     { title => 'e1' },
31     { title => 'e2' },
32     { title => 'e3' },
33   ],
34   single_track => {
35     title => 'o1',
36     cd => {
37       title => 'Oxygene',
38       year => 1976,
39       artist => { name => 'JMJ' },
40       tracks => [
41         { title => 'o2', position => 2},  # the position should not be needed here, bug in MC
42       ],
43     },
44   },
45 });
46
47 $schema->resultset('CD')->create({ artist => 1, year => 1977, title => "fuzzy_1" });
48
49 $schema->resultset('Artist')->create({ name => "${_}_cdless" })
50   for (qw( Z A ));
51
52 # subs at the end of the test refer to this
53 my $native_inflator;
54
55 ### TESTS START
56 # run entire test twice - with and without "native inflator"
57 INFTYPE: for ('', '(native inflator)') {
58
59   $native_inflator = $_;
60
61   cmp_structures(
62     rs_contents( $schema->resultset ('CD')->search_rs ({}, {
63       prefetch => { single_track => { cd => 'artist' } },
64       order_by => 'me.cdid',
65     }) ),
66     [
67       [
68         { cdid => 1, single_track => undef, artist => 1, genreid => 1, year => 1981, title => "Magnetic Fields" },
69         { single_track => code(sub { null_branch ( \@_, [
70           { trackid => undef, title => undef, position => undef, cd => undef, last_updated_at => undef, last_updated_on => undef },
71           {  cd => code(sub { null_branch ( \@_, [
72             { cdid => undef, single_track => undef, artist => undef, genreid => undef, year => undef, title => undef },
73             {
74               artist => code(sub { null_branch ( \@_, [
75                 { artistid => undef, name => undef, charfield => undef, rank => undef }
76               ] ) } )
77             }
78           ] ) } ) }
79         ] ) } ) }
80       ],
81       [
82         { cdid => 2, single_track => undef, artist => 1, genreid => undef, year => 1976, title => "Oxygene" },
83         { single_track => code(sub { null_branch ( \@_, [
84           { trackid => undef, title => undef, position => undef, cd => undef, last_updated_at => undef, last_updated_on => undef },
85           {  cd => code(sub { null_branch ( \@_, [
86             { cdid => undef, single_track => undef, artist => undef, genreid => undef, year => undef, title => undef },
87             {
88               artist => code(sub { null_branch ( \@_, [
89                 { artistid => undef, name => undef, charfield => undef, rank => undef }
90               ] ) } )
91             }
92           ] ) } ) }
93         ] ) } ) }
94       ],
95       [
96         { cdid => 3, single_track => 6, artist => 1, genreid => 1, year => 1978, title => "Equinoxe" },
97         { single_track => [
98           { trackid => 6, title => 'o1', position => 1, cd => 2, last_updated_at => undef, last_updated_on => undef },
99           {  cd => [
100             { cdid => 2, single_track => undef, artist => 1, genreid => undef, year => 1976, title => "Oxygene" },
101             {
102               artist => [
103                 { artistid => 1, name => 'JMJ', charfield => undef, rank => 13 }
104               ]
105             }
106           ] }
107         ] }
108       ],
109       [
110         { cdid => 4, single_track => undef, artist => 1, genreid => undef, year => 1977, title => "fuzzy_1" },
111         { single_track => code(sub { null_branch ( \@_, [
112           { trackid => undef, title => undef, position => undef, cd => undef, last_updated_at => undef, last_updated_on => undef },
113           {  cd => code(sub { null_branch ( \@_, [
114             { cdid => undef, single_track => undef, artist => undef, genreid => undef, year => undef, title => undef },
115             {
116               artist => code(sub { null_branch ( \@_, [
117                 { artistid => undef, name => undef, charfield => undef, rank => undef }
118               ] ) } )
119             }
120           ] ) } ) }
121         ] ) } ) }
122       ],
123     ],
124     "Simple 1:1 descend with classic prefetch $native_inflator"
125   );
126
127   cmp_structures(
128     rs_contents( $schema->resultset ('CD')->search_rs ({}, {
129       join => { single_track => { cd => 'artist' } },
130       columns => [
131         { 'year'                                    => 'me.year' },
132         { 'genreid'                                 => 'me.genreid' },
133         { 'single_track.cd.artist.artistid'         => 'artist.artistid' },
134         { 'title'                                   => 'me.title' },
135         { 'artist'                                  => 'me.artist' },
136       ],
137       order_by => 'me.cdid',
138     }) ),
139     [
140       [
141         { artist => 1, genreid => 1, year => 1981, title => "Magnetic Fields" },
142         { single_track => code(sub { null_branch ( \@_, [
143           undef,
144           {  cd => [
145             undef,
146             {
147               artist => [
148                 { artistid => undef }
149               ]
150             }
151           ] }
152         ] ) } ) }
153       ],
154       [
155         { artist => 1, genreid => undef, year => 1976, title => "Oxygene" },
156         { single_track => code(sub { null_branch ( \@_, [
157           undef,
158           {  cd => [
159             undef,
160             {
161               artist => [
162                 { artistid => undef }
163               ]
164             }
165           ] }
166         ] ) } ) }
167       ],
168       [
169         { artist => 1, genreid => 1, year => 1978, title => "Equinoxe" },
170         { single_track => [
171           undef,
172           {  cd => [
173             undef,
174             {
175               artist => [
176                 { artistid => 1 }
177               ]
178             }
179           ] }
180         ] }
181       ],
182       [
183         { artist => 1, genreid => undef, year => 1977, title => "fuzzy_1" },
184         { single_track => code(sub { null_branch ( \@_, [
185           undef,
186           {  cd => [
187             undef,
188             {
189               artist => [
190                 { artistid => undef }
191               ]
192             }
193           ] }
194         ] ) } ) }
195       ],
196     ],
197     "Simple 1:1 descend with missing selectors $native_inflator",
198   );
199
200   cmp_structures(
201     rs_contents( $schema->resultset ('CD')->search_rs ({}, {
202       prefetch => [ { single_track => { cd => { artist => { cds => 'tracks' } } } } ],
203       order_by => [qw/me.cdid tracks.trackid/],
204     }) ),
205     [
206       [
207         { cdid => 1, single_track => undef, artist => 1, genreid => 1, year => 1981, title => "Magnetic Fields" },
208         { single_track => code(sub { null_collapsed_branch ( \@_, [
209           { trackid => undef, title => undef, position => undef, cd => undef, last_updated_at => undef, last_updated_on => undef },
210           {  cd => [
211             { cdid => undef, single_track => undef, artist => undef, genreid => undef, year => undef, title => undef },
212             {
213               artist => [
214                 { artistid => undef, name => undef, charfield => undef, rank => undef },
215                 { cds => code(sub { null_collapsed_branch ( \@_, [ [
216                   { cdid => undef, single_track => undef, artist => undef, genreid => undef, year => undef, title => undef },
217                   { tracks => code(sub { null_collapsed_branch ( \@_, [ [
218                     { trackid => undef, title => undef, position => undef, cd => undef, last_updated_at => undef, last_updated_on => undef },
219                   ] ] ) } ) },
220                 ] ] ) } ) },
221               ],
222             },
223           ] },
224         ] ) } ) },
225       ],
226       [
227         { cdid => 2, single_track => undef, artist => 1, genreid => undef, year => 1976, title => "Oxygene" },
228         { single_track => code(sub { null_collapsed_branch ( \@_, [
229           { trackid => undef, title => undef, position => undef, cd => undef, last_updated_at => undef, last_updated_on => undef },
230           {  cd => [
231             { cdid => undef, single_track => undef, artist => undef, genreid => undef, year => undef, title => undef },
232             {
233               artist => [
234                 { artistid => undef, name => undef, charfield => undef, rank => undef },
235                 { cds => code(sub { null_collapsed_branch ( \@_, [ [
236                   { cdid => undef, single_track => undef, artist => undef, genreid => undef, year => undef, title => undef },
237                   { tracks => code(sub { null_collapsed_branch ( \@_, [ [
238                     { trackid => undef, title => undef, position => undef, cd => undef, last_updated_at => undef, last_updated_on => undef },
239                   ] ] ) } ) },
240                 ] ] ) } ) },
241               ],
242             },
243           ] },
244         ] ) } ) },
245       ],
246       [
247         { cdid => 3, single_track => 6, artist => 1, genreid => 1, year => 1978, title => "Equinoxe" },
248         { single_track => [
249           { trackid => 6, title => 'o1', position => 1, cd => 2, last_updated_at => undef, last_updated_on => undef },
250           {  cd => [
251             { cdid => 2, single_track => undef, artist => 1, genreid => undef, year => 1976, title => "Oxygene" },
252             {
253               artist => [
254                 { artistid => 1, name => 'JMJ', charfield => undef, rank => 13 },
255                 { cds => [
256                   [
257                     { cdid => 4, single_track => undef, artist => 1, genreid => undef, year => 1977, title => "fuzzy_1" },
258                     { tracks => code(sub { null_collapsed_branch ( \@_, [
259                       [ { trackid => undef, title => undef, position => undef, cd => undef, last_updated_at => undef, last_updated_on => undef } ],
260                     ] ) } ) },
261                   ],
262                   [
263                     { cdid => 1, single_track => undef, artist => 1, genreid => 1, year => 1981, title => "Magnetic Fields" },
264                     { tracks => [
265                       [ { trackid => 1, title => 'm1', position => 1, cd => 1, last_updated_at => undef, last_updated_on => undef } ],
266                       [ { trackid => 2, title => 'm2', position => 2, cd => 1, last_updated_at => undef, last_updated_on => undef } ],
267                       [ { trackid => 3, title => 'm3', position => 3, cd => 1, last_updated_at => undef, last_updated_on => undef } ],
268                       [ { trackid => 4, title => 'm4', position => 4, cd => 1, last_updated_at => undef, last_updated_on => undef } ],
269                     ]},
270                   ],
271                   [
272                     { cdid => 2, single_track => undef, artist => 1, genreid => undef, year => 1976, title => "Oxygene" },
273                     { tracks => [
274                       [ { trackid => 5, title => 'o2', position => 2, cd => 2, last_updated_at => undef, last_updated_on => undef } ],
275                       [ { trackid => 6, title => 'o1', position => 1, cd => 2, last_updated_at => undef, last_updated_on => undef } ],
276                     ]},
277                   ],
278                   [
279                     { cdid => 3, single_track => 6, artist => 1, genreid => 1, year => 1978, title => "Equinoxe" },
280                     { tracks => [
281                       [ { trackid => 7, title => 'e1', position => 1, cd => 3, last_updated_at => undef, last_updated_on => undef } ],
282                       [ { trackid => 8, title => 'e2', position => 2, cd => 3, last_updated_at => undef, last_updated_on => undef } ],
283                       [ { trackid => 9, title => 'e3', position => 3, cd => 3, last_updated_at => undef, last_updated_on => undef } ],
284                     ]},
285                   ],
286                 ]},
287               ]
288             }
289           ] }
290         ] }
291       ],
292       [
293         { cdid => 4, single_track => undef, artist => 1, genreid => undef, year => 1977, title => "fuzzy_1" },
294         { single_track => code(sub { null_collapsed_branch ( \@_, [
295           { trackid => undef, title => undef, position => undef, cd => undef, last_updated_at => undef, last_updated_on => undef },
296           {  cd => [
297             { cdid => undef, single_track => undef, artist => undef, genreid => undef, year => undef, title => undef },
298             {
299               artist => [
300                 { artistid => undef, name => undef, charfield => undef, rank => undef },
301                 { cds => code(sub { null_collapsed_branch ( \@_, [ [
302                   { cdid => undef, single_track => undef, artist => undef, genreid => undef, year => undef, title => undef },
303                   { tracks => code(sub { null_collapsed_branch ( \@_, [ [
304                     { trackid => undef, title => undef, position => undef, cd => undef, last_updated_at => undef, last_updated_on => undef },
305                   ] ] ) } ) },
306                 ] ] ) } ) },
307               ],
308             },
309           ] },
310         ] ) } ) },
311       ],
312     ],
313     "Collapsing 1:1 ending in chained has_many with classic prefetch $native_inflator",
314   );
315
316   cmp_structures (
317     rs_contents( $schema->resultset ('Artist')->search_rs ({}, {
318       join => { cds => 'tracks' },
319       '+columns' => [
320         (map { "cds.$_" } $schema->source('CD')->columns),
321         (map { +{ "cds.tracks.$_" => "tracks.$_" } } $schema->source('Track')->columns),
322       ],
323       order_by => [qw/cds.cdid tracks.trackid me.name/],
324     }) ),
325     [
326       [
327         { artistid => 3, name => 'A_cdless', charfield => undef, rank => 13 },
328         { cds => code(sub { null_branch ( \@_, [
329           { cdid => undef, single_track => undef, artist => undef, genreid => undef, year => undef, title => undef },
330           { tracks => code(sub { null_branch ( \@_, [
331             { trackid => undef, title => undef, position => undef, cd => undef, last_updated_at => undef, last_updated_on => undef },
332           ] ) } ) },
333         ] ) } ) },
334       ],
335       [
336         { artistid => 2, name => 'Z_cdless', charfield => undef, rank => 13 },
337         { cds => code(sub { null_branch ( \@_, [
338           { cdid => undef, single_track => undef, artist => undef, genreid => undef, year => undef, title => undef },
339           { tracks => code(sub { null_branch ( \@_, [
340             { trackid => undef, title => undef, position => undef, cd => undef, last_updated_at => undef, last_updated_on => undef },
341           ] ) } ) },
342         ] ) } ) },
343       ],
344       [
345         { artistid => 1, name => 'JMJ', charfield => undef, rank => 13 },
346         { cds => [
347           { cdid => 1, single_track => undef, artist => 1, genreid => 1, year => 1981, title => "Magnetic Fields" },
348           { tracks => [
349             { trackid => 1, title => 'm1', position => 1, cd => 1, last_updated_at => undef, last_updated_on => undef },
350           ]},
351         ]},
352       ],
353       [
354         { artistid => 1, name => 'JMJ', charfield => undef, rank => 13 },
355         { cds => [
356           { cdid => 1, single_track => undef, artist => 1, genreid => 1, year => 1981, title => "Magnetic Fields" },
357           { tracks => [
358             { trackid => 2, title => 'm2', position => 2, cd => 1, last_updated_at => undef, last_updated_on => undef },
359           ]},
360         ]},
361       ],
362       [
363         { artistid => 1, name => 'JMJ', charfield => undef, rank => 13 },
364         { cds => [
365           { cdid => 1, single_track => undef, artist => 1, genreid => 1, year => 1981, title => "Magnetic Fields" },
366           { tracks => [
367             { trackid => 3, title => 'm3', position => 3, cd => 1, last_updated_at => undef, last_updated_on => undef },
368           ]},
369         ]},
370       ],
371       [
372         { artistid => 1, name => 'JMJ', charfield => undef, rank => 13 },
373         { cds => [
374           { cdid => 1, single_track => undef, artist => 1, genreid => 1, year => 1981, title => "Magnetic Fields" },
375           { tracks => [
376             { trackid => 4, title => 'm4', position => 4, cd => 1, last_updated_at => undef, last_updated_on => undef },
377           ]},
378         ]},
379       ],
380       [
381         { artistid => 1, name => 'JMJ', charfield => undef, rank => 13 },
382         { cds => [
383           { cdid => 2, single_track => undef, artist => 1, genreid => undef, year => 1976, title => "Oxygene" },
384           { tracks => [
385             { trackid => 5, title => 'o2', position => 2, cd => 2, last_updated_at => undef, last_updated_on => undef },
386           ]},
387         ]},
388       ],
389       [
390         { artistid => 1, name => 'JMJ', charfield => undef, rank => 13 },
391         { cds => [
392           { cdid => 2, single_track => undef, artist => 1, genreid => undef, year => 1976, title => "Oxygene" },
393           { tracks => [
394             { trackid => 6, title => 'o1', position => 1, cd => 2, last_updated_at => undef, last_updated_on => undef },
395           ]},
396         ]},
397       ],
398       [
399         { artistid => 1, name => 'JMJ', charfield => undef, rank => 13 },
400         { cds => [
401           { cdid => 3, single_track => 6, artist => 1, genreid => 1, year => 1978, title => "Equinoxe" },
402           { tracks => [
403             { trackid => 7, title => 'e1', position => 1, cd => 3, last_updated_at => undef, last_updated_on => undef },
404           ]},
405         ]},
406       ],
407       [
408         { artistid => 1, name => 'JMJ', charfield => undef, rank => 13 },
409         { cds => [
410           { cdid => 3, single_track => 6, artist => 1, genreid => 1, year => 1978, title => "Equinoxe" },
411           { tracks => [
412             { trackid => 8, title => 'e2', position => 2, cd => 3, last_updated_at => undef, last_updated_on => undef },
413           ]},
414         ]},
415       ],
416       [
417         { artistid => 1, name => 'JMJ', charfield => undef, rank => 13 },
418         { cds => [
419           { cdid => 3, single_track => 6, artist => 1, genreid => 1, year => 1978, title => "Equinoxe" },
420           { tracks => [
421             { trackid => 9, title => 'e3', position => 3, cd => 3, last_updated_at => undef, last_updated_on => undef },
422           ]},
423         ]},
424       ],
425       [
426         { artistid => 1, name => 'JMJ', charfield => undef, rank => 13 },
427         { cds => [
428           { cdid => 4, single_track => undef, artist => 1, genreid => undef, year => 1977, title => "fuzzy_1" },
429           { tracks => code(sub { null_branch ( \@_, [
430             { trackid => undef, title => undef, position => undef, cd => undef, last_updated_at => undef, last_updated_on => undef },
431           ] ) } ) },
432         ]},
433       ],
434     ],
435     "Non-Collapsing chained has_many $native_inflator",
436   );
437
438   cmp_structures (
439     rs_contents( $schema->resultset ('Artist')->search_rs ({}, {
440       collapse => 1,
441       join => 'cds',
442       columns => [qw( cds.title cds.artist )],
443       order_by => [qw( me.name cds.title )],
444     }) ),
445     [
446       [
447         undef,
448         { cds => code(sub { null_collapsed_branch ( \@_, [
449           [ { artist => undef, title => undef } ]
450         ] ) } ) },
451       ],
452       [
453         undef,
454         { cds => [
455           [ { artist => 1, title => "Equinoxe" } ],
456           [ { artist => 1, title => "Magnetic Fields" } ],
457           [ { artist => 1, title => "Oxygene" } ],
458           [ { artist => 1, title => "fuzzy_1" } ],
459         ] }
460       ],
461       [
462         undef,
463         { cds => code(sub { null_collapsed_branch ( \@_, [
464           [ { artist => undef, title => undef } ]
465         ] ) } ) },
466       ],
467     ],
468     "Expected output of collapsing 1:M with empty root selection $native_inflator",
469   );
470 }
471
472 sub null_branch {
473   cmp_deeply(
474     $_[0][0],
475     $native_inflator ? undef : bless( $_[1], $DBIx::Class::ResultSource::RowParser::Util::null_branch_class ),
476   );
477 }
478 sub null_collapsed_branch {
479   cmp_deeply(
480     $_[0][0],
481     $native_inflator ? [] : bless( $_[1], $DBIx::Class::ResultSource::RowParser::Util::null_branch_class ),
482   );
483 }
484
485 {
486   package DBICTest::_IRCapture;
487   sub inflate_result { [@_[2,3]] };
488 }
489
490 sub rs_contents {
491   my $rs = shift;
492   $rs->result_class('DBICTest::_IRCapture');
493   die 'eeeeek - preprocessed $rs' if defined $rs->{_result_inflator}{is_core_row};
494   $rs->{_result_inflator}{is_core_row} = 1 if $native_inflator;
495   [$rs->all],
496 }
497
498 sub cmp_structures {
499   my ($left, $right, $msg) = @_;
500
501   local $Test::Builder::Level = $Test::Builder::Level + 1;
502   cmp_deeply($left, $right, $msg||()) or next INFTYPE;
503 }
504
505 {
506   package DBICTest::_DoubleResult;
507
508   sub inflate_result {
509     my $class = shift;
510     return map { DBIx::Class::ResultClass::HashRefInflator->inflate_result(@_) } (1,2);
511   }
512 }
513
514 my $oxygene_rs = $schema->resultset('CD')->search({ 'me.title' => 'Oxygene' });
515
516 is_deeply(
517   [ $oxygene_rs->search({}, { result_class => 'DBICTest::_DoubleResult' })->all ],
518   [ ({ $oxygene_rs->single->get_columns }) x 2 ],
519 );
520
521 is_deeply(
522   [ $oxygene_rs->search({}, {
523     result_class => 'DBICTest::_DoubleResult', prefetch => [qw(artist tracks)],
524     order_by => [qw(me.cdid tracks.title)],
525   })->all ],
526   [ (@{$oxygene_rs->search({}, {
527     prefetch=> [qw(artist tracks)],
528     order_by => [qw(me.cdid tracks.title)],
529   })->all_hri}) x 2 ],
530 );
531
532 done_testing;