1 BEGIN { do "./t/lib/ANFANG.pm" or die ( $@ || $! ) }
10 use DBIx::Class::_Util 'perlstring';
12 my $schema = DBICTest->init_schema(no_deploy => 1);
14 single_track.cd.artist.name
19 ($schema->source ('CD')->_mk_row_parser({
20 inflate_map => $infmap,
24 { single_track => ( ! defined( $_->[0]) )
45 'Simple 1:1 descending non-collapsing parser',
49 single_track.cd.artist.cds.tracks.title
50 single_track.cd.artist.artistid
52 single_track.cd.artist.cds.cdid
58 ($schema->source ('CD')->_mk_row_parser({
59 inflate_map => $infmap,
62 { artist => $_->[5], title => $_->[4], year => $_->[2] },
64 single_track => ( (! defined $_->[0] ) && (! defined $_->[1]) && (! defined $_->[3] ) )
72 { artistid => $_->[1] },
74 cds => ( (! defined $_->[0] ) && ( ! defined $_->[3] ) )
78 tracks => ( ! defined $_->[0] )
79 ? bless ( [{ title => $_->[0] }], __NBC__ )
80 : [{ title => $_->[0] }]
86 tracks => ( ! defined $_->[0] )
87 ? bless ( [{ title => $_->[0] }], __NBC__ )
88 : [{ title => $_->[0] }]
104 { artistid => $_->[1] },
106 cds => ( (! defined $_->[0] ) && ( ! defined $_->[3] ) )
110 tracks => ( ! defined $_->[0] )
111 ? bless ( [{ title => $_->[0] }], __NBC__ )
112 : [{ title => $_->[0] }]
118 tracks => ( ! defined $_->[0] )
119 ? bless ( [{ title => $_->[0] }], __NBC__ )
120 : [{ title => $_->[0] }]
131 '1:1 descending non-collapsing parser terminating with chained 1:M:M',
135 ($schema->source ('CD')->_mk_row_parser({
136 prune_null_branches => 1,
137 inflate_map => $infmap,
140 { artist => $_->[5], title => $_->[4], year => $_->[2] },
142 single_track => ( (! defined $_->[0] ) && (! defined $_->[1]) && (! defined $_->[3] ) ) ? undef : [
149 { artistid => $_->[1] },
151 cds => ( (! defined $_->[0] ) && ( ! defined $_->[3] ) ) ? undef : [
154 tracks => ( ! defined $_->[0] ) ? undef : [
155 { title => $_->[0] },
167 '1:1 descending non-collapsing pruning parser terminating with chained 1:M:M',
171 ($schema->source ('CD')->_mk_row_parser({
173 prune_null_branches => 1,
174 inflate_map => $infmap,
177 artist => $_->[5], title => $_->[4], year => $_->[2],
179 ( single_track => ( (! defined $_->[0] ) && (! defined $_->[1]) && (! defined $_->[3] ) )
186 ( cds => ( (! defined $_->[0] ) && ( ! defined $_->[3] ) )
190 ( tracks => ( ! defined $_->[0] )
192 : { title => $_->[0] }
201 '1:1 descending non-collapsing HRI-direct parser terminating with chained 1:M:M',
207 ($schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} })),
209 -identifying_columns => [ 4, 5 ],
212 -identifying_columns => [ 1, 4, 5 ],
217 -identifying_columns => [ 1, 4, 5 ],
221 -identifying_columns => [ 1, 4, 5 ],
225 -identifying_columns => [ 1, 3, 4, 5 ],
229 -identifying_columns => [ 0, 1, 3, 4, 5 ],
237 'Correct collapse map for 1:1 descending chain terminating with chained 1:M:M'
241 ($schema->source ('CD')->_mk_row_parser({
242 inflate_map => $infmap,
246 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
248 while ($cur_row_data = (
255 ( ($rows_pos = -1), undef )
259 ( $_[1] and $_[1]->() )
262 ( @cur_row_ids{0,1,3,4,5} = (
263 ( $cur_row_data->[0] // "\0NULL\xFF$rows_pos\xFF0\0" ),
264 ( $cur_row_data->[1] // "\0NULL\xFF$rows_pos\xFF1\0" ),
265 ( $cur_row_data->[3] // "\0NULL\xFF$rows_pos\xFF3\0" ),
266 ( $cur_row_data->[4] // "\0NULL\xFF$rows_pos\xFF4\0" ),
267 ( $cur_row_data->[5] // "\0NULL\xFF$rows_pos\xFF5\0" ),
270 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
271 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} and (unshift @{$_[2]}, $cur_row_data) and last ),
273 # the rowdata itself for root node
274 ( $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] }] ),
276 # prefetch data of single_track (placed in root)
277 ( $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}} = [] ),
278 ( defined($cur_row_data->[1]) or bless( $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{single_track}, __NBC__ ) ),
280 # prefetch data of cd (placed in single_track)
281 ( $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}} = [] ),
283 # prefetch data of artist ( placed in single_track->cd)
284 ( $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] }] ),
286 # prefetch data of cds (if available)
288 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
290 push @{$collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{cds}}, (
291 $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} = [{ cdid => $cur_row_data->[3] }]
294 ( 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__ ) ),
296 # prefetch data of tracks (if available)
298 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
300 push @{$collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{tracks}}, (
301 $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] }]
304 ( 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__ ) ),
307 $#{$_[0]} = $result_pos - 1;
309 'Same 1:1 descending terminating with chained 1:M:M but with collapse',
313 ($schema->source ('CD')->_mk_row_parser({
314 inflate_map => $infmap,
317 prune_null_branches => 1,
320 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
322 while ($cur_row_data = (
329 ( ($rows_pos = -1), undef )
333 ( $_[1] and $_[1]->() )
336 ( @cur_row_ids{0, 1, 3, 4, 5} = @{$cur_row_data}[0, 1, 3, 4, 5] ),
338 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
339 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} and (unshift @{$_[2]}, $cur_row_data) and last ),
341 # the rowdata itself for root node
342 ( $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] } ),
344 # prefetch data of single_track (placed in root)
345 ( (! defined($cur_row_data->[1]) ) ? $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}{single_track} = undef : do {
346 ( $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}} = {} ),
348 # prefetch data of cd (placed in single_track)
349 ( $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}} = {} ),
351 # prefetch data of artist ( placed in single_track->cd)
352 ( $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] } ),
354 # prefetch data of cds (if available)
355 ( (! defined $cur_row_data->[3] ) ? $collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}{cds} = [] : do {
358 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
360 push @{$collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}{cds}}, (
361 $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} = { cdid => $cur_row_data->[3] }
365 # prefetch data of tracks (if available)
366 (( ! 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 {
369 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
371 push @{$collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}{tracks}}, (
372 $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] }
379 $#{$_[0]} = $result_pos - 1;
381 'Same 1:1 descending terminating with chained 1:M:M but with collapse, HRI-direct',
385 tracks.lyrics.existing_lyric_versions.text
386 existing_single_track.cd.artist.artistid
387 existing_single_track.cd.artist.cds.year
391 existing_single_track.cd.artist.cds.cdid
393 existing_single_track.cd.artist.cds.tracks.title
394 existing_single_track.cd.artist.cds.genreid
395 tracks.lyrics.existing_lyric_versions.lyric_id
399 $schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} }),
401 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
403 existing_single_track => {
404 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
408 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
412 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
416 -identifying_columns => [ 1, 6 ], # existing_single_track.cd.artist.cds.cdid
420 -identifying_columns => [ 1, 6, 8 ], # existing_single_track.cd.artist.cds.cdid, existing_single_track.cd.artist.cds.tracks.title
428 -identifying_columns => [ 1, 5 ], # existing_single_track.cd.artist.artistid, tracks.title
432 -identifying_columns => [ 1, 5, 10 ], # existing_single_track.cd.artist.artistid, tracks.title, tracks.lyrics.existing_lyric_versions.lyric_id
436 existing_lyric_versions => {
437 -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
442 'Correct collapse map constructed',
446 ($schema->source ('CD')->_mk_row_parser({
447 inflate_map => $infmap,
451 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
453 while ($cur_row_data = (
460 ( ($rows_pos = -1), undef )
464 ( $_[1] and $_[1]->() )
467 ( @cur_row_ids{0, 1, 5, 6, 8, 10} = (
468 $cur_row_data->[0] // "\0NULL\xFF$rows_pos\xFF0\0",
469 $cur_row_data->[1] // "\0NULL\xFF$rows_pos\xFF1\0",
470 $cur_row_data->[5] // "\0NULL\xFF$rows_pos\xFF5\0",
471 $cur_row_data->[6] // "\0NULL\xFF$rows_pos\xFF6\0",
472 $cur_row_data->[8] // "\0NULL\xFF$rows_pos\xFF8\0",
473 $cur_row_data->[10] // "\0NULL\xFF$rows_pos\xFF10\0",
476 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
477 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{1}} and (unshift @{$_[2]}, $cur_row_data) and last ),
479 ( $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] }] ),
481 ( $collapse_idx[0]{$cur_row_ids{1}}[1]{existing_single_track} //= $collapse_idx[1]{$cur_row_ids{1}} = [] ),
482 ( $collapse_idx[1]{$cur_row_ids{1}}[1]{cd} //= $collapse_idx[2]{$cur_row_ids{1}} = [] ),
483 ( $collapse_idx[2]{$cur_row_ids{1}}[1]{artist} //= $collapse_idx[3]{$cur_row_ids{1}} = [{ artistid => $cur_row_data->[1] }] ),
486 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}} )
488 push @{ $collapse_idx[3]{$cur_row_ids{1}}[1]{cds} }, (
489 $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] }]
492 ( defined($cur_row_data->[6]) or bless( $collapse_idx[3]{$cur_row_ids{1}}[1]{cds}, __NBC__ ) ),
495 (! $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} )
497 push @{ $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks} }, (
498 $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} = [{ title => $cur_row_data->[8] }]
501 ( defined($cur_row_data->[8]) or bless( $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks}, __NBC__ ) ),
504 (! $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} )
506 push @{ $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks} }, (
507 $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} = [{ title => $cur_row_data->[5] }]
510 ( defined($cur_row_data->[5]) or bless( $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks}, __NBC__ ) ),
512 ( $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}} = [] ),
513 ( defined($cur_row_data->[10]) or bless( $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics}, __NBC__ ) ),
516 (! $collapse_idx[8]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} )
518 push @{ $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}}[1]{existing_lyric_versions} }, (
519 $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] }]
524 $#{$_[0]} = $result_pos - 1;
526 'Multiple has_many on multiple branches torture test',
530 ($schema->source ('CD')->_mk_row_parser({
531 inflate_map => $infmap,
533 prune_null_branches => 1,
536 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
538 while ($cur_row_data = (
545 ( ($rows_pos = -1), undef )
549 ( $_[1] and $_[1]->() )
552 ( @cur_row_ids{( 0, 1, 5, 6, 8, 10 )} = @{$cur_row_data}[( 0, 1, 5, 6, 8, 10 )] ),
554 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
555 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{1}} and (unshift @{$_[2]}, $cur_row_data) and last ),
557 ( $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] }] ),
559 ( $collapse_idx[0]{$cur_row_ids{1}}[1]{existing_single_track} //= $collapse_idx[1]{$cur_row_ids{1}} = [] ),
560 ( $collapse_idx[1]{$cur_row_ids{1}}[1]{cd} //= $collapse_idx[2]{$cur_row_ids{1}} = [] ),
561 ( $collapse_idx[2]{$cur_row_ids{1}}[1]{artist} //= $collapse_idx[3]{$cur_row_ids{1}} = [{ artistid => $cur_row_data->[1] }] ),
563 ( (! defined($cur_row_data->[6])) ? $collapse_idx[3]{$cur_row_ids{1}}[1]{cds} = [] : do {
565 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}} )
567 push @{ $collapse_idx[3]{$cur_row_ids{1}}[1]{cds} }, (
568 $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] }]
572 ( (! defined($cur_row_data->[8]) ) ? $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks} = [] : do {
574 (! $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} )
576 push @{ $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks} }, (
577 $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} = [{ title => $cur_row_data->[8] }]
583 ( (! defined($cur_row_data->[5]) ) ? $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks} = [] : do {
586 (! $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} )
588 push @{ $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks} }, (
589 $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} = [{ title => $cur_row_data->[5] }]
593 ( (! defined($cur_row_data->[10]) ) ? $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics} = [] : do {
595 ( $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}} = [] ),
598 (! $collapse_idx[8]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} )
600 push @{ $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}}[1]{existing_lyric_versions} }, (
601 $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] }]
608 $#{$_[0]} = $result_pos - 1;
610 'Multiple has_many on multiple branches with branch pruning torture test',
614 'single_track.trackid', # (0) definitive link to root from 1:1:1:1:M:M chain
615 'year', # (1) non-unique
616 'tracks.cd', # (2) \ together both uniqueness for second multirel
617 'tracks.title', # (3) / and definitive link back to root
618 'single_track.cd.artist.cds.cdid', # (4) to give uniquiness to ...tracks.title below
619 'single_track.cd.artist.cds.year', # (5) non-unique
620 'single_track.cd.artist.artistid', # (6) uniqufies entire parental chain
621 'single_track.cd.artist.cds.genreid', # (7) nullable
622 'single_track.cd.artist.cds.tracks.title',# (8) unique when combined with ...cds.cdid above
626 $schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} }),
628 -identifying_columns => [],
629 -identifying_columns_variants => [
633 -identifying_columns => [ 0 ],
637 -identifying_columns => [ 0 ],
640 -identifying_columns => [ 0 ],
643 -identifying_columns => [ 0, 4 ],
646 -identifying_columns => [ 0, 4, 8 ],
654 -identifying_columns => [ 2, 3 ],
658 'Correct underdefined root collapse map constructed'
662 ($schema->source ('CD')->_mk_row_parser({
663 inflate_map => $infmap,
667 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
669 while ($cur_row_data = (
676 ( ($rows_pos = -1), undef )
680 ( $_[1] and $_[1]->() )
683 ( @cur_row_ids{( 0, 2, 3, 4, 8 )} = (
684 $cur_row_data->[0] // "\0NULL\xFF$rows_pos\xFF0\0",
685 $cur_row_data->[2] // "\0NULL\xFF$rows_pos\xFF2\0",
686 $cur_row_data->[3] // "\0NULL\xFF$rows_pos\xFF3\0",
687 $cur_row_data->[4] // "\0NULL\xFF$rows_pos\xFF4\0",
688 $cur_row_data->[8] // "\0NULL\xFF$rows_pos\xFF8\0",
691 # cache expensive set of ops in a non-existent rowid slot
692 ( $cur_row_ids{10} = (
693 ( ( defined $cur_row_data->[0] ) && (join "\xFF", q{}, $cur_row_ids{0}, q{} ))
695 ( ( defined $cur_row_data->[2] ) && (join "\xFF", q{}, $cur_row_ids{2}, q{} ))
700 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
701 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{10}} and (unshift @{$_[2]}, $cur_row_data) and last ),
703 ( $collapse_idx[0]{$cur_row_ids{10}} //= $_[0][$result_pos++] = [{ year => $$cur_row_data[1] }] ),
705 ( $collapse_idx[0]{$cur_row_ids{10}}[1]{single_track} //= ($collapse_idx[1]{$cur_row_ids{0}} = [{ trackid => $cur_row_data->[0] }]) ),
706 ( defined($cur_row_data->[0]) or bless ( $collapse_idx[0]{$cur_row_ids{10}}[1]{single_track}, __NBC__ ) ),
708 ( $collapse_idx[1]{$cur_row_ids{0}}[1]{cd} //= $collapse_idx[2]{$cur_row_ids{0}} = [] ),
710 ( $collapse_idx[2]{$cur_row_ids{0}}[1]{artist} //= ($collapse_idx[3]{$cur_row_ids{0}} = [{ artistid => $cur_row_data->[6] }]) ),
713 (! $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}} )
715 push @{$collapse_idx[3]{$cur_row_ids{0}}[1]{cds}}, (
716 $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] }]
719 ( defined($cur_row_data->[4]) or bless ( $collapse_idx[3]{$cur_row_ids{0}}[1]{cds}, __NBC__ ) ),
722 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} )
724 push @{$collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}[1]{tracks}}, (
725 $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} = [{ title => $cur_row_data->[8] }]
728 ( defined($cur_row_data->[8]) or bless ( $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}[1]{tracks}, __NBC__ ) ),
731 (! $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} )
733 push @{$collapse_idx[0]{$cur_row_ids{10}}[1]{tracks}}, (
734 $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} = [{ cd => $$cur_row_data[2], title => $cur_row_data->[3] }]
737 ( defined($cur_row_data->[2]) or bless ( $collapse_idx[0]{$cur_row_ids{10}}[1]{tracks}, __NBC__ ) ),
740 $#{$_[0]} = $result_pos - 1;
742 'Multiple has_many on multiple branches with underdefined root torture test',
746 ($schema->source ('CD')->_mk_row_parser({
747 inflate_map => $infmap,
750 prune_null_branches => 1,
753 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
755 while ($cur_row_data = (
762 ( ($rows_pos = -1), undef )
766 ( $_[1] and $_[1]->() )
769 # do not care about nullability here
770 ( @cur_row_ids{( 0, 2, 3, 4, 8 )} = @{$cur_row_data}[( 0, 2, 3, 4, 8 )] ),
772 # cache expensive set of ops in a non-existent rowid slot
773 ( $cur_row_ids{10} = (
774 ( ( defined $cur_row_data->[0] ) && (join "\xFF", q{}, $cur_row_ids{0}, q{} ))
776 ( ( defined $cur_row_data->[2] ) && (join "\xFF", q{}, $cur_row_ids{2}, q{} ))
781 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
782 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{10}} and (unshift @{$_[2]}, $cur_row_data) and last ),
784 ( $collapse_idx[0]{$cur_row_ids{10}} //= $_[0][$result_pos++] = { year => $$cur_row_data[1] } ),
786 ( (! defined $cur_row_data->[0] ) ? $collapse_idx[0]{$cur_row_ids{10}}{single_track} = undef : do {
788 ( $collapse_idx[0]{$cur_row_ids{10}}{single_track} //= ($collapse_idx[1]{$cur_row_ids{0}} = { trackid => $$cur_row_data[0] }) ),
790 ( $collapse_idx[1]{$cur_row_ids{0}}{cd} //= $collapse_idx[2]{$cur_row_ids{0}} = {} ),
792 ( $collapse_idx[2]{$cur_row_ids{0}}{artist} //= ($collapse_idx[3]{$cur_row_ids{0}} = { artistid => $$cur_row_data[6] }) ),
794 ( (! defined $cur_row_data->[4] ) ? $collapse_idx[3]{$cur_row_ids{0}}{cds} = [] : do {
797 (! $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}} )
799 push @{$collapse_idx[3]{$cur_row_ids{0}}{cds}}, (
800 $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] }
804 ( (! defined $cur_row_data->[8] ) ? $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}{tracks} = [] : do {
806 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} )
808 push @{$collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}{tracks}}, (
809 $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} = { title => $$cur_row_data[8] }
815 ( (! defined $cur_row_data->[2] ) ? $collapse_idx[0]{$cur_row_ids{10}}{tracks} = [] : do {
817 (! $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} )
819 push @{$collapse_idx[0]{$cur_row_ids{10}}{tracks}}, (
820 $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} = { cd => $$cur_row_data[2], title => $$cur_row_data[3] }
826 $#{$_[0]} = $result_pos - 1;
828 'Multiple has_many on multiple branches with underdefined root, HRI-direct torture test',
833 'single_track.lyrics.track_id', # (0) random optional 1:1:1 chain
834 'year', # (1) non-unique
835 'tracks.cd', # (2) \ together both uniqueness for second multirel
836 'tracks.title', # (3) / and definitive link back to root
837 'single_track.cd.artist.cds.cdid', # (4) to give uniquiness to ...tracks.title below
838 'single_track.cd.artist.cds.year', # (5) non-unique
839 'single_track.cd.artist.artistid', # (6) uniqufies entire parental chain
840 'single_track.cd.artist.cds.genreid', # (7) nullable
841 'single_track.cd.artist.cds.tracks.title', # (8) unique when combined with ...cds.cdid above
842 'single_track.lyrics.lyric_versions.text', # (9) unique combined with the single_track.lyrics 1:1:1
846 $schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} }),
848 -identifying_columns => [],
849 -identifying_columns_variants => [
853 -identifying_columns => [ 6 ],
857 -identifying_columns => [ 6 ],
860 -identifying_columns => [ 6 ],
863 -identifying_columns => [ 4, 6 ],
866 -identifying_columns => [ 4, 6, 8 ],
873 -identifying_columns => [ 0, 6 ],
877 -identifying_columns => [ 0, 6, 9 ],
883 -identifying_columns => [ 2, 3 ],
887 'Correct underdefined root tripple-has-many-torture collapse map constructed'
891 ($schema->source ('CD')->_mk_row_parser({
892 inflate_map => $infmap,
895 prune_null_branches => 1,
898 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
900 while ($cur_row_data = (
907 ( ($rows_pos = -1), undef )
911 ( $_[1] and $_[1]->() )
914 # do not care about nullability here
915 ( @cur_row_ids{( 0, 2, 3, 4, 6, 8, 9 )} = @{$cur_row_data}[( 0, 2, 3, 4, 6, 8, 9 )] ),
917 # cache expensive set of ops in a non-existent rowid slot
918 ( $cur_row_ids{11} = (
919 ( ( defined $cur_row_data->[2] ) && (join "\xFF", q{}, $cur_row_ids{2}, q{} ))
921 ( ( defined $cur_row_data->[6] ) && (join "\xFF", q{}, $cur_row_ids{6}, q{} ))
926 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
927 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{11}} and (unshift @{$_[2]}, $cur_row_data) and last ),
929 ( $collapse_idx[0]{$cur_row_ids{11}} //= $_[0][$result_pos++] = { year => $$cur_row_data[1] } ),
931 ( (! defined $cur_row_data->[6] ) ? $collapse_idx[0]{$cur_row_ids{11}}{single_track} = undef : do {
933 ( $collapse_idx[0]{$cur_row_ids{11}}{single_track} //= ( $collapse_idx[1]{$cur_row_ids{6}} = {} ) ),
935 ( $collapse_idx[1]{$cur_row_ids{6}}{cd} //= $collapse_idx[2]{$cur_row_ids{6}} = {} ),
937 ( $collapse_idx[2]{$cur_row_ids{6}}{artist} //= ($collapse_idx[3]{$cur_row_ids{6}} = { artistid => $$cur_row_data[6] }) ),
939 ( (! defined $cur_row_data->[4] ) ? $collapse_idx[3]{$cur_row_ids{6}}{cds} = [] : do {
942 (! $collapse_idx[4]{$cur_row_ids{4}}{$cur_row_ids{6}} )
944 push @{$collapse_idx[3]{$cur_row_ids{6}}{cds}}, (
945 $collapse_idx[4]{$cur_row_ids{4}}{$cur_row_ids{6}} = { cdid => $$cur_row_data[4], genreid => $$cur_row_data[7], year => $$cur_row_data[5] }
949 ( (! defined $cur_row_data->[8] ) ? $collapse_idx[4]{$cur_row_ids{4}}{$cur_row_ids{6}}{tracks} = [] : do {
951 (! $collapse_idx[5]{$cur_row_ids{4}}{$cur_row_ids{6}}{$cur_row_ids{8}} )
953 push @{$collapse_idx[4]{$cur_row_ids{4}}{$cur_row_ids{6}}{tracks}}, (
954 $collapse_idx[5]{$cur_row_ids{4}}{$cur_row_ids{6}}{$cur_row_ids{8}} = { title => $$cur_row_data[8] }
959 ( ( ! defined $cur_row_data->[0] ) ? $collapse_idx[1]{ $cur_row_ids{6} }{"lyrics"} = undef : do {
961 ( $collapse_idx[1]{ $cur_row_ids{6} }{"lyrics"} //= ( $collapse_idx[6]{ $cur_row_ids{0} }{ $cur_row_ids{6} } = { "track_id" => $cur_row_data->[0] } ) ),
963 ( ( ! defined $cur_row_data->[9] ) ? $collapse_idx[6]{ $cur_row_ids{0} }{ $cur_row_ids{6} }{"lyric_versions"} = [] : do {
965 (! $collapse_idx[7]{ $cur_row_ids{0} }{ $cur_row_ids{6} }{ $cur_row_ids{9} })
967 push @{$collapse_idx[6]{ $cur_row_ids{0} }{ $cur_row_ids{6} }{"lyric_versions"}}, (
968 $collapse_idx[7]{ $cur_row_ids{0} }{ $cur_row_ids{6} }{ $cur_row_ids{9} } = { "text" => $cur_row_data->[9] }
975 ( (! defined $cur_row_data->[2] ) ? $collapse_idx[0]{$cur_row_ids{11}}{tracks} = [] : do {
977 (! $collapse_idx[8]{$cur_row_ids{2}}{$cur_row_ids{3}} )
979 push @{$collapse_idx[0]{$cur_row_ids{11}}{tracks}}, (
980 $collapse_idx[8]{$cur_row_ids{2}}{$cur_row_ids{3}} = { cd => $$cur_row_data[2], title => $$cur_row_data[3] }
986 $#{$_[0]} = $result_pos - 1;
988 'Tripple multiple has_many on multiple branches with underdefined root, HRI-direct torture test',
992 ($schema->source ('Owners')->_mk_row_parser({
993 inflate_map => [qw( books.title books.owner )],
995 prune_null_branches => 1,
998 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids );
1000 while ($cur_row_data = (
1007 ( ($rows_pos = -1), undef )
1011 ( $_[1] and $_[1]->() )
1014 ( @cur_row_ids{0,1} = @{$cur_row_data}[0,1] ),
1016 ( $cur_row_ids{3} = (
1017 ( ( defined $cur_row_data->[1] ) && (join "\xFF", q{}, $cur_row_ids{1}, q{} ))
1022 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{3}} and (unshift @{$_[2]}, $cur_row_data) and last ),
1024 # empty data for the root node
1025 ( $collapse_idx[0]{$cur_row_ids{3}} //= $_[0][$result_pos++] = [] ),
1027 ( ( ! defined $cur_row_data->[0] ) ? $collapse_idx[0]{$cur_row_ids{3}}[1]{"books"} = [] : do {
1028 ( ! $collapse_idx[1]{$cur_row_ids{0}} )
1030 push @{$collapse_idx[0]{$cur_row_ids{3}}[1]{books}},
1031 $collapse_idx[1]{$cur_row_ids{0}} = [ { owner => $cur_row_data->[1], title => $cur_row_data->[0] } ]
1035 $#{$_[0]} = $result_pos - 1; # truncate the passed in array to where we filled it with results
1037 'Non-premultiplied implicit collapse with missing join columns',
1043 sub is_same_src { SKIP: {
1045 skip "Skipping comparison of unicode-poisoned source", 1
1046 if DBIx::Class::_ENV_::STRESSTEST_UTF8_UPGRADE_GENERATED_COLLAPSER_SOURCE;
1048 $deparser ||= B::Deparse->new;
1049 local $Test::Builder::Level = $Test::Builder::Level + 1;
1051 my ($got, $expect) = @_;
1053 skip "Not testing equality of source containing defined-or operator on this perl $]", 1
1054 if ( "$]" < 5.010 and $expect =~ m!\Q//=! );
1056 $expect =~ s/__NBC__/perlstring($DBIx::Class::ResultSource::RowParser::Util::null_branch_class)/ge;
1058 $expect = " { use strict; use warnings FATAL => 'uninitialized';\n$expect\n }";
1060 my @normalized = map {
1061 my $cref = eval "sub { $_ }" or do {
1062 fail "Coderef does not compile!\n\n$@\n\n$_";
1065 $deparser->coderef2text($cref);
1068 &is (@normalized, $_[2]||() ) or do {
1069 eval { require Test::Differences }
1070 ? &Test::Differences::eq_or_diff( @normalized, $_[2]||() )
1071 : note ("Original sources:\n\n$got\n\n$expect\n")