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} = $cur_row_data->[0] // "\0NULL\xFF$rows_pos\xFF0\0";
261 $cur_row_ids{1} = $cur_row_data->[1] // "\0NULL\xFF$rows_pos\xFF1\0";
262 $cur_row_ids{3} = $cur_row_data->[3] // "\0NULL\xFF$rows_pos\xFF3\0";
263 $cur_row_ids{4} = $cur_row_data->[4] // "\0NULL\xFF$rows_pos\xFF4\0";
264 $cur_row_ids{5} = $cur_row_data->[5] // "\0NULL\xFF$rows_pos\xFF5\0";
266 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
267 $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} and (unshift @{$_[2]}, $cur_row_data) and last;
269 # the rowdata itself for root node
270 $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] }];
272 # prefetch data of single_track (placed in root)
273 $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}} = [];
274 defined($cur_row_data->[1]) or bless( $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{single_track}, __NBC__ );
276 # prefetch data of cd (placed in single_track)
277 $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}} = [];
279 # prefetch data of artist ( placed in single_track->cd)
280 $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] }];
282 # prefetch data of cds (if available)
283 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
285 push @{$collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{cds}}, (
286 $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} = [{ cdid => $cur_row_data->[3] }]
288 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__ );
290 # prefetch data of tracks (if available)
291 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
293 push @{$collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{tracks}}, (
294 $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] }]
296 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__ );
299 $#{$_[0]} = $result_pos - 1;
301 'Same 1:1 descending terminating with chained 1:M:M but with collapse',
305 ($schema->source ('CD')->_mk_row_parser({
306 inflate_map => $infmap,
309 prune_null_branches => 1,
312 my ($result_pos, @collapse_idx, $cur_row_data);
314 while ($cur_row_data = (
315 ( $rows_pos >= 0 and $_[0][$rows_pos++] )
317 ( $_[1] and $rows_pos = -1 and $_[1]->() )
320 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
321 $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_data->[4]}{$cur_row_data->[5]} and (unshift @{$_[2]}, $cur_row_data) and last;
323 # the rowdata itself for root node
324 $collapse_idx[0]{$cur_row_data->[4]}{$cur_row_data->[5]} //= $_[0][$result_pos++] = { artist => $cur_row_data->[5], title => $cur_row_data->[4], year => $cur_row_data->[2] };
326 # prefetch data of single_track (placed in root)
327 (! defined($cur_row_data->[1]) ) ? $collapse_idx[0]{$cur_row_data->[4]}{$cur_row_data->[5]}{single_track} = undef : do {
328 $collapse_idx[0]{$cur_row_data->[4]}{$cur_row_data->[5]}{single_track} //= $collapse_idx[1]{$cur_row_data->[1]}{$cur_row_data->[4]}{$cur_row_data->[5]};
330 # prefetch data of cd (placed in single_track)
331 $collapse_idx[1]{$cur_row_data->[1]}{$cur_row_data->[4]}{$cur_row_data->[5]}{cd} //= $collapse_idx[2]{$cur_row_data->[1]}{$cur_row_data->[4]}{$cur_row_data->[5]};
333 # prefetch data of artist ( placed in single_track->cd)
334 $collapse_idx[2]{$cur_row_data->[1]}{$cur_row_data->[4]}{$cur_row_data->[5]}{artist} //= $collapse_idx[3]{$cur_row_data->[1]}{$cur_row_data->[4]}{$cur_row_data->[5]} = { artistid => $cur_row_data->[1] };
336 # prefetch data of cds (if available)
337 (! defined $cur_row_data->[3] ) ? $collapse_idx[3]{$cur_row_data->[1]}{$cur_row_data->[4]}{$cur_row_data->[5]}{cds} = [] : do {
339 (! $collapse_idx[4]{$cur_row_data->[1]}{$cur_row_data->[3]}{$cur_row_data->[4]}{$cur_row_data->[5]} )
341 push @{$collapse_idx[3]{$cur_row_data->[1]}{$cur_row_data->[4]}{$cur_row_data->[5]}{cds}}, (
342 $collapse_idx[4]{$cur_row_data->[1]}{$cur_row_data->[3]}{$cur_row_data->[4]}{$cur_row_data->[5]} = { cdid => $cur_row_data->[3] }
345 # prefetch data of tracks (if available)
346 ( ! defined $cur_row_data->[0] ) ? $collapse_idx[4]{$cur_row_data->[1]}{$cur_row_data->[3]}{$cur_row_data->[4]}{$cur_row_data->[5]}{tracks} = [] : do {
348 (! $collapse_idx[5]{$cur_row_data->[0]}{$cur_row_data->[1]}{$cur_row_data->[3]}{$cur_row_data->[4]}{$cur_row_data->[5]} )
350 push @{$collapse_idx[4]{$cur_row_data->[1]}{$cur_row_data->[3]}{$cur_row_data->[4]}{$cur_row_data->[5]}{tracks}}, (
351 $collapse_idx[5]{$cur_row_data->[0]}{$cur_row_data->[1]}{$cur_row_data->[3]}{$cur_row_data->[4]}{$cur_row_data->[5]} = { title => $cur_row_data->[0] }
357 $#{$_[0]} = $result_pos - 1;
359 'Same 1:1 descending terminating with chained 1:M:M but with collapse, HRI-direct',
363 tracks.lyrics.existing_lyric_versions.text
364 existing_single_track.cd.artist.artistid
365 existing_single_track.cd.artist.cds.year
369 existing_single_track.cd.artist.cds.cdid
371 existing_single_track.cd.artist.cds.tracks.title
372 existing_single_track.cd.artist.cds.genreid
373 tracks.lyrics.existing_lyric_versions.lyric_id
377 $schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} }),
379 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
381 existing_single_track => {
382 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
386 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
390 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
394 -identifying_columns => [ 1, 6 ], # existing_single_track.cd.artist.cds.cdid
398 -identifying_columns => [ 1, 6, 8 ], # existing_single_track.cd.artist.cds.cdid, existing_single_track.cd.artist.cds.tracks.title
406 -identifying_columns => [ 1, 5 ], # existing_single_track.cd.artist.artistid, tracks.title
410 -identifying_columns => [ 1, 5, 10 ], # existing_single_track.cd.artist.artistid, tracks.title, tracks.lyrics.existing_lyric_versions.lyric_id
414 existing_lyric_versions => {
415 -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
420 'Correct collapse map constructed',
424 ($schema->source ('CD')->_mk_row_parser({
425 inflate_map => $infmap,
429 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
431 while ($cur_row_data = (
432 ( $rows_pos >= 0 and $_[0][$rows_pos++] )
434 ( $_[1] and $rows_pos = -1 and $_[1]->() )
437 $cur_row_ids{0} = $cur_row_data->[0] // "\0NULL\xFF$rows_pos\xFF0\0";
438 $cur_row_ids{1} = $cur_row_data->[1] // "\0NULL\xFF$rows_pos\xFF1\0";
439 $cur_row_ids{5} = $cur_row_data->[5] // "\0NULL\xFF$rows_pos\xFF5\0";
440 $cur_row_ids{6} = $cur_row_data->[6] // "\0NULL\xFF$rows_pos\xFF6\0";
441 $cur_row_ids{8} = $cur_row_data->[8] // "\0NULL\xFF$rows_pos\xFF8\0";
442 $cur_row_ids{10} = $cur_row_data->[10] // "\0NULL\xFF$rows_pos\xFF10\0";
444 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
445 $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{1}} and (unshift @{$_[2]}, $cur_row_data) and last;
447 $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] }];
449 $collapse_idx[0]{$cur_row_ids{1}}[1]{existing_single_track} //= $collapse_idx[1]{$cur_row_ids{1}} = [];
450 $collapse_idx[1]{$cur_row_ids{1}}[1]{cd} //= $collapse_idx[2]{$cur_row_ids{1}} = [];
451 $collapse_idx[2]{$cur_row_ids{1}}[1]{artist} //= $collapse_idx[3]{$cur_row_ids{1}} = [{ artistid => $cur_row_data->[1] }];
453 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}} )
455 push @{ $collapse_idx[3]{$cur_row_ids{1}}[1]{cds} }, (
456 $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] }]
458 defined($cur_row_data->[6]) or bless( $collapse_idx[3]{$cur_row_ids{1}}[1]{cds}, __NBC__ );
460 (! $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} )
462 push @{ $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks} }, (
463 $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} = [{ title => $cur_row_data->[8] }]
465 defined($cur_row_data->[8]) or bless( $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks}, __NBC__ );
467 (! $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} )
469 push @{ $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks} }, (
470 $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} = [{ title => $cur_row_data->[5] }]
472 defined($cur_row_data->[5]) or bless( $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks}, __NBC__ );
474 $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}} = [];
475 defined($cur_row_data->[10]) or bless( $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics}, __NBC__ );
477 (! $collapse_idx[8]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} )
479 push @{ $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}}[1]{existing_lyric_versions} }, (
480 $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] }]
484 $#{$_[0]} = $result_pos - 1;
486 'Multiple has_many on multiple branches torture test',
490 ($schema->source ('CD')->_mk_row_parser({
491 inflate_map => $infmap,
493 prune_null_branches => 1,
496 my ($result_pos, @collapse_idx, $cur_row_data);
498 while ($cur_row_data = (
499 ( $rows_pos >= 0 and $_[0][$rows_pos++] )
501 ( $_[1] and $rows_pos = -1 and $_[1]->() )
504 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
505 $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_data->[1]} and (unshift @{$_[2]}, $cur_row_data) and last;
507 $collapse_idx[0]{$cur_row_data->[1]} //= $_[0][$result_pos++] = [{ genreid => $cur_row_data->[4], latest_cd => $cur_row_data->[7], year => $cur_row_data->[3] }];
509 $collapse_idx[0]{$cur_row_data->[1]}[1]{existing_single_track} //= $collapse_idx[1]{$cur_row_data->[1]} = [];
510 $collapse_idx[1]{$cur_row_data->[1]}[1]{cd} //= $collapse_idx[2]{$cur_row_data->[1]} = [];
511 $collapse_idx[2]{$cur_row_data->[1]}[1]{artist} //= $collapse_idx[3]{$cur_row_data->[1]} = [{ artistid => $cur_row_data->[1] }];
513 (! defined($cur_row_data->[6])) ? $collapse_idx[3]{$cur_row_data->[1]}[1]{cds} = [] : do {
514 (! $collapse_idx[4]{$cur_row_data->[1]}{$cur_row_data->[6]} )
516 push @{ $collapse_idx[3]{$cur_row_data->[1]}[1]{cds} }, (
517 $collapse_idx[4]{$cur_row_data->[1]}{$cur_row_data->[6]} = [{ cdid => $cur_row_data->[6], genreid => $cur_row_data->[9], year => $cur_row_data->[2] }]
520 (! defined($cur_row_data->[8]) ) ? $collapse_idx[4]{$cur_row_data->[1]}{$cur_row_data->[6]}[1]{tracks} = [] : do {
522 (! $collapse_idx[5]{$cur_row_data->[1]}{$cur_row_data->[6]}{$cur_row_data->[8]} )
524 push @{ $collapse_idx[4]{$cur_row_data->[1]}{$cur_row_data->[6]}[1]{tracks} }, (
525 $collapse_idx[5]{$cur_row_data->[1]}{$cur_row_data->[6]}{$cur_row_data->[8]} = [{ title => $cur_row_data->[8] }]
530 (! defined($cur_row_data->[5]) ) ? $collapse_idx[0]{$cur_row_data->[1]}[1]{tracks} = [] : do {
532 (! $collapse_idx[6]{$cur_row_data->[1]}{$cur_row_data->[5]} )
534 push @{ $collapse_idx[0]{$cur_row_data->[1]}[1]{tracks} }, (
535 $collapse_idx[6]{$cur_row_data->[1]}{$cur_row_data->[5]} = [{ title => $cur_row_data->[5] }]
538 (! defined($cur_row_data->[10]) ) ? $collapse_idx[6]{$cur_row_data->[1]}{$cur_row_data->[5]}[1]{lyrics} = [] : do {
540 $collapse_idx[6]{$cur_row_data->[1]}{$cur_row_data->[5]}[1]{lyrics} //= $collapse_idx[7]{$cur_row_data->[1]}{$cur_row_data->[5]}{$cur_row_data->[10]} = [];
542 (! $collapse_idx[8]{$cur_row_data->[0]}{$cur_row_data->[1]}{$cur_row_data->[5]}{$cur_row_data->[10]} )
544 push @{ $collapse_idx[7]{$cur_row_data->[1]}{$cur_row_data->[5]}{$cur_row_data->[10]}[1]{existing_lyric_versions} }, (
545 $collapse_idx[8]{$cur_row_data->[0]}{$cur_row_data->[1]}{$cur_row_data->[5]}{$cur_row_data->[10]} = [{ lyric_id => $cur_row_data->[10], text => $cur_row_data->[0] }]
551 $#{$_[0]} = $result_pos - 1;
553 'Multiple has_many on multiple branches with branch pruning torture test',
557 'single_track.trackid', # (0) definitive link to root from 1:1:1:1:M:M chain
558 'year', # (1) non-unique
559 'tracks.cd', # (2) \ together both uniqueness for second multirel
560 'tracks.title', # (3) / and definitive link back to root
561 'single_track.cd.artist.cds.cdid', # (4) to give uniquiness to ...tracks.title below
562 'single_track.cd.artist.cds.year', # (5) non-unique
563 'single_track.cd.artist.artistid', # (6) uniqufies entire parental chain
564 'single_track.cd.artist.cds.genreid', # (7) nullable
565 'single_track.cd.artist.cds.tracks.title',# (8) unique when combined with ...cds.cdid above
569 $schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} }),
571 -identifying_columns => [],
572 -identifying_columns_variants => [
576 -identifying_columns => [ 0 ],
580 -identifying_columns => [ 0 ],
583 -identifying_columns => [ 0 ],
586 -identifying_columns => [ 0, 4 ],
589 -identifying_columns => [ 0, 4, 8 ],
597 -identifying_columns => [ 2, 3 ],
601 'Correct underdefined root collapse map constructed'
605 ($schema->source ('CD')->_mk_row_parser({
606 inflate_map => $infmap,
610 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
612 while ($cur_row_data = (
613 ( $rows_pos >= 0 and $_[0][$rows_pos++] )
615 ( $_[1] and $rows_pos = -1 and $_[1]->() )
618 $cur_row_ids{0} = $cur_row_data->[0] // "\0NULL\xFF$rows_pos\xFF0\0";
619 $cur_row_ids{2} = $cur_row_data->[2] // "\0NULL\xFF$rows_pos\xFF2\0";
620 $cur_row_ids{3} = $cur_row_data->[3] // "\0NULL\xFF$rows_pos\xFF3\0";
621 $cur_row_ids{4} = $cur_row_data->[4] // "\0NULL\xFF$rows_pos\xFF4\0";
622 $cur_row_ids{8} = $cur_row_data->[8] // "\0NULL\xFF$rows_pos\xFF8\0";
624 # cache expensive set of ops in a non-existent rowid slot
626 ( ( defined $cur_row_data->[0] ) && (join "\xFF", q{}, $cur_row_data->[0], q{} ))
628 ( ( defined $cur_row_data->[2] ) && (join "\xFF", q{}, $cur_row_data->[2], q{} ))
633 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
634 $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{10}} and (unshift @{$_[2]}, $cur_row_data) and last;
636 $collapse_idx[0]{$cur_row_ids{10}} //= $_[0][$result_pos++] = [{ year => $$cur_row_data[1] }];
638 $collapse_idx[0]{$cur_row_ids{10}}[1]{single_track} //= ($collapse_idx[1]{$cur_row_ids{0}} = [{ trackid => $cur_row_data->[0] }]);
639 defined($cur_row_data->[0]) or bless ( $collapse_idx[0]{$cur_row_ids{10}}[1]{single_track}, __NBC__ );
641 $collapse_idx[1]{$cur_row_ids{0}}[1]{cd} //= $collapse_idx[2]{$cur_row_ids{0}} = [];
643 $collapse_idx[2]{$cur_row_ids{0}}[1]{artist} //= ($collapse_idx[3]{$cur_row_ids{0}} = [{ artistid => $cur_row_data->[6] }]);
645 (! $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}} )
647 push @{$collapse_idx[3]{$cur_row_ids{0}}[1]{cds}}, (
648 $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] }]
650 defined($cur_row_data->[4]) or bless ( $collapse_idx[3]{$cur_row_ids{0}}[1]{cds}, __NBC__ );
652 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} )
654 push @{$collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}[1]{tracks}}, (
655 $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} = [{ title => $cur_row_data->[8] }]
657 defined($cur_row_data->[8]) or bless ( $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}[1]{tracks}, __NBC__ );
659 (! $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} )
661 push @{$collapse_idx[0]{$cur_row_ids{10}}[1]{tracks}}, (
662 $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} = [{ cd => $$cur_row_data[2], title => $cur_row_data->[3] }]
664 defined($cur_row_data->[2]) or bless ( $collapse_idx[0]{$cur_row_ids{10}}[1]{tracks}, __NBC__ );
667 $#{$_[0]} = $result_pos - 1;
669 'Multiple has_many on multiple branches with underdefined root torture test',
673 ($schema->source ('CD')->_mk_row_parser({
674 inflate_map => $infmap,
677 prune_null_branches => 1,
680 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
682 while ($cur_row_data = (
683 ( $rows_pos >= 0 and $_[0][$rows_pos++] )
685 ( $_[1] and $rows_pos = -1 and $_[1]->() )
688 # do not care about nullability here
689 $cur_row_ids{0} = $cur_row_data->[0];
690 $cur_row_ids{2} = $cur_row_data->[2];
691 $cur_row_ids{3} = $cur_row_data->[3];
692 $cur_row_ids{4} = $cur_row_data->[4];
693 $cur_row_ids{8} = $cur_row_data->[8];
695 # cache expensive set of ops in a non-existent rowid slot
697 ( ( defined $cur_row_data->[0] ) && (join "\xFF", q{}, $cur_row_data->[0], q{} ))
699 ( ( defined $cur_row_data->[2] ) && (join "\xFF", q{}, $cur_row_data->[2], q{} ))
704 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
705 $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{10}} and (unshift @{$_[2]}, $cur_row_data) and last;
707 $collapse_idx[0]{$cur_row_ids{10}} //= $_[0][$result_pos++] = { year => $$cur_row_data[1] };
709 (! defined $cur_row_data->[0] ) ? $collapse_idx[0]{$cur_row_ids{10}}{single_track} = undef : do {
711 $collapse_idx[0]{$cur_row_ids{10}}{single_track} //= ($collapse_idx[1]{$cur_row_ids{0}} = { trackid => $$cur_row_data[0] });
713 $collapse_idx[1]{$cur_row_ids{0}}{cd} //= $collapse_idx[2]{$cur_row_ids{0}};
715 $collapse_idx[2]{$cur_row_ids{0}}{artist} //= ($collapse_idx[3]{$cur_row_ids{0}} = { artistid => $$cur_row_data[6] });
717 (! defined $cur_row_data->[4] ) ? $collapse_idx[3]{$cur_row_ids{0}}{cds} = [] : do {
719 (! $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}} )
721 push @{$collapse_idx[3]{$cur_row_ids{0}}{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->[8] ) ? $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}{tracks} = [] : do {
727 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} )
729 push @{$collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}{tracks}}, (
730 $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} = { title => $$cur_row_data[8] }
736 (! defined $cur_row_data->[2] ) ? $collapse_idx[0]{$cur_row_ids{10}}{tracks} = [] : do {
737 (! $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} )
739 push @{$collapse_idx[0]{$cur_row_ids{10}}{tracks}}, (
740 $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} = { cd => $$cur_row_data[2], title => $$cur_row_data[3] }
745 $#{$_[0]} = $result_pos - 1;
747 'Multiple has_many on multiple branches with underdefined root, HRI-direct torture test',
753 sub is_same_src { SKIP: {
754 $deparser ||= B::Deparse->new;
755 local $Test::Builder::Level = $Test::Builder::Level + 1;
757 my ($got, $expect) = @_;
759 skip "Not testing equality of source containing defined-or operator on this perl $]", 1
760 if ($] < 5.010 and$expect =~ m!\Q//=!);
762 $expect =~ s/__NBC__/perlstring($DBIx::Class::ResultSource::RowParser::Util::null_branch_class)/ge;
764 $expect = " { use strict; use warnings FATAL => 'all';\n$expect\n }";
766 my @normalized = map {
767 my $cref = eval "sub { $_ }" or do {
768 fail "Coderef does not compile!\n\n$@\n\n$_";
771 $deparser->coderef2text($cref);
774 &is (@normalized, $_[2]||() ) or do {
775 eval { require Test::Differences }
776 ? &Test::Differences::eq_or_diff( @normalized, $_[2]||() )
777 : note ("Original sources:\n\n$got\n\n$expect\n")