Test for restricted prefetch (now passing again after previous commit)
[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);
18my $infmap = [qw/single_track.cd.artist.name year/];
19
20is_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/
3faac878 40 single_track.cd.artist.cds.tracks.title
4e9fc3f3 41 single_track.cd.artist.artistid
42 year
4e9fc3f3 43 single_track.cd.artist.cds.cdid
44 title
45 artist
46/];
47is_same_src (
48 $schema->source ('CD')->_mk_row_parser({
49 inflate_map => $infmap,
50 }),
51 '$_ = [
3faac878 52 { artist => $_->[5], title => $_->[4], year => $_->[2] },
4e9fc3f3 53 { single_track => [
54 undef,
55 { cd => [
56 undef,
57 { artist => [
3faac878 58 { artistid => $_->[1] },
4e9fc3f3 59 { cds => [
60 { cdid => $_->[3] },
61 { tracks => [
3faac878 62 { title => $_->[0] }
4e9fc3f3 63 ] },
64 ] },
65 ] },
66 ] },
67 ] },
68 ] for @{$_[0]}',
69 '1:1 descending non-collapsing parser terminating with chained 1:M:M',
70);
71
72is_deeply (
3faac878 73 ($schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} })),
4e9fc3f3 74 {
75 -node_index => 1,
3faac878 76 -idcols_current_node => [ 4, 5 ],
77 -idcols_extra_from_children => [ 0, 3 ],
4e9fc3f3 78
79 single_track => {
80 -node_index => 2,
3faac878 81 -idcols_current_node => [ 4, 5 ],
82 -idcols_extra_from_children => [ 0, 3 ],
4e9fc3f3 83 -is_optional => 1,
84 -is_single => 1,
85
86 cd => {
87 -node_index => 3,
3faac878 88 -idcols_current_node => [ 4, 5 ],
89 -idcols_extra_from_children => [ 0, 3 ],
4e9fc3f3 90 -is_single => 1,
91
92 artist => {
93 -node_index => 4,
3faac878 94 -idcols_current_node => [ 4, 5 ],
95 -idcols_extra_from_children => [ 0, 3 ],
4e9fc3f3 96 -is_single => 1,
97
98 cds => {
99 -node_index => 5,
3faac878 100 -idcols_current_node => [ 3, 4, 5 ],
101 -idcols_extra_from_children => [ 0 ],
4e9fc3f3 102 -is_optional => 1,
103
104 tracks => {
105 -node_index => 6,
3faac878 106 -idcols_current_node => [ 0, 3, 4, 5 ],
4e9fc3f3 107 -is_optional => 1,
108 },
109 },
110 },
111 },
112 },
113 },
114 'Correct collapse map for 1:1 descending chain terminating with chained 1:M:M'
115);
116
117is_same_src (
118 $schema->source ('CD')->_mk_row_parser({
119 inflate_map => $infmap,
120 collapse => 1,
121 }),
122 ' my($rows_pos, $result_pos, $cur_row, @cur_row_ids, @collapse_idx, $is_new_res) = (0, 0);
123
124 while ($cur_row = (
125 ( $rows_pos >= 0 and $_[0][$rows_pos++] ) or do { $rows_pos = -1; undef } )
126 ||
127 ( $_[1] and $_[1]->() )
128 ) {
129
130 $cur_row_ids[$_] = defined $cur_row->[$_] ? $cur_row->[$_] : "\xFF\xFFN\xFFU\xFFL\xFFL\xFF\xFF"
3faac878 131 for (0, 3, 4, 5);
4e9fc3f3 132
3faac878 133 # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2]
4e9fc3f3 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]};
136
3faac878 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] }];
139
140 # prefetch data of single_track (placed in root)
4e9fc3f3 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]};
3faac878 142
143 # prefetch data of cd (placed in single_track)
4e9fc3f3 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]};
4e9fc3f3 145
3faac878 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] }];
148
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]};
4e9fc3f3 152
3faac878 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]};
4e9fc3f3 156
157 $_[0][$result_pos++] = $collapse_idx[1]{$cur_row_ids[4]}{$cur_row_ids[5]}
158 if $is_new_res;
159 }
160 splice @{$_[0]}, $result_pos;
161 ',
162 'Same 1:1 descending terminating with chained 1:M:M but with collapse',
163);
164
165$infmap = [qw/
166 tracks.lyrics.lyric_versions.text
167 existing_single_track.cd.artist.artistid
168 existing_single_track.cd.artist.cds.year
169 year
170 genreid
171 tracks.title
172 existing_single_track.cd.artist.cds.cdid
173 latest_cd
174 existing_single_track.cd.artist.cds.tracks.title
175 existing_single_track.cd.artist.cds.genreid
176/];
177
178is_deeply (
82f0e0aa 179 $schema->source('CD')->_resolve_collapse({ as => {map { $infmap->[$_] => $_ } 0 .. $#$infmap} }),
4e9fc3f3 180 {
181 -node_index => 1,
3faac878 182 -idcols_current_node => [ 1 ], # existing_single_track.cd.artist.artistid
183 -idcols_extra_from_children => [ 0, 5, 6, 8 ],
4e9fc3f3 184
185 existing_single_track => {
186 -node_index => 2,
3faac878 187 -idcols_current_node => [ 1 ], # existing_single_track.cd.artist.artistid
188 -idcols_extra_from_children => [ 6, 8 ],
4e9fc3f3 189 -is_single => 1,
190
191 cd => {
192 -node_index => 3,
3faac878 193 -idcols_current_node => [ 1 ], # existing_single_track.cd.artist.artistid
194 -idcols_extra_from_children => [ 6, 8 ],
4e9fc3f3 195 -is_single => 1,
196
197 artist => {
198 -node_index => 4,
3faac878 199 -idcols_current_node => [ 1 ], # existing_single_track.cd.artist.artistid
200 -idcols_extra_from_children => [ 6, 8 ],
4e9fc3f3 201 -is_single => 1,
202
203 cds => {
204 -node_index => 5,
3faac878 205 -idcols_current_node => [ 1, 6 ], # existing_single_track.cd.artist.cds.cdid
206 -idcols_extra_from_children => [ 8 ],
4e9fc3f3 207 -is_optional => 1,
208
209 tracks => {
210 -node_index => 6,
3faac878 211 -idcols_current_node => [ 1, 6, 8 ], # existing_single_track.cd.artist.cds.cdid, existing_single_track.cd.artist.cds.tracks.title
4e9fc3f3 212 -is_optional => 1,
213 }
214 }
215 }
216 }
217 },
218 tracks => {
219 -node_index => 7,
3faac878 220 -idcols_current_node => [ 1, 5 ], # existing_single_track.cd.artist.artistid, tracks.title
221 -idcols_extra_from_children => [ 0 ],
4e9fc3f3 222 -is_optional => 1,
223
224 lyrics => {
225 -node_index => 8,
3faac878 226 -idcols_current_node => [ 1, 5 ], # existing_single_track.cd.artist.artistid, tracks.title
227 -idcols_extra_from_children => [ 0 ],
4e9fc3f3 228 -is_single => 1,
229 -is_optional => 1,
230
231 lyric_versions => {
232 -node_index => 9,
3faac878 233 -idcols_current_node => [ 0, 1, 5 ], # tracks.lyrics.lyric_versions.text, existing_single_track.cd.artist.artistid, tracks.title
4e9fc3f3 234 -is_optional => 1,
235 },
236 },
237 }
238 },
239 'Correct collapse map constructed',
240);
241
242is_same_src (
243 $schema->source ('CD')->_mk_row_parser({
244 inflate_map => $infmap,
245 collapse => 1,
246 }),
247 ' my ($rows_pos, $result_pos, $cur_row, @cur_row_ids, @collapse_idx, $is_new_res) = (0,0);
248
249 while ($cur_row = (
250 ( $rows_pos >= 0 and $_[0][$rows_pos++] ) or do { $rows_pos = -1; undef } )
251 ||
252 ( $_[1] and $_[1]->() )
253 ) {
254
255 $cur_row_ids[$_] = defined $cur_row->[$_] ? $cur_row->[$_] : "\xFF\xFFN\xFFU\xFFL\xFFL\xFF\xFF"
256 for (0, 1, 5, 6, 8);
257
258 $is_new_res = ! $collapse_idx[1]{$cur_row_ids[1]} and (
259 $_[1] and $result_pos and (unshift @{$_[2]}, $cur_row) and last
260 );
261
7d5371dc 262 $collapse_idx[1]{$cur_row_ids[1]} ||= [{ genreid => $cur_row->[4], latest_cd => $cur_row->[7], year => $cur_row->[3] }];
4e9fc3f3 263
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] }];
267
3faac878 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]};
4e9fc3f3 270
3faac878 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]};
4e9fc3f3 273
4e9fc3f3 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]};
276
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] };
278
4e9fc3f3 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
291done_testing;
292
293my $deparser;
294sub 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