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 = (
261 ( ($rows_pos = -1), undef )
265 ( $_[1] and $_[1]->() )
268 ( @cur_row_ids{0,1,3,4,5} = (
269 ( $cur_row_data->[0] // "\0NULL\xFF$rows_pos\xFF0\0" ),
270 ( $cur_row_data->[1] // "\0NULL\xFF$rows_pos\xFF1\0" ),
271 ( $cur_row_data->[3] // "\0NULL\xFF$rows_pos\xFF3\0" ),
272 ( $cur_row_data->[4] // "\0NULL\xFF$rows_pos\xFF4\0" ),
273 ( $cur_row_data->[5] // "\0NULL\xFF$rows_pos\xFF5\0" ),
276 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
277 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} and (unshift @{$_[2]}, $cur_row_data) and last ),
279 # the rowdata itself for root node
280 ( $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] }] ),
282 # prefetch data of single_track (placed in root)
283 ( $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}} = [] ),
284 ( defined($cur_row_data->[1]) or bless( $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{single_track}, __NBC__ ) ),
286 # prefetch data of cd (placed in single_track)
287 ( $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}} = [] ),
289 # prefetch data of artist ( placed in single_track->cd)
290 ( $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] }] ),
292 # prefetch data of cds (if available)
294 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
296 push @{$collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{cds}}, (
297 $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} = [{ cdid => $cur_row_data->[3] }]
300 ( 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__ ) ),
302 # prefetch data of tracks (if available)
304 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
306 push @{$collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{tracks}}, (
307 $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] }]
310 ( 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__ ) ),
313 $#{$_[0]} = $result_pos - 1;
315 'Same 1:1 descending terminating with chained 1:M:M but with collapse',
319 ($schema->source ('CD')->_mk_row_parser({
320 inflate_map => $infmap,
323 prune_null_branches => 1,
326 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
328 while ($cur_row_data = (
335 ( ($rows_pos = -1), undef )
339 ( $_[1] and $_[1]->() )
342 ( @cur_row_ids{0, 1, 3, 4, 5} = @{$cur_row_data}[0, 1, 3, 4, 5] ),
344 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
345 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} and (unshift @{$_[2]}, $cur_row_data) and last ),
347 # the rowdata itself for root node
348 ( $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] } ),
350 # prefetch data of single_track (placed in root)
351 ( (! defined($cur_row_data->[1]) ) ? $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}{single_track} = undef : do {
352 ( $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}} ),
354 # prefetch data of cd (placed in single_track)
355 ( $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}} ),
357 # prefetch data of artist ( placed in single_track->cd)
358 ( $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] } ),
360 # prefetch data of cds (if available)
361 ( (! defined $cur_row_data->[3] ) ? $collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}{cds} = [] : do {
364 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
366 push @{$collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}{cds}}, (
367 $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} = { cdid => $cur_row_data->[3] }
371 # prefetch data of tracks (if available)
372 (( ! 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 {
375 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
377 push @{$collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}{tracks}}, (
378 $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] }
385 $#{$_[0]} = $result_pos - 1;
387 'Same 1:1 descending terminating with chained 1:M:M but with collapse, HRI-direct',
391 tracks.lyrics.existing_lyric_versions.text
392 existing_single_track.cd.artist.artistid
393 existing_single_track.cd.artist.cds.year
397 existing_single_track.cd.artist.cds.cdid
399 existing_single_track.cd.artist.cds.tracks.title
400 existing_single_track.cd.artist.cds.genreid
401 tracks.lyrics.existing_lyric_versions.lyric_id
405 $schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} }),
407 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
409 existing_single_track => {
410 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
414 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
418 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
422 -identifying_columns => [ 1, 6 ], # existing_single_track.cd.artist.cds.cdid
426 -identifying_columns => [ 1, 6, 8 ], # existing_single_track.cd.artist.cds.cdid, existing_single_track.cd.artist.cds.tracks.title
434 -identifying_columns => [ 1, 5 ], # existing_single_track.cd.artist.artistid, tracks.title
438 -identifying_columns => [ 1, 5, 10 ], # existing_single_track.cd.artist.artistid, tracks.title, tracks.lyrics.existing_lyric_versions.lyric_id
442 existing_lyric_versions => {
443 -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
448 'Correct collapse map constructed',
452 ($schema->source ('CD')->_mk_row_parser({
453 inflate_map => $infmap,
457 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
459 while ($cur_row_data = (
466 ( ($rows_pos = -1), undef )
470 ( $_[1] and $_[1]->() )
473 ( @cur_row_ids{0, 1, 5, 6, 8, 10} = (
474 $cur_row_data->[0] // "\0NULL\xFF$rows_pos\xFF0\0",
475 $cur_row_data->[1] // "\0NULL\xFF$rows_pos\xFF1\0",
476 $cur_row_data->[5] // "\0NULL\xFF$rows_pos\xFF5\0",
477 $cur_row_data->[6] // "\0NULL\xFF$rows_pos\xFF6\0",
478 $cur_row_data->[8] // "\0NULL\xFF$rows_pos\xFF8\0",
479 $cur_row_data->[10] // "\0NULL\xFF$rows_pos\xFF10\0",
482 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
483 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{1}} and (unshift @{$_[2]}, $cur_row_data) and last ),
485 ( $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] }] ),
487 ( $collapse_idx[0]{$cur_row_ids{1}}[1]{existing_single_track} //= $collapse_idx[1]{$cur_row_ids{1}} = [] ),
488 ( $collapse_idx[1]{$cur_row_ids{1}}[1]{cd} //= $collapse_idx[2]{$cur_row_ids{1}} = [] ),
489 ( $collapse_idx[2]{$cur_row_ids{1}}[1]{artist} //= $collapse_idx[3]{$cur_row_ids{1}} = [{ artistid => $cur_row_data->[1] }] ),
492 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}} )
494 push @{ $collapse_idx[3]{$cur_row_ids{1}}[1]{cds} }, (
495 $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] }]
498 ( defined($cur_row_data->[6]) or bless( $collapse_idx[3]{$cur_row_ids{1}}[1]{cds}, __NBC__ ) ),
501 (! $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} )
503 push @{ $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks} }, (
504 $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} = [{ title => $cur_row_data->[8] }]
507 ( defined($cur_row_data->[8]) or bless( $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks}, __NBC__ ) ),
510 (! $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} )
512 push @{ $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks} }, (
513 $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} = [{ title => $cur_row_data->[5] }]
516 ( defined($cur_row_data->[5]) or bless( $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks}, __NBC__ ) ),
518 ( $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}} = [] ),
519 ( defined($cur_row_data->[10]) or bless( $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics}, __NBC__ ) ),
522 (! $collapse_idx[8]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} )
524 push @{ $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}}[1]{existing_lyric_versions} }, (
525 $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] }]
530 $#{$_[0]} = $result_pos - 1;
532 'Multiple has_many on multiple branches torture test',
536 ($schema->source ('CD')->_mk_row_parser({
537 inflate_map => $infmap,
539 prune_null_branches => 1,
542 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
544 while ($cur_row_data = (
551 ( ($rows_pos = -1), undef )
555 ( $_[1] and $_[1]->() )
558 ( @cur_row_ids{( 0, 1, 5, 6, 8, 10 )} = @{$cur_row_data}[( 0, 1, 5, 6, 8, 10 )] ),
560 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
561 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{1}} and (unshift @{$_[2]}, $cur_row_data) and last ),
563 ( $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] }] ),
565 ( $collapse_idx[0]{$cur_row_ids{1}}[1]{existing_single_track} //= $collapse_idx[1]{$cur_row_ids{1}} = [] ),
566 ( $collapse_idx[1]{$cur_row_ids{1}}[1]{cd} //= $collapse_idx[2]{$cur_row_ids{1}} = [] ),
567 ( $collapse_idx[2]{$cur_row_ids{1}}[1]{artist} //= $collapse_idx[3]{$cur_row_ids{1}} = [{ artistid => $cur_row_data->[1] }] ),
569 ( (! defined($cur_row_data->[6])) ? $collapse_idx[3]{$cur_row_ids{1}}[1]{cds} = [] : do {
571 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}} )
573 push @{ $collapse_idx[3]{$cur_row_ids{1}}[1]{cds} }, (
574 $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] }]
578 ( (! defined($cur_row_data->[8]) ) ? $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks} = [] : do {
580 (! $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} )
582 push @{ $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks} }, (
583 $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} = [{ title => $cur_row_data->[8] }]
589 ( (! defined($cur_row_data->[5]) ) ? $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks} = [] : do {
592 (! $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} )
594 push @{ $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks} }, (
595 $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} = [{ title => $cur_row_data->[5] }]
599 ( (! defined($cur_row_data->[10]) ) ? $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics} = [] : do {
601 ( $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}} = [] ),
604 (! $collapse_idx[8]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} )
606 push @{ $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}}[1]{existing_lyric_versions} }, (
607 $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] }]
614 $#{$_[0]} = $result_pos - 1;
616 'Multiple has_many on multiple branches with branch pruning torture test',
620 'single_track.trackid', # (0) definitive link to root from 1:1:1:1:M:M chain
621 'year', # (1) non-unique
622 'tracks.cd', # (2) \ together both uniqueness for second multirel
623 'tracks.title', # (3) / and definitive link back to root
624 'single_track.cd.artist.cds.cdid', # (4) to give uniquiness to ...tracks.title below
625 'single_track.cd.artist.cds.year', # (5) non-unique
626 'single_track.cd.artist.artistid', # (6) uniqufies entire parental chain
627 'single_track.cd.artist.cds.genreid', # (7) nullable
628 'single_track.cd.artist.cds.tracks.title',# (8) unique when combined with ...cds.cdid above
632 $schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} }),
634 -identifying_columns => [],
635 -identifying_columns_variants => [
639 -identifying_columns => [ 0 ],
643 -identifying_columns => [ 0 ],
646 -identifying_columns => [ 0 ],
649 -identifying_columns => [ 0, 4 ],
652 -identifying_columns => [ 0, 4, 8 ],
660 -identifying_columns => [ 2, 3 ],
664 'Correct underdefined root collapse map constructed'
668 ($schema->source ('CD')->_mk_row_parser({
669 inflate_map => $infmap,
673 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
675 while ($cur_row_data = (
682 ( ($rows_pos = -1), undef )
686 ( $_[1] and $_[1]->() )
689 ( @cur_row_ids{( 0, 2, 3, 4, 8 )} = (
690 $cur_row_data->[0] // "\0NULL\xFF$rows_pos\xFF0\0",
691 $cur_row_data->[2] // "\0NULL\xFF$rows_pos\xFF2\0",
692 $cur_row_data->[3] // "\0NULL\xFF$rows_pos\xFF3\0",
693 $cur_row_data->[4] // "\0NULL\xFF$rows_pos\xFF4\0",
694 $cur_row_data->[8] // "\0NULL\xFF$rows_pos\xFF8\0",
697 # cache expensive set of ops in a non-existent rowid slot
698 ( $cur_row_ids{10} = (
699 ( ( defined $cur_row_data->[0] ) && (join "\xFF", q{}, $cur_row_ids{0}, q{} ))
701 ( ( defined $cur_row_data->[2] ) && (join "\xFF", q{}, $cur_row_ids{2}, q{} ))
706 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
707 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{10}} and (unshift @{$_[2]}, $cur_row_data) and last ),
709 ( $collapse_idx[0]{$cur_row_ids{10}} //= $_[0][$result_pos++] = [{ year => $$cur_row_data[1] }] ),
711 ( $collapse_idx[0]{$cur_row_ids{10}}[1]{single_track} //= ($collapse_idx[1]{$cur_row_ids{0}} = [{ trackid => $cur_row_data->[0] }]) ),
712 ( defined($cur_row_data->[0]) or bless ( $collapse_idx[0]{$cur_row_ids{10}}[1]{single_track}, __NBC__ ) ),
714 ( $collapse_idx[1]{$cur_row_ids{0}}[1]{cd} //= $collapse_idx[2]{$cur_row_ids{0}} = [] ),
716 ( $collapse_idx[2]{$cur_row_ids{0}}[1]{artist} //= ($collapse_idx[3]{$cur_row_ids{0}} = [{ artistid => $cur_row_data->[6] }]) ),
719 (! $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}} )
721 push @{$collapse_idx[3]{$cur_row_ids{0}}[1]{cds}}, (
722 $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] }]
725 ( defined($cur_row_data->[4]) or bless ( $collapse_idx[3]{$cur_row_ids{0}}[1]{cds}, __NBC__ ) ),
728 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} )
730 push @{$collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}[1]{tracks}}, (
731 $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} = [{ title => $cur_row_data->[8] }]
734 ( defined($cur_row_data->[8]) or bless ( $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}[1]{tracks}, __NBC__ ) ),
737 (! $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} )
739 push @{$collapse_idx[0]{$cur_row_ids{10}}[1]{tracks}}, (
740 $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} = [{ cd => $$cur_row_data[2], title => $cur_row_data->[3] }]
743 ( defined($cur_row_data->[2]) or bless ( $collapse_idx[0]{$cur_row_ids{10}}[1]{tracks}, __NBC__ ) ),
746 $#{$_[0]} = $result_pos - 1;
748 'Multiple has_many on multiple branches with underdefined root torture test',
752 ($schema->source ('CD')->_mk_row_parser({
753 inflate_map => $infmap,
756 prune_null_branches => 1,
759 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
761 while ($cur_row_data = (
768 ( ($rows_pos = -1), undef )
772 ( $_[1] and $_[1]->() )
775 # do not care about nullability here
776 ( @cur_row_ids{( 0, 2, 3, 4, 8 )} = @{$cur_row_data}[( 0, 2, 3, 4, 8 )] ),
778 # cache expensive set of ops in a non-existent rowid slot
779 ( $cur_row_ids{10} = (
780 ( ( defined $cur_row_data->[0] ) && (join "\xFF", q{}, $cur_row_ids{0}, q{} ))
782 ( ( defined $cur_row_data->[2] ) && (join "\xFF", q{}, $cur_row_ids{2}, q{} ))
787 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
788 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{10}} and (unshift @{$_[2]}, $cur_row_data) and last ),
790 ( $collapse_idx[0]{$cur_row_ids{10}} //= $_[0][$result_pos++] = { year => $$cur_row_data[1] } ),
792 ( (! defined $cur_row_data->[0] ) ? $collapse_idx[0]{$cur_row_ids{10}}{single_track} = undef : do {
794 ( $collapse_idx[0]{$cur_row_ids{10}}{single_track} //= ($collapse_idx[1]{$cur_row_ids{0}} = { trackid => $$cur_row_data[0] }) ),
796 ( $collapse_idx[1]{$cur_row_ids{0}}{cd} //= $collapse_idx[2]{$cur_row_ids{0}} ),
798 ( $collapse_idx[2]{$cur_row_ids{0}}{artist} //= ($collapse_idx[3]{$cur_row_ids{0}} = { artistid => $$cur_row_data[6] }) ),
800 ( (! defined $cur_row_data->[4] ) ? $collapse_idx[3]{$cur_row_ids{0}}{cds} = [] : do {
803 (! $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}} )
805 push @{$collapse_idx[3]{$cur_row_ids{0}}{cds}}, (
806 $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] }
810 ( (! defined $cur_row_data->[8] ) ? $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}{tracks} = [] : do {
812 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} )
814 push @{$collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}{tracks}}, (
815 $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} = { title => $$cur_row_data[8] }
821 ( (! defined $cur_row_data->[2] ) ? $collapse_idx[0]{$cur_row_ids{10}}{tracks} = [] : do {
823 (! $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} )
825 push @{$collapse_idx[0]{$cur_row_ids{10}}{tracks}}, (
826 $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} = { cd => $$cur_row_data[2], title => $$cur_row_data[3] }
832 $#{$_[0]} = $result_pos - 1;
834 'Multiple has_many on multiple branches with underdefined root, HRI-direct torture test',
838 ($schema->source ('Owners')->_mk_row_parser({
839 inflate_map => [qw( books.title books.owner )],
841 prune_null_branches => 1,
844 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids );
846 while ($cur_row_data = (
853 ( ($rows_pos = -1), undef )
857 ( $_[1] and $_[1]->() )
860 ( @cur_row_ids{0,1} = @{$cur_row_data}[0,1] ),
862 ( $cur_row_ids{3} = (
863 ( ( defined $cur_row_data->[1] ) && (join "\xFF", q{}, $cur_row_ids{1}, q{} ))
868 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{3}} and (unshift @{$_[2]}, $cur_row_data) and last ),
870 # empty data for the root node
871 ( $collapse_idx[0]{$cur_row_ids{3}} //= $_[0][$result_pos++] = [] ),
873 ( ( ! defined $cur_row_data->[0] ) ? $collapse_idx[0]{$cur_row_ids{3}}[1]{"books"} = [] : do {
874 ( ! $collapse_idx[1]{$cur_row_ids{0}} )
876 push @{$collapse_idx[0]{$cur_row_ids{3}}[1]{books}},
877 $collapse_idx[1]{$cur_row_ids{0}} = [ { owner => $cur_row_data->[1], title => $cur_row_data->[0] } ]
881 $#{$_[0]} = $result_pos - 1; # truncate the passed in array to where we filled it with results
883 'Non-premultiplied implicit collapse with missing join columns',
889 sub is_same_src { SKIP: {
891 skip "Skipping comparison of unicode-posioned source", 1
892 if DBIx::Class::_ENV_::STRESSTEST_UTF8_UPGRADE_GENERATED_COLLAPSER_SOURCE;
894 $deparser ||= B::Deparse->new;
895 local $Test::Builder::Level = $Test::Builder::Level + 1;
897 my ($got, $expect) = @_;
899 skip "Not testing equality of source containing defined-or operator on this perl $]", 1
900 if ( "$]" < 5.010 and $expect =~ m!\Q//=! );
902 $expect =~ s/__NBC__/perlstring($DBIx::Class::ResultSource::RowParser::Util::null_branch_class)/ge;
904 $expect = " { use strict; use warnings FATAL => 'uninitialized';\n$expect\n }";
906 my @normalized = map {
907 my $cref = eval "sub { $_ }" or do {
908 fail "Coderef does not compile!\n\n$@\n\n$_";
911 $deparser->coderef2text($cref);
914 &is (@normalized, $_[2]||() ) or do {
915 eval { require Test::Differences }
916 ? &Test::Differences::eq_or_diff( @normalized, $_[2]||() )
917 : note ("Original sources:\n\n$got\n\n$expect\n")