9 # globally set for the rest of test
10 # the rowparser maker does not order its hashes by default for the miniscule
11 # speed gain. But it does not disable sorting either - for this test
12 # everything will be ordered nicely, and the hash randomization of 5.18
13 # will not trip up anything
15 $Data::Dumper::Sortkeys = 1;
17 my $schema = DBICTest->init_schema(no_deploy => 1);
19 single_track.cd.artist.name
24 $schema->source ('CD')->_mk_row_parser({
25 inflate_map => $infmap,
29 { single_track => ( ! defined( $_->[0]) )
50 'Simple 1:1 descending non-collapsing parser',
54 single_track.cd.artist.cds.tracks.title
55 single_track.cd.artist.artistid
57 single_track.cd.artist.cds.cdid
63 $schema->source ('CD')->_mk_row_parser({
64 inflate_map => $infmap,
67 { artist => $_->[5], title => $_->[4], year => $_->[2] },
69 single_track => ( (! defined $_->[0] ) && (! defined $_->[1]) && (! defined $_->[3] ) )
77 { artistid => $_->[1] },
79 cds => ( (! defined $_->[0] ) && ( ! defined $_->[3] ) )
83 tracks => ( ! defined $_->[0] )
84 ? bless ( [{ title => $_->[0] }], __NBC__ )
85 : [{ title => $_->[0] }]
91 tracks => ( ! defined $_->[0] )
92 ? bless ( [{ title => $_->[0] }], __NBC__ )
93 : [{ title => $_->[0] }]
109 { artistid => $_->[1] },
111 cds => ( (! defined $_->[0] ) && ( ! defined $_->[3] ) )
115 tracks => ( ! defined $_->[0] )
116 ? bless ( [{ title => $_->[0] }], __NBC__ )
117 : [{ title => $_->[0] }]
123 tracks => ( ! defined $_->[0] )
124 ? bless ( [{ title => $_->[0] }], __NBC__ )
125 : [{ title => $_->[0] }]
136 '1:1 descending non-collapsing parser terminating with chained 1:M:M',
140 $schema->source ('CD')->_mk_row_parser({
142 inflate_map => $infmap,
145 artist => $_->[5], title => $_->[4], year => $_->[2],
147 ( single_track => ( (! defined $_->[0] ) && (! defined $_->[1]) && (! defined $_->[3] ) )
154 ( cds => ( (! defined $_->[0] ) && ( ! defined $_->[3] ) )
158 ( tracks => ( ! defined $_->[0] )
160 : { title => $_->[0] }
169 '1:1 descending non-collapsing HRI-direct parser terminating with chained 1:M:M',
175 ($schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} })),
177 -identifying_columns => [ 4, 5 ],
180 -identifying_columns => [ 1, 4, 5 ],
185 -identifying_columns => [ 1, 4, 5 ],
189 -identifying_columns => [ 1, 4, 5 ],
193 -identifying_columns => [ 1, 3, 4, 5 ],
197 -identifying_columns => [ 0, 1, 3, 4, 5 ],
205 'Correct collapse map for 1:1 descending chain terminating with chained 1:M:M'
209 $schema->source ('CD')->_mk_row_parser({
210 inflate_map => $infmap,
213 ' my($rows_pos, $result_pos, $cur_row_data, %cur_row_ids, @collapse_idx, $is_new_res) = (0, 0);
215 while ($cur_row_data = (
216 ( $rows_pos >= 0 and $_[0][$rows_pos++] ) or do { $rows_pos = -1; undef } )
218 ( $_[1] and $_[1]->() )
221 $cur_row_ids{$_} = defined $cur_row_data->[$_] ? $cur_row_data->[$_] : "\0NULL\xFF$rows_pos\xFF$_\0"
224 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
225 $_[1] and $result_pos and unshift(@{$_[2]}, $cur_row_data) and last
226 if ( $is_new_res = ! $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} );
228 # the rowdata itself for root node
229 $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} ||= [{ artist => $cur_row_data->[5], title => $cur_row_data->[4], year => $cur_row_data->[2] }];
231 # prefetch data of single_track (placed in root)
232 $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}} ||= [];
233 defined($cur_row_data->[1]) or bless( $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{single_track}, __NBC__ );
235 # prefetch data of cd (placed in single_track)
236 $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}} ||= [];
238 # prefetch data of artist ( placed in single_track->cd)
239 $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] }];
241 # prefetch data of cds (if available)
242 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
244 push @{$collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{cds}}, (
245 $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} = [{ cdid => $cur_row_data->[3] }]
247 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__ );
249 # prefetch data of tracks (if available)
250 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
252 push @{$collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{tracks}}, (
253 $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] }]
255 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__ );
257 $_[0][$result_pos++] = $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}
260 splice @{$_[0]}, $result_pos;
262 'Same 1:1 descending terminating with chained 1:M:M but with collapse',
266 $schema->source ('CD')->_mk_row_parser({
267 inflate_map => $infmap,
271 ' my($rows_pos, $result_pos, $cur_row_data, %cur_row_ids, @collapse_idx, $is_new_res) = (0, 0);
273 while ($cur_row_data = (
274 ( $rows_pos >= 0 and $_[0][$rows_pos++] ) or do { $rows_pos = -1; undef } )
276 ( $_[1] and $_[1]->() )
279 $cur_row_ids{$_} = defined $cur_row_data->[$_] ? $cur_row_data->[$_] : "\0NULL\xFF$rows_pos\xFF$_\0"
282 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
283 $_[1] and $result_pos and unshift(@{$_[2]}, $cur_row_data) and last
284 if ( $is_new_res = ! $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} );
286 # the rowdata itself for root node
287 $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} ||= { artist => $cur_row_data->[5], title => $cur_row_data->[4], year => $cur_row_data->[2] };
289 # prefetch data of single_track (placed in root)
290 $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}}
291 if defined $cur_row_data->[1];
292 $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}{single_track} ||= undef;
294 # prefetch data of cd (placed in single_track)
295 $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}};
297 # prefetch data of artist ( placed in single_track->cd)
298 $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] };
300 # prefetch data of cds (if available)
301 ( defined $cur_row_data->[3] )
303 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
305 push @{$collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}{cds}}, (
306 $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} = { cdid => $cur_row_data->[3] }
308 $collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}{cds} ||= [];
310 # prefetch data of tracks (if available)
311 ( defined $cur_row_data->[0] )
313 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
315 push @{$collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}{tracks}}, (
316 $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] }
318 $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}{tracks} ||= [];
320 $_[0][$result_pos++] = $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}
323 splice @{$_[0]}, $result_pos;
325 'Same 1:1 descending terminating with chained 1:M:M but with collapse, HRI-direct',
329 tracks.lyrics.existing_lyric_versions.text
330 existing_single_track.cd.artist.artistid
331 existing_single_track.cd.artist.cds.year
335 existing_single_track.cd.artist.cds.cdid
337 existing_single_track.cd.artist.cds.tracks.title
338 existing_single_track.cd.artist.cds.genreid
339 tracks.lyrics.existing_lyric_versions.lyric_id
343 $schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} }),
345 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
347 existing_single_track => {
348 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
352 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
356 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
360 -identifying_columns => [ 1, 6 ], # existing_single_track.cd.artist.cds.cdid
364 -identifying_columns => [ 1, 6, 8 ], # existing_single_track.cd.artist.cds.cdid, existing_single_track.cd.artist.cds.tracks.title
372 -identifying_columns => [ 1, 5 ], # existing_single_track.cd.artist.artistid, tracks.title
376 -identifying_columns => [ 1, 5, 10 ], # existing_single_track.cd.artist.artistid, tracks.title, tracks.lyrics.existing_lyric_versions.lyric_id
380 existing_lyric_versions => {
381 -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
386 'Correct collapse map constructed',
390 $schema->source ('CD')->_mk_row_parser({
391 inflate_map => $infmap,
394 ' my ($rows_pos, $result_pos, $cur_row_data, %cur_row_ids, @collapse_idx, $is_new_res) = (0,0);
396 while ($cur_row_data = (
397 ( $rows_pos >= 0 and $_[0][$rows_pos++] ) or do { $rows_pos = -1; undef } )
399 ( $_[1] and $_[1]->() )
402 $cur_row_ids{$_} = defined $cur_row_data->[$_] ? $cur_row_data->[$_] : "\0NULL\xFF$rows_pos\xFF$_\0"
403 for (0, 1, 5, 6, 8, 10);
405 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
406 $_[1] and $result_pos and unshift(@{$_[2]}, $cur_row_data) and last
407 if ( $is_new_res = ! $collapse_idx[0]{$cur_row_ids{1}} );
409 $collapse_idx[0]{$cur_row_ids{1}} ||= [{ genreid => $cur_row_data->[4], latest_cd => $cur_row_data->[7], year => $cur_row_data->[3] }];
411 $collapse_idx[0]{$cur_row_ids{1}}[1]{existing_single_track} ||= $collapse_idx[1]{$cur_row_ids{1}} ||= [];
412 $collapse_idx[1]{$cur_row_ids{1}}[1]{cd} ||= $collapse_idx[2]{$cur_row_ids{1}} ||= [];
413 $collapse_idx[2]{$cur_row_ids{1}}[1]{artist} ||= $collapse_idx[3]{$cur_row_ids{1}} ||= [{ artistid => $cur_row_data->[1] }];
415 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}} )
417 push @{ $collapse_idx[3]{$cur_row_ids{1}}[1]{cds} }, (
418 $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] }]
420 defined($cur_row_data->[6]) or bless( $collapse_idx[3]{$cur_row_ids{1}}[1]{cds}, __NBC__ );
422 (! $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} )
424 push @{ $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks} }, (
425 $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} = [{ title => $cur_row_data->[8] }]
427 defined($cur_row_data->[8]) or bless( $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks}, __NBC__ );
429 (! $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} )
431 push @{ $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks} }, (
432 $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} = [{ title => $cur_row_data->[5] }]
434 defined($cur_row_data->[5]) or bless( $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks}, __NBC__ );
436 $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}} ||= [];
437 defined($cur_row_data->[10]) or bless( $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics}, __NBC__ );
439 (! $collapse_idx[8]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} )
441 push @{ $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}}[1]{existing_lyric_versions} }, (
442 $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] }]
445 $_[0][$result_pos++] = $collapse_idx[0]{$cur_row_ids{1}}
449 splice @{$_[0]}, $result_pos;
451 'Multiple has_many on multiple branches torture test',
455 $schema->source ('CD')->_mk_row_parser({
456 inflate_map => $infmap,
459 ' my ($rows_pos, $result_pos, $cur_row_data, %cur_row_ids, @collapse_idx, $is_new_res) = (0,0);
461 while ($cur_row_data = (
462 ( $rows_pos >= 0 and $_[0][$rows_pos++] ) or do { $rows_pos = -1; undef } )
464 ( $_[1] and $_[1]->() )
467 $cur_row_ids{$_} = defined $cur_row_data->[$_] ? $cur_row_data->[$_] : "\0NULL\xFF$rows_pos\xFF$_\0"
468 for (0, 1, 5, 6, 8, 10);
470 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
471 $_[1] and $result_pos and unshift(@{$_[2]}, $cur_row_data) and last
472 if ( $is_new_res = ! $collapse_idx[0]{$cur_row_ids{1}} );
474 $collapse_idx[0]{$cur_row_ids{1}} ||= [{ genreid => $cur_row_data->[4], latest_cd => $cur_row_data->[7], year => $cur_row_data->[3] }];
476 $collapse_idx[0]{$cur_row_ids{1}}[1]{existing_single_track} ||= $collapse_idx[1]{$cur_row_ids{1}} ||= [];
477 $collapse_idx[1]{$cur_row_ids{1}}[1]{cd} ||= $collapse_idx[2]{$cur_row_ids{1}} ||= [];
478 $collapse_idx[2]{$cur_row_ids{1}}[1]{artist} ||= $collapse_idx[3]{$cur_row_ids{1}} ||= [{ artistid => $cur_row_data->[1] }];
480 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}} )
482 push @{ $collapse_idx[3]{$cur_row_ids{1}}[1]{cds} }, (
483 $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] }]
485 defined($cur_row_data->[6]) or bless( $collapse_idx[3]{$cur_row_ids{1}}[1]{cds}, __NBC__ );
487 (! $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} )
489 push @{ $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks} }, (
490 $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} = [{ title => $cur_row_data->[8] }]
492 defined($cur_row_data->[8]) or bless( $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks}, __NBC__ );
494 (! $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} )
496 push @{ $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks} }, (
497 $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} = [{ title => $cur_row_data->[5] }]
499 defined($cur_row_data->[5]) or bless( $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks}, __NBC__ );
501 $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}} ||= [];
502 defined($cur_row_data->[10]) or bless( $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics}, __NBC__ );
504 (! $collapse_idx[8]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} )
506 push @{ $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}}[1]{existing_lyric_versions} }, (
507 $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] }]
510 $_[0][$result_pos++] = $collapse_idx[0]{$cur_row_ids{1}}
514 splice @{$_[0]}, $result_pos;
516 'Multiple has_many on multiple branches with branch torture test',
520 'single_track.trackid', # (0) definitive link to root from 1:1:1:1:M:M chain
521 'year', # (1) non-unique
522 'tracks.cd', # (2) \ together both uniqueness for second multirel
523 'tracks.title', # (3) / and definitive link back to root
524 'single_track.cd.artist.cds.cdid', # (4) to give uniquiness to ...tracks.title below
525 'single_track.cd.artist.cds.year', # (5) non-unique
526 'single_track.cd.artist.artistid', # (6) uniqufies entire parental chain
527 'single_track.cd.artist.cds.genreid', # (7) nullable
528 'single_track.cd.artist.cds.tracks.title',# (8) unique when combined with ...cds.cdid above
532 $schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} }),
534 -identifying_columns => [],
535 -identifying_columns_variants => [
539 -identifying_columns => [ 0 ],
543 -identifying_columns => [ 0 ],
546 -identifying_columns => [ 0 ],
549 -identifying_columns => [ 0, 4 ],
552 -identifying_columns => [ 0, 4, 8 ],
560 -identifying_columns => [ 2, 3 ],
564 'Correct underdefined root collapse map constructed'
568 $schema->source ('CD')->_mk_row_parser({
569 inflate_map => $infmap,
572 ' my($rows_pos, $result_pos, $cur_row_data, %cur_row_ids, @collapse_idx, $is_new_res) = (0, 0);
574 while ($cur_row_data = (
575 ( $rows_pos >= 0 and $_[0][$rows_pos++] ) or do { $rows_pos = -1; undef } )
577 ( $_[1] and $_[1]->() )
580 $cur_row_ids{$_} = defined $$cur_row_data[$_] ? $$cur_row_data[$_] : "\0NULL\xFF$rows_pos\xFF$_\0"
583 # cache expensive set of ops in a non-existent rowid slot
585 ( ( defined $cur_row_data->[0] ) && (join "\xFF", q{}, $cur_row_data->[0], q{} ))
587 ( ( defined $cur_row_data->[2] ) && (join "\xFF", q{}, $cur_row_data->[2], q{} ))
592 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
593 $_[1] and $result_pos and unshift(@{$_[2]}, $cur_row_data) and last
594 if ( $is_new_res = ! $collapse_idx[0]{$cur_row_ids{10}} );
596 $collapse_idx[0]{$cur_row_ids{10}} ||= [{ year => $$cur_row_data[1] }];
598 $collapse_idx[0]{$cur_row_ids{10}}[1]{single_track} ||= ($collapse_idx[1]{$cur_row_ids{0}} ||= [{ trackid => $cur_row_data->[0] }]);
599 defined($cur_row_data->[0]) or bless ( $collapse_idx[0]{$cur_row_ids{10}}[1]{single_track}, __NBC__ );
601 $collapse_idx[1]{$cur_row_ids{0}}[1]{cd} ||= $collapse_idx[2]{$cur_row_ids{0}} ||= [];
603 $collapse_idx[2]{$cur_row_ids{0}}[1]{artist} ||= ($collapse_idx[3]{$cur_row_ids{0}} ||= [{ artistid => $cur_row_data->[6] }]);
605 (! $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}} )
607 push @{$collapse_idx[3]{$cur_row_ids{0}}[1]{cds}}, (
608 $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] }]
610 defined($cur_row_data->[4]) or bless ( $collapse_idx[3]{$cur_row_ids{0}}[1]{cds}, __NBC__ );
612 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} )
614 push @{$collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}[1]{tracks}}, (
615 $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} = [{ title => $cur_row_data->[8] }]
617 defined($cur_row_data->[8]) or bless ( $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}[1]{tracks}, __NBC__ );
619 (! $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} )
621 push @{$collapse_idx[0]{$cur_row_ids{10}}[1]{tracks}}, (
622 $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} = [{ cd => $$cur_row_data[2], title => $cur_row_data->[3] }]
624 defined($cur_row_data->[2]) or bless ( $collapse_idx[0]{$cur_row_ids{10}}[1]{tracks}, __NBC__ );
626 $_[0][$result_pos++] = $collapse_idx[0]{$cur_row_ids{10}}
630 splice @{$_[0]}, $result_pos;
632 'Multiple has_many on multiple branches with underdefined root torture test',
636 $schema->source ('CD')->_mk_row_parser({
637 inflate_map => $infmap,
641 ' my($rows_pos, $result_pos, $cur_row_data, %cur_row_ids, @collapse_idx, $is_new_res) = (0, 0);
643 while ($cur_row_data = (
644 ( $rows_pos >= 0 and $_[0][$rows_pos++] ) or do { $rows_pos = -1; undef } )
646 ( $_[1] and $_[1]->() )
649 $cur_row_ids{$_} = defined $$cur_row_data[$_] ? $$cur_row_data[$_] : "\0NULL\xFF$rows_pos\xFF$_\0"
652 # cache expensive set of ops in a non-existent rowid slot
654 ( ( defined $cur_row_data->[0] ) && (join "\xFF", q{}, $cur_row_data->[0], q{} ))
656 ( ( defined $cur_row_data->[2] ) && (join "\xFF", q{}, $cur_row_data->[2], q{} ))
661 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
662 $_[1] and $result_pos and unshift(@{$_[2]}, $cur_row_data) and last
663 if ( $is_new_res = ! $collapse_idx[0]{$cur_row_ids{10}} );
665 $collapse_idx[0]{$cur_row_ids{10}} ||= { year => $$cur_row_data[1] };
667 (defined $cur_row_data->[0])
669 $collapse_idx[0]{$cur_row_ids{10}}{single_track} ||= ($collapse_idx[1]{$cur_row_ids{0}} ||= { trackid => $$cur_row_data[0] });
670 $collapse_idx[0]{$cur_row_ids{10}}{single_track} ||= undef;
672 $collapse_idx[1]{$cur_row_ids{0}}{cd} ||= $collapse_idx[2]{$cur_row_ids{0}};
674 $collapse_idx[2]{$cur_row_ids{0}}{artist} ||= ($collapse_idx[3]{$cur_row_ids{0}} ||= { artistid => $$cur_row_data[6] });
676 (defined $cur_row_data->[4])
678 (! $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}} )
680 push @{$collapse_idx[3]{$cur_row_ids{0}}{cds}}, (
681 $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] }
683 $collapse_idx[3]{$cur_row_ids{0}}{cds} ||= [];
685 (defined $cur_row_data->[8])
687 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} )
689 push @{$collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}{tracks}}, (
690 $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} = { title => $$cur_row_data[8] }
692 $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}{tracks} ||= [];
694 (defined $cur_row_data->[2])
696 (! $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} )
698 push @{$collapse_idx[0]{$cur_row_ids{10}}{tracks}}, (
699 $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} = { cd => $$cur_row_data[2], title => $$cur_row_data[3] }
701 $collapse_idx[0]{$cur_row_ids{10}}{tracks} ||= [];
703 $_[0][$result_pos++] = $collapse_idx[0]{$cur_row_ids{10}}
707 splice @{$_[0]}, $result_pos;
709 'Multiple has_many on multiple branches with underdefined root, HRI-direct torture test',
716 $deparser ||= B::Deparse->new;
717 local $Test::Builder::Level = $Test::Builder::Level + 1;
719 my ($got, $expect) = @_;
721 $expect =~ s/__NBC__/B::perlstring($DBIx::Class::ResultSource::RowParser::Util::null_branch_class)/ge;
723 my @normalized = map {
724 my $cref = eval "sub { $_ }" or do {
725 fail "Coderef does not compile!\n\n$@\n\n$_";
728 $deparser->coderef2text($cref);
731 &is (@normalized, $_[2]||() ) or do {
732 eval { require Test::Differences }
733 ? &Test::Differences::eq_or_diff( @normalized, $_[2]||() )
734 : note ("Original sources:\n\n$got\n\n$expect\n");