Resolve $rsrc instance duality on metadata traversal
[dbsrgits/DBIx-Class.git] / t / 87ordered.t
1 BEGIN { do "./t/lib/ANFANG.pm" or die ( $@ || $! ) }
2
3 # vim: filetype=perl
4 use strict;
5 use warnings;
6
7 use Test::More;
8
9 use DBICTest;
10
11 use POSIX ();
12
13 my $schema = DBICTest->init_schema();
14
15 my $employees = $schema->resultset('Employee');
16 $employees->delete();
17
18 foreach (1..5) {
19     $employees->create({ name=>'temp' });
20 }
21 $employees = $employees->search(undef,{order_by=>'position'});
22 ok( check_rs($employees), "intial positions" );
23
24 hammer_rs( $employees );
25
26 DBICTest::Employee->grouping_column('group_id');
27 $employees->delete();
28 foreach my $group_id (1..4) {
29     foreach (1..6) {
30         $employees->create({ name=>'temp', group_id=>$group_id });
31     }
32 }
33 $employees = $employees->search(undef,{order_by=>'group_id,position'});
34
35 foreach my $group_id (1..4) {
36     my $group_employees = $employees->search({group_id=>$group_id});
37     $group_employees->all();
38     ok( check_rs($group_employees), "group intial positions" );
39     hammer_rs( $group_employees );
40 }
41
42 my $group_3 = $employees->search({group_id=>3});
43 my $to_group = 1;
44 my $to_pos = undef;
45 {
46   my @empl = $group_3->all;
47   while (my $employee = shift @empl) {
48     $employee->move_to_group($to_group, $to_pos);
49     $to_pos++;
50     $to_group = $to_group==1 ? 2 : 1;
51   }
52 }
53 foreach my $group_id (1..4) {
54     my $group_employees = $employees->search({group_id=>$group_id});
55     ok( check_rs($group_employees), "group positions after move_to_group" );
56 }
57
58 my $employee = $employees->search({group_id=>4})->first;
59 $employee->position(2);
60 $employee->update;
61 ok( check_rs($employees->search_rs({group_id=>4})), "overloaded update 1" );
62 $employee = $employees->search({group_id=>4})->first;
63 $employee->update({position=>3});
64 ok( check_rs($employees->search_rs({group_id=>4})), "overloaded update 2" );
65 $employee = $employees->search({group_id=>4})->first;
66 $employee->group_id(1);
67 $employee->update;
68 ok(
69   check_rs($employees->search_rs({group_id=>1})) && check_rs($employees->search_rs({group_id=>4})),
70   "overloaded update 3"
71 );
72 $employee = $employees->search({group_id=>4})->first;
73 $employee->update({group_id=>2});
74 ok(
75   check_rs($employees->search_rs({group_id=>2})) && check_rs($employees->search_rs({group_id=>4})),
76   "overloaded update 4"
77 );
78 $employee = $employees->search({group_id=>4})->first;
79 $employee->group_id(1);
80 $employee->position(3);
81 $employee->update;
82 ok(
83   check_rs($employees->search_rs({group_id=>1})) && check_rs($employees->search_rs({group_id=>4})),
84   "overloaded update 5"
85 );
86 $employee = $employees->search({group_id=>4})->first;
87 $employee->group_id(2);
88 $employee->position(undef);
89 $employee->update;
90 ok(
91   check_rs($employees->search_rs({group_id=>2})) && check_rs($employees->search_rs({group_id=>4})),
92   "overloaded update 6"
93 );
94 $employee = $employees->search({group_id=>4})->first;
95 $employee->update({group_id=>1,position=>undef});
96 ok(
97   check_rs($employees->search_rs({group_id=>1})) && check_rs($employees->search_rs({group_id=>4})),
98   "overloaded update 7"
99 );
100
101 $employee->group_id(2);
102 $employee->name('E of the month');
103 $employee->update({ employee_id => 666, position => 2 });
104 is_deeply(
105   { $employee->get_columns },
106   {
107     employee_id => 666,
108     encoded => undef,
109     group_id => 2,
110     group_id_2 => undef,
111     group_id_3 => undef,
112     name => "E of the month",
113     position => 2
114   },
115   'combined update() worked correctly'
116 );
117 is_deeply(
118   { $employee->get_columns },
119   { $employee->get_from_storage->get_columns },
120   'object matches database state',
121 );
122
123 #####
124 # multicol tests begin here
125 #####
126
127 DBICTest::Employee->grouping_column(['group_id_2', 'group_id_3']);
128 $employees->delete();
129 foreach my $group_id_2 (1..4) {
130     foreach my $group_id_3 (1..4) {
131         foreach (1..4) {
132             $employees->create({ name=>'temp', group_id_2=>$group_id_2, group_id_3=>$group_id_3 });
133         }
134     }
135 }
136 $employees = $employees->search(undef,{order_by=>[qw/group_id_2 group_id_3 position/]});
137
138 foreach my $group_id_2 (1..3) {
139     foreach my $group_id_3 (1..3) {
140         my $group_employees = $employees->search({group_id_2=>$group_id_2, group_id_3=>$group_id_3});
141         $group_employees->all();
142         ok( check_rs($group_employees), "group intial positions" );
143         hammer_rs( $group_employees );
144     }
145 }
146
147 # move_to_group, specifying group by hash
148 my $group_4 = $employees->search({group_id_2=>4});
149 $to_group = 1;
150 my $to_group_2_base = 7;
151 my $to_group_2 = 1;
152 $to_pos = undef;
153
154 {
155   my @empl = $group_3->all;
156   while (my $employee = shift @empl) {
157     $employee->move_to_group({group_id_2=>$to_group, group_id_3=>$to_group_2}, $to_pos);
158     $to_pos++;
159     $to_group = ($to_group % 3) + 1;
160     $to_group_2_base++;
161     $to_group_2 = (
162       POSIX::ceil( $to_group_2_base / 3.0 ) % 3
163     ) + 1;
164   }
165 }
166 foreach my $group_id_2 (1..4) {
167     foreach my $group_id_3 (1..4) {
168         my $group_employees = $employees->search({group_id_2=>$group_id_2,group_id_3=>$group_id_3});
169         ok( check_rs($group_employees), "group positions after move_to_group" );
170     }
171 }
172
173 $employees->delete();
174 foreach my $group_id_2 (1..4) {
175     foreach my $group_id_3 (1..4) {
176         foreach (1..4) {
177             $employees->create({ name=>'temp', group_id_2=>$group_id_2, group_id_3=>$group_id_3 });
178         }
179     }
180 }
181 $employees = $employees->search(undef,{order_by=>[qw/group_id_2 group_id_3 position/]});
182
183 $employee = $employees->search({group_id_2=>4, group_id_3=>1})->first;
184 $employee->group_id_2(1);
185 $employee->update;
186 ok(
187     check_rs($employees->search_rs({group_id_2=>4, group_id_3=>1}))
188     && check_rs($employees->search_rs({group_id_2=>1, group_id_3=>1})),
189     "overloaded multicol update 1"
190 );
191
192 $employee = $employees->search({group_id_2=>4, group_id_3=>1})->first;
193 $employee->update({group_id_2=>2});
194 ok( check_rs($employees->search_rs({group_id_2=>4, group_id_3=>1}))
195     && check_rs($employees->search_rs({group_id_2=>2, group_id_3=>1})),
196    "overloaded multicol update 2"
197 );
198
199 $employee = $employees->search({group_id_2=>3, group_id_3=>1})->first;
200 $employee->group_id_2(1);
201 $employee->group_id_3(3);
202 $employee->update();
203 ok( check_rs($employees->search_rs({group_id_2=>3, group_id_3=>1}))
204     && check_rs($employees->search_rs({group_id_2=>1, group_id_3=>3})),
205     "overloaded multicol update 3"
206 );
207
208 $employee = $employees->search({group_id_2=>3, group_id_3=>1})->first;
209 $employee->update({group_id_2=>2, group_id_3=>3});
210 ok( check_rs($employees->search_rs({group_id_2=>3, group_id_3=>1}))
211     && check_rs($employees->search_rs({group_id_2=>2, group_id_3=>3})),
212     "overloaded multicol update 4"
213 );
214
215 $employee = $employees->search({group_id_2=>3, group_id_3=>2})->first;
216 $employee->update({group_id_2=>2, group_id_3=>4, position=>2});
217 ok( check_rs($employees->search_rs({group_id_2=>3, group_id_3=>2}))
218     && check_rs($employees->search_rs({group_id_2=>2, group_id_3=>4})),
219     "overloaded multicol update 5"
220 );
221
222 sub hammer_rs {
223     my $rs = shift;
224     my $employee;
225     my $count = $rs->count();
226     my $position_column = $rs->result_class->position_column();
227     my $row;
228
229     foreach my $position (1..$count) {
230
231         ($row) = $rs->search({ $position_column=>$position })->all();
232         $row->move_previous();
233         ok( check_rs($rs), "move_previous( $position )" );
234
235         ($row) = $rs->search({ $position_column=>$position })->all();
236         $row->move_next();
237         ok( check_rs($rs), "move_next( $position )" );
238
239         ($row) = $rs->search({ $position_column=>$position })->all();
240         $row->move_first();
241         ok( check_rs($rs), "move_first( $position )" );
242
243         ($row) = $rs->search({ $position_column=>$position })->all();
244         $row->move_last();
245         ok( check_rs($rs), "move_last( $position )" );
246
247         foreach my $to_position (1..$count) {
248             ($row) = $rs->search({ $position_column=>$position })->all();
249             $row->move_to($to_position);
250             ok( check_rs($rs), "move_to( $position => $to_position )" );
251         }
252
253         $row = $rs->find({ position => $position });
254         if ($position==1) {
255             ok( !$row->previous_sibling(), 'no previous sibling' );
256             ok( !$row->first_sibling(), 'no first sibling' );
257             ok( $row->next_sibling->position > $position, 'next sibling position > than us');
258             is( $row->next_sibling->previous_sibling->position, $position, 'next-prev sibling is us');
259             ok( $row->last_sibling->position > $position, 'last sibling position > than us');
260         }
261         else {
262             ok( $row->previous_sibling(), 'previous sibling' );
263             ok( $row->first_sibling(), 'first sibling' );
264             ok( $row->previous_sibling->position < $position, 'prev sibling position < than us');
265             is( $row->previous_sibling->next_sibling->position, $position, 'prev-next sibling is us');
266             ok( $row->first_sibling->position < $position, 'first sibling position < than us');
267         }
268         if ($position==$count) {
269             ok( !$row->next_sibling(), 'no next sibling' );
270             ok( !$row->last_sibling(), 'no last sibling' );
271             ok( $row->previous_sibling->position < $position, 'prev sibling position < than us');
272             is( $row->previous_sibling->next_sibling->position, $position, 'prev-next sibling is us');
273             ok( $row->first_sibling->position < $position, 'first sibling position < than us');
274         }
275         else {
276             ok( $row->next_sibling(), 'next sibling' );
277             ok( $row->last_sibling(), 'last sibling' );
278             ok( $row->next_sibling->position > $row->position, 'next sibling position > than us');
279             is( $row->next_sibling->previous_sibling->position, $position, 'next-prev sibling is us');
280             ok( $row->last_sibling->position > $row->position, 'last sibling position > than us');
281         }
282
283     }
284 }
285
286 sub check_rs {
287     my( $rs ) = @_;
288     $rs->reset();
289     my $position_column = $rs->result_class->position_column();
290     my $expected_position = 0;
291     while (my $row = $rs->next()) {
292         $expected_position ++;
293         if ($row->get_column($position_column)!=$expected_position) {
294             return 0;
295         }
296     }
297     return 1;
298 }
299
300 done_testing;