Step up the error reporting on unexpected NULLs during collapse
[dbsrgits/DBIx-Class.git] / t / resultset / rowparser_internals.t
CommitLineData
c0329273 1BEGIN { do "./t/lib/ANFANG.pm" or die ( $@ || $! ) }
2
4e9fc3f3 3use strict;
4use warnings;
5
6use Test::More;
c0329273 7
4e9fc3f3 8use DBICTest;
9use B::Deparse;
01b25f12 10use DBIx::Class::_Util 'perlstring';
4e9fc3f3 11
12my $schema = DBICTest->init_schema(no_deploy => 1);
ce556881 13my $infmap = [qw/
14 single_track.cd.artist.name
15 year
16/];
4e9fc3f3 17
18is_same_src (
02a73c96 19 ($schema->source ('CD')->_mk_row_parser({
4e9fc3f3 20 inflate_map => $infmap,
02a73c96 21 }))[0],
4e9fc3f3 22 '$_ = [
23 { year => $_->[1] },
52864fbd 24 { single_track => ( ! defined( $_->[0]) )
25 ? bless( [
4e9fc3f3 26 undef,
52864fbd 27 { cd => [
28 undef,
29 { artist => [
30 { name => $_->[0] },
31 ] },
4e9fc3f3 32 ] },
52864fbd 33 ], __NBC__ )
34 : [
35 undef,
36 { cd => [
37 undef,
38 { artist => [
39 { name => $_->[0] },
40 ] },
41 ] },
42 ]
43 },
4e9fc3f3 44 ] for @{$_[0]}',
45 'Simple 1:1 descending non-collapsing parser',
46);
47
48$infmap = [qw/
3faac878 49 single_track.cd.artist.cds.tracks.title
4e9fc3f3 50 single_track.cd.artist.artistid
51 year
4e9fc3f3 52 single_track.cd.artist.cds.cdid
53 title
54 artist
55/];
4e9fc3f3 56
ce556881 57is_same_src (
02a73c96 58 ($schema->source ('CD')->_mk_row_parser({
ce556881 59 inflate_map => $infmap,
02a73c96 60 }))[0],
ce556881 61 '$_ = [
62 { artist => $_->[5], title => $_->[4], year => $_->[2] },
63 {
52864fbd 64 single_track => ( (! defined $_->[0] ) && (! defined $_->[1]) && (! defined $_->[3] ) )
65 ? bless( [
66 undef,
67 {
68 cd => [
69 undef,
70 {
71 artist => [
72 { artistid => $_->[1] },
73 {
74 cds => ( (! defined $_->[0] ) && ( ! defined $_->[3] ) )
75 ? bless ([
76 { cdid => $_->[3] },
77 {
78 tracks => ( ! defined $_->[0] )
79 ? bless ( [{ title => $_->[0] }], __NBC__ )
80 : [{ title => $_->[0] }]
81 }
82 ], __NBC__)
83 : [
84 { cdid => $_->[3] },
85 {
86 tracks => ( ! defined $_->[0] )
87 ? bless ( [{ title => $_->[0] }], __NBC__ )
88 : [{ title => $_->[0] }]
89 }
90 ]
91 }
92 ]
93 }
94 ]
95 }
96 ], __NBC__)
97 : [
ce556881 98 undef,
99 {
100 cd => [
101 undef,
102 {
103 artist => [
104 { artistid => $_->[1] },
105 {
52864fbd 106 cds => ( (! defined $_->[0] ) && ( ! defined $_->[3] ) )
107 ? bless ([
108 { cdid => $_->[3] },
109 {
110 tracks => ( ! defined $_->[0] )
111 ? bless ( [{ title => $_->[0] }], __NBC__ )
112 : [{ title => $_->[0] }]
113 }
114 ], __NBC__)
115 : [
ce556881 116 { cdid => $_->[3] },
117 {
52864fbd 118 tracks => ( ! defined $_->[0] )
119 ? bless ( [{ title => $_->[0] }], __NBC__ )
120 : [{ title => $_->[0] }]
ce556881 121 }
52864fbd 122 ]
ce556881 123 }
124 ]
125 }
126 ]
127 }
52864fbd 128 ]
ce556881 129 }
130 ] for @{$_[0]}',
52864fbd 131 '1:1 descending non-collapsing parser terminating with chained 1:M:M',
ce556881 132);
133
134is_same_src (
02a73c96 135 ($schema->source ('CD')->_mk_row_parser({
79adc44f 136 prune_null_branches => 1,
137 inflate_map => $infmap,
02a73c96 138 }))[0],
79adc44f 139 '$_ = [
140 { artist => $_->[5], title => $_->[4], year => $_->[2] },
141 {
142 single_track => ( (! defined $_->[0] ) && (! defined $_->[1]) && (! defined $_->[3] ) ) ? undef : [
143 undef,
144 {
145 cd => [
146 undef,
147 {
148 artist => [
149 { artistid => $_->[1] },
150 {
151 cds => ( (! defined $_->[0] ) && ( ! defined $_->[3] ) ) ? undef : [
152 { cdid => $_->[3] },
153 {
154 tracks => ( ! defined $_->[0] ) ? undef : [
155 { title => $_->[0] },
156 ]
157 }
158 ]
159 }
160 ]
161 }
162 ]
163 }
164 ]
165 }
166 ] for @{$_[0]}',
167 '1:1 descending non-collapsing pruning parser terminating with chained 1:M:M',
168);
169
170is_same_src (
02a73c96 171 ($schema->source ('CD')->_mk_row_parser({
ce556881 172 hri_style => 1,
79adc44f 173 prune_null_branches => 1,
ce556881 174 inflate_map => $infmap,
02a73c96 175 }))[0],
ce556881 176 '$_ = {
177 artist => $_->[5], title => $_->[4], year => $_->[2],
178
52864fbd 179 ( single_track => ( (! defined $_->[0] ) && (! defined $_->[1]) && (! defined $_->[3] ) )
180 ? undef
181 : {
ce556881 182 cd =>
183 {
184 artist => {
185 artistid => $_->[1],
52864fbd 186 ( cds => ( (! defined $_->[0] ) && ( ! defined $_->[3] ) )
187 ? undef
188 : {
ce556881 189 cdid => $_->[3],
52864fbd 190 ( tracks => ( ! defined $_->[0] )
191 ? undef
192 : { title => $_->[0] }
193 )
ce556881 194 }
52864fbd 195 )
ce556881 196 }
197 }
198 }
52864fbd 199 )
ce556881 200 } for @{$_[0]}',
52864fbd 201 '1:1 descending non-collapsing HRI-direct parser terminating with chained 1:M:M',
ce556881 202);
203
204
205
4e9fc3f3 206is_deeply (
3faac878 207 ($schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} })),
4e9fc3f3 208 {
9f98c4b2 209 -identifying_columns => [ 4, 5 ],
4e9fc3f3 210
211 single_track => {
a0726a33 212 -identifying_columns => [ 1, 4, 5 ],
4e9fc3f3 213 -is_optional => 1,
214 -is_single => 1,
215
216 cd => {
a0726a33 217 -identifying_columns => [ 1, 4, 5 ],
4e9fc3f3 218 -is_single => 1,
219
220 artist => {
a0726a33 221 -identifying_columns => [ 1, 4, 5 ],
4e9fc3f3 222 -is_single => 1,
223
224 cds => {
a0726a33 225 -identifying_columns => [ 1, 3, 4, 5 ],
4e9fc3f3 226 -is_optional => 1,
227
228 tracks => {
a0726a33 229 -identifying_columns => [ 0, 1, 3, 4, 5 ],
4e9fc3f3 230 -is_optional => 1,
231 },
232 },
233 },
234 },
235 },
236 },
237 'Correct collapse map for 1:1 descending chain terminating with chained 1:M:M'
238);
239
240is_same_src (
02a73c96 241 ($schema->source ('CD')->_mk_row_parser({
4e9fc3f3 242 inflate_map => $infmap,
243 collapse => 1,
02a73c96 244 }))[0],
aa1d8a87 245 ' my $rows_pos = 0;
246 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
4e9fc3f3 247
9f98c4b2 248 while ($cur_row_data = (
164aab8c 249 (
250 $rows_pos >= 0
251 and
252 (
253 $_[0][$rows_pos++]
254 or
255 ( ($rows_pos = -1), undef )
256 )
257 )
258 or
259 ( $_[1] and $_[1]->() )
3b4cd124 260 ) ) {
4e9fc3f3 261
b3a400a0 262
263 # NULL checks
264 # mandatory => { 4 => 1, 5 => 1 }
265 # from_first_encounter => [ [ 1, 3, 0 ] ]
266 #
267 ( defined( $cur_row_data->[4] ) or $_[3]->{4} = 1 ),
268
269 ( defined( $cur_row_data->[5] ) or $_[3]->{5} = 1 ),
270
271 (
272 ( not defined $cur_row_data->[1] )
273 ? (
274 ( not defined $cur_row_data->[3] )
275 and
276 ( not defined $cur_row_data->[0] )
277 or
278 ( $_[3]->{1} = 1 )
279 )
280 : ( not defined $cur_row_data->[3] )
281 ? (
282 ( not defined $cur_row_data->[0] )
283 or
284 ( $_[3]->{3} = 1 )
285 )
286 : ()
287 ),
288
289 ( keys %{$_[3]} and (
290 ( @{$_[2]} = $cur_row_data ),
291 ( $result_pos = 0 ),
292 last
293 ) ),
294
295
05a5ca4b 296 ( @cur_row_ids{0,1,3,4,5} = (
c863e102 297 ( $cur_row_data->[0] // "\0NULL\xFF$rows_pos\xFF0\0" ),
298 ( $cur_row_data->[1] // "\0NULL\xFF$rows_pos\xFF1\0" ),
299 ( $cur_row_data->[3] // "\0NULL\xFF$rows_pos\xFF3\0" ),
5ff6d603 300 ( $cur_row_data->[4] ),
301 ( $cur_row_data->[5] ),
05a5ca4b 302 ) ),
4e9fc3f3 303
3faac878 304 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
05a5ca4b 305 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} and (unshift @{$_[2]}, $cur_row_data) and last ),
4e9fc3f3 306
3faac878 307 # the rowdata itself for root node
05a5ca4b 308 ( $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] }] ),
3faac878 309
310 # prefetch data of single_track (placed in root)
05a5ca4b 311 ( $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}} = [] ),
312 ( defined($cur_row_data->[1]) or bless( $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{single_track}, __NBC__ ) ),
3faac878 313
314 # prefetch data of cd (placed in single_track)
05a5ca4b 315 ( $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}} = [] ),
4e9fc3f3 316
3faac878 317 # prefetch data of artist ( placed in single_track->cd)
05a5ca4b 318 ( $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] }] ),
3faac878 319
320 # prefetch data of cds (if available)
05a5ca4b 321 (
322 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
323 and
324 push @{$collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{cds}}, (
325 $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} = [{ cdid => $cur_row_data->[3] }]
326 )
327 ),
328 ( 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__ ) ),
4e9fc3f3 329
3faac878 330 # prefetch data of tracks (if available)
05a5ca4b 331 (
332 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
333 and
334 push @{$collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{tracks}}, (
335 $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] }]
336 )
337 ),
338 ( 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__ ) ),
4e9fc3f3 339
4e9fc3f3 340 }
aa1d8a87 341 $#{$_[0]} = $result_pos - 1;
4e9fc3f3 342 ',
343 'Same 1:1 descending terminating with chained 1:M:M but with collapse',
344);
345
ce556881 346is_same_src (
02a73c96 347 ($schema->source ('CD')->_mk_row_parser({
ce556881 348 inflate_map => $infmap,
349 collapse => 1,
ce556881 350 hri_style => 1,
79adc44f 351 prune_null_branches => 1,
02a73c96 352 }))[0],
aa1d8a87 353 ' my $rows_pos = 0;
c863e102 354 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
ce556881 355
356 while ($cur_row_data = (
164aab8c 357 (
358 $rows_pos >= 0
359 and
360 (
361 $_[0][$rows_pos++]
362 or
363 ( ($rows_pos = -1), undef )
364 )
365 )
366 or
367 ( $_[1] and $_[1]->() )
3b4cd124 368 ) ) {
ce556881 369
b3a400a0 370
371 # NULL checks
372 # mandatory => { 4 => 1, 5 => 1 }
373 # from_first_encounter => [ [ 1, 3, 0 ] ]
374 #
375 ( defined( $cur_row_data->[4] ) or $_[3]->{4} = 1 ),
376
377 ( defined( $cur_row_data->[5] ) or $_[3]->{5} = 1 ),
378
379 (
380 ( not defined $cur_row_data->[1] )
381 ? (
382 ( not defined $cur_row_data->[3] )
383 and
384 ( not defined $cur_row_data->[0] )
385 or
386 ( $_[3]->{1} = 1 )
387 )
388 : ( not defined $cur_row_data->[3] )
389 ? (
390 ( not defined $cur_row_data->[0] )
391 or
392 ( $_[3]->{3} = 1 )
393 )
394 : ()
395 ),
396
397 ( keys %{$_[3]} and (
398 ( @{$_[2]} = $cur_row_data ),
399 ( $result_pos = 0 ),
400 last
401 ) ),
402
403
05a5ca4b 404 ( @cur_row_ids{0, 1, 3, 4, 5} = @{$cur_row_data}[0, 1, 3, 4, 5] ),
c863e102 405
ce556881 406 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
05a5ca4b 407 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} and (unshift @{$_[2]}, $cur_row_data) and last ),
ce556881 408
409 # the rowdata itself for root node
05a5ca4b 410 ( $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] } ),
ce556881 411
412 # prefetch data of single_track (placed in root)
05a5ca4b 413 ( (! defined($cur_row_data->[1]) ) ? $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}{single_track} = undef : do {
40471d46 414 ( $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}} = {} ),
ce556881 415
7596ddca 416 # prefetch data of cd (placed in single_track)
40471d46 417 ( $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}} = {} ),
ce556881 418
7596ddca 419 # prefetch data of artist ( placed in single_track->cd)
05a5ca4b 420 ( $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] } ),
ce556881 421
7596ddca 422 # prefetch data of cds (if available)
05a5ca4b 423 ( (! defined $cur_row_data->[3] ) ? $collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}{cds} = [] : do {
ce556881 424
05a5ca4b 425 (
426 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
427 and
428 push @{$collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}{cds}}, (
429 $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} = { cdid => $cur_row_data->[3] }
430 )
431 ),
ce556881 432
7596ddca 433 # prefetch data of tracks (if available)
05a5ca4b 434 (( ! 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 {
435
436 (
437 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
438 and
439 push @{$collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}{tracks}}, (
440 $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] }
441 )
442 ),
443 } ),
444 } ),
445 } ),
ce556881 446 }
aa1d8a87 447 $#{$_[0]} = $result_pos - 1;
ce556881 448 ',
52864fbd 449 'Same 1:1 descending terminating with chained 1:M:M but with collapse, HRI-direct',
ce556881 450);
451
4e9fc3f3 452$infmap = [qw/
3d8caf63 453 tracks.lyrics.existing_lyric_versions.text
4e9fc3f3 454 existing_single_track.cd.artist.artistid
455 existing_single_track.cd.artist.cds.year
456 year
457 genreid
458 tracks.title
459 existing_single_track.cd.artist.cds.cdid
460 latest_cd
461 existing_single_track.cd.artist.cds.tracks.title
462 existing_single_track.cd.artist.cds.genreid
3d8caf63 463 tracks.lyrics.existing_lyric_versions.lyric_id
4e9fc3f3 464/];
465
466is_deeply (
82f0e0aa 467 $schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} }),
4e9fc3f3 468 {
9f98c4b2 469 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
4e9fc3f3 470
471 existing_single_track => {
9f98c4b2 472 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
4e9fc3f3 473 -is_single => 1,
474
475 cd => {
9f98c4b2 476 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
4e9fc3f3 477 -is_single => 1,
478
479 artist => {
9f98c4b2 480 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
4e9fc3f3 481 -is_single => 1,
482
483 cds => {
9f98c4b2 484 -identifying_columns => [ 1, 6 ], # existing_single_track.cd.artist.cds.cdid
4e9fc3f3 485 -is_optional => 1,
486
487 tracks => {
9f98c4b2 488 -identifying_columns => [ 1, 6, 8 ], # existing_single_track.cd.artist.cds.cdid, existing_single_track.cd.artist.cds.tracks.title
4e9fc3f3 489 -is_optional => 1,
490 }
491 }
492 }
493 }
494 },
495 tracks => {
9f98c4b2 496 -identifying_columns => [ 1, 5 ], # existing_single_track.cd.artist.artistid, tracks.title
4e9fc3f3 497 -is_optional => 1,
498
499 lyrics => {
3d8caf63 500 -identifying_columns => [ 1, 5, 10 ], # existing_single_track.cd.artist.artistid, tracks.title, tracks.lyrics.existing_lyric_versions.lyric_id
4e9fc3f3 501 -is_single => 1,
502 -is_optional => 1,
503
3d8caf63 504 existing_lyric_versions => {
505 -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
4e9fc3f3 506 },
507 },
508 }
509 },
510 'Correct collapse map constructed',
511);
512
513is_same_src (
02a73c96 514 ($schema->source ('CD')->_mk_row_parser({
4e9fc3f3 515 inflate_map => $infmap,
516 collapse => 1,
02a73c96 517 }))[0],
aa1d8a87 518 ' my $rows_pos = 0;
519 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
4e9fc3f3 520
9f98c4b2 521 while ($cur_row_data = (
164aab8c 522 (
523 $rows_pos >= 0
524 and
525 (
526 $_[0][$rows_pos++]
527 or
528 ( ($rows_pos = -1), undef )
529 )
530 )
531 or
532 ( $_[1] and $_[1]->() )
3b4cd124 533 ) ) {
4e9fc3f3 534
b3a400a0 535
536 # NULL checks
537 # mandatory => { 1 => 1 }
538 # from_first_encounter => [ [6, 8], [5, 10, 0] ],
539 #
540 ( defined( $cur_row_data->[1] ) or $_[3]->{1} = 1 ),
541
542 (
543 ( not defined $cur_row_data->[6] )
544 ? (
545 ( not defined $cur_row_data->[8] )
546 or
547 ( $_[3]->{6} = 1 )
548 )
549 : ()
550 ),
551
552 (
553 ( not defined $cur_row_data->[5] )
554 ? (
555 ( not defined $cur_row_data->[10] )
556 and
557 ( not defined $cur_row_data->[0] )
558 or
559 ( $_[3]->{5} = 1 )
560 )
561 : ( not defined $cur_row_data->[10] )
562 ? (
563 ( not defined $cur_row_data->[0] )
564 or
565 ( $_[3]->{10} = 1 )
566 )
567 : ()
568 ),
569
570 ( keys %{$_[3]} and (
571 ( @{$_[2]} = $cur_row_data ),
572 ( $result_pos = 0 ),
573 last
574 ) ),
575
576
05a5ca4b 577 ( @cur_row_ids{0, 1, 5, 6, 8, 10} = (
c863e102 578 $cur_row_data->[0] // "\0NULL\xFF$rows_pos\xFF0\0",
5ff6d603 579 $cur_row_data->[1],
c863e102 580 $cur_row_data->[5] // "\0NULL\xFF$rows_pos\xFF5\0",
581 $cur_row_data->[6] // "\0NULL\xFF$rows_pos\xFF6\0",
582 $cur_row_data->[8] // "\0NULL\xFF$rows_pos\xFF8\0",
583 $cur_row_data->[10] // "\0NULL\xFF$rows_pos\xFF10\0",
05a5ca4b 584 ) ),
4e9fc3f3 585
9f98c4b2 586 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
05a5ca4b 587 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{1}} and (unshift @{$_[2]}, $cur_row_data) and last ),
588
589 ( $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] }] ),
590
591 ( $collapse_idx[0]{$cur_row_ids{1}}[1]{existing_single_track} //= $collapse_idx[1]{$cur_row_ids{1}} = [] ),
592 ( $collapse_idx[1]{$cur_row_ids{1}}[1]{cd} //= $collapse_idx[2]{$cur_row_ids{1}} = [] ),
593 ( $collapse_idx[2]{$cur_row_ids{1}}[1]{artist} //= $collapse_idx[3]{$cur_row_ids{1}} = [{ artistid => $cur_row_data->[1] }] ),
594
595 (
596 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}} )
597 and
598 push @{ $collapse_idx[3]{$cur_row_ids{1}}[1]{cds} }, (
599 $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] }]
600 )
601 ),
602 ( defined($cur_row_data->[6]) or bless( $collapse_idx[3]{$cur_row_ids{1}}[1]{cds}, __NBC__ ) ),
603
604 (
605 (! $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} )
606 and
607 push @{ $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks} }, (
608 $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} = [{ title => $cur_row_data->[8] }]
609 )
610 ),
611 ( defined($cur_row_data->[8]) or bless( $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks}, __NBC__ ) ),
612
613 (
614 (! $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} )
615 and
616 push @{ $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks} }, (
617 $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} = [{ title => $cur_row_data->[5] }]
618 )
619 ),
620 ( defined($cur_row_data->[5]) or bless( $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks}, __NBC__ ) ),
621
622 ( $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}} = [] ),
623 ( defined($cur_row_data->[10]) or bless( $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics}, __NBC__ ) ),
624
625 (
626 (! $collapse_idx[8]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} )
627 and
628 push @{ $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}}[1]{existing_lyric_versions} }, (
629 $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] }]
630 )
631 ),
4e9fc3f3 632 }
633
aa1d8a87 634 $#{$_[0]} = $result_pos - 1;
4e9fc3f3 635 ',
636 'Multiple has_many on multiple branches torture test',
637);
638
ce556881 639is_same_src (
02a73c96 640 ($schema->source ('CD')->_mk_row_parser({
ce556881 641 inflate_map => $infmap,
642 collapse => 1,
79adc44f 643 prune_null_branches => 1,
02a73c96 644 }))[0],
aa1d8a87 645 ' my $rows_pos = 0;
c863e102 646 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
ce556881 647
648 while ($cur_row_data = (
164aab8c 649 (
650 $rows_pos >= 0
651 and
652 (
653 $_[0][$rows_pos++]
654 or
655 ( ($rows_pos = -1), undef )
656 )
657 )
658 or
659 ( $_[1] and $_[1]->() )
3b4cd124 660 ) ) {
ce556881 661
b3a400a0 662
663 # NULL checks
664 # mandatory => { 1 => 1 }
665 # from_first_encounter => [ [6, 8], [5, 10, 0] ],
666 #
667 ( defined( $cur_row_data->[1] ) or $_[3]->{1} = 1 ),
668
669 (
670 ( not defined $cur_row_data->[6] )
671 ? (
672 ( not defined $cur_row_data->[8] )
673 or
674 ( $_[3]->{6} = 1 )
675 )
676 : ()
677 ),
678
679 (
680 ( not defined $cur_row_data->[5] )
681 ? (
682 ( not defined $cur_row_data->[10] )
683 and
684 ( not defined $cur_row_data->[0] )
685 or
686 ( $_[3]->{5} = 1 )
687 )
688 : ( not defined $cur_row_data->[10] )
689 ? (
690 ( not defined $cur_row_data->[0] )
691 or
692 ( $_[3]->{10} = 1 )
693 )
694 : ()
695 ),
696
697 ( keys %{$_[3]} and (
698 ( @{$_[2]} = $cur_row_data ),
699 ( $result_pos = 0 ),
700 last
701 ) ),
702
703
05a5ca4b 704 ( @cur_row_ids{( 0, 1, 5, 6, 8, 10 )} = @{$cur_row_data}[( 0, 1, 5, 6, 8, 10 )] ),
c863e102 705
ce556881 706 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
05a5ca4b 707 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{1}} and (unshift @{$_[2]}, $cur_row_data) and last ),
ce556881 708
05a5ca4b 709 ( $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] }] ),
ce556881 710
05a5ca4b 711 ( $collapse_idx[0]{$cur_row_ids{1}}[1]{existing_single_track} //= $collapse_idx[1]{$cur_row_ids{1}} = [] ),
712 ( $collapse_idx[1]{$cur_row_ids{1}}[1]{cd} //= $collapse_idx[2]{$cur_row_ids{1}} = [] ),
713 ( $collapse_idx[2]{$cur_row_ids{1}}[1]{artist} //= $collapse_idx[3]{$cur_row_ids{1}} = [{ artistid => $cur_row_data->[1] }] ),
ce556881 714
05a5ca4b 715 ( (! defined($cur_row_data->[6])) ? $collapse_idx[3]{$cur_row_ids{1}}[1]{cds} = [] : do {
716 (
717 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}} )
79adc44f 718 and
05a5ca4b 719 push @{ $collapse_idx[3]{$cur_row_ids{1}}[1]{cds} }, (
720 $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] }]
721 )
722 ),
723
724 ( (! defined($cur_row_data->[8]) ) ? $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks} = [] : do {
725 (
726 (! $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} )
727 and
728 push @{ $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks} }, (
729 $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} = [{ title => $cur_row_data->[8] }]
730 )
731 ),
732 } ),
733 } ),
ce556881 734
05a5ca4b 735 ( (! defined($cur_row_data->[5]) ) ? $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks} = [] : do {
ce556881 736
05a5ca4b 737 (
738 (! $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} )
739 and
740 push @{ $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks} }, (
741 $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} = [{ title => $cur_row_data->[5] }]
742 )
743 ),
79adc44f 744
05a5ca4b 745 ( (! defined($cur_row_data->[10]) ) ? $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics} = [] : do {
79adc44f 746
05a5ca4b 747 ( $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}} = [] ),
79adc44f 748
05a5ca4b 749 (
750 (! $collapse_idx[8]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} )
751 and
752 push @{ $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}}[1]{existing_lyric_versions} }, (
753 $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] }]
754 )
755 ),
756 } ),
757 } ),
ce556881 758 }
759
aa1d8a87 760 $#{$_[0]} = $result_pos - 1;
ce556881 761 ',
79adc44f 762 'Multiple has_many on multiple branches with branch pruning torture test',
ce556881 763);
764
fcf32d04 765$infmap = [
766 'single_track.trackid', # (0) definitive link to root from 1:1:1:1:M:M chain
767 'year', # (1) non-unique
768 'tracks.cd', # (2) \ together both uniqueness for second multirel
769 'tracks.title', # (3) / and definitive link back to root
770 'single_track.cd.artist.cds.cdid', # (4) to give uniquiness to ...tracks.title below
771 'single_track.cd.artist.cds.year', # (5) non-unique
772 'single_track.cd.artist.artistid', # (6) uniqufies entire parental chain
773 'single_track.cd.artist.cds.genreid', # (7) nullable
774 'single_track.cd.artist.cds.tracks.title',# (8) unique when combined with ...cds.cdid above
775];
776
777is_deeply (
778 $schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} }),
779 {
9f98c4b2 780 -identifying_columns => [],
781 -identifying_columns_variants => [
fcf32d04 782 [ 0 ], [ 2 ],
783 ],
784 single_track => {
9f98c4b2 785 -identifying_columns => [ 0 ],
fcf32d04 786 -is_optional => 1,
787 -is_single => 1,
fcf32d04 788 cd => {
9f98c4b2 789 -identifying_columns => [ 0 ],
fcf32d04 790 -is_single => 1,
fcf32d04 791 artist => {
9f98c4b2 792 -identifying_columns => [ 0 ],
fcf32d04 793 -is_single => 1,
fcf32d04 794 cds => {
9f98c4b2 795 -identifying_columns => [ 0, 4 ],
fcf32d04 796 -is_optional => 1,
fcf32d04 797 tracks => {
9f98c4b2 798 -identifying_columns => [ 0, 4, 8 ],
fcf32d04 799 -is_optional => 1,
fcf32d04 800 }
801 }
802 }
803 }
804 },
805 tracks => {
9f98c4b2 806 -identifying_columns => [ 2, 3 ],
fcf32d04 807 -is_optional => 1,
fcf32d04 808 }
809 },
810 'Correct underdefined root collapse map constructed'
811);
812
813is_same_src (
02a73c96 814 ($schema->source ('CD')->_mk_row_parser({
fcf32d04 815 inflate_map => $infmap,
816 collapse => 1,
02a73c96 817 }))[0],
aa1d8a87 818 ' my $rows_pos = 0;
819 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
fcf32d04 820
9f98c4b2 821 while ($cur_row_data = (
164aab8c 822 (
823 $rows_pos >= 0
824 and
825 (
826 $_[0][$rows_pos++]
827 or
828 ( ($rows_pos = -1), undef )
829 )
830 )
831 or
832 ( $_[1] and $_[1]->() )
3b4cd124 833 ) ) {
fcf32d04 834
b3a400a0 835
836 # NULL checks
837 #
838 # from_first_encounter => [ [0, 4, 8] ]
839 # all_or_nothing => [ { 2 => 1, 3 => 1 } ]
840 (
841 ( not defined $cur_row_data->[0] )
842 ? (
843 ( not defined $cur_row_data->[4] )
844 and
845 ( not defined $cur_row_data->[8] )
846 or
847 ( $_[3]->{0} = 1 )
848 )
849 : ( not defined $cur_row_data->[4] )
850 ? (
851 ( not defined $cur_row_data->[8] )
852 or
853 ( $_[3]->{4} = 1 )
854 )
855 : ()
856 ),
857
858 (
859 (
860 ( not defined $cur_row_data->[2] )
861 and
862 ( not defined $cur_row_data->[3] )
863 )
864 or
865 (
866 ( defined($cur_row_data->[2]) or $_[3]->{2} = 1 ),
867 ( defined($cur_row_data->[3]) or $_[3]->{3} = 1 ),
868 )
869 ),
870
871 ( keys %{$_[3]} and (
872 ( @{$_[2]} = $cur_row_data ),
873 ( $result_pos = 0 ),
874 last
875 ) ),
876
877
05a5ca4b 878 ( @cur_row_ids{( 0, 2, 3, 4, 8 )} = (
c863e102 879 $cur_row_data->[0] // "\0NULL\xFF$rows_pos\xFF0\0",
880 $cur_row_data->[2] // "\0NULL\xFF$rows_pos\xFF2\0",
881 $cur_row_data->[3] // "\0NULL\xFF$rows_pos\xFF3\0",
882 $cur_row_data->[4] // "\0NULL\xFF$rows_pos\xFF4\0",
883 $cur_row_data->[8] // "\0NULL\xFF$rows_pos\xFF8\0",
05a5ca4b 884 )),
fcf32d04 885
886 # cache expensive set of ops in a non-existent rowid slot
05a5ca4b 887 ( $cur_row_ids{10} = (
c863e102 888 ( ( defined $cur_row_data->[0] ) && (join "\xFF", q{}, $cur_row_ids{0}, q{} ))
fcf32d04 889 or
c863e102 890 ( ( defined $cur_row_data->[2] ) && (join "\xFF", q{}, $cur_row_ids{2}, q{} ))
fcf32d04 891 or
892 "\0$rows_pos\0"
05a5ca4b 893 )),
fcf32d04 894
9f98c4b2 895 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
05a5ca4b 896 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{10}} and (unshift @{$_[2]}, $cur_row_data) and last ),
fcf32d04 897
05a5ca4b 898 ( $collapse_idx[0]{$cur_row_ids{10}} //= $_[0][$result_pos++] = [{ year => $$cur_row_data[1] }] ),
fcf32d04 899
05a5ca4b 900 ( $collapse_idx[0]{$cur_row_ids{10}}[1]{single_track} //= ($collapse_idx[1]{$cur_row_ids{0}} = [{ trackid => $cur_row_data->[0] }]) ),
901 ( defined($cur_row_data->[0]) or bless ( $collapse_idx[0]{$cur_row_ids{10}}[1]{single_track}, __NBC__ ) ),
fcf32d04 902
05a5ca4b 903 ( $collapse_idx[1]{$cur_row_ids{0}}[1]{cd} //= $collapse_idx[2]{$cur_row_ids{0}} = [] ),
fcf32d04 904
05a5ca4b 905 ( $collapse_idx[2]{$cur_row_ids{0}}[1]{artist} //= ($collapse_idx[3]{$cur_row_ids{0}} = [{ artistid => $cur_row_data->[6] }]) ),
fcf32d04 906
05a5ca4b 907 (
908 (! $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}} )
909 and
910 push @{$collapse_idx[3]{$cur_row_ids{0}}[1]{cds}}, (
52864fbd 911 $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] }]
05a5ca4b 912 )
913 ),
914 ( defined($cur_row_data->[4]) or bless ( $collapse_idx[3]{$cur_row_ids{0}}[1]{cds}, __NBC__ ) ),
915
916 (
917 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} )
918 and
919 push @{$collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}[1]{tracks}}, (
920 $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} = [{ title => $cur_row_data->[8] }]
921 )
922 ),
923 ( defined($cur_row_data->[8]) or bless ( $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}[1]{tracks}, __NBC__ ) ),
924
925 (
926 (! $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} )
927 and
928 push @{$collapse_idx[0]{$cur_row_ids{10}}[1]{tracks}}, (
52864fbd 929 $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} = [{ cd => $$cur_row_data[2], title => $cur_row_data->[3] }]
05a5ca4b 930 )
931 ),
932 ( defined($cur_row_data->[2]) or bless ( $collapse_idx[0]{$cur_row_ids{10}}[1]{tracks}, __NBC__ ) ),
fcf32d04 933 }
934
aa1d8a87 935 $#{$_[0]} = $result_pos - 1;
fcf32d04 936 ',
937 'Multiple has_many on multiple branches with underdefined root torture test',
938);
939
ce556881 940is_same_src (
02a73c96 941 ($schema->source ('CD')->_mk_row_parser({
ce556881 942 inflate_map => $infmap,
943 collapse => 1,
ce556881 944 hri_style => 1,
79adc44f 945 prune_null_branches => 1,
02a73c96 946 }))[0],
aa1d8a87 947 ' my $rows_pos = 0;
06b3406d 948 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
ce556881 949
950 while ($cur_row_data = (
164aab8c 951 (
952 $rows_pos >= 0
953 and
954 (
955 $_[0][$rows_pos++]
956 or
957 ( ($rows_pos = -1), undef )
958 )
959 )
960 or
961 ( $_[1] and $_[1]->() )
3b4cd124 962 ) ) {
963
b3a400a0 964
965 # NULL checks
966 #
967 # from_first_encounter => [ [0, 4, 8] ]
968 # all_or_nothing => [ { 2 => 1, 3 => 1 } ]
969 (
970 ( not defined $cur_row_data->[0] )
971 ? (
972 ( not defined $cur_row_data->[4] )
973 and
974 ( not defined $cur_row_data->[8] )
975 or
976 ( $_[3]->{0} = 1 )
977 )
978 : ( not defined $cur_row_data->[4] )
979 ? (
980 ( not defined $cur_row_data->[8] )
981 or
982 ( $_[3]->{4} = 1 )
983 )
984 : ()
985 ),
986
987 (
988 (
989 ( not defined $cur_row_data->[2] )
990 and
991 ( not defined $cur_row_data->[3] )
992 )
993 or
994 (
995 ( defined($cur_row_data->[2]) or $_[3]->{2} = 1 ),
996 ( defined($cur_row_data->[3]) or $_[3]->{3} = 1 ),
997 )
998 ),
999
1000 ( keys %{$_[3]} and (
1001 ( @{$_[2]} = $cur_row_data ),
1002 ( $result_pos = 0 ),
1003 last
1004 ) ),
1005
1006
5e6d06f4 1007 # do not care about nullability here
05a5ca4b 1008 ( @cur_row_ids{( 0, 2, 3, 4, 8 )} = @{$cur_row_data}[( 0, 2, 3, 4, 8 )] ),
06b3406d 1009
ce556881 1010 # cache expensive set of ops in a non-existent rowid slot
05a5ca4b 1011 ( $cur_row_ids{10} = (
c863e102 1012 ( ( defined $cur_row_data->[0] ) && (join "\xFF", q{}, $cur_row_ids{0}, q{} ))
ce556881 1013 or
c863e102 1014 ( ( defined $cur_row_data->[2] ) && (join "\xFF", q{}, $cur_row_ids{2}, q{} ))
ce556881 1015 or
1016 "\0$rows_pos\0"
05a5ca4b 1017 )),
ce556881 1018
1019 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
05a5ca4b 1020 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{10}} and (unshift @{$_[2]}, $cur_row_data) and last ),
ce556881 1021
05a5ca4b 1022 ( $collapse_idx[0]{$cur_row_ids{10}} //= $_[0][$result_pos++] = { year => $$cur_row_data[1] } ),
ce556881 1023
05a5ca4b 1024 ( (! defined $cur_row_data->[0] ) ? $collapse_idx[0]{$cur_row_ids{10}}{single_track} = undef : do {
ce556881 1025
05a5ca4b 1026 ( $collapse_idx[0]{$cur_row_ids{10}}{single_track} //= ($collapse_idx[1]{$cur_row_ids{0}} = { trackid => $$cur_row_data[0] }) ),
ce556881 1027
40471d46 1028 ( $collapse_idx[1]{$cur_row_ids{0}}{cd} //= $collapse_idx[2]{$cur_row_ids{0}} = {} ),
ce556881 1029
05a5ca4b 1030 ( $collapse_idx[2]{$cur_row_ids{0}}{artist} //= ($collapse_idx[3]{$cur_row_ids{0}} = { artistid => $$cur_row_data[6] }) ),
ce556881 1031
05a5ca4b 1032 ( (! defined $cur_row_data->[4] ) ? $collapse_idx[3]{$cur_row_ids{0}}{cds} = [] : do {
ce556881 1033
05a5ca4b 1034 (
1035 (! $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}} )
1036 and
1037 push @{$collapse_idx[3]{$cur_row_ids{0}}{cds}}, (
1038 $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] }
1039 )
1040 ),
ce556881 1041
05a5ca4b 1042 ( (! defined $cur_row_data->[8] ) ? $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}{tracks} = [] : do {
7596ddca 1043
06b3406d 1044 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} )
7596ddca 1045 and
06b3406d 1046 push @{$collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}{tracks}}, (
1047 $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} = { title => $$cur_row_data[8] }
05a5ca4b 1048 ),
1049 } ),
1050 } ),
1051 } ),
7596ddca 1052
05a5ca4b 1053 ( (! defined $cur_row_data->[2] ) ? $collapse_idx[0]{$cur_row_ids{10}}{tracks} = [] : do {
1054 (
1055 (! $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} )
1056 and
1057 push @{$collapse_idx[0]{$cur_row_ids{10}}{tracks}}, (
06b3406d 1058 $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} = { cd => $$cur_row_data[2], title => $$cur_row_data[3] }
05a5ca4b 1059 )
1060 ),
1061 } ),
ce556881 1062 }
1063
aa1d8a87 1064 $#{$_[0]} = $result_pos - 1;
ce556881 1065 ',
52864fbd 1066 'Multiple has_many on multiple branches with underdefined root, HRI-direct torture test',
ce556881 1067);
1068
fd2d3c95 1069
1070$infmap = [
1071 'single_track.lyrics.track_id', # (0) random optional 1:1:1 chain
1072 'year', # (1) non-unique
1073 'tracks.cd', # (2) \ together both uniqueness for second multirel
1074 'tracks.title', # (3) / and definitive link back to root
1075 'single_track.cd.artist.cds.cdid', # (4) to give uniquiness to ...tracks.title below
1076 'single_track.cd.artist.cds.year', # (5) non-unique
1077 'single_track.cd.artist.artistid', # (6) uniqufies entire parental chain
1078 'single_track.cd.artist.cds.genreid', # (7) nullable
1079 'single_track.cd.artist.cds.tracks.title', # (8) unique when combined with ...cds.cdid above
1080 'single_track.lyrics.lyric_versions.text', # (9) unique combined with the single_track.lyrics 1:1:1
1081];
1082
1083is_deeply (
1084 $schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} }),
1085 {
1086 -identifying_columns => [],
1087 -identifying_columns_variants => [
1088 [ 2 ], [ 6 ],
1089 ],
1090 single_track => {
1091 -identifying_columns => [ 6 ],
1092 -is_optional => 1,
1093 -is_single => 1,
1094 cd => {
1095 -identifying_columns => [ 6 ],
1096 -is_single => 1,
1097 artist => {
1098 -identifying_columns => [ 6 ],
1099 -is_single => 1,
1100 cds => {
1101 -identifying_columns => [ 4, 6 ],
1102 -is_optional => 1,
1103 tracks => {
1104 -identifying_columns => [ 4, 6, 8 ],
1105 -is_optional => 1,
1106 }
1107 }
1108 }
1109 },
1110 lyrics => {
1111 -identifying_columns => [ 0, 6 ],
1112 -is_optional => 1,
1113 -is_single => 1,
1114 lyric_versions => {
1115 -identifying_columns => [ 0, 6, 9 ],
1116 -is_optional => 1,
1117 },
1118 },
1119 },
1120 tracks => {
1121 -identifying_columns => [ 2, 3 ],
1122 -is_optional => 1,
1123 }
1124 },
1125 'Correct underdefined root tripple-has-many-torture collapse map constructed'
1126);
1127
1128is_same_src (
1129 ($schema->source ('CD')->_mk_row_parser({
1130 inflate_map => $infmap,
1131 collapse => 1,
1132 hri_style => 1,
1133 prune_null_branches => 1,
1134 }))[0],
1135 ' my $rows_pos = 0;
1136 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
1137
1138 while ($cur_row_data = (
1139 (
1140 $rows_pos >= 0
1141 and
1142 (
1143 $_[0][$rows_pos++]
1144 or
1145 ( ($rows_pos = -1), undef )
1146 )
1147 )
1148 or
1149 ( $_[1] and $_[1]->() )
1150 ) ) {
1151
b3a400a0 1152 # NULL checks
1153 #
1154 # from_first_encounter => [ [6, 4, 8], [6, 0, 9] ]
1155 # all_or_nothing => [ { 2 => 1, 3 => 1 } ]
1156 (
1157 ( not defined $cur_row_data->[6] )
1158 ? (
1159 ( not defined $cur_row_data->[4] )
1160 and
1161 ( not defined $cur_row_data->[8] )
1162 or
1163 ( $_[3]->{6} = 1 )
1164 )
1165 : ( not defined $cur_row_data->[4] )
1166 ? (
1167 ( not defined $cur_row_data->[8] )
1168 or
1169 ( $_[3]->{4} = 1 )
1170 )
1171 : ()
1172 ),
1173
1174 (
1175 ( not defined $cur_row_data->[6] )
1176 ? (
1177 ( not defined $cur_row_data->[0] )
1178 and
1179 ( not defined $cur_row_data->[9] )
1180 or
1181 ( $_[3]->{6} = 1 )
1182 )
1183 : ( not defined $cur_row_data->[0] )
1184 ? (
1185 ( not defined $cur_row_data->[9] )
1186 or
1187 ( $_[3]->{0} = 1 )
1188 )
1189 : ()
1190 ),
1191
1192 (
1193 (
1194 ( not defined $cur_row_data->[2] )
1195 and
1196 ( not defined $cur_row_data->[3] )
1197 )
1198 or
1199 (
1200 ( defined($cur_row_data->[2]) or $_[3]->{2} = 1 ),
1201 ( defined($cur_row_data->[3]) or $_[3]->{3} = 1 ),
1202 )
1203 ),
1204
1205 ( keys %{$_[3]} and (
1206 ( @{$_[2]} = $cur_row_data ),
1207 ( $result_pos = 0 ),
1208 last
1209 ) ),
1210
1211
fd2d3c95 1212 # do not care about nullability here
1213 ( @cur_row_ids{( 0, 2, 3, 4, 6, 8, 9 )} = @{$cur_row_data}[( 0, 2, 3, 4, 6, 8, 9 )] ),
1214
1215 # cache expensive set of ops in a non-existent rowid slot
1216 ( $cur_row_ids{11} = (
1217 ( ( defined $cur_row_data->[2] ) && (join "\xFF", q{}, $cur_row_ids{2}, q{} ))
1218 or
1219 ( ( defined $cur_row_data->[6] ) && (join "\xFF", q{}, $cur_row_ids{6}, q{} ))
1220 or
1221 "\0$rows_pos\0"
1222 )),
1223
1224 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
1225 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{11}} and (unshift @{$_[2]}, $cur_row_data) and last ),
1226
1227 ( $collapse_idx[0]{$cur_row_ids{11}} //= $_[0][$result_pos++] = { year => $$cur_row_data[1] } ),
1228
1229 ( (! defined $cur_row_data->[6] ) ? $collapse_idx[0]{$cur_row_ids{11}}{single_track} = undef : do {
1230
1231 ( $collapse_idx[0]{$cur_row_ids{11}}{single_track} //= ( $collapse_idx[1]{$cur_row_ids{6}} = {} ) ),
1232
1233 ( $collapse_idx[1]{$cur_row_ids{6}}{cd} //= $collapse_idx[2]{$cur_row_ids{6}} = {} ),
1234
1235 ( $collapse_idx[2]{$cur_row_ids{6}}{artist} //= ($collapse_idx[3]{$cur_row_ids{6}} = { artistid => $$cur_row_data[6] }) ),
1236
1237 ( (! defined $cur_row_data->[4] ) ? $collapse_idx[3]{$cur_row_ids{6}}{cds} = [] : do {
1238
1239 (
1240 (! $collapse_idx[4]{$cur_row_ids{4}}{$cur_row_ids{6}} )
1241 and
1242 push @{$collapse_idx[3]{$cur_row_ids{6}}{cds}}, (
1243 $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] }
1244 )
1245 ),
1246
1247 ( (! defined $cur_row_data->[8] ) ? $collapse_idx[4]{$cur_row_ids{4}}{$cur_row_ids{6}}{tracks} = [] : do {
1248
1249 (! $collapse_idx[5]{$cur_row_ids{4}}{$cur_row_ids{6}}{$cur_row_ids{8}} )
1250 and
1251 push @{$collapse_idx[4]{$cur_row_ids{4}}{$cur_row_ids{6}}{tracks}}, (
1252 $collapse_idx[5]{$cur_row_ids{4}}{$cur_row_ids{6}}{$cur_row_ids{8}} = { title => $$cur_row_data[8] }
1253 ),
1254 } ),
1255 } ),
1256
1257 ( ( ! defined $cur_row_data->[0] ) ? $collapse_idx[1]{ $cur_row_ids{6} }{"lyrics"} = undef : do {
1258
1259 ( $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] } ) ),
1260
1261 ( ( ! defined $cur_row_data->[9] ) ? $collapse_idx[6]{ $cur_row_ids{0} }{ $cur_row_ids{6} }{"lyric_versions"} = [] : do {
1262 (
1263 (! $collapse_idx[7]{ $cur_row_ids{0} }{ $cur_row_ids{6} }{ $cur_row_ids{9} })
1264 and
1265 push @{$collapse_idx[6]{ $cur_row_ids{0} }{ $cur_row_ids{6} }{"lyric_versions"}}, (
1266 $collapse_idx[7]{ $cur_row_ids{0} }{ $cur_row_ids{6} }{ $cur_row_ids{9} } = { "text" => $cur_row_data->[9] }
1267 ),
1268 ),
1269 } ),
1270 } ),
1271 } ),
1272
1273 ( (! defined $cur_row_data->[2] ) ? $collapse_idx[0]{$cur_row_ids{11}}{tracks} = [] : do {
1274 (
1275 (! $collapse_idx[8]{$cur_row_ids{2}}{$cur_row_ids{3}} )
1276 and
1277 push @{$collapse_idx[0]{$cur_row_ids{11}}{tracks}}, (
1278 $collapse_idx[8]{$cur_row_ids{2}}{$cur_row_ids{3}} = { cd => $$cur_row_data[2], title => $$cur_row_data[3] }
1279 )
1280 ),
1281 } ),
1282 }
1283
1284 $#{$_[0]} = $result_pos - 1;
1285 ',
1286 'Tripple multiple has_many on multiple branches with underdefined root, HRI-direct torture test',
1287);
1288
c863e102 1289is_same_src (
1290 ($schema->source ('Owners')->_mk_row_parser({
1291 inflate_map => [qw( books.title books.owner )],
1292 collapse => 1,
1293 prune_null_branches => 1,
1294 }))[0],
1295 ' my $rows_pos = 0;
1296 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids );
1297
1298 while ($cur_row_data = (
164aab8c 1299 (
1300 $rows_pos >= 0
1301 and
1302 (
1303 $_[0][$rows_pos++]
1304 or
1305 ( ($rows_pos = -1), undef )
1306 )
1307 )
c863e102 1308 or
164aab8c 1309 ( $_[1] and $_[1]->() )
c863e102 1310 ) ) {
1311
05a5ca4b 1312 ( @cur_row_ids{0,1} = @{$cur_row_data}[0,1] ),
c863e102 1313
05a5ca4b 1314 ( $cur_row_ids{3} = (
c863e102 1315 ( ( defined $cur_row_data->[1] ) && (join "\xFF", q{}, $cur_row_ids{1}, q{} ))
1316 or
1317 "\0${rows_pos}\0"
05a5ca4b 1318 )),
c863e102 1319
05a5ca4b 1320 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{3}} and (unshift @{$_[2]}, $cur_row_data) and last ),
c863e102 1321
1322 # empty data for the root node
05a5ca4b 1323 ( $collapse_idx[0]{$cur_row_ids{3}} //= $_[0][$result_pos++] = [] ),
c863e102 1324
05a5ca4b 1325 ( ( ! defined $cur_row_data->[0] ) ? $collapse_idx[0]{$cur_row_ids{3}}[1]{"books"} = [] : do {
17f1b61e 1326 ( ! $collapse_idx[1]{$cur_row_ids{0}} )
1327 and
c863e102 1328 push @{$collapse_idx[0]{$cur_row_ids{3}}[1]{books}},
1329 $collapse_idx[1]{$cur_row_ids{0}} = [ { owner => $cur_row_data->[1], title => $cur_row_data->[0] } ]
05a5ca4b 1330 } ),
c863e102 1331 }
1332
1333 $#{$_[0]} = $result_pos - 1; # truncate the passed in array to where we filled it with results
1334 ',
1335 'Non-premultiplied implicit collapse with missing join columns',
1336);
1337
b3a400a0 1338is_same_src (
1339 ($schema->source('Artist')->_mk_row_parser({
1340 inflate_map => [qw( artistid cds.artist cds.title cds.tracks.title )],
1341 collapse => 1,
1342 prune_null_branches => 1,
1343 }))[0],
1344 ' my $rows_pos = 0;
1345 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids );
1346
1347 while ($cur_row_data = (
1348 (
1349 $rows_pos >= 0
1350 and
1351 (
1352 $_[0][$rows_pos++]
1353 or
1354 ( ($rows_pos = -1), undef )
1355 )
1356 )
1357 or
1358 ( $_[1] and $_[1]->() )
1359 ) ) {
1360
1361 # NULL checks
1362 #
1363 # mandatory => { 0 => 1 }
1364 # from_first_encounter => [ [1, 2, 3] ]
1365 # all_or_nothing => [ { 1 => 1, 2 => 1 } ]
1366
1367 ( defined( $cur_row_data->[0] ) or $_[3]->{0} = 1 ),
1368
1369 (
1370 ( not defined $cur_row_data->[1] )
1371 ? (
1372 ( not defined $cur_row_data->[2] )
1373 and
1374 ( not defined $cur_row_data->[3] )
1375 or
1376 $_[3]->{1} = 1
1377 )
1378 : ( not defined $cur_row_data->[2] )
1379 ? (
1380 ( not defined $cur_row_data->[3] )
1381 or
1382 $_[3]->{2} = 1
1383 )
1384 : ()
1385 ),
1386
1387 (
1388 (
1389 ( not defined $cur_row_data->[1] )
1390 and
1391 ( not defined $cur_row_data->[2] )
1392 )
1393 or
1394 (
1395 ( defined($cur_row_data->[1]) or $_[3]->{1} = 1 ),
1396 ( defined($cur_row_data->[2]) or $_[3]->{2} = 1 ),
1397 )
1398 ),
1399
1400 ( keys %{$_[3]} and (
1401 ( @{$_[2]} = $cur_row_data ),
1402 ( $result_pos = 0 ),
1403 last
1404 ) ),
1405
1406
1407 ( @cur_row_ids{( 0, 1, 2, 3 )} = @{$cur_row_data}[ 0, 1, 2, 3 ] ),
1408
1409 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{0}} and (unshift @{$_[2]}, $cur_row_data) and last ),
1410
1411 ( $collapse_idx[0]{ $cur_row_ids{0} }
1412 //= $_[0][$result_pos++] = [ { "artistid" => $cur_row_data->[0] } ]
1413 ),
1414
1415 ( ( ! defined $cur_row_data->[1] ) ? $collapse_idx[0]{ $cur_row_ids{0} }[1]{"cds"} = [] : do {
1416
1417 (
1418 ! $collapse_idx[1]{ $cur_row_ids{0} }{ $cur_row_ids{1} }{ $cur_row_ids{2} }
1419 and
1420 push @{$collapse_idx[0]{ $cur_row_ids{0} }[1]{"cds"}},
1421 $collapse_idx[1]{ $cur_row_ids{0} }{ $cur_row_ids{1} }{ $cur_row_ids{2} }
1422 = [ { "artist" => $cur_row_data->[1], "title" => $cur_row_data->[2] } ]
1423 ),
1424
1425 ( ( ! defined $cur_row_data->[3] ) ? $collapse_idx[1]{ $cur_row_ids{0} }{ $cur_row_ids{1} }{ $cur_row_ids{2} }[1]{"tracks"} = [] : do {
1426 (
1427 ! $collapse_idx[2]{ $cur_row_ids{0} }{ $cur_row_ids{1} }{ $cur_row_ids{2} }{ $cur_row_ids{3} }
1428 and
1429 push @{$collapse_idx[1]{ $cur_row_ids{0} }{ $cur_row_ids{1} }{ $cur_row_ids{2} }[1]{"tracks"}},
1430 $collapse_idx[2]{ $cur_row_ids{0} }{ $cur_row_ids{1} }{ $cur_row_ids{2} }{ $cur_row_ids{3} }
1431 = [ { "title" => $cur_row_data->[3] } ]
1432 ),
1433 } ),
1434 } ),
1435 }
1436
1437 $#{$_[0]} = $result_pos - 1
1438 ',
1439 'A rolled out version of inflate map of misled_rowparser.t'
1440);
1441
4e9fc3f3 1442done_testing;
1443
1444my $deparser;
cd784aab 1445sub is_same_src { SKIP: {
2fdeef65 1446
3cff955a 1447 skip "Skipping comparison of unicode-poisoned source", 1
2fdeef65 1448 if DBIx::Class::_ENV_::STRESSTEST_UTF8_UPGRADE_GENERATED_COLLAPSER_SOURCE;
1449
4e9fc3f3 1450 $deparser ||= B::Deparse->new;
1451 local $Test::Builder::Level = $Test::Builder::Level + 1;
1452
52864fbd 1453 my ($got, $expect) = @_;
1454
cd784aab 1455 skip "Not testing equality of source containing defined-or operator on this perl $]", 1
750a4ad2 1456 if ( "$]" < 5.010 and $expect =~ m!\Q//=! );
cd784aab 1457
01b25f12 1458 $expect =~ s/__NBC__/perlstring($DBIx::Class::ResultSource::RowParser::Util::null_branch_class)/ge;
52864fbd 1459
9f7d5590 1460 $expect = " { use strict; use warnings FATAL => 'uninitialized';\n$expect\n }";
bdbd2ae8 1461
52864fbd 1462 my @normalized = map {
4e9fc3f3 1463 my $cref = eval "sub { $_ }" or do {
1464 fail "Coderef does not compile!\n\n$@\n\n$_";
1465 return undef;
1466 };
1467 $deparser->coderef2text($cref);
52864fbd 1468 } ($got, $expect);
1469
1470 &is (@normalized, $_[2]||() ) or do {
1471 eval { require Test::Differences }
1472 ? &Test::Differences::eq_or_diff( @normalized, $_[2]||() )
e81b50f4 1473 : note ("Original sources:\n\n$got\n\n$expect\n")
1474 ;
1475 exit 1;
52864fbd 1476 };
cd784aab 1477} }