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); |
18 | my $infmap = [qw/single_track.cd.artist.name year/]; |
19 | |
20 | is_same_src ( |
21 | $schema->source ('CD')->_mk_row_parser({ |
22 | inflate_map => $infmap, |
23 | }), |
24 | '$_ = [ |
25 | { year => $_->[1] }, |
26 | { single_track => [ |
27 | undef, |
28 | { cd => [ |
29 | undef, |
30 | { artist => [ |
31 | { name => $_->[0] }, |
32 | ] }, |
33 | ]}, |
34 | ]}, |
35 | ] for @{$_[0]}', |
36 | 'Simple 1:1 descending non-collapsing parser', |
37 | ); |
38 | |
39 | $infmap = [qw/ |
40 | single_track.cd.artist.artistid |
41 | year |
42 | single_track.cd.artist.cds.tracks.title |
43 | single_track.cd.artist.cds.cdid |
44 | title |
45 | artist |
46 | /]; |
47 | is_same_src ( |
48 | $schema->source ('CD')->_mk_row_parser({ |
49 | inflate_map => $infmap, |
50 | }), |
51 | '$_ = [ |
52 | { artist => $_->[5], title => $_->[4], year => $_->[1] }, |
53 | { single_track => [ |
54 | undef, |
55 | { cd => [ |
56 | undef, |
57 | { artist => [ |
58 | { artistid => $_->[0] }, |
59 | { cds => [ |
60 | { cdid => $_->[3] }, |
61 | { tracks => [ |
62 | { title => $_->[2] } |
63 | ] }, |
64 | ] }, |
65 | ] }, |
66 | ] }, |
67 | ] }, |
68 | ] for @{$_[0]}', |
69 | '1:1 descending non-collapsing parser terminating with chained 1:M:M', |
70 | ); |
71 | |
72 | is_deeply ( |
73 | $schema->source('CD')->_resolve_collapse({map { $infmap->[$_] => $_ } 0 .. $#$infmap}), |
74 | { |
75 | -node_index => 1, |
76 | -node_id => [ 4, 5 ], |
77 | -branch_id => [ 0, 2, 3, 4, 5 ], |
78 | |
79 | single_track => { |
80 | -node_index => 2, |
81 | -node_id => [ 4, 5], |
82 | -branch_id => [ 0, 2, 3, 4, 5], |
83 | -is_optional => 1, |
84 | -is_single => 1, |
85 | |
86 | cd => { |
87 | -node_index => 3, |
88 | -node_id => [ 4, 5 ], |
89 | -branch_id => [ 0, 2, 3, 4, 5 ], |
90 | -is_single => 1, |
91 | |
92 | artist => { |
93 | -node_index => 4, |
94 | -node_id => [ 0 ], |
95 | -branch_id => [ 0, 2, 3 ], |
96 | -is_single => 1, |
97 | |
98 | cds => { |
99 | -node_index => 5, |
100 | -node_id => [ 3 ], |
101 | -branch_id => [ 2, 3 ], |
102 | -is_optional => 1, |
103 | |
104 | tracks => { |
105 | -node_index => 6, |
106 | -node_id => [ 2, 3 ], |
107 | -branch_id => [ 2, 3 ], |
108 | -is_optional => 1, |
109 | }, |
110 | }, |
111 | }, |
112 | }, |
113 | }, |
114 | }, |
115 | 'Correct collapse map for 1:1 descending chain terminating with chained 1:M:M' |
116 | ); |
117 | |
118 | is_same_src ( |
119 | $schema->source ('CD')->_mk_row_parser({ |
120 | inflate_map => $infmap, |
121 | collapse => 1, |
122 | }), |
123 | ' my($rows_pos, $result_pos, $cur_row, @cur_row_ids, @collapse_idx, $is_new_res) = (0, 0); |
124 | |
125 | while ($cur_row = ( |
126 | ( $rows_pos >= 0 and $_[0][$rows_pos++] ) or do { $rows_pos = -1; undef } ) |
127 | || |
128 | ( $_[1] and $_[1]->() ) |
129 | ) { |
130 | |
131 | $cur_row_ids[$_] = defined $cur_row->[$_] ? $cur_row->[$_] : "\xFF\xFFN\xFFU\xFFL\xFFL\xFF\xFF" |
132 | for (0, 2, 3, 4, 5); |
133 | |
134 | # a present cref implies lazy prefetch, implies a supplied stash in $_[2] |
135 | $_[1] and $result_pos and unshift(@{$_[2]}, $cur_row) and last |
136 | if $is_new_res = ! $collapse_idx[1]{$cur_row_ids[4]}{$cur_row_ids[5]}; |
137 | |
138 | $collapse_idx[1]{$cur_row_ids[4]}{$cur_row_ids[5]} ||= [{ artist => $cur_row->[5], title => $cur_row->[4], year => $cur_row->[1] }]; |
139 | $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]}; |
140 | $collapse_idx[2]{$cur_row_ids[4]}{$cur_row_ids[5]}[1]{cd} ||= $collapse_idx[3]{$cur_row_ids[4]}{$cur_row_ids[5]}; |
141 | $collapse_idx[3]{$cur_row_ids[4]}{$cur_row_ids[5]}[1]{artist} ||= $collapse_idx[4]{$cur_row_ids[0]} ||= [{ artistid => $cur_row->[0] }]; |
142 | |
143 | $collapse_idx[4]{$cur_row_ids[0]}[1]{cds} ||= []; |
144 | push @{$collapse_idx[4]{$cur_row_ids[0]}[1]{cds}}, $collapse_idx[5]{$cur_row_ids[3]} ||= [{ cdid => $cur_row->[3] }] |
145 | unless $collapse_idx[5]{$cur_row_ids[3]}; |
146 | |
147 | $collapse_idx[5]{$cur_row_ids[3]}[1]{tracks} ||= []; |
148 | push @{$collapse_idx[5]{$cur_row_ids[3]}[1]{tracks}}, $collapse_idx[6]{$cur_row_ids[2]}{$cur_row_ids[3]} ||= [{ title => $cur_row->[2] }] |
149 | unless $collapse_idx[6]{$cur_row_ids[2]}{$cur_row_ids[3]}; |
150 | |
151 | $_[0][$result_pos++] = $collapse_idx[1]{$cur_row_ids[4]}{$cur_row_ids[5]} |
152 | if $is_new_res; |
153 | } |
154 | splice @{$_[0]}, $result_pos; |
155 | ', |
156 | 'Same 1:1 descending terminating with chained 1:M:M but with collapse', |
157 | ); |
158 | |
159 | $infmap = [qw/ |
160 | tracks.lyrics.lyric_versions.text |
161 | existing_single_track.cd.artist.artistid |
162 | existing_single_track.cd.artist.cds.year |
163 | year |
164 | genreid |
165 | tracks.title |
166 | existing_single_track.cd.artist.cds.cdid |
167 | latest_cd |
168 | existing_single_track.cd.artist.cds.tracks.title |
169 | existing_single_track.cd.artist.cds.genreid |
170 | /]; |
171 | |
172 | is_deeply ( |
173 | $schema->source('CD')->_resolve_collapse({map { $infmap->[$_] => $_ } 0 .. $#$infmap}), |
174 | { |
175 | -node_index => 1, |
176 | -node_id => [ 1 ], # existing_single_track.cd.artist.artistid |
177 | -branch_id => [ 0, 1, 5, 6, 8 ], |
178 | |
179 | existing_single_track => { |
180 | -node_index => 2, |
181 | -node_id => [ 1 ], # existing_single_track.cd.artist.artistid |
182 | -branch_id => [ 1, 6, 8 ], |
183 | -is_single => 1, |
184 | |
185 | cd => { |
186 | -node_index => 3, |
187 | -node_id => [ 1 ], # existing_single_track.cd.artist.artistid |
188 | -branch_id => [ 1, 6, 8 ], |
189 | -is_single => 1, |
190 | |
191 | artist => { |
192 | -node_index => 4, |
193 | -node_id => [ 1 ], # existing_single_track.cd.artist.artistid |
194 | -branch_id => [ 1, 6, 8 ], |
195 | -is_single => 1, |
196 | |
197 | cds => { |
198 | -node_index => 5, |
199 | -node_id => [ 6 ], # existing_single_track.cd.artist.cds.cdid |
200 | -branch_id => [ 6, 8 ], |
201 | -is_optional => 1, |
202 | |
203 | tracks => { |
204 | -node_index => 6, |
205 | -node_id => [ 6, 8 ], # existing_single_track.cd.artist.cds.cdid, existing_single_track.cd.artist.cds.tracks.title |
206 | -branch_id => [ 6, 8 ], |
207 | -is_optional => 1, |
208 | } |
209 | } |
210 | } |
211 | } |
212 | }, |
213 | tracks => { |
214 | -node_index => 7, |
215 | -node_id => [ 1, 5 ], # existing_single_track.cd.artist.artistid, tracks.title |
216 | -branch_id => [ 0, 1, 5 ], |
217 | -is_optional => 1, |
218 | |
219 | lyrics => { |
220 | -node_index => 8, |
221 | -node_id => [ 1, 5 ], # existing_single_track.cd.artist.artistid, tracks.title |
222 | -branch_id => [ 0, 1, 5 ], |
223 | -is_single => 1, |
224 | -is_optional => 1, |
225 | |
226 | lyric_versions => { |
227 | -node_index => 9, |
228 | -node_id => [ 0, 1, 5 ], # tracks.lyrics.lyric_versions.text, existing_single_track.cd.artist.artistid, tracks.title |
229 | -branch_id => [ 0, 1, 5 ], |
230 | -is_optional => 1, |
231 | }, |
232 | }, |
233 | } |
234 | }, |
235 | 'Correct collapse map constructed', |
236 | ); |
237 | |
238 | is_same_src ( |
239 | $schema->source ('CD')->_mk_row_parser({ |
240 | inflate_map => $infmap, |
241 | collapse => 1, |
242 | }), |
243 | ' my ($rows_pos, $result_pos, $cur_row, @cur_row_ids, @collapse_idx, $is_new_res) = (0,0); |
244 | |
245 | while ($cur_row = ( |
246 | ( $rows_pos >= 0 and $_[0][$rows_pos++] ) or do { $rows_pos = -1; undef } ) |
247 | || |
248 | ( $_[1] and $_[1]->() ) |
249 | ) { |
250 | |
251 | $cur_row_ids[$_] = defined $cur_row->[$_] ? $cur_row->[$_] : "\xFF\xFFN\xFFU\xFFL\xFFL\xFF\xFF" |
252 | for (0, 1, 5, 6, 8); |
253 | |
254 | $is_new_res = ! $collapse_idx[1]{$cur_row_ids[1]} and ( |
255 | $_[1] and $result_pos and (unshift @{$_[2]}, $cur_row) and last |
256 | ); |
257 | |
7d5371dc |
258 | $collapse_idx[1]{$cur_row_ids[1]} ||= [{ genreid => $cur_row->[4], latest_cd => $cur_row->[7], year => $cur_row->[3] }]; |
4e9fc3f3 |
259 | |
260 | $collapse_idx[1]{$cur_row_ids[1]}[1]{existing_single_track} ||= $collapse_idx[2]{$cur_row_ids[1]}; |
261 | $collapse_idx[2]{$cur_row_ids[1]}[1]{cd} ||= $collapse_idx[3]{$cur_row_ids[1]}; |
262 | $collapse_idx[3]{$cur_row_ids[1]}[1]{artist} ||= $collapse_idx[4]{$cur_row_ids[1]} ||= [{ artistid => $cur_row->[1] }]; |
263 | |
264 | $collapse_idx[4]{$cur_row_ids[1]}[1]{cds} ||= []; |
265 | push @{ $collapse_idx[4]{$cur_row_ids[1]}[1]{cds} }, $collapse_idx[5]{$cur_row_ids[6]} ||= [{ cdid => $cur_row->[6], genreid => $cur_row->[9], year => $cur_row->[2] }] |
266 | unless $collapse_idx[5]{$cur_row_ids[6]}; |
267 | |
268 | $collapse_idx[5]{$cur_row_ids[6]}[1]{tracks} ||= []; |
269 | push @{ $collapse_idx[5]{$cur_row_ids[6]}[1]{tracks} }, $collapse_idx[6]{$cur_row_ids[6]}{$cur_row_ids[8]} ||= [{ title => $cur_row->[8] }] |
270 | unless $collapse_idx[6]{$cur_row_ids[6]}{$cur_row_ids[8]}; |
271 | |
272 | $collapse_idx[1]{$cur_row_ids[1]}[1]{tracks} ||= []; |
273 | 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] }] |
274 | unless $collapse_idx[7]{$cur_row_ids[1]}{$cur_row_ids[5]}; |
275 | |
276 | $collapse_idx[7]{$cur_row_ids[1]}{$cur_row_ids[5]}[1]{lyrics} ||= $collapse_idx[8]{$cur_row_ids[1]}{$cur_row_ids[5] }; |
277 | |
278 | $collapse_idx[8]{$cur_row_ids[1]}{$cur_row_ids[5]}[1]{lyric_versions} ||= []; |
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]}; |
281 | |
282 | $_[0][$result_pos++] = $collapse_idx[1]{$cur_row_ids[1]} |
283 | if $is_new_res; |
284 | } |
285 | |
286 | splice @{$_[0]}, $result_pos; |
287 | ', |
288 | 'Multiple has_many on multiple branches torture test', |
289 | ); |
290 | |
291 | done_testing; |
292 | |
293 | my $deparser; |
294 | sub is_same_src { |
295 | $deparser ||= B::Deparse->new; |
296 | local $Test::Builder::Level = $Test::Builder::Level + 1; |
297 | |
298 | my ($got, $expect) = map { |
299 | my $cref = eval "sub { $_ }" or do { |
300 | fail "Coderef does not compile!\n\n$@\n\n$_"; |
301 | return undef; |
302 | }; |
303 | $deparser->coderef2text($cref); |
304 | } @_[0,1]; |
305 | |
306 | is ($got, $expect, $_[2]||() ) |
307 | or note ("Originals source:\n\n$_[0]\n\n$_[1]\n"); |
308 | } |
309 | |