Modify the null-branch pruning introduced in ce556881, restore compat
[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;
8
7d5371dc 9# globally set for the rest of test
10# the rowparser maker does not order its hashes by default for the miniscule
11# speed gain. But it does not disable sorting either - for this test
12# everything will be ordered nicely, and the hash randomization of 5.18
13# will not trip up anything
14use Data::Dumper;
15$Data::Dumper::Sortkeys = 1;
16
4e9fc3f3 17my $schema = DBICTest->init_schema(no_deploy => 1);
ce556881 18my $infmap = [qw/
19 single_track.cd.artist.name
20 year
21/];
4e9fc3f3 22
23is_same_src (
24 $schema->source ('CD')->_mk_row_parser({
25 inflate_map => $infmap,
26 }),
27 '$_ = [
28 { year => $_->[1] },
52864fbd 29 { single_track => ( ! defined( $_->[0]) )
30 ? bless( [
4e9fc3f3 31 undef,
52864fbd 32 { cd => [
33 undef,
34 { artist => [
35 { name => $_->[0] },
36 ] },
4e9fc3f3 37 ] },
52864fbd 38 ], __NBC__ )
39 : [
40 undef,
41 { cd => [
42 undef,
43 { artist => [
44 { name => $_->[0] },
45 ] },
46 ] },
47 ]
48 },
4e9fc3f3 49 ] for @{$_[0]}',
50 'Simple 1:1 descending non-collapsing parser',
51);
52
53$infmap = [qw/
3faac878 54 single_track.cd.artist.cds.tracks.title
4e9fc3f3 55 single_track.cd.artist.artistid
56 year
4e9fc3f3 57 single_track.cd.artist.cds.cdid
58 title
59 artist
60/];
4e9fc3f3 61
ce556881 62is_same_src (
63 $schema->source ('CD')->_mk_row_parser({
ce556881 64 inflate_map => $infmap,
65 }),
66 '$_ = [
67 { artist => $_->[5], title => $_->[4], year => $_->[2] },
68 {
52864fbd 69 single_track => ( (! defined $_->[0] ) && (! defined $_->[1]) && (! defined $_->[3] ) )
70 ? bless( [
71 undef,
72 {
73 cd => [
74 undef,
75 {
76 artist => [
77 { artistid => $_->[1] },
78 {
79 cds => ( (! defined $_->[0] ) && ( ! defined $_->[3] ) )
80 ? bless ([
81 { cdid => $_->[3] },
82 {
83 tracks => ( ! defined $_->[0] )
84 ? bless ( [{ title => $_->[0] }], __NBC__ )
85 : [{ title => $_->[0] }]
86 }
87 ], __NBC__)
88 : [
89 { cdid => $_->[3] },
90 {
91 tracks => ( ! defined $_->[0] )
92 ? bless ( [{ title => $_->[0] }], __NBC__ )
93 : [{ title => $_->[0] }]
94 }
95 ]
96 }
97 ]
98 }
99 ]
100 }
101 ], __NBC__)
102 : [
ce556881 103 undef,
104 {
105 cd => [
106 undef,
107 {
108 artist => [
109 { artistid => $_->[1] },
110 {
52864fbd 111 cds => ( (! defined $_->[0] ) && ( ! defined $_->[3] ) )
112 ? bless ([
113 { cdid => $_->[3] },
114 {
115 tracks => ( ! defined $_->[0] )
116 ? bless ( [{ title => $_->[0] }], __NBC__ )
117 : [{ title => $_->[0] }]
118 }
119 ], __NBC__)
120 : [
ce556881 121 { cdid => $_->[3] },
122 {
52864fbd 123 tracks => ( ! defined $_->[0] )
124 ? bless ( [{ title => $_->[0] }], __NBC__ )
125 : [{ title => $_->[0] }]
ce556881 126 }
52864fbd 127 ]
ce556881 128 }
129 ]
130 }
131 ]
132 }
52864fbd 133 ]
ce556881 134 }
135 ] for @{$_[0]}',
52864fbd 136 '1:1 descending non-collapsing parser terminating with chained 1:M:M',
ce556881 137);
138
139is_same_src (
140 $schema->source ('CD')->_mk_row_parser({
ce556881 141 hri_style => 1,
142 inflate_map => $infmap,
143 }),
144 '$_ = {
145 artist => $_->[5], title => $_->[4], year => $_->[2],
146
52864fbd 147 ( single_track => ( (! defined $_->[0] ) && (! defined $_->[1]) && (! defined $_->[3] ) )
148 ? undef
149 : {
ce556881 150 cd =>
151 {
152 artist => {
153 artistid => $_->[1],
52864fbd 154 ( cds => ( (! defined $_->[0] ) && ( ! defined $_->[3] ) )
155 ? undef
156 : {
ce556881 157 cdid => $_->[3],
52864fbd 158 ( tracks => ( ! defined $_->[0] )
159 ? undef
160 : { title => $_->[0] }
161 )
ce556881 162 }
52864fbd 163 )
ce556881 164 }
165 }
166 }
52864fbd 167 )
ce556881 168 } for @{$_[0]}',
52864fbd 169 '1:1 descending non-collapsing HRI-direct parser terminating with chained 1:M:M',
ce556881 170);
171
172
173
4e9fc3f3 174is_deeply (
3faac878 175 ($schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} })),
4e9fc3f3 176 {
9f98c4b2 177 -identifying_columns => [ 4, 5 ],
4e9fc3f3 178
179 single_track => {
a0726a33 180 -identifying_columns => [ 1, 4, 5 ],
4e9fc3f3 181 -is_optional => 1,
182 -is_single => 1,
183
184 cd => {
a0726a33 185 -identifying_columns => [ 1, 4, 5 ],
4e9fc3f3 186 -is_single => 1,
187
188 artist => {
a0726a33 189 -identifying_columns => [ 1, 4, 5 ],
4e9fc3f3 190 -is_single => 1,
191
192 cds => {
a0726a33 193 -identifying_columns => [ 1, 3, 4, 5 ],
4e9fc3f3 194 -is_optional => 1,
195
196 tracks => {
a0726a33 197 -identifying_columns => [ 0, 1, 3, 4, 5 ],
4e9fc3f3 198 -is_optional => 1,
199 },
200 },
201 },
202 },
203 },
204 },
205 'Correct collapse map for 1:1 descending chain terminating with chained 1:M:M'
206);
207
208is_same_src (
209 $schema->source ('CD')->_mk_row_parser({
210 inflate_map => $infmap,
211 collapse => 1,
212 }),
9f98c4b2 213 ' my($rows_pos, $result_pos, $cur_row_data, %cur_row_ids, @collapse_idx, $is_new_res) = (0, 0);
4e9fc3f3 214
9f98c4b2 215 while ($cur_row_data = (
4e9fc3f3 216 ( $rows_pos >= 0 and $_[0][$rows_pos++] ) or do { $rows_pos = -1; undef } )
217 ||
218 ( $_[1] and $_[1]->() )
219 ) {
220
9f98c4b2 221 $cur_row_ids{$_} = defined $cur_row_data->[$_] ? $cur_row_data->[$_] : "\0NULL\xFF$rows_pos\xFF$_\0"
a0726a33 222 for (0, 1, 3, 4, 5);
4e9fc3f3 223
3faac878 224 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
9f98c4b2 225 $_[1] and $result_pos and unshift(@{$_[2]}, $cur_row_data) and last
226 if ( $is_new_res = ! $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} );
4e9fc3f3 227
3faac878 228 # the rowdata itself for root node
9f98c4b2 229 $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} ||= [{ artist => $cur_row_data->[5], title => $cur_row_data->[4], year => $cur_row_data->[2] }];
3faac878 230
231 # prefetch data of single_track (placed in root)
52864fbd 232 $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{single_track} ||= $collapse_idx[1]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}} ||= [];
233 defined($cur_row_data->[1]) or bless( $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{single_track}, __NBC__ );
3faac878 234
235 # prefetch data of cd (placed in single_track)
52864fbd 236 $collapse_idx[1]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{cd} ||= $collapse_idx[2]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}} ||= [];
4e9fc3f3 237
3faac878 238 # prefetch data of artist ( placed in single_track->cd)
a0726a33 239 $collapse_idx[2]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{artist} ||= $collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}} ||= [{ artistid => $cur_row_data->[1] }];
3faac878 240
241 # prefetch data of cds (if available)
ce556881 242 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
243 and
244 push @{$collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{cds}}, (
245 $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} = [{ cdid => $cur_row_data->[3] }]
246 );
52864fbd 247 defined($cur_row_data->[3]) or bless( $collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{cds}, __NBC__ );
4e9fc3f3 248
3faac878 249 # prefetch data of tracks (if available)
ce556881 250 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
251 and
252 push @{$collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{tracks}}, (
253 $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} = [{ title => $cur_row_data->[0] }]
254 );
52864fbd 255 defined($cur_row_data->[0]) or bless( $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{tracks}, __NBC__ );
4e9fc3f3 256
9f98c4b2 257 $_[0][$result_pos++] = $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}
4e9fc3f3 258 if $is_new_res;
259 }
260 splice @{$_[0]}, $result_pos;
261 ',
262 'Same 1:1 descending terminating with chained 1:M:M but with collapse',
263);
264
ce556881 265is_same_src (
266 $schema->source ('CD')->_mk_row_parser({
267 inflate_map => $infmap,
268 collapse => 1,
ce556881 269 hri_style => 1,
270 }),
271 ' my($rows_pos, $result_pos, $cur_row_data, %cur_row_ids, @collapse_idx, $is_new_res) = (0, 0);
272
273 while ($cur_row_data = (
274 ( $rows_pos >= 0 and $_[0][$rows_pos++] ) or do { $rows_pos = -1; undef } )
275 ||
276 ( $_[1] and $_[1]->() )
277 ) {
278
279 $cur_row_ids{$_} = defined $cur_row_data->[$_] ? $cur_row_data->[$_] : "\0NULL\xFF$rows_pos\xFF$_\0"
280 for (0, 1, 3, 4, 5);
281
282 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
283 $_[1] and $result_pos and unshift(@{$_[2]}, $cur_row_data) and last
284 if ( $is_new_res = ! $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} );
285
286 # the rowdata itself for root node
287 $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} ||= { artist => $cur_row_data->[5], title => $cur_row_data->[4], year => $cur_row_data->[2] };
288
289 # prefetch data of single_track (placed in root)
290 $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}{single_track} ||= $collapse_idx[1]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}
291 if defined $cur_row_data->[1];
292 $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}{single_track} ||= undef;
293
294 # prefetch data of cd (placed in single_track)
295 $collapse_idx[1]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}{cd} ||= $collapse_idx[2]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}};
296
297 # prefetch data of artist ( placed in single_track->cd)
298 $collapse_idx[2]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}{artist} ||= $collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}} ||= { artistid => $cur_row_data->[1] };
299
300 # prefetch data of cds (if available)
301 ( defined $cur_row_data->[3] )
302 and
303 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
304 and
305 push @{$collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}{cds}}, (
306 $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} = { cdid => $cur_row_data->[3] }
307 );
308 $collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}{cds} ||= [];
309
310 # prefetch data of tracks (if available)
311 ( defined $cur_row_data->[0] )
312 and
313 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} )
314 and
315 push @{$collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}{tracks}}, (
316 $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} = { title => $cur_row_data->[0] }
317 );
318 $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}{tracks} ||= [];
319
320 $_[0][$result_pos++] = $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}
321 if $is_new_res;
322 }
323 splice @{$_[0]}, $result_pos;
324 ',
52864fbd 325 'Same 1:1 descending terminating with chained 1:M:M but with collapse, HRI-direct',
ce556881 326);
327
4e9fc3f3 328$infmap = [qw/
3d8caf63 329 tracks.lyrics.existing_lyric_versions.text
4e9fc3f3 330 existing_single_track.cd.artist.artistid
331 existing_single_track.cd.artist.cds.year
332 year
333 genreid
334 tracks.title
335 existing_single_track.cd.artist.cds.cdid
336 latest_cd
337 existing_single_track.cd.artist.cds.tracks.title
338 existing_single_track.cd.artist.cds.genreid
3d8caf63 339 tracks.lyrics.existing_lyric_versions.lyric_id
4e9fc3f3 340/];
341
342is_deeply (
82f0e0aa 343 $schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} }),
4e9fc3f3 344 {
9f98c4b2 345 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
4e9fc3f3 346
347 existing_single_track => {
9f98c4b2 348 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
4e9fc3f3 349 -is_single => 1,
350
351 cd => {
9f98c4b2 352 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
4e9fc3f3 353 -is_single => 1,
354
355 artist => {
9f98c4b2 356 -identifying_columns => [ 1 ], # existing_single_track.cd.artist.artistid
4e9fc3f3 357 -is_single => 1,
358
359 cds => {
9f98c4b2 360 -identifying_columns => [ 1, 6 ], # existing_single_track.cd.artist.cds.cdid
4e9fc3f3 361 -is_optional => 1,
362
363 tracks => {
9f98c4b2 364 -identifying_columns => [ 1, 6, 8 ], # existing_single_track.cd.artist.cds.cdid, existing_single_track.cd.artist.cds.tracks.title
4e9fc3f3 365 -is_optional => 1,
366 }
367 }
368 }
369 }
370 },
371 tracks => {
9f98c4b2 372 -identifying_columns => [ 1, 5 ], # existing_single_track.cd.artist.artistid, tracks.title
4e9fc3f3 373 -is_optional => 1,
374
375 lyrics => {
3d8caf63 376 -identifying_columns => [ 1, 5, 10 ], # existing_single_track.cd.artist.artistid, tracks.title, tracks.lyrics.existing_lyric_versions.lyric_id
4e9fc3f3 377 -is_single => 1,
378 -is_optional => 1,
379
3d8caf63 380 existing_lyric_versions => {
381 -identifying_columns => [ 0, 1, 5, 10 ], # tracks.lyrics.existing_lyric_versions.text, existing_single_track.cd.artist.artistid, tracks.title, tracks.lyrics.existing_lyric_versions.lyric_id
4e9fc3f3 382 },
383 },
384 }
385 },
386 'Correct collapse map constructed',
387);
388
389is_same_src (
390 $schema->source ('CD')->_mk_row_parser({
391 inflate_map => $infmap,
392 collapse => 1,
393 }),
9f98c4b2 394 ' my ($rows_pos, $result_pos, $cur_row_data, %cur_row_ids, @collapse_idx, $is_new_res) = (0,0);
4e9fc3f3 395
9f98c4b2 396 while ($cur_row_data = (
4e9fc3f3 397 ( $rows_pos >= 0 and $_[0][$rows_pos++] ) or do { $rows_pos = -1; undef } )
398 ||
399 ( $_[1] and $_[1]->() )
400 ) {
401
9f98c4b2 402 $cur_row_ids{$_} = defined $cur_row_data->[$_] ? $cur_row_data->[$_] : "\0NULL\xFF$rows_pos\xFF$_\0"
3d8caf63 403 for (0, 1, 5, 6, 8, 10);
4e9fc3f3 404
9f98c4b2 405 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
406 $_[1] and $result_pos and unshift(@{$_[2]}, $cur_row_data) and last
407 if ( $is_new_res = ! $collapse_idx[0]{$cur_row_ids{1}} );
4e9fc3f3 408
9f98c4b2 409 $collapse_idx[0]{$cur_row_ids{1}} ||= [{ genreid => $cur_row_data->[4], latest_cd => $cur_row_data->[7], year => $cur_row_data->[3] }];
4e9fc3f3 410
52864fbd 411 $collapse_idx[0]{$cur_row_ids{1}}[1]{existing_single_track} ||= $collapse_idx[1]{$cur_row_ids{1}} ||= [];
412 $collapse_idx[1]{$cur_row_ids{1}}[1]{cd} ||= $collapse_idx[2]{$cur_row_ids{1}} ||= [];
9f98c4b2 413 $collapse_idx[2]{$cur_row_ids{1}}[1]{artist} ||= $collapse_idx[3]{$cur_row_ids{1}} ||= [{ artistid => $cur_row_data->[1] }];
4e9fc3f3 414
ce556881 415 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}} )
416 and
417 push @{ $collapse_idx[3]{$cur_row_ids{1}}[1]{cds} }, (
418 $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}} = [{ cdid => $cur_row_data->[6], genreid => $cur_row_data->[9], year => $cur_row_data->[2] }]
419 );
52864fbd 420 defined($cur_row_data->[6]) or bless( $collapse_idx[3]{$cur_row_ids{1}}[1]{cds}, __NBC__ );
4e9fc3f3 421
ce556881 422 (! $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} )
423 and
424 push @{ $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks} }, (
425 $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} = [{ title => $cur_row_data->[8] }]
426 );
52864fbd 427 defined($cur_row_data->[8]) or bless( $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks}, __NBC__ );
4e9fc3f3 428
ce556881 429 (! $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} )
430 and
431 push @{ $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks} }, (
432 $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} = [{ title => $cur_row_data->[5] }]
433 );
52864fbd 434 defined($cur_row_data->[5]) or bless( $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks}, __NBC__ );
4e9fc3f3 435
52864fbd 436 $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics} ||= $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} ||= [];
437 defined($cur_row_data->[10]) or bless( $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics}, __NBC__ );
4e9fc3f3 438
ce556881 439 (! $collapse_idx[8]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} )
440 and
441 push @{ $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}}[1]{existing_lyric_versions} }, (
442 $collapse_idx[8]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} = [{ lyric_id => $cur_row_data->[10], text => $cur_row_data->[0] }]
443 );
4e9fc3f3 444
9f98c4b2 445 $_[0][$result_pos++] = $collapse_idx[0]{$cur_row_ids{1}}
4e9fc3f3 446 if $is_new_res;
447 }
448
449 splice @{$_[0]}, $result_pos;
450 ',
451 'Multiple has_many on multiple branches torture test',
452);
453
ce556881 454is_same_src (
455 $schema->source ('CD')->_mk_row_parser({
456 inflate_map => $infmap,
457 collapse => 1,
ce556881 458 }),
459 ' my ($rows_pos, $result_pos, $cur_row_data, %cur_row_ids, @collapse_idx, $is_new_res) = (0,0);
460
461 while ($cur_row_data = (
462 ( $rows_pos >= 0 and $_[0][$rows_pos++] ) or do { $rows_pos = -1; undef } )
463 ||
464 ( $_[1] and $_[1]->() )
465 ) {
466
467 $cur_row_ids{$_} = defined $cur_row_data->[$_] ? $cur_row_data->[$_] : "\0NULL\xFF$rows_pos\xFF$_\0"
468 for (0, 1, 5, 6, 8, 10);
469
470 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
471 $_[1] and $result_pos and unshift(@{$_[2]}, $cur_row_data) and last
472 if ( $is_new_res = ! $collapse_idx[0]{$cur_row_ids{1}} );
473
474 $collapse_idx[0]{$cur_row_ids{1}} ||= [{ genreid => $cur_row_data->[4], latest_cd => $cur_row_data->[7], year => $cur_row_data->[3] }];
475
52864fbd 476 $collapse_idx[0]{$cur_row_ids{1}}[1]{existing_single_track} ||= $collapse_idx[1]{$cur_row_ids{1}} ||= [];
477 $collapse_idx[1]{$cur_row_ids{1}}[1]{cd} ||= $collapse_idx[2]{$cur_row_ids{1}} ||= [];
ce556881 478 $collapse_idx[2]{$cur_row_ids{1}}[1]{artist} ||= $collapse_idx[3]{$cur_row_ids{1}} ||= [{ artistid => $cur_row_data->[1] }];
479
ce556881 480 (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}} )
481 and
482 push @{ $collapse_idx[3]{$cur_row_ids{1}}[1]{cds} }, (
483 $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}} = [{ cdid => $cur_row_data->[6], genreid => $cur_row_data->[9], year => $cur_row_data->[2] }]
484 );
52864fbd 485 defined($cur_row_data->[6]) or bless( $collapse_idx[3]{$cur_row_ids{1}}[1]{cds}, __NBC__ );
ce556881 486
ce556881 487 (! $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} )
488 and
489 push @{ $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks} }, (
490 $collapse_idx[5]{$cur_row_ids{1}}{$cur_row_ids{6}}{$cur_row_ids{8}} = [{ title => $cur_row_data->[8] }]
491 );
52864fbd 492 defined($cur_row_data->[8]) or bless( $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}}[1]{tracks}, __NBC__ );
ce556881 493
ce556881 494 (! $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} )
495 and
496 push @{ $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks} }, (
497 $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}} = [{ title => $cur_row_data->[5] }]
498 );
52864fbd 499 defined($cur_row_data->[5]) or bless( $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks}, __NBC__ );
ce556881 500
52864fbd 501 $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics} ||= $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} ||= [];
502 defined($cur_row_data->[10]) or bless( $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics}, __NBC__ );
ce556881 503
ce556881 504 (! $collapse_idx[8]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} )
505 and
506 push @{ $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}}[1]{existing_lyric_versions} }, (
507 $collapse_idx[8]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} = [{ lyric_id => $cur_row_data->[10], text => $cur_row_data->[0] }]
508 );
ce556881 509
510 $_[0][$result_pos++] = $collapse_idx[0]{$cur_row_ids{1}}
511 if $is_new_res;
512 }
513
514 splice @{$_[0]}, $result_pos;
515 ',
52864fbd 516 'Multiple has_many on multiple branches with branch torture test',
ce556881 517);
518
fcf32d04 519$infmap = [
520 'single_track.trackid', # (0) definitive link to root from 1:1:1:1:M:M chain
521 'year', # (1) non-unique
522 'tracks.cd', # (2) \ together both uniqueness for second multirel
523 'tracks.title', # (3) / and definitive link back to root
524 'single_track.cd.artist.cds.cdid', # (4) to give uniquiness to ...tracks.title below
525 'single_track.cd.artist.cds.year', # (5) non-unique
526 'single_track.cd.artist.artistid', # (6) uniqufies entire parental chain
527 'single_track.cd.artist.cds.genreid', # (7) nullable
528 'single_track.cd.artist.cds.tracks.title',# (8) unique when combined with ...cds.cdid above
529];
530
531is_deeply (
532 $schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} }),
533 {
9f98c4b2 534 -identifying_columns => [],
535 -identifying_columns_variants => [
fcf32d04 536 [ 0 ], [ 2 ],
537 ],
538 single_track => {
9f98c4b2 539 -identifying_columns => [ 0 ],
fcf32d04 540 -is_optional => 1,
541 -is_single => 1,
fcf32d04 542 cd => {
9f98c4b2 543 -identifying_columns => [ 0 ],
fcf32d04 544 -is_single => 1,
fcf32d04 545 artist => {
9f98c4b2 546 -identifying_columns => [ 0 ],
fcf32d04 547 -is_single => 1,
fcf32d04 548 cds => {
9f98c4b2 549 -identifying_columns => [ 0, 4 ],
fcf32d04 550 -is_optional => 1,
fcf32d04 551 tracks => {
9f98c4b2 552 -identifying_columns => [ 0, 4, 8 ],
fcf32d04 553 -is_optional => 1,
fcf32d04 554 }
555 }
556 }
557 }
558 },
559 tracks => {
9f98c4b2 560 -identifying_columns => [ 2, 3 ],
fcf32d04 561 -is_optional => 1,
fcf32d04 562 }
563 },
564 'Correct underdefined root collapse map constructed'
565);
566
567is_same_src (
568 $schema->source ('CD')->_mk_row_parser({
569 inflate_map => $infmap,
570 collapse => 1,
571 }),
9f98c4b2 572 ' my($rows_pos, $result_pos, $cur_row_data, %cur_row_ids, @collapse_idx, $is_new_res) = (0, 0);
fcf32d04 573
9f98c4b2 574 while ($cur_row_data = (
fcf32d04 575 ( $rows_pos >= 0 and $_[0][$rows_pos++] ) or do { $rows_pos = -1; undef } )
576 ||
577 ( $_[1] and $_[1]->() )
578 ) {
579
9f98c4b2 580 $cur_row_ids{$_} = defined $$cur_row_data[$_] ? $$cur_row_data[$_] : "\0NULL\xFF$rows_pos\xFF$_\0"
fcf32d04 581 for (0, 2, 3, 4, 8);
582
583 # cache expensive set of ops in a non-existent rowid slot
9f98c4b2 584 $cur_row_ids{10} = (
585 ( ( defined $cur_row_data->[0] ) && (join "\xFF", q{}, $cur_row_data->[0], q{} ))
fcf32d04 586 or
9f98c4b2 587 ( ( defined $cur_row_data->[2] ) && (join "\xFF", q{}, $cur_row_data->[2], q{} ))
fcf32d04 588 or
589 "\0$rows_pos\0"
590 );
591
9f98c4b2 592 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
593 $_[1] and $result_pos and unshift(@{$_[2]}, $cur_row_data) and last
594 if ( $is_new_res = ! $collapse_idx[0]{$cur_row_ids{10}} );
fcf32d04 595
9f98c4b2 596 $collapse_idx[0]{$cur_row_ids{10}} ||= [{ year => $$cur_row_data[1] }];
fcf32d04 597
52864fbd 598 $collapse_idx[0]{$cur_row_ids{10}}[1]{single_track} ||= ($collapse_idx[1]{$cur_row_ids{0}} ||= [{ trackid => $cur_row_data->[0] }]);
599 defined($cur_row_data->[0]) or bless ( $collapse_idx[0]{$cur_row_ids{10}}[1]{single_track}, __NBC__ );
fcf32d04 600
52864fbd 601 $collapse_idx[1]{$cur_row_ids{0}}[1]{cd} ||= $collapse_idx[2]{$cur_row_ids{0}} ||= [];
fcf32d04 602
52864fbd 603 $collapse_idx[2]{$cur_row_ids{0}}[1]{artist} ||= ($collapse_idx[3]{$cur_row_ids{0}} ||= [{ artistid => $cur_row_data->[6] }]);
fcf32d04 604
ce556881 605 (! $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}} )
606 and
607 push @{$collapse_idx[3]{$cur_row_ids{0}}[1]{cds}}, (
52864fbd 608 $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}} = [{ cdid => $cur_row_data->[4], genreid => $cur_row_data->[7], year => $cur_row_data->[5] }]
ce556881 609 );
52864fbd 610 defined($cur_row_data->[4]) or bless ( $collapse_idx[3]{$cur_row_ids{0}}[1]{cds}, __NBC__ );
fcf32d04 611
ce556881 612 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} )
613 and
614 push @{$collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}[1]{tracks}}, (
52864fbd 615 $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} = [{ title => $cur_row_data->[8] }]
ce556881 616 );
52864fbd 617 defined($cur_row_data->[8]) or bless ( $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}[1]{tracks}, __NBC__ );
fcf32d04 618
ce556881 619 (! $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} )
620 and
621 push @{$collapse_idx[0]{$cur_row_ids{10}}[1]{tracks}}, (
52864fbd 622 $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} = [{ cd => $$cur_row_data[2], title => $cur_row_data->[3] }]
ce556881 623 );
52864fbd 624 defined($cur_row_data->[2]) or bless ( $collapse_idx[0]{$cur_row_ids{10}}[1]{tracks}, __NBC__ );
fcf32d04 625
9f98c4b2 626 $_[0][$result_pos++] = $collapse_idx[0]{$cur_row_ids{10}}
fcf32d04 627 if $is_new_res;
628 }
629
630 splice @{$_[0]}, $result_pos;
631 ',
632 'Multiple has_many on multiple branches with underdefined root torture test',
633);
634
ce556881 635is_same_src (
636 $schema->source ('CD')->_mk_row_parser({
637 inflate_map => $infmap,
638 collapse => 1,
ce556881 639 hri_style => 1,
640 }),
641 ' my($rows_pos, $result_pos, $cur_row_data, %cur_row_ids, @collapse_idx, $is_new_res) = (0, 0);
642
643 while ($cur_row_data = (
644 ( $rows_pos >= 0 and $_[0][$rows_pos++] ) or do { $rows_pos = -1; undef } )
645 ||
646 ( $_[1] and $_[1]->() )
647 ) {
648
649 $cur_row_ids{$_} = defined $$cur_row_data[$_] ? $$cur_row_data[$_] : "\0NULL\xFF$rows_pos\xFF$_\0"
650 for (0, 2, 3, 4, 8);
651
652 # cache expensive set of ops in a non-existent rowid slot
653 $cur_row_ids{10} = (
654 ( ( defined $cur_row_data->[0] ) && (join "\xFF", q{}, $cur_row_data->[0], q{} ))
655 or
656 ( ( defined $cur_row_data->[2] ) && (join "\xFF", q{}, $cur_row_data->[2], q{} ))
657 or
658 "\0$rows_pos\0"
659 );
660
661 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
662 $_[1] and $result_pos and unshift(@{$_[2]}, $cur_row_data) and last
663 if ( $is_new_res = ! $collapse_idx[0]{$cur_row_ids{10}} );
664
665 $collapse_idx[0]{$cur_row_ids{10}} ||= { year => $$cur_row_data[1] };
666
667 (defined $cur_row_data->[0])
668 and
669 $collapse_idx[0]{$cur_row_ids{10}}{single_track} ||= ($collapse_idx[1]{$cur_row_ids{0}} ||= { trackid => $$cur_row_data[0] });
670 $collapse_idx[0]{$cur_row_ids{10}}{single_track} ||= undef;
671
672 $collapse_idx[1]{$cur_row_ids{0}}{cd} ||= $collapse_idx[2]{$cur_row_ids{0}};
673
674 $collapse_idx[2]{$cur_row_ids{0}}{artist} ||= ($collapse_idx[3]{$cur_row_ids{0}} ||= { artistid => $$cur_row_data[6] });
675
676 (defined $cur_row_data->[4])
677 and
678 (! $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}} )
679 and
680 push @{$collapse_idx[3]{$cur_row_ids{0}}{cds}}, (
681 $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}} = { cdid => $$cur_row_data[4], genreid => $$cur_row_data[7], year => $$cur_row_data[5] }
682 );
683 $collapse_idx[3]{$cur_row_ids{0}}{cds} ||= [];
684
685 (defined $cur_row_data->[8])
686 and
687 (! $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} )
688 and
689 push @{$collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}{tracks}}, (
690 $collapse_idx[5]{$cur_row_ids{0}}{$cur_row_ids{4}}{$cur_row_ids{8}} = { title => $$cur_row_data[8] }
691 );
692 $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}}{tracks} ||= [];
693
694 (defined $cur_row_data->[2])
695 and
696 (! $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} )
697 and
698 push @{$collapse_idx[0]{$cur_row_ids{10}}{tracks}}, (
699 $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} = { cd => $$cur_row_data[2], title => $$cur_row_data[3] }
700 );
701 $collapse_idx[0]{$cur_row_ids{10}}{tracks} ||= [];
702
703 $_[0][$result_pos++] = $collapse_idx[0]{$cur_row_ids{10}}
704 if $is_new_res;
705 }
706
707 splice @{$_[0]}, $result_pos;
708 ',
52864fbd 709 'Multiple has_many on multiple branches with underdefined root, HRI-direct torture test',
ce556881 710);
711
4e9fc3f3 712done_testing;
713
714my $deparser;
715sub is_same_src {
716 $deparser ||= B::Deparse->new;
717 local $Test::Builder::Level = $Test::Builder::Level + 1;
718
52864fbd 719 my ($got, $expect) = @_;
720
721 $expect =~ s/__NBC__/B::perlstring($DBIx::Class::ResultSource::RowParser::Util::null_branch_class)/ge;
722
723 my @normalized = map {
4e9fc3f3 724 my $cref = eval "sub { $_ }" or do {
725 fail "Coderef does not compile!\n\n$@\n\n$_";
726 return undef;
727 };
728 $deparser->coderef2text($cref);
52864fbd 729 } ($got, $expect);
730
731 &is (@normalized, $_[2]||() ) or do {
732 eval { require Test::Differences }
733 ? &Test::Differences::eq_or_diff( @normalized, $_[2]||() )
734 : note ("Original sources:\n\n$got\n\n$expect\n");
735 BAIL_OUT('');
736 };
4e9fc3f3 737}