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
15 $Data::Dumper::Sortkeys = 1;
17 my $schema = DBICTest->init_schema(no_deploy => 1);
18 my $infmap = [qw/single_track.cd.artist.name year/];
21 $schema->source ('CD')->_mk_row_parser({
22 inflate_map => $infmap,
36 'Simple 1:1 descending non-collapsing parser',
40 single_track.cd.artist.cds.tracks.title
41 single_track.cd.artist.artistid
43 single_track.cd.artist.cds.cdid
48 $schema->source ('CD')->_mk_row_parser({
49 inflate_map => $infmap,
52 { artist => $_->[5], title => $_->[4], year => $_->[2] },
58 { artistid => $_->[1] },
69 '1:1 descending non-collapsing parser terminating with chained 1:M:M',
73 ($schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} })),
76 -idcols_current_node => [ 4, 5 ],
77 -idcols_extra_from_children => [ 0, 3 ],
81 -idcols_current_node => [ 4, 5 ],
82 -idcols_extra_from_children => [ 0, 3 ],
88 -idcols_current_node => [ 4, 5 ],
89 -idcols_extra_from_children => [ 0, 3 ],
94 -idcols_current_node => [ 4, 5 ],
95 -idcols_extra_from_children => [ 0, 3 ],
100 -idcols_current_node => [ 3, 4, 5 ],
101 -idcols_extra_from_children => [ 0 ],
106 -idcols_current_node => [ 0, 3, 4, 5 ],
114 'Correct collapse map for 1:1 descending chain terminating with chained 1:M:M'
118 $schema->source ('CD')->_mk_row_parser({
119 inflate_map => $infmap,
122 ' my($rows_pos, $result_pos, $cur_row, @cur_row_ids, @collapse_idx, $is_new_res) = (0, 0);
125 ( $rows_pos >= 0 and $_[0][$rows_pos++] ) or do { $rows_pos = -1; undef } )
127 ( $_[1] and $_[1]->() )
130 $cur_row_ids[$_] = defined $cur_row->[$_] ? $cur_row->[$_] : "\0NULL\xFF$rows_pos\xFF$_\0"
133 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
134 $_[1] and $result_pos and unshift(@{$_[2]}, $cur_row) and last
135 if $is_new_res = ! $collapse_idx[1]{$cur_row_ids[4]}{$cur_row_ids[5]};
137 # the rowdata itself for root node
138 $collapse_idx[1]{$cur_row_ids[4]}{$cur_row_ids[5]} ||= [{ artist => $cur_row->[5], title => $cur_row->[4], year => $cur_row->[2] }];
140 # prefetch data of single_track (placed in root)
141 $collapse_idx[1]{$cur_row_ids[4]}{$cur_row_ids[5]}[1]{single_track} ||= $collapse_idx[2]{$cur_row_ids[4]}{$cur_row_ids[5]};
143 # prefetch data of cd (placed in single_track)
144 $collapse_idx[2]{$cur_row_ids[4]}{$cur_row_ids[5]}[1]{cd} ||= $collapse_idx[3]{$cur_row_ids[4]}{$cur_row_ids[5]};
146 # prefetch data of artist ( placed in single_track->cd)
147 $collapse_idx[3]{$cur_row_ids[4]}{$cur_row_ids[5]}[1]{artist} ||= $collapse_idx[4]{$cur_row_ids[4]}{$cur_row_ids[5]} ||= [{ artistid => $cur_row->[1] }];
149 # prefetch data of cds (if available)
150 push @{$collapse_idx[4]{$cur_row_ids[4]}{$cur_row_ids[5]}[1]{cds}}, $collapse_idx[5]{$cur_row_ids[3]}{$cur_row_ids[4]}{$cur_row_ids[5]} ||= [{ cdid => $cur_row->[3] }]
151 unless $collapse_idx[5]{$cur_row_ids[3]}{$cur_row_ids[4]}{$cur_row_ids[5]};
153 # prefetch data of tracks (if available)
154 push @{$collapse_idx[5]{$cur_row_ids[3]}{$cur_row_ids[4]}{$cur_row_ids[5]}[1]{tracks}}, $collapse_idx[6]{$cur_row_ids[0]}{$cur_row_ids[3]}{$cur_row_ids[4]}{$cur_row_ids[5]} ||= [{ title => $cur_row->[0] }]
155 unless $collapse_idx[6]{$cur_row_ids[0]}{$cur_row_ids[3]}{$cur_row_ids[4]}{$cur_row_ids[5]};
157 $_[0][$result_pos++] = $collapse_idx[1]{$cur_row_ids[4]}{$cur_row_ids[5]}
160 splice @{$_[0]}, $result_pos;
162 'Same 1:1 descending terminating with chained 1:M:M but with collapse',
166 tracks.lyrics.lyric_versions.text
167 existing_single_track.cd.artist.artistid
168 existing_single_track.cd.artist.cds.year
172 existing_single_track.cd.artist.cds.cdid
174 existing_single_track.cd.artist.cds.tracks.title
175 existing_single_track.cd.artist.cds.genreid
179 $schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} }),
182 -idcols_current_node => [ 1 ], # existing_single_track.cd.artist.artistid
183 -idcols_extra_from_children => [ 0, 5, 6, 8 ],
185 existing_single_track => {
187 -idcols_current_node => [ 1 ], # existing_single_track.cd.artist.artistid
188 -idcols_extra_from_children => [ 6, 8 ],
193 -idcols_current_node => [ 1 ], # existing_single_track.cd.artist.artistid
194 -idcols_extra_from_children => [ 6, 8 ],
199 -idcols_current_node => [ 1 ], # existing_single_track.cd.artist.artistid
200 -idcols_extra_from_children => [ 6, 8 ],
205 -idcols_current_node => [ 1, 6 ], # existing_single_track.cd.artist.cds.cdid
206 -idcols_extra_from_children => [ 8 ],
211 -idcols_current_node => [ 1, 6, 8 ], # existing_single_track.cd.artist.cds.cdid, existing_single_track.cd.artist.cds.tracks.title
220 -idcols_current_node => [ 1, 5 ], # existing_single_track.cd.artist.artistid, tracks.title
221 -idcols_extra_from_children => [ 0 ],
226 -idcols_current_node => [ 1, 5 ], # existing_single_track.cd.artist.artistid, tracks.title
227 -idcols_extra_from_children => [ 0 ],
233 -idcols_current_node => [ 0, 1, 5 ], # tracks.lyrics.lyric_versions.text, existing_single_track.cd.artist.artistid, tracks.title
239 'Correct collapse map constructed',
243 $schema->source ('CD')->_mk_row_parser({
244 inflate_map => $infmap,
247 ' my ($rows_pos, $result_pos, $cur_row, @cur_row_ids, @collapse_idx, $is_new_res) = (0,0);
250 ( $rows_pos >= 0 and $_[0][$rows_pos++] ) or do { $rows_pos = -1; undef } )
252 ( $_[1] and $_[1]->() )
255 $cur_row_ids[$_] = defined $cur_row->[$_] ? $cur_row->[$_] : "\0NULL\xFF$rows_pos\xFF$_\0"
258 $is_new_res = ! $collapse_idx[1]{$cur_row_ids[1]} and (
259 $_[1] and $result_pos and (unshift @{$_[2]}, $cur_row) and last
262 $collapse_idx[1]{$cur_row_ids[1]} ||= [{ genreid => $cur_row->[4], latest_cd => $cur_row->[7], year => $cur_row->[3] }];
264 $collapse_idx[1]{$cur_row_ids[1]}[1]{existing_single_track} ||= $collapse_idx[2]{$cur_row_ids[1]};
265 $collapse_idx[2]{$cur_row_ids[1]}[1]{cd} ||= $collapse_idx[3]{$cur_row_ids[1]};
266 $collapse_idx[3]{$cur_row_ids[1]}[1]{artist} ||= $collapse_idx[4]{$cur_row_ids[1]} ||= [{ artistid => $cur_row->[1] }];
268 push @{ $collapse_idx[4]{$cur_row_ids[1]}[1]{cds} }, $collapse_idx[5]{$cur_row_ids[1]}{$cur_row_ids[6]} ||= [{ cdid => $cur_row->[6], genreid => $cur_row->[9], year => $cur_row->[2] }]
269 unless $collapse_idx[5]{$cur_row_ids[1]}{$cur_row_ids[6]};
271 push @{ $collapse_idx[5]{$cur_row_ids[1]}{$cur_row_ids[6]}[1]{tracks} }, $collapse_idx[6]{$cur_row_ids[1]}{$cur_row_ids[6]}{$cur_row_ids[8]} ||= [{ title => $cur_row->[8] }]
272 unless $collapse_idx[6]{$cur_row_ids[1]}{$cur_row_ids[6]}{$cur_row_ids[8]};
274 push @{ $collapse_idx[1]{$cur_row_ids[1]}[1]{tracks} }, $collapse_idx[7]{$cur_row_ids[1]}{$cur_row_ids[5]} ||= [{ title => $cur_row->[5] }]
275 unless $collapse_idx[7]{$cur_row_ids[1]}{$cur_row_ids[5]};
277 $collapse_idx[7]{$cur_row_ids[1]}{$cur_row_ids[5]}[1]{lyrics} ||= $collapse_idx[8]{$cur_row_ids[1]}{$cur_row_ids[5] };
279 push @{ $collapse_idx[8]{$cur_row_ids[1]}{$cur_row_ids[5]}[1]{lyric_versions} }, $collapse_idx[9]{$cur_row_ids[0]}{$cur_row_ids[1]}{$cur_row_ids[5]} ||= [{ text => $cur_row->[0] }]
280 unless $collapse_idx[9]{$cur_row_ids[0]}{$cur_row_ids[1]}{$cur_row_ids[5]};
282 $_[0][$result_pos++] = $collapse_idx[1]{$cur_row_ids[1]}
286 splice @{$_[0]}, $result_pos;
288 'Multiple has_many on multiple branches torture test',
292 'single_track.trackid', # (0) definitive link to root from 1:1:1:1:M:M chain
293 'year', # (1) non-unique
294 'tracks.cd', # (2) \ together both uniqueness for second multirel
295 'tracks.title', # (3) / and definitive link back to root
296 'single_track.cd.artist.cds.cdid', # (4) to give uniquiness to ...tracks.title below
297 'single_track.cd.artist.cds.year', # (5) non-unique
298 'single_track.cd.artist.artistid', # (6) uniqufies entire parental chain
299 'single_track.cd.artist.cds.genreid', # (7) nullable
300 'single_track.cd.artist.cds.tracks.title',# (8) unique when combined with ...cds.cdid above
304 $schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} }),
306 -idcols_current_node => [],
307 -idcols_extra_from_children => [ 0, 2, 3, 4, 8 ],
309 -root_node_idcol_variants => [
313 -idcols_current_node => [ 0 ],
314 -idcols_extra_from_children => [ 4, 8 ],
319 -idcols_current_node => [ 0 ],
320 -idcols_extra_from_children => [ 4, 8 ],
324 -idcols_current_node => [ 0 ],
325 -idcols_extra_from_children => [ 4, 8 ],
329 -idcols_current_node => [ 0, 4 ],
330 -idcols_extra_from_children => [ 8 ],
334 -idcols_current_node => [ 0, 4, 8 ],
343 -idcols_current_node => [ 2, 3 ],
348 'Correct underdefined root collapse map constructed'
352 $schema->source ('CD')->_mk_row_parser({
353 inflate_map => $infmap,
356 ' my($rows_pos, $result_pos, $cur_row, @cur_row_ids, @collapse_idx, $is_new_res) = (0, 0);
359 ( $rows_pos >= 0 and $_[0][$rows_pos++] ) or do { $rows_pos = -1; undef } )
361 ( $_[1] and $_[1]->() )
364 $cur_row_ids[$_] = defined $$cur_row[$_] ? $$cur_row[$_] : "\0NULL\xFF$rows_pos\xFF$_\0"
367 # cache expensive set of ops in a non-existent rowid slot
369 ( ( defined $cur_row->[0] ) && (join "\xFF", q{}, $cur_row->[0], q{} ))
371 ( ( defined $cur_row->[2] ) && (join "\xFF", q{}, $cur_row->[2], q{} ))
376 $is_new_res = ! $collapse_idx[1]{$cur_row_ids[9]} and (
377 $_[1] and $result_pos and (unshift @{$_[2]}, $cur_row) and last
380 $collapse_idx[1]{$cur_row_ids[9]} ||= [{ year => $$cur_row[1] }];
382 $collapse_idx[1]{$cur_row_ids[9]}[1]{single_track} ||= ($collapse_idx[2]{$cur_row_ids[0]} ||= [{ trackid => $$cur_row[0] }]);
384 $collapse_idx[2]{$cur_row_ids[0]}[1]{cd} ||= $collapse_idx[3]{$cur_row_ids[0]};
386 $collapse_idx[3]{$cur_row_ids[0]}[1]{artist} ||= ($collapse_idx[4]{$cur_row_ids[0]} ||= [{ artistid => $$cur_row[6] }]);
388 push @{$collapse_idx[4]{$cur_row_ids[0]}[1]{cds}},
389 $collapse_idx[5]{$cur_row_ids[0]}{$cur_row_ids[4]} ||= [{ cdid => $$cur_row[4], genreid => $$cur_row[7], year => $$cur_row[5] }]
390 unless $collapse_idx[5]{$cur_row_ids[0]}{$cur_row_ids[4]};
392 push @{$collapse_idx[5]{$cur_row_ids[0]}{$cur_row_ids[4]}[1]{tracks}},
393 $collapse_idx[6]{$cur_row_ids[0]}{$cur_row_ids[4]}{$cur_row_ids[8]} ||= [{ title => $$cur_row[8] }]
394 unless $collapse_idx[6]{$cur_row_ids[0]}{$cur_row_ids[4]}{$cur_row_ids[8]};
396 push @{$collapse_idx[1]{$cur_row_ids[9]}[1]{tracks}},
397 $collapse_idx[7]{$cur_row_ids[2]}{$cur_row_ids[3]} ||= [{ cd => $$cur_row[2], title => $$cur_row[3] }]
398 unless $collapse_idx[7]{$cur_row_ids[2]}{$cur_row_ids[3]};
400 $_[0][$result_pos++] = $collapse_idx[1]{$cur_row_ids[9]}
404 splice @{$_[0]}, $result_pos;
406 'Multiple has_many on multiple branches with underdefined root torture test',
413 $deparser ||= B::Deparse->new;
414 local $Test::Builder::Level = $Test::Builder::Level + 1;
416 my ($got, $expect) = map {
417 my $cref = eval "sub { $_ }" or do {
418 fail "Coderef does not compile!\n\n$@\n\n$_";
421 $deparser->coderef2text($cref);
424 is ($got, $expect, $_[2]||() )
425 or note ("Originals source:\n\n$_[0]\n\n$_[1]\n");