8 use DBIx::Class::_Util 'perlstring';
10 # globally set for the rest of test
11 # the rowparser maker does not order its hashes by default for the miniscule
12 # speed gain. But it does not disable sorting either - for this test
13 # everything will be ordered nicely, and the hash randomization of 5.18
14 # will not trip up anything
16 $Data::Dumper::Sortkeys = 1;
18 my $schema = DBICTest->init_schema(no_deploy => 1);
20 single_track.cd.artist.name
25 ($schema->source ('CD')->_mk_row_parser({
26 inflate_map => $infmap,
30 { single_track => ( ! defined( $_->[0]) )
51 'Simple 1:1 descending non-collapsing parser',
55 single_track.cd.artist.cds.tracks.title
56 single_track.cd.artist.artistid
58 single_track.cd.artist.cds.cdid
64 ($schema->source ('CD')->_mk_row_parser({
65 inflate_map => $infmap,
68 { artist => $_->[5], title => $_->[4], year => $_->[2] },
70 single_track => ( (! defined $_->[0] ) && (! defined $_->[1]) && (! defined $_->[3] ) )
78 { artistid => $_->[1] },
80 cds => ( (! defined $_->[0] ) && ( ! defined $_->[3] ) )
84 tracks => ( ! defined $_->[0] )
85 ? bless ( [{ title => $_->[0] }], __NBC__ )
86 : [{ title => $_->[0] }]
92 tracks => ( ! defined $_->[0] )
93 ? bless ( [{ title => $_->[0] }], __NBC__ )
94 : [{ title => $_->[0] }]
110 { artistid => $_->[1] },
112 cds => ( (! defined $_->[0] ) && ( ! defined $_->[3] ) )
116 tracks => ( ! defined $_->[0] )
117 ? bless ( [{ title => $_->[0] }], __NBC__ )
118 : [{ title => $_->[0] }]
124 tracks => ( ! defined $_->[0] )
125 ? bless ( [{ title => $_->[0] }], __NBC__ )
126 : [{ title => $_->[0] }]
137 '1:1 descending non-collapsing parser terminating with chained 1:M:M',
141 ($schema->source ('CD')->_mk_row_parser({
142 prune_null_branches => 1,
143 inflate_map => $infmap,
146 { artist => $_->[5], title => $_->[4], year => $_->[2] },
148 single_track => ( (! defined $_->[0] ) && (! defined $_->[1]) && (! defined $_->[3] ) ) ? undef : [
155 { artistid => $_->[1] },
157 cds => ( (! defined $_->[0] ) && ( ! defined $_->[3] ) ) ? undef : [
160 tracks => ( ! defined $_->[0] ) ? undef : [
161 { title => $_->[0] },
173 '1:1 descending non-collapsing pruning parser terminating with chained 1:M:M',
177 ($schema->source ('CD')->_mk_row_parser({
179 prune_null_branches => 1,
180 inflate_map => $infmap,
183 artist => $_->[5], title => $_->[4], year => $_->[2],
185 ( single_track => ( (! defined $_->[0] ) && (! defined $_->[1]) && (! defined $_->[3] ) )
192 ( cds => ( (! defined $_->[0] ) && ( ! defined $_->[3] ) )
196 ( tracks => ( ! defined $_->[0] )
198 : { title => $_->[0] }
207 '1:1 descending non-collapsing HRI-direct parser terminating with chained 1:M:M',
213 ($schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} })),
215 -identifying_columns => [ 4, 5 ],
218 -identifying_columns => [ 1, 4, 5 ],
223 -identifying_columns => [ 1, 4, 5 ],
227 -identifying_columns => [ 1, 4, 5 ],
231 -identifying_columns => [ 1, 3, 4, 5 ],
235 -identifying_columns => [ 0, 1, 3, 4, 5 ],
243 'Correct collapse map for 1:1 descending chain terminating with chained 1:M:M'
247 ($schema->source ('CD')->_mk_row_parser({
248 inflate_map => $infmap,
252 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
254 while ($cur_row_data = (
255 ( $rows_pos >= 0 and $_[0][$rows_pos++] )
257 ( $_[1] and $rows_pos = -1 and $_[1]->() )
260 @cur_row_ids{0,1,3,4,5} = (
261 ( $cur_row_data->[0] // "\0NULL\xFF$rows_pos\xFF0\0" ),
262 ( $cur_row_data->[1] // "\0NULL\xFF$rows_pos\xFF1\0" ),
263 ( $cur_row_data->[3] // "\0NULL\xFF$rows_pos\xFF3\0" ),
264 ( $cur_row_data->[4] // "\0NULL\xFF$rows_pos\xFF4\0" ),
265 ( $cur_row_data->[5] // "\0NULL\xFF$rows_pos\xFF5\0" ),
268 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
269 $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} and (unshift @{$_[2]}, $cur_row_data) and last;
271 # the rowdata itself for root node
272 $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} //= $_[0][$result_pos++] = [{ artist => $cur_row_data->[5], title => $cur_row_data->[4], year => $cur_row_data->[2] }];
274 # prefetch data of single_track (placed in root)
275 $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{single_track} //= $collapse_idx[1]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}} = [];
276 defined($cur_row_data->[1]) or bless( $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{single_track}, __NBC__ );
278 # prefetch data of cd (placed in single_track)
279 $collapse_idx[1]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{cd} //= $collapse_idx[2]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}} = [];
281 # prefetch data of artist ( placed in single_track->cd)
282 $collapse_idx[2]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{artist} //= $collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}} = [{ artistid => $cur_row_data->[1] }];
284 # prefetch data of cds (if available)
285 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
287 push @{$collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{cds}}, (
288 $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} = [{ cdid => $cur_row_data->[3] }]
290 defined($cur_row_data->[3]) or bless( $collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{cds}, __NBC__ );
292 # prefetch data of tracks (if available)
293 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
295 push @{$collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{tracks}}, (
296 $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} = [{ title => $cur_row_data->[0] }]
298 defined($cur_row_data->[0]) or bless( $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{tracks}, __NBC__ );
301 $#{$_[0]} = $result_pos - 1;
303 'Same 1:1 descending terminating with chained 1:M:M but with collapse',
307 ($schema->source ('CD')->_mk_row_parser({
308 inflate_map => $infmap,
311 prune_null_branches => 1,
314 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
316 while ($cur_row_data = (
317 ( $rows_pos >= 0 and $_[0][$rows_pos++] )
319 ( $_[1] and $rows_pos = -1 and $_[1]->() )
322 @cur_row_ids{0, 1, 3, 4, 5} = @{$cur_row_data}[0, 1, 3, 4, 5];
324 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
325 $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} and (unshift @{$_[2]}, $cur_row_data) and last;
327 # the rowdata itself for root node
328 $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} //= $_[0][$result_pos++] = { artist => $cur_row_data->[5], title => $cur_row_data->[4], year => $cur_row_data->[2] };
330 # prefetch data of single_track (placed in root)
331 (! defined($cur_row_data->[1]) ) ? $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}{single_track} = undef : do {
332 $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}{single_track} //= $collapse_idx[1]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}};
334 # prefetch data of cd (placed in single_track)
335 $collapse_idx[1]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}{cd} //= $collapse_idx[2]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}};
337 # prefetch data of artist ( placed in single_track->cd)
338 $collapse_idx[2]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}{artist} //= $collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}} = { artistid => $cur_row_data->[1] };
340 # prefetch data of cds (if available)
341 (! defined $cur_row_data->[3] ) ? $collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}{cds} = [] : do {
343 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
345 push @{$collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}{cds}}, (
346 $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} = { cdid => $cur_row_data->[3] }
349 # prefetch data of tracks (if available)
350 ( ! defined $cur_row_data->[0] ) ? $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}{tracks} = [] : do {
352 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
354 push @{$collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}{tracks}}, (
355 $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} = { title => $cur_row_data->[0] }
361 $#{$_[0]} = $result_pos - 1;
363 'Same 1:1 descending terminating with chained 1:M:M but with collapse, HRI-direct',
367 tracks.lyrics.existing_lyric_versions.text
368 existing_single_track.cd.artist.artistid
369 existing_single_track.cd.artist.cds.year
373 existing_single_track.cd.artist.cds.cdid
375 existing_single_track.cd.artist.cds.tracks.title
376 existing_single_track.cd.artist.cds.genreid
377 tracks.lyrics.existing_lyric_versions.lyric_id
381 $schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} }),
383 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
385 existing_single_track => {
386 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
390 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
394 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
398 -identifying_columns => [ 1, 6 ], # existing_single_track.cd.artist.cds.cdid
402 -identifying_columns => [ 1, 6, 8 ], # existing_single_track.cd.artist.cds.cdid, existing_single_track.cd.artist.cds.tracks.title
410 -identifying_columns => [ 1, 5 ], # existing_single_track.cd.artist.artistid, tracks.title
414 -identifying_columns => [ 1, 5, 10 ], # existing_single_track.cd.artist.artistid, tracks.title, tracks.lyrics.existing_lyric_versions.lyric_id
418 existing_lyric_versions => {
419 -identifying_columns => [ 0, 1, 5, 10 ], # tracks.lyrics.existing_lyric_versions.text, existing_single_track.cd.artist.artistid, tracks.title, tracks.lyrics.existing_lyric_versions.lyric_id
424 'Correct collapse map constructed',
428 ($schema->source ('CD')->_mk_row_parser({
429 inflate_map => $infmap,
433 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
435 while ($cur_row_data = (
436 ( $rows_pos >= 0 and $_[0][$rows_pos++] )
438 ( $_[1] and $rows_pos = -1 and $_[1]->() )
441 @cur_row_ids{0, 1, 5, 6, 8, 10} = (
442 $cur_row_data->[0] // "\0NULL\xFF$rows_pos\xFF0\0",
443 $cur_row_data->[1] // "\0NULL\xFF$rows_pos\xFF1\0",
444 $cur_row_data->[5] // "\0NULL\xFF$rows_pos\xFF5\0",
445 $cur_row_data->[6] // "\0NULL\xFF$rows_pos\xFF6\0",
446 $cur_row_data->[8] // "\0NULL\xFF$rows_pos\xFF8\0",
447 $cur_row_data->[10] // "\0NULL\xFF$rows_pos\xFF10\0",
450 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
451 $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{1}} and (unshift @{$_[2]}, $cur_row_data) and last;
453 $collapse_idx[0]{$cur_row_ids{1}} //= $_[0][$result_pos++] = [{ genreid => $cur_row_data->[4], latest_cd => $cur_row_data->[7], year => $cur_row_data->[3] }];
455 $collapse_idx[0]{$cur_row_ids{1}}[1]{existing_single_track} //= $collapse_idx[1]{$cur_row_ids{1}} = [];
456 $collapse_idx[1]{$cur_row_ids{1}}[1]{cd} //= $collapse_idx[2]{$cur_row_ids{1}} = [];
457 $collapse_idx[2]{$cur_row_ids{1}}[1]{artist} //= $collapse_idx[3]{$cur_row_ids{1}} = [{ artistid => $cur_row_data->[1] }];
459 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}} )
461 push @{ $collapse_idx[3]{$cur_row_ids{1}}[1]{cds} }, (
462 $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}} = [{ cdid => $cur_row_data->[6], genreid => $cur_row_data->[9], year => $cur_row_data->[2] }]
464 defined($cur_row_data->[6]) or bless( $collapse_idx[3]{$cur_row_ids{1}}[1]{cds}, __NBC__ );
466 (! $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} )
468 push @{ $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks} }, (
469 $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} = [{ title => $cur_row_data->[8] }]
471 defined($cur_row_data->[8]) or bless( $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks}, __NBC__ );
473 (! $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} )
475 push @{ $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks} }, (
476 $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} = [{ title => $cur_row_data->[5] }]
478 defined($cur_row_data->[5]) or bless( $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks}, __NBC__ );
480 $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics} //= $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} = [];
481 defined($cur_row_data->[10]) or bless( $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics}, __NBC__ );
483 (! $collapse_idx[8]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} )
485 push @{ $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}}[1]{existing_lyric_versions} }, (
486 $collapse_idx[8]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} = [{ lyric_id => $cur_row_data->[10], text => $cur_row_data->[0] }]
490 $#{$_[0]} = $result_pos - 1;
492 'Multiple has_many on multiple branches torture test',
496 ($schema->source ('CD')->_mk_row_parser({
497 inflate_map => $infmap,
499 prune_null_branches => 1,
502 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
504 while ($cur_row_data = (
505 ( $rows_pos >= 0 and $_[0][$rows_pos++] )
507 ( $_[1] and $rows_pos = -1 and $_[1]->() )
510 @cur_row_ids{( 0, 1, 5, 6, 8, 10 )} = @{$cur_row_data}[( 0, 1, 5, 6, 8, 10 )];
512 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
513 $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{1}} and (unshift @{$_[2]}, $cur_row_data) and last;
515 $collapse_idx[0]{$cur_row_ids{1}} //= $_[0][$result_pos++] = [{ genreid => $cur_row_data->[4], latest_cd => $cur_row_data->[7], year => $cur_row_data->[3] }];
517 $collapse_idx[0]{$cur_row_ids{1}}[1]{existing_single_track} //= $collapse_idx[1]{$cur_row_ids{1}} = [];
518 $collapse_idx[1]{$cur_row_ids{1}}[1]{cd} //= $collapse_idx[2]{$cur_row_ids{1}} = [];
519 $collapse_idx[2]{$cur_row_ids{1}}[1]{artist} //= $collapse_idx[3]{$cur_row_ids{1}} = [{ artistid => $cur_row_data->[1] }];
521 (! defined($cur_row_data->[6])) ? $collapse_idx[3]{$cur_row_ids{1}}[1]{cds} = [] : do {
522 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}} )
524 push @{ $collapse_idx[3]{$cur_row_ids{1}}[1]{cds} }, (
525 $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}} = [{ cdid => $cur_row_data->[6], genreid => $cur_row_data->[9], year => $cur_row_data->[2] }]
528 (! defined($cur_row_data->[8]) ) ? $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks} = [] : do {
530 (! $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} )
532 push @{ $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks} }, (
533 $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} = [{ title => $cur_row_data->[8] }]
538 (! defined($cur_row_data->[5]) ) ? $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks} = [] : do {
540 (! $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} )
542 push @{ $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks} }, (
543 $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} = [{ title => $cur_row_data->[5] }]
546 (! defined($cur_row_data->[10]) ) ? $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics} = [] : do {
548 $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics} //= $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} = [];
550 (! $collapse_idx[8]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} )
552 push @{ $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}}[1]{existing_lyric_versions} }, (
553 $collapse_idx[8]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} = [{ lyric_id => $cur_row_data->[10], text => $cur_row_data->[0] }]
559 $#{$_[0]} = $result_pos - 1;
561 'Multiple has_many on multiple branches with branch pruning torture test',
565 'single_track.trackid', # (0) definitive link to root from 1:1:1:1:M:M chain
566 'year', # (1) non-unique
567 'tracks.cd', # (2) \ together both uniqueness for second multirel
568 'tracks.title', # (3) / and definitive link back to root
569 'single_track.cd.artist.cds.cdid', # (4) to give uniquiness to ...tracks.title below
570 'single_track.cd.artist.cds.year', # (5) non-unique
571 'single_track.cd.artist.artistid', # (6) uniqufies entire parental chain
572 'single_track.cd.artist.cds.genreid', # (7) nullable
573 'single_track.cd.artist.cds.tracks.title',# (8) unique when combined with ...cds.cdid above
577 $schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} }),
579 -identifying_columns => [],
580 -identifying_columns_variants => [
584 -identifying_columns => [ 0 ],
588 -identifying_columns => [ 0 ],
591 -identifying_columns => [ 0 ],
594 -identifying_columns => [ 0, 4 ],
597 -identifying_columns => [ 0, 4, 8 ],
605 -identifying_columns => [ 2, 3 ],
609 'Correct underdefined root collapse map constructed'
613 ($schema->source ('CD')->_mk_row_parser({
614 inflate_map => $infmap,
618 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
620 while ($cur_row_data = (
621 ( $rows_pos >= 0 and $_[0][$rows_pos++] )
623 ( $_[1] and $rows_pos = -1 and $_[1]->() )
626 @cur_row_ids{( 0, 2, 3, 4, 8 )} = (
627 $cur_row_data->[0] // "\0NULL\xFF$rows_pos\xFF0\0",
628 $cur_row_data->[2] // "\0NULL\xFF$rows_pos\xFF2\0",
629 $cur_row_data->[3] // "\0NULL\xFF$rows_pos\xFF3\0",
630 $cur_row_data->[4] // "\0NULL\xFF$rows_pos\xFF4\0",
631 $cur_row_data->[8] // "\0NULL\xFF$rows_pos\xFF8\0",
634 # cache expensive set of ops in a non-existent rowid slot
636 ( ( defined $cur_row_data->[0] ) && (join "\xFF", q{}, $cur_row_ids{0}, q{} ))
638 ( ( defined $cur_row_data->[2] ) && (join "\xFF", q{}, $cur_row_ids{2}, q{} ))
643 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
644 $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{10}} and (unshift @{$_[2]}, $cur_row_data) and last;
646 $collapse_idx[0]{$cur_row_ids{10}} //= $_[0][$result_pos++] = [{ year => $$cur_row_data[1] }];
648 $collapse_idx[0]{$cur_row_ids{10}}[1]{single_track} //= ($collapse_idx[1]{$cur_row_ids{0}} = [{ trackid => $cur_row_data->[0] }]);
649 defined($cur_row_data->[0]) or bless ( $collapse_idx[0]{$cur_row_ids{10}}[1]{single_track}, __NBC__ );
651 $collapse_idx[1]{$cur_row_ids{0}}[1]{cd} //= $collapse_idx[2]{$cur_row_ids{0}} = [];
653 $collapse_idx[2]{$cur_row_ids{0}}[1]{artist} //= ($collapse_idx[3]{$cur_row_ids{0}} = [{ artistid => $cur_row_data->[6] }]);
655 (! $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}} )
657 push @{$collapse_idx[3]{$cur_row_ids{0}}[1]{cds}}, (
658 $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}} = [{ cdid => $cur_row_data->[4], genreid => $cur_row_data->[7], year => $cur_row_data->[5] }]
660 defined($cur_row_data->[4]) or bless ( $collapse_idx[3]{$cur_row_ids{0}}[1]{cds}, __NBC__ );
662 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} )
664 push @{$collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}[1]{tracks}}, (
665 $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} = [{ title => $cur_row_data->[8] }]
667 defined($cur_row_data->[8]) or bless ( $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}[1]{tracks}, __NBC__ );
669 (! $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} )
671 push @{$collapse_idx[0]{$cur_row_ids{10}}[1]{tracks}}, (
672 $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} = [{ cd => $$cur_row_data[2], title => $cur_row_data->[3] }]
674 defined($cur_row_data->[2]) or bless ( $collapse_idx[0]{$cur_row_ids{10}}[1]{tracks}, __NBC__ );
677 $#{$_[0]} = $result_pos - 1;
679 'Multiple has_many on multiple branches with underdefined root torture test',
683 ($schema->source ('CD')->_mk_row_parser({
684 inflate_map => $infmap,
687 prune_null_branches => 1,
690 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
692 while ($cur_row_data = (
693 ( $rows_pos >= 0 and $_[0][$rows_pos++] )
695 ( $_[1] and $rows_pos = -1 and $_[1]->() )
698 # do not care about nullability here
699 @cur_row_ids{( 0, 2, 3, 4, 8 )} = @{$cur_row_data}[( 0, 2, 3, 4, 8 )];
701 # cache expensive set of ops in a non-existent rowid slot
703 ( ( defined $cur_row_data->[0] ) && (join "\xFF", q{}, $cur_row_ids{0}, q{} ))
705 ( ( defined $cur_row_data->[2] ) && (join "\xFF", q{}, $cur_row_ids{2}, q{} ))
710 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
711 $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{10}} and (unshift @{$_[2]}, $cur_row_data) and last;
713 $collapse_idx[0]{$cur_row_ids{10}} //= $_[0][$result_pos++] = { year => $$cur_row_data[1] };
715 (! defined $cur_row_data->[0] ) ? $collapse_idx[0]{$cur_row_ids{10}}{single_track} = undef : do {
717 $collapse_idx[0]{$cur_row_ids{10}}{single_track} //= ($collapse_idx[1]{$cur_row_ids{0}} = { trackid => $$cur_row_data[0] });
719 $collapse_idx[1]{$cur_row_ids{0}}{cd} //= $collapse_idx[2]{$cur_row_ids{0}};
721 $collapse_idx[2]{$cur_row_ids{0}}{artist} //= ($collapse_idx[3]{$cur_row_ids{0}} = { artistid => $$cur_row_data[6] });
723 (! defined $cur_row_data->[4] ) ? $collapse_idx[3]{$cur_row_ids{0}}{cds} = [] : do {
725 (! $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}} )
727 push @{$collapse_idx[3]{$cur_row_ids{0}}{cds}}, (
728 $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}} = { cdid => $$cur_row_data[4], genreid => $$cur_row_data[7], year => $$cur_row_data[5] }
731 (! defined $cur_row_data->[8] ) ? $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}{tracks} = [] : do {
733 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} )
735 push @{$collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}{tracks}}, (
736 $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} = { title => $$cur_row_data[8] }
742 (! defined $cur_row_data->[2] ) ? $collapse_idx[0]{$cur_row_ids{10}}{tracks} = [] : do {
743 (! $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} )
745 push @{$collapse_idx[0]{$cur_row_ids{10}}{tracks}}, (
746 $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} = { cd => $$cur_row_data[2], title => $$cur_row_data[3] }
751 $#{$_[0]} = $result_pos - 1;
753 'Multiple has_many on multiple branches with underdefined root, HRI-direct torture test',
757 ($schema->source ('Owners')->_mk_row_parser({
758 inflate_map => [qw( books.title books.owner )],
760 prune_null_branches => 1,
763 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids );
765 while ($cur_row_data = (
766 ( $rows_pos >= 0 and $_[0][$rows_pos++] )
768 ( $_[1] and $rows_pos = -1 and $_[1]->() )
771 @cur_row_ids{0,1} = @{$cur_row_data}[0,1];
774 ( ( defined $cur_row_data->[1] ) && (join "\xFF", q{}, $cur_row_ids{1}, q{} ))
779 $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{3}} and (unshift @{$_[2]}, $cur_row_data) and last;
781 # empty data for the root node
782 $collapse_idx[0]{$cur_row_ids{3}} //= $_[0][$result_pos++] = [];
784 ( ! defined $cur_row_data->[0] ) ? $collapse_idx[0]{$cur_row_ids{3}}[1]{"books"} = [] : do {
785 ( ! $collapse_idx[1]{$cur_row_ids{0}} )
787 push @{$collapse_idx[0]{$cur_row_ids{3}}[1]{books}},
788 $collapse_idx[1]{$cur_row_ids{0}} = [ { owner => $cur_row_data->[1], title => $cur_row_data->[0] } ]
792 $#{$_[0]} = $result_pos - 1; # truncate the passed in array to where we filled it with results
794 'Non-premultiplied implicit collapse with missing join columns',
800 sub is_same_src { SKIP: {
802 skip "Skipping comparison of unicode-posioned source", 1
803 if DBIx::Class::_ENV_::STRESSTEST_UTF8_UPGRADE_GENERATED_COLLAPSER_SOURCE;
805 $deparser ||= B::Deparse->new;
806 local $Test::Builder::Level = $Test::Builder::Level + 1;
808 my ($got, $expect) = @_;
810 skip "Not testing equality of source containing defined-or operator on this perl $]", 1
811 if ($] < 5.010 and$expect =~ m!\Q//=!);
813 $expect =~ s/__NBC__/perlstring($DBIx::Class::ResultSource::RowParser::Util::null_branch_class)/ge;
815 $expect = " { use strict; use warnings FATAL => 'uninitialized';\n$expect\n }";
817 my @normalized = map {
818 my $cref = eval "sub { $_ }" or do {
819 fail "Coderef does not compile!\n\n$@\n\n$_";
822 $deparser->coderef2text($cref);
825 &is (@normalized, $_[2]||() ) or do {
826 eval { require Test::Differences }
827 ? &Test::Differences::eq_or_diff( @normalized, $_[2]||() )
828 : note ("Original sources:\n\n$got\n\n$expect\n")