Write correct odd (not even) relchain depth on primary joins
[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/
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/];
47is_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
72is_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
118is_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
172is_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
238is_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
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