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