Commit | Line | Data |
4e9fc3f3 |
1 | use strict; |
2 | use warnings; |
3 | |
4 | use Test::More; |
5 | use lib qw(t/lib); |
6 | use DBICTest; |
7 | use 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 |
14 | use Data::Dumper; |
15 | $Data::Dumper::Sortkeys = 1; |
16 | |
4e9fc3f3 |
17 | my $schema = DBICTest->init_schema(no_deploy => 1); |
ce556881 |
18 | my $infmap = [qw/ |
19 | single_track.cd.artist.name |
20 | year |
21 | /]; |
4e9fc3f3 |
22 | |
23 | is_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 | /]; |
50 | is_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 |
75 | is_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 | |
115 | is_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 |
150 | is_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 | |
184 | is_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 |
238 | is_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 | |
316 | is_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 | |
363 | is_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 |
424 | is_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 | |
513 | is_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 | |
549 | is_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 |
613 | is_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 |
691 | done_testing; |
692 | |
693 | my $deparser; |
694 | sub 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 | |