Add extra (passing) test for operations on sourceless results
[dbsrgits/DBIx-Class.git] / t / resultset / rowparser_internals.t
CommitLineData
4e9fc3f3 1use strict;
2use warnings;
3
4use Test::More;
5use lib qw(t/lib);
6use DBICTest;
7use B::Deparse;
01b25f12 8use DBIx::Class::_Util 'perlstring';
4e9fc3f3 9
7d5371dc 10# globally set for the rest of test
11# the rowparser maker does not order its hashes by default for the miniscule
12# speed gain. But it does not disable sorting either - for this test
13# everything will be ordered nicely, and the hash randomization of 5.18
14# will not trip up anything
15use Data::Dumper;
16$Data::Dumper::Sortkeys = 1;
17
4e9fc3f3 18my $schema = DBICTest->init_schema(no_deploy => 1);
ce556881 19my $infmap = [qw/
20 single_track.cd.artist.name
21 year
22/];
4e9fc3f3 23
24is_same_src (
02a73c96 25 ($schema->source ('CD')->_mk_row_parser({
4e9fc3f3 26 inflate_map => $infmap,
02a73c96 27 }))[0],
4e9fc3f3 28 '$_ = [
29 { year => $_->[1] },
52864fbd 30 { single_track => ( ! defined( $_->[0]) )
31 ? bless( [
4e9fc3f3 32 undef,
52864fbd 33 { cd => [
34 undef,
35 { artist => [
36 { name => $_->[0] },
37 ] },
4e9fc3f3 38 ] },
52864fbd 39 ], __NBC__ )
40 : [
41 undef,
42 { cd => [
43 undef,
44 { artist => [
45 { name => $_->[0] },
46 ] },
47 ] },
48 ]
49 },
4e9fc3f3 50 ] for @{$_[0]}',
51 'Simple 1:1 descending non-collapsing parser',
52);
53
54$infmap = [qw/
3faac878 55 single_track.cd.artist.cds.tracks.title
4e9fc3f3 56 single_track.cd.artist.artistid
57 year
4e9fc3f3 58 single_track.cd.artist.cds.cdid
59 title
60 artist
61/];
4e9fc3f3 62
ce556881 63is_same_src (
02a73c96 64 ($schema->source ('CD')->_mk_row_parser({
ce556881 65 inflate_map => $infmap,
02a73c96 66 }))[0],
ce556881 67 '$_ = [
68 { artist => $_->[5], title => $_->[4], year => $_->[2] },
69 {
52864fbd 70 single_track => ( (! defined $_->[0] ) && (! defined $_->[1]) && (! defined $_->[3] ) )
71 ? bless( [
72 undef,
73 {
74 cd => [
75 undef,
76 {
77 artist => [
78 { artistid => $_->[1] },
79 {
80 cds => ( (! defined $_->[0] ) && ( ! defined $_->[3] ) )
81 ? bless ([
82 { cdid => $_->[3] },
83 {
84 tracks => ( ! defined $_->[0] )
85 ? bless ( [{ title => $_->[0] }], __NBC__ )
86 : [{ title => $_->[0] }]
87 }
88 ], __NBC__)
89 : [
90 { cdid => $_->[3] },
91 {
92 tracks => ( ! defined $_->[0] )
93 ? bless ( [{ title => $_->[0] }], __NBC__ )
94 : [{ title => $_->[0] }]
95 }
96 ]
97 }
98 ]
99 }
100 ]
101 }
102 ], __NBC__)
103 : [
ce556881 104 undef,
105 {
106 cd => [
107 undef,
108 {
109 artist => [
110 { artistid => $_->[1] },
111 {
52864fbd 112 cds => ( (! defined $_->[0] ) && ( ! defined $_->[3] ) )
113 ? bless ([
114 { cdid => $_->[3] },
115 {
116 tracks => ( ! defined $_->[0] )
117 ? bless ( [{ title => $_->[0] }], __NBC__ )
118 : [{ title => $_->[0] }]
119 }
120 ], __NBC__)
121 : [
ce556881 122 { cdid => $_->[3] },
123 {
52864fbd 124 tracks => ( ! defined $_->[0] )
125 ? bless ( [{ title => $_->[0] }], __NBC__ )
126 : [{ title => $_->[0] }]
ce556881 127 }
52864fbd 128 ]
ce556881 129 }
130 ]
131 }
132 ]
133 }
52864fbd 134 ]
ce556881 135 }
136 ] for @{$_[0]}',
52864fbd 137 '1:1 descending non-collapsing parser terminating with chained 1:M:M',
ce556881 138);
139
140is_same_src (
02a73c96 141 ($schema->source ('CD')->_mk_row_parser({
79adc44f 142 prune_null_branches => 1,
143 inflate_map => $infmap,
02a73c96 144 }))[0],
79adc44f 145 '$_ = [
146 { artist => $_->[5], title => $_->[4], year => $_->[2] },
147 {
148 single_track => ( (! defined $_->[0] ) && (! defined $_->[1]) && (! defined $_->[3] ) ) ? undef : [
149 undef,
150 {
151 cd => [
152 undef,
153 {
154 artist => [
155 { artistid => $_->[1] },
156 {
157 cds => ( (! defined $_->[0] ) && ( ! defined $_->[3] ) ) ? undef : [
158 { cdid => $_->[3] },
159 {
160 tracks => ( ! defined $_->[0] ) ? undef : [
161 { title => $_->[0] },
162 ]
163 }
164 ]
165 }
166 ]
167 }
168 ]
169 }
170 ]
171 }
172 ] for @{$_[0]}',
173 '1:1 descending non-collapsing pruning parser terminating with chained 1:M:M',
174);
175
176is_same_src (
02a73c96 177 ($schema->source ('CD')->_mk_row_parser({
ce556881 178 hri_style => 1,
79adc44f 179 prune_null_branches => 1,
ce556881 180 inflate_map => $infmap,
02a73c96 181 }))[0],
ce556881 182 '$_ = {
183 artist => $_->[5], title => $_->[4], year => $_->[2],
184
52864fbd 185 ( single_track => ( (! defined $_->[0] ) && (! defined $_->[1]) && (! defined $_->[3] ) )
186 ? undef
187 : {
ce556881 188 cd =>
189 {
190 artist => {
191 artistid => $_->[1],
52864fbd 192 ( cds => ( (! defined $_->[0] ) && ( ! defined $_->[3] ) )
193 ? undef
194 : {
ce556881 195 cdid => $_->[3],
52864fbd 196 ( tracks => ( ! defined $_->[0] )
197 ? undef
198 : { title => $_->[0] }
199 )
ce556881 200 }
52864fbd 201 )
ce556881 202 }
203 }
204 }
52864fbd 205 )
ce556881 206 } for @{$_[0]}',
52864fbd 207 '1:1 descending non-collapsing HRI-direct parser terminating with chained 1:M:M',
ce556881 208);
209
210
211
4e9fc3f3 212is_deeply (
3faac878 213 ($schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} })),
4e9fc3f3 214 {
9f98c4b2 215 -identifying_columns => [ 4, 5 ],
4e9fc3f3 216
217 single_track => {
a0726a33 218 -identifying_columns => [ 1, 4, 5 ],
4e9fc3f3 219 -is_optional => 1,
220 -is_single => 1,
221
222 cd => {
a0726a33 223 -identifying_columns => [ 1, 4, 5 ],
4e9fc3f3 224 -is_single => 1,
225
226 artist => {
a0726a33 227 -identifying_columns => [ 1, 4, 5 ],
4e9fc3f3 228 -is_single => 1,
229
230 cds => {
a0726a33 231 -identifying_columns => [ 1, 3, 4, 5 ],
4e9fc3f3 232 -is_optional => 1,
233
234 tracks => {
a0726a33 235 -identifying_columns => [ 0, 1, 3, 4, 5 ],
4e9fc3f3 236 -is_optional => 1,
237 },
238 },
239 },
240 },
241 },
242 },
243 'Correct collapse map for 1:1 descending chain terminating with chained 1:M:M'
244);
245
246is_same_src (
02a73c96 247 ($schema->source ('CD')->_mk_row_parser({
4e9fc3f3 248 inflate_map => $infmap,
249 collapse => 1,
02a73c96 250 }))[0],
aa1d8a87 251 ' my $rows_pos = 0;
252 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
4e9fc3f3 253
9f98c4b2 254 while ($cur_row_data = (
164aab8c 255 (
256 $rows_pos >= 0
257 and
258 (
259 $_[0][$rows_pos++]
260 or
261 ( ($rows_pos = -1), undef )
262 )
263 )
264 or
265 ( $_[1] and $_[1]->() )
3b4cd124 266 ) ) {
4e9fc3f3 267
05a5ca4b 268 ( @cur_row_ids{0,1,3,4,5} = (
c863e102 269 ( $cur_row_data->[0] // "\0NULL\xFF$rows_pos\xFF0\0" ),
270 ( $cur_row_data->[1] // "\0NULL\xFF$rows_pos\xFF1\0" ),
271 ( $cur_row_data->[3] // "\0NULL\xFF$rows_pos\xFF3\0" ),
272 ( $cur_row_data->[4] // "\0NULL\xFF$rows_pos\xFF4\0" ),
273 ( $cur_row_data->[5] // "\0NULL\xFF$rows_pos\xFF5\0" ),
05a5ca4b 274 ) ),
4e9fc3f3 275
3faac878 276 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
05a5ca4b 277 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} and (unshift @{$_[2]}, $cur_row_data) and last ),
4e9fc3f3 278
3faac878 279 # the rowdata itself for root node
05a5ca4b 280 ( $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} //= $_[0][$result_pos++] = [{ artist => $cur_row_data->[5], title => $cur_row_data->[4], year => $cur_row_data->[2] }] ),
3faac878 281
282 # prefetch data of single_track (placed in root)
05a5ca4b 283 ( $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{single_track} //= $collapse_idx[1]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}} = [] ),
284 ( defined($cur_row_data->[1]) or bless( $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{single_track}, __NBC__ ) ),
3faac878 285
286 # prefetch data of cd (placed in single_track)
05a5ca4b 287 ( $collapse_idx[1]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{cd} //= $collapse_idx[2]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}} = [] ),
4e9fc3f3 288
3faac878 289 # prefetch data of artist ( placed in single_track->cd)
05a5ca4b 290 ( $collapse_idx[2]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{artist} //= $collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}} = [{ artistid => $cur_row_data->[1] }] ),
3faac878 291
292 # prefetch data of cds (if available)
05a5ca4b 293 (
294 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
295 and
296 push @{$collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{cds}}, (
297 $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} = [{ cdid => $cur_row_data->[3] }]
298 )
299 ),
300 ( defined($cur_row_data->[3]) or bless( $collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{cds}, __NBC__ ) ),
4e9fc3f3 301
3faac878 302 # prefetch data of tracks (if available)
05a5ca4b 303 (
304 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
305 and
306 push @{$collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{tracks}}, (
307 $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} = [{ title => $cur_row_data->[0] }]
308 )
309 ),
310 ( defined($cur_row_data->[0]) or bless( $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{tracks}, __NBC__ ) ),
4e9fc3f3 311
4e9fc3f3 312 }
aa1d8a87 313 $#{$_[0]} = $result_pos - 1;
4e9fc3f3 314 ',
315 'Same 1:1 descending terminating with chained 1:M:M but with collapse',
316);
317
ce556881 318is_same_src (
02a73c96 319 ($schema->source ('CD')->_mk_row_parser({
ce556881 320 inflate_map => $infmap,
321 collapse => 1,
ce556881 322 hri_style => 1,
79adc44f 323 prune_null_branches => 1,
02a73c96 324 }))[0],
aa1d8a87 325 ' my $rows_pos = 0;
c863e102 326 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
ce556881 327
328 while ($cur_row_data = (
164aab8c 329 (
330 $rows_pos >= 0
331 and
332 (
333 $_[0][$rows_pos++]
334 or
335 ( ($rows_pos = -1), undef )
336 )
337 )
338 or
339 ( $_[1] and $_[1]->() )
3b4cd124 340 ) ) {
ce556881 341
05a5ca4b 342 ( @cur_row_ids{0, 1, 3, 4, 5} = @{$cur_row_data}[0, 1, 3, 4, 5] ),
c863e102 343
ce556881 344 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
05a5ca4b 345 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} and (unshift @{$_[2]}, $cur_row_data) and last ),
ce556881 346
347 # the rowdata itself for root node
05a5ca4b 348 ( $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} //= $_[0][$result_pos++] = { artist => $cur_row_data->[5], title => $cur_row_data->[4], year => $cur_row_data->[2] } ),
ce556881 349
350 # prefetch data of single_track (placed in root)
05a5ca4b 351 ( (! defined($cur_row_data->[1]) ) ? $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}{single_track} = undef : do {
352 ( $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}{single_track} //= $collapse_idx[1]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}} ),
ce556881 353
7596ddca 354 # prefetch data of cd (placed in single_track)
05a5ca4b 355 ( $collapse_idx[1]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}{cd} //= $collapse_idx[2]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}} ),
ce556881 356
7596ddca 357 # prefetch data of artist ( placed in single_track->cd)
05a5ca4b 358 ( $collapse_idx[2]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}{artist} //= $collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}} = { artistid => $cur_row_data->[1] } ),
ce556881 359
7596ddca 360 # prefetch data of cds (if available)
05a5ca4b 361 ( (! defined $cur_row_data->[3] ) ? $collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}{cds} = [] : do {
ce556881 362
05a5ca4b 363 (
364 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
365 and
366 push @{$collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}{cds}}, (
367 $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} = { cdid => $cur_row_data->[3] }
368 )
369 ),
ce556881 370
7596ddca 371 # prefetch data of tracks (if available)
05a5ca4b 372 (( ! defined $cur_row_data->[0] ) ? $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}{tracks} = [] : do {
373
374 (
375 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
376 and
377 push @{$collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}{tracks}}, (
378 $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} = { title => $cur_row_data->[0] }
379 )
380 ),
381 } ),
382 } ),
383 } ),
ce556881 384 }
aa1d8a87 385 $#{$_[0]} = $result_pos - 1;
ce556881 386 ',
52864fbd 387 'Same 1:1 descending terminating with chained 1:M:M but with collapse, HRI-direct',
ce556881 388);
389
4e9fc3f3 390$infmap = [qw/
3d8caf63 391 tracks.lyrics.existing_lyric_versions.text
4e9fc3f3 392 existing_single_track.cd.artist.artistid
393 existing_single_track.cd.artist.cds.year
394 year
395 genreid
396 tracks.title
397 existing_single_track.cd.artist.cds.cdid
398 latest_cd
399 existing_single_track.cd.artist.cds.tracks.title
400 existing_single_track.cd.artist.cds.genreid
3d8caf63 401 tracks.lyrics.existing_lyric_versions.lyric_id
4e9fc3f3 402/];
403
404is_deeply (
82f0e0aa 405 $schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} }),
4e9fc3f3 406 {
9f98c4b2 407 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
4e9fc3f3 408
409 existing_single_track => {
9f98c4b2 410 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
4e9fc3f3 411 -is_single => 1,
412
413 cd => {
9f98c4b2 414 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
4e9fc3f3 415 -is_single => 1,
416
417 artist => {
9f98c4b2 418 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
4e9fc3f3 419 -is_single => 1,
420
421 cds => {
9f98c4b2 422 -identifying_columns => [ 1, 6 ], # existing_single_track.cd.artist.cds.cdid
4e9fc3f3 423 -is_optional => 1,
424
425 tracks => {
9f98c4b2 426 -identifying_columns => [ 1, 6, 8 ], # existing_single_track.cd.artist.cds.cdid, existing_single_track.cd.artist.cds.tracks.title
4e9fc3f3 427 -is_optional => 1,
428 }
429 }
430 }
431 }
432 },
433 tracks => {
9f98c4b2 434 -identifying_columns => [ 1, 5 ], # existing_single_track.cd.artist.artistid, tracks.title
4e9fc3f3 435 -is_optional => 1,
436
437 lyrics => {
3d8caf63 438 -identifying_columns => [ 1, 5, 10 ], # existing_single_track.cd.artist.artistid, tracks.title, tracks.lyrics.existing_lyric_versions.lyric_id
4e9fc3f3 439 -is_single => 1,
440 -is_optional => 1,
441
3d8caf63 442 existing_lyric_versions => {
443 -identifying_columns => [ 0, 1, 5, 10 ], # tracks.lyrics.existing_lyric_versions.text, existing_single_track.cd.artist.artistid, tracks.title, tracks.lyrics.existing_lyric_versions.lyric_id
4e9fc3f3 444 },
445 },
446 }
447 },
448 'Correct collapse map constructed',
449);
450
451is_same_src (
02a73c96 452 ($schema->source ('CD')->_mk_row_parser({
4e9fc3f3 453 inflate_map => $infmap,
454 collapse => 1,
02a73c96 455 }))[0],
aa1d8a87 456 ' my $rows_pos = 0;
457 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
4e9fc3f3 458
9f98c4b2 459 while ($cur_row_data = (
164aab8c 460 (
461 $rows_pos >= 0
462 and
463 (
464 $_[0][$rows_pos++]
465 or
466 ( ($rows_pos = -1), undef )
467 )
468 )
469 or
470 ( $_[1] and $_[1]->() )
3b4cd124 471 ) ) {
4e9fc3f3 472
05a5ca4b 473 ( @cur_row_ids{0, 1, 5, 6, 8, 10} = (
c863e102 474 $cur_row_data->[0] // "\0NULL\xFF$rows_pos\xFF0\0",
475 $cur_row_data->[1] // "\0NULL\xFF$rows_pos\xFF1\0",
476 $cur_row_data->[5] // "\0NULL\xFF$rows_pos\xFF5\0",
477 $cur_row_data->[6] // "\0NULL\xFF$rows_pos\xFF6\0",
478 $cur_row_data->[8] // "\0NULL\xFF$rows_pos\xFF8\0",
479 $cur_row_data->[10] // "\0NULL\xFF$rows_pos\xFF10\0",
05a5ca4b 480 ) ),
4e9fc3f3 481
9f98c4b2 482 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
05a5ca4b 483 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{1}} and (unshift @{$_[2]}, $cur_row_data) and last ),
484
485 ( $collapse_idx[0]{$cur_row_ids{1}} //= $_[0][$result_pos++] = [{ genreid => $cur_row_data->[4], latest_cd => $cur_row_data->[7], year => $cur_row_data->[3] }] ),
486
487 ( $collapse_idx[0]{$cur_row_ids{1}}[1]{existing_single_track} //= $collapse_idx[1]{$cur_row_ids{1}} = [] ),
488 ( $collapse_idx[1]{$cur_row_ids{1}}[1]{cd} //= $collapse_idx[2]{$cur_row_ids{1}} = [] ),
489 ( $collapse_idx[2]{$cur_row_ids{1}}[1]{artist} //= $collapse_idx[3]{$cur_row_ids{1}} = [{ artistid => $cur_row_data->[1] }] ),
490
491 (
492 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}} )
493 and
494 push @{ $collapse_idx[3]{$cur_row_ids{1}}[1]{cds} }, (
495 $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}} = [{ cdid => $cur_row_data->[6], genreid => $cur_row_data->[9], year => $cur_row_data->[2] }]
496 )
497 ),
498 ( defined($cur_row_data->[6]) or bless( $collapse_idx[3]{$cur_row_ids{1}}[1]{cds}, __NBC__ ) ),
499
500 (
501 (! $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} )
502 and
503 push @{ $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks} }, (
504 $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} = [{ title => $cur_row_data->[8] }]
505 )
506 ),
507 ( defined($cur_row_data->[8]) or bless( $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks}, __NBC__ ) ),
508
509 (
510 (! $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} )
511 and
512 push @{ $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks} }, (
513 $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} = [{ title => $cur_row_data->[5] }]
514 )
515 ),
516 ( defined($cur_row_data->[5]) or bless( $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks}, __NBC__ ) ),
517
518 ( $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics} //= $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} = [] ),
519 ( defined($cur_row_data->[10]) or bless( $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics}, __NBC__ ) ),
520
521 (
522 (! $collapse_idx[8]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} )
523 and
524 push @{ $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}}[1]{existing_lyric_versions} }, (
525 $collapse_idx[8]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} = [{ lyric_id => $cur_row_data->[10], text => $cur_row_data->[0] }]
526 )
527 ),
4e9fc3f3 528 }
529
aa1d8a87 530 $#{$_[0]} = $result_pos - 1;
4e9fc3f3 531 ',
532 'Multiple has_many on multiple branches torture test',
533);
534
ce556881 535is_same_src (
02a73c96 536 ($schema->source ('CD')->_mk_row_parser({
ce556881 537 inflate_map => $infmap,
538 collapse => 1,
79adc44f 539 prune_null_branches => 1,
02a73c96 540 }))[0],
aa1d8a87 541 ' my $rows_pos = 0;
c863e102 542 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
ce556881 543
544 while ($cur_row_data = (
164aab8c 545 (
546 $rows_pos >= 0
547 and
548 (
549 $_[0][$rows_pos++]
550 or
551 ( ($rows_pos = -1), undef )
552 )
553 )
554 or
555 ( $_[1] and $_[1]->() )
3b4cd124 556 ) ) {
ce556881 557
05a5ca4b 558 ( @cur_row_ids{( 0, 1, 5, 6, 8, 10 )} = @{$cur_row_data}[( 0, 1, 5, 6, 8, 10 )] ),
c863e102 559
ce556881 560 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
05a5ca4b 561 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{1}} and (unshift @{$_[2]}, $cur_row_data) and last ),
ce556881 562
05a5ca4b 563 ( $collapse_idx[0]{$cur_row_ids{1}} //= $_[0][$result_pos++] = [{ genreid => $cur_row_data->[4], latest_cd => $cur_row_data->[7], year => $cur_row_data->[3] }] ),
ce556881 564
05a5ca4b 565 ( $collapse_idx[0]{$cur_row_ids{1}}[1]{existing_single_track} //= $collapse_idx[1]{$cur_row_ids{1}} = [] ),
566 ( $collapse_idx[1]{$cur_row_ids{1}}[1]{cd} //= $collapse_idx[2]{$cur_row_ids{1}} = [] ),
567 ( $collapse_idx[2]{$cur_row_ids{1}}[1]{artist} //= $collapse_idx[3]{$cur_row_ids{1}} = [{ artistid => $cur_row_data->[1] }] ),
ce556881 568
05a5ca4b 569 ( (! defined($cur_row_data->[6])) ? $collapse_idx[3]{$cur_row_ids{1}}[1]{cds} = [] : do {
570 (
571 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}} )
79adc44f 572 and
05a5ca4b 573 push @{ $collapse_idx[3]{$cur_row_ids{1}}[1]{cds} }, (
574 $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}} = [{ cdid => $cur_row_data->[6], genreid => $cur_row_data->[9], year => $cur_row_data->[2] }]
575 )
576 ),
577
578 ( (! defined($cur_row_data->[8]) ) ? $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks} = [] : do {
579 (
580 (! $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} )
581 and
582 push @{ $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks} }, (
583 $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} = [{ title => $cur_row_data->[8] }]
584 )
585 ),
586 } ),
587 } ),
ce556881 588
05a5ca4b 589 ( (! defined($cur_row_data->[5]) ) ? $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks} = [] : do {
ce556881 590
05a5ca4b 591 (
592 (! $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} )
593 and
594 push @{ $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks} }, (
595 $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} = [{ title => $cur_row_data->[5] }]
596 )
597 ),
79adc44f 598
05a5ca4b 599 ( (! defined($cur_row_data->[10]) ) ? $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics} = [] : do {
79adc44f 600
05a5ca4b 601 ( $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics} //= $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} = [] ),
79adc44f 602
05a5ca4b 603 (
604 (! $collapse_idx[8]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} )
605 and
606 push @{ $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}}[1]{existing_lyric_versions} }, (
607 $collapse_idx[8]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} = [{ lyric_id => $cur_row_data->[10], text => $cur_row_data->[0] }]
608 )
609 ),
610 } ),
611 } ),
ce556881 612 }
613
aa1d8a87 614 $#{$_[0]} = $result_pos - 1;
ce556881 615 ',
79adc44f 616 'Multiple has_many on multiple branches with branch pruning torture test',
ce556881 617);
618
fcf32d04 619$infmap = [
620 'single_track.trackid', # (0) definitive link to root from 1:1:1:1:M:M chain
621 'year', # (1) non-unique
622 'tracks.cd', # (2) \ together both uniqueness for second multirel
623 'tracks.title', # (3) / and definitive link back to root
624 'single_track.cd.artist.cds.cdid', # (4) to give uniquiness to ...tracks.title below
625 'single_track.cd.artist.cds.year', # (5) non-unique
626 'single_track.cd.artist.artistid', # (6) uniqufies entire parental chain
627 'single_track.cd.artist.cds.genreid', # (7) nullable
628 'single_track.cd.artist.cds.tracks.title',# (8) unique when combined with ...cds.cdid above
629];
630
631is_deeply (
632 $schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} }),
633 {
9f98c4b2 634 -identifying_columns => [],
635 -identifying_columns_variants => [
fcf32d04 636 [ 0 ], [ 2 ],
637 ],
638 single_track => {
9f98c4b2 639 -identifying_columns => [ 0 ],
fcf32d04 640 -is_optional => 1,
641 -is_single => 1,
fcf32d04 642 cd => {
9f98c4b2 643 -identifying_columns => [ 0 ],
fcf32d04 644 -is_single => 1,
fcf32d04 645 artist => {
9f98c4b2 646 -identifying_columns => [ 0 ],
fcf32d04 647 -is_single => 1,
fcf32d04 648 cds => {
9f98c4b2 649 -identifying_columns => [ 0, 4 ],
fcf32d04 650 -is_optional => 1,
fcf32d04 651 tracks => {
9f98c4b2 652 -identifying_columns => [ 0, 4, 8 ],
fcf32d04 653 -is_optional => 1,
fcf32d04 654 }
655 }
656 }
657 }
658 },
659 tracks => {
9f98c4b2 660 -identifying_columns => [ 2, 3 ],
fcf32d04 661 -is_optional => 1,
fcf32d04 662 }
663 },
664 'Correct underdefined root collapse map constructed'
665);
666
667is_same_src (
02a73c96 668 ($schema->source ('CD')->_mk_row_parser({
fcf32d04 669 inflate_map => $infmap,
670 collapse => 1,
02a73c96 671 }))[0],
aa1d8a87 672 ' my $rows_pos = 0;
673 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
fcf32d04 674
9f98c4b2 675 while ($cur_row_data = (
164aab8c 676 (
677 $rows_pos >= 0
678 and
679 (
680 $_[0][$rows_pos++]
681 or
682 ( ($rows_pos = -1), undef )
683 )
684 )
685 or
686 ( $_[1] and $_[1]->() )
3b4cd124 687 ) ) {
fcf32d04 688
05a5ca4b 689 ( @cur_row_ids{( 0, 2, 3, 4, 8 )} = (
c863e102 690 $cur_row_data->[0] // "\0NULL\xFF$rows_pos\xFF0\0",
691 $cur_row_data->[2] // "\0NULL\xFF$rows_pos\xFF2\0",
692 $cur_row_data->[3] // "\0NULL\xFF$rows_pos\xFF3\0",
693 $cur_row_data->[4] // "\0NULL\xFF$rows_pos\xFF4\0",
694 $cur_row_data->[8] // "\0NULL\xFF$rows_pos\xFF8\0",
05a5ca4b 695 )),
fcf32d04 696
697 # cache expensive set of ops in a non-existent rowid slot
05a5ca4b 698 ( $cur_row_ids{10} = (
c863e102 699 ( ( defined $cur_row_data->[0] ) && (join "\xFF", q{}, $cur_row_ids{0}, q{} ))
fcf32d04 700 or
c863e102 701 ( ( defined $cur_row_data->[2] ) && (join "\xFF", q{}, $cur_row_ids{2}, q{} ))
fcf32d04 702 or
703 "\0$rows_pos\0"
05a5ca4b 704 )),
fcf32d04 705
9f98c4b2 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{10}} and (unshift @{$_[2]}, $cur_row_data) and last ),
fcf32d04 708
05a5ca4b 709 ( $collapse_idx[0]{$cur_row_ids{10}} //= $_[0][$result_pos++] = [{ year => $$cur_row_data[1] }] ),
fcf32d04 710
05a5ca4b 711 ( $collapse_idx[0]{$cur_row_ids{10}}[1]{single_track} //= ($collapse_idx[1]{$cur_row_ids{0}} = [{ trackid => $cur_row_data->[0] }]) ),
712 ( defined($cur_row_data->[0]) or bless ( $collapse_idx[0]{$cur_row_ids{10}}[1]{single_track}, __NBC__ ) ),
fcf32d04 713
05a5ca4b 714 ( $collapse_idx[1]{$cur_row_ids{0}}[1]{cd} //= $collapse_idx[2]{$cur_row_ids{0}} = [] ),
fcf32d04 715
05a5ca4b 716 ( $collapse_idx[2]{$cur_row_ids{0}}[1]{artist} //= ($collapse_idx[3]{$cur_row_ids{0}} = [{ artistid => $cur_row_data->[6] }]) ),
fcf32d04 717
05a5ca4b 718 (
719 (! $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}} )
720 and
721 push @{$collapse_idx[3]{$cur_row_ids{0}}[1]{cds}}, (
52864fbd 722 $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}} = [{ cdid => $cur_row_data->[4], genreid => $cur_row_data->[7], year => $cur_row_data->[5] }]
05a5ca4b 723 )
724 ),
725 ( defined($cur_row_data->[4]) or bless ( $collapse_idx[3]{$cur_row_ids{0}}[1]{cds}, __NBC__ ) ),
726
727 (
728 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} )
729 and
730 push @{$collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}[1]{tracks}}, (
731 $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} = [{ title => $cur_row_data->[8] }]
732 )
733 ),
734 ( defined($cur_row_data->[8]) or bless ( $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}[1]{tracks}, __NBC__ ) ),
735
736 (
737 (! $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} )
738 and
739 push @{$collapse_idx[0]{$cur_row_ids{10}}[1]{tracks}}, (
52864fbd 740 $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} = [{ cd => $$cur_row_data[2], title => $cur_row_data->[3] }]
05a5ca4b 741 )
742 ),
743 ( defined($cur_row_data->[2]) or bless ( $collapse_idx[0]{$cur_row_ids{10}}[1]{tracks}, __NBC__ ) ),
fcf32d04 744 }
745
aa1d8a87 746 $#{$_[0]} = $result_pos - 1;
fcf32d04 747 ',
748 'Multiple has_many on multiple branches with underdefined root torture test',
749);
750
ce556881 751is_same_src (
02a73c96 752 ($schema->source ('CD')->_mk_row_parser({
ce556881 753 inflate_map => $infmap,
754 collapse => 1,
ce556881 755 hri_style => 1,
79adc44f 756 prune_null_branches => 1,
02a73c96 757 }))[0],
aa1d8a87 758 ' my $rows_pos = 0;
06b3406d 759 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids);
ce556881 760
761 while ($cur_row_data = (
164aab8c 762 (
763 $rows_pos >= 0
764 and
765 (
766 $_[0][$rows_pos++]
767 or
768 ( ($rows_pos = -1), undef )
769 )
770 )
771 or
772 ( $_[1] and $_[1]->() )
3b4cd124 773 ) ) {
774
5e6d06f4 775 # do not care about nullability here
05a5ca4b 776 ( @cur_row_ids{( 0, 2, 3, 4, 8 )} = @{$cur_row_data}[( 0, 2, 3, 4, 8 )] ),
06b3406d 777
ce556881 778 # cache expensive set of ops in a non-existent rowid slot
05a5ca4b 779 ( $cur_row_ids{10} = (
c863e102 780 ( ( defined $cur_row_data->[0] ) && (join "\xFF", q{}, $cur_row_ids{0}, q{} ))
ce556881 781 or
c863e102 782 ( ( defined $cur_row_data->[2] ) && (join "\xFF", q{}, $cur_row_ids{2}, q{} ))
ce556881 783 or
784 "\0$rows_pos\0"
05a5ca4b 785 )),
ce556881 786
787 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
05a5ca4b 788 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{10}} and (unshift @{$_[2]}, $cur_row_data) and last ),
ce556881 789
05a5ca4b 790 ( $collapse_idx[0]{$cur_row_ids{10}} //= $_[0][$result_pos++] = { year => $$cur_row_data[1] } ),
ce556881 791
05a5ca4b 792 ( (! defined $cur_row_data->[0] ) ? $collapse_idx[0]{$cur_row_ids{10}}{single_track} = undef : do {
ce556881 793
05a5ca4b 794 ( $collapse_idx[0]{$cur_row_ids{10}}{single_track} //= ($collapse_idx[1]{$cur_row_ids{0}} = { trackid => $$cur_row_data[0] }) ),
ce556881 795
05a5ca4b 796 ( $collapse_idx[1]{$cur_row_ids{0}}{cd} //= $collapse_idx[2]{$cur_row_ids{0}} ),
ce556881 797
05a5ca4b 798 ( $collapse_idx[2]{$cur_row_ids{0}}{artist} //= ($collapse_idx[3]{$cur_row_ids{0}} = { artistid => $$cur_row_data[6] }) ),
ce556881 799
05a5ca4b 800 ( (! defined $cur_row_data->[4] ) ? $collapse_idx[3]{$cur_row_ids{0}}{cds} = [] : do {
ce556881 801
05a5ca4b 802 (
803 (! $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}} )
804 and
805 push @{$collapse_idx[3]{$cur_row_ids{0}}{cds}}, (
806 $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}} = { cdid => $$cur_row_data[4], genreid => $$cur_row_data[7], year => $$cur_row_data[5] }
807 )
808 ),
ce556881 809
05a5ca4b 810 ( (! defined $cur_row_data->[8] ) ? $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}{tracks} = [] : do {
7596ddca 811
06b3406d 812 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} )
7596ddca 813 and
06b3406d 814 push @{$collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}{tracks}}, (
815 $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} = { title => $$cur_row_data[8] }
05a5ca4b 816 ),
817 } ),
818 } ),
819 } ),
7596ddca 820
05a5ca4b 821 ( (! defined $cur_row_data->[2] ) ? $collapse_idx[0]{$cur_row_ids{10}}{tracks} = [] : do {
822 (
823 (! $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} )
824 and
825 push @{$collapse_idx[0]{$cur_row_ids{10}}{tracks}}, (
06b3406d 826 $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} = { cd => $$cur_row_data[2], title => $$cur_row_data[3] }
05a5ca4b 827 )
828 ),
829 } ),
ce556881 830 }
831
aa1d8a87 832 $#{$_[0]} = $result_pos - 1;
ce556881 833 ',
52864fbd 834 'Multiple has_many on multiple branches with underdefined root, HRI-direct torture test',
ce556881 835);
836
c863e102 837is_same_src (
838 ($schema->source ('Owners')->_mk_row_parser({
839 inflate_map => [qw( books.title books.owner )],
840 collapse => 1,
841 prune_null_branches => 1,
842 }))[0],
843 ' my $rows_pos = 0;
844 my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids );
845
846 while ($cur_row_data = (
164aab8c 847 (
848 $rows_pos >= 0
849 and
850 (
851 $_[0][$rows_pos++]
852 or
853 ( ($rows_pos = -1), undef )
854 )
855 )
c863e102 856 or
164aab8c 857 ( $_[1] and $_[1]->() )
c863e102 858 ) ) {
859
05a5ca4b 860 ( @cur_row_ids{0,1} = @{$cur_row_data}[0,1] ),
c863e102 861
05a5ca4b 862 ( $cur_row_ids{3} = (
c863e102 863 ( ( defined $cur_row_data->[1] ) && (join "\xFF", q{}, $cur_row_ids{1}, q{} ))
864 or
865 "\0${rows_pos}\0"
05a5ca4b 866 )),
c863e102 867
05a5ca4b 868 ( $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{3}} and (unshift @{$_[2]}, $cur_row_data) and last ),
c863e102 869
870 # empty data for the root node
05a5ca4b 871 ( $collapse_idx[0]{$cur_row_ids{3}} //= $_[0][$result_pos++] = [] ),
c863e102 872
05a5ca4b 873 ( ( ! defined $cur_row_data->[0] ) ? $collapse_idx[0]{$cur_row_ids{3}}[1]{"books"} = [] : do {
c863e102 874 push @{$collapse_idx[0]{$cur_row_ids{3}}[1]{books}},
875 $collapse_idx[1]{$cur_row_ids{0}} = [ { owner => $cur_row_data->[1], title => $cur_row_data->[0] } ]
876 unless $collapse_idx[1]{$cur_row_ids{0}}
05a5ca4b 877 } ),
c863e102 878 }
879
880 $#{$_[0]} = $result_pos - 1; # truncate the passed in array to where we filled it with results
881 ',
882 'Non-premultiplied implicit collapse with missing join columns',
883);
884
4e9fc3f3 885done_testing;
886
887my $deparser;
cd784aab 888sub is_same_src { SKIP: {
2fdeef65 889
890 skip "Skipping comparison of unicode-posioned source", 1
891 if DBIx::Class::_ENV_::STRESSTEST_UTF8_UPGRADE_GENERATED_COLLAPSER_SOURCE;
892
4e9fc3f3 893 $deparser ||= B::Deparse->new;
894 local $Test::Builder::Level = $Test::Builder::Level + 1;
895
52864fbd 896 my ($got, $expect) = @_;
897
cd784aab 898 skip "Not testing equality of source containing defined-or operator on this perl $]", 1
899 if ($] < 5.010 and$expect =~ m!\Q//=!);
900
01b25f12 901 $expect =~ s/__NBC__/perlstring($DBIx::Class::ResultSource::RowParser::Util::null_branch_class)/ge;
52864fbd 902
9f7d5590 903 $expect = " { use strict; use warnings FATAL => 'uninitialized';\n$expect\n }";
bdbd2ae8 904
52864fbd 905 my @normalized = map {
4e9fc3f3 906 my $cref = eval "sub { $_ }" or do {
907 fail "Coderef does not compile!\n\n$@\n\n$_";
908 return undef;
909 };
910 $deparser->coderef2text($cref);
52864fbd 911 } ($got, $expect);
912
913 &is (@normalized, $_[2]||() ) or do {
914 eval { require Test::Differences }
915 ? &Test::Differences::eq_or_diff( @normalized, $_[2]||() )
e81b50f4 916 : note ("Original sources:\n\n$got\n\n$expect\n")
917 ;
918 exit 1;
52864fbd 919 };
cd784aab 920} }