1DBIx::Class::Ordered(3)User Contributed Perl DocumentatioDnBIx::Class::Ordered(3)
2
3
4
6 DBIx::Class::Ordered - Modify the position of objects in an ordered
7 list.
8
10 Create a table for your ordered data.
11
12 CREATE TABLE items (
13 item_id INTEGER PRIMARY KEY AUTOINCREMENT,
14 name TEXT NOT NULL,
15 position INTEGER NOT NULL
16 );
17
18 Optionally, add one or more columns to specify groupings, allowing you
19 to maintain independent ordered lists within one table:
20
21 CREATE TABLE items (
22 item_id INTEGER PRIMARY KEY AUTOINCREMENT,
23 name TEXT NOT NULL,
24 position INTEGER NOT NULL,
25 group_id INTEGER NOT NULL
26 );
27
28 Or even
29
30 CREATE TABLE items (
31 item_id INTEGER PRIMARY KEY AUTOINCREMENT,
32 name TEXT NOT NULL,
33 position INTEGER NOT NULL,
34 group_id INTEGER NOT NULL,
35 other_group_id INTEGER NOT NULL
36 );
37
38 In your Schema or DB class add "Ordered" to the top of the component
39 list.
40
41 __PACKAGE__->load_components(qw( Ordered ... ));
42
43 Specify the column that stores the position number for each row.
44
45 package My::Item;
46 __PACKAGE__->position_column('position');
47
48 If you are using one grouping column, specify it as follows:
49
50 __PACKAGE__->grouping_column('group_id');
51
52 Or if you have multiple grouping columns:
53
54 __PACKAGE__->grouping_column(['group_id', 'other_group_id']);
55
56 That's it, now you can change the position of your objects.
57
58 #!/use/bin/perl
59 use My::Item;
60
61 my $item = My::Item->create({ name=>'Matt S. Trout' });
62 # If using grouping_column:
63 my $item = My::Item->create({ name=>'Matt S. Trout', group_id=>1 });
64
65 my $rs = $item->siblings();
66 my @siblings = $item->siblings();
67
68 my $sibling;
69 $sibling = $item->first_sibling();
70 $sibling = $item->last_sibling();
71 $sibling = $item->previous_sibling();
72 $sibling = $item->next_sibling();
73
74 $item->move_previous();
75 $item->move_next();
76 $item->move_first();
77 $item->move_last();
78 $item->move_to( $position );
79 $item->move_to_group( 'groupname' );
80 $item->move_to_group( 'groupname', $position );
81 $item->move_to_group( {group_id=>'groupname', 'other_group_id=>'othergroupname'} );
82 $item->move_to_group( {group_id=>'groupname', 'other_group_id=>'othergroupname'}, $position );
83
85 This module provides a simple interface for modifying the ordered
86 position of DBIx::Class objects.
87
89 All of the move_* methods automatically update the rows involved in the
90 query. This is not configurable and is due to the fact that if you
91 move a record it always causes other records in the list to be updated.
92
94 position_column
95 __PACKAGE__->position_column('position');
96
97 Sets and retrieves the name of the column that stores the positional
98 value of each record. Defaults to "position".
99
100 grouping_column
101 __PACKAGE__->grouping_column('group_id');
102
103 This method specifies a column to limit all queries in this module by.
104 This effectively allows you to have multiple ordered lists within the
105 same table.
106
107 null_position_value
108 __PACKAGE__->null_position_value(undef);
109
110 This method specifies a value of "position_column" which would never be
111 assigned to a row during normal operation. When a row is moved, its
112 position is set to this value temporarily, so that any unique
113 constraints can not be violated. This value defaults to 0, which should
114 work for all cases except when your positions do indeed start from 0.
115
116 siblings
117 my $rs = $item->siblings();
118 my @siblings = $item->siblings();
119
120 Returns an ordered resultset of all other objects in the same group
121 excluding the one you called it on.
122
123 The ordering is a backwards-compatibility artifact - if you need a
124 resultset with no ordering applied use "_siblings"
125
126 previous_siblings
127 my $prev_rs = $item->previous_siblings();
128 my @prev_siblings = $item->previous_siblings();
129
130 Returns a resultset of all objects in the same group positioned before
131 the object on which this method was called.
132
133 next_siblings
134 my $next_rs = $item->next_siblings();
135 my @next_siblings = $item->next_siblings();
136
137 Returns a resultset of all objects in the same group positioned after
138 the object on which this method was called.
139
140 previous_sibling
141 my $sibling = $item->previous_sibling();
142
143 Returns the sibling that resides one position back. Returns 0 if the
144 current object is the first one.
145
146 first_sibling
147 my $sibling = $item->first_sibling();
148
149 Returns the first sibling object, or 0 if the first sibling is this
150 sibling.
151
152 next_sibling
153 my $sibling = $item->next_sibling();
154
155 Returns the sibling that resides one position forward. Returns 0 if the
156 current object is the last one.
157
158 last_sibling
159 my $sibling = $item->last_sibling();
160
161 Returns the last sibling, or 0 if the last sibling is this sibling.
162
163 move_previous
164 $item->move_previous();
165
166 Swaps position with the sibling in the position previous in the list.
167 Returns 1 on success, and 0 if the object is already the first one.
168
169 move_next
170 $item->move_next();
171
172 Swaps position with the sibling in the next position in the list.
173 Returns 1 on success, and 0 if the object is already the last in the
174 list.
175
176 move_first
177 $item->move_first();
178
179 Moves the object to the first position in the list. Returns 1 on
180 success, and 0 if the object is already the first.
181
182 move_last
183 $item->move_last();
184
185 Moves the object to the last position in the list. Returns 1 on
186 success, and 0 if the object is already the last one.
187
188 move_to
189 $item->move_to( $position );
190
191 Moves the object to the specified position. Returns 1 on success, and
192 0 if the object is already at the specified position.
193
194 move_to_group
195 $item->move_to_group( $group, $position );
196
197 Moves the object to the specified position of the specified group, or
198 to the end of the group if $position is undef. 1 is returned on
199 success, and 0 is returned if the object is already at the specified
200 position of the specified group.
201
202 $group may be specified as a single scalar if only one grouping column
203 is in use, or as a hashref of column => value pairs if multiple
204 grouping columns are in use.
205
206 insert
207 Overrides the DBIC insert() method by providing a default position
208 number. The default will be the number of rows in the table +1, thus
209 positioning the new record at the last position.
210
211 update
212 Overrides the DBIC update() method by checking for a change to the
213 position and/or group columns. Movement within a group or to another
214 group is handled by repositioning the appropriate siblings. Position
215 defaults to the end of a new group if it has been changed to undef.
216
217 delete
218 Overrides the DBIC delete() method by first moving the object to the
219 last position, then deleting it, thus ensuring the integrity of the
220 positions.
221
223 You would want to override the methods below if you use sparse (non-
224 linear) or non-numeric position values. This can be useful if you are
225 working with preexisting non-normalised position data, or if you need
226 to work with materialized path columns.
227
228 _position_from_value
229 my $num_pos = $item->_position_from_value ( $pos_value )
230
231 Returns the absolute numeric position of an object with a position
232 value set to $pos_value. By default simply returns $pos_value.
233
234 _position_value
235 my $pos_value = $item->_position_value ( $pos )
236
237 Returns the value of "position_column" of the object at numeric
238 position $pos. By default simply returns $pos.
239
240 _initial_position_value
241 __PACKAGE__->_initial_position_value(0);
242
243 This method specifies a value of "position_column" which is assigned to
244 the first inserted element of a group, if no value was supplied at
245 insertion time. All subsequent values are derived from this one by
246 "_next_position_value" below. Defaults to 1.
247
248 _next_position_value
249 my $new_value = $item->_next_position_value ( $position_value )
250
251 Returns a position value that would be considered "next" with regards
252 to $position_value. Can be pretty much anything, given that
253 "$position_value < $new_value" where "<" is the SQL comparison operator
254 (usually works fine on strings). The default method expects
255 $position_value to be numeric, and returns "$position_value + 1"
256
257 _shift_siblings
258 $item->_shift_siblings ($direction, @between)
259
260 Shifts all siblings with positions values in the range @between
261 (inclusive) by one position as specified by $direction (left if < 0,
262 right if > 0). By default simply increments/decrements each
263 position_column value by 1, doing so in a way as to not violate any
264 existing constraints.
265
266 Note that if you override this method and have unique constraints
267 including the position_column the shift is not a trivial task. Refer
268 to the implementation source of the default method for more
269 information.
270
272 These methods are used internally. You should never have the need to
273 use them.
274
275 _group_rs
276 This method returns a resultset containing all members of the row group
277 (including the row itself).
278
279 _siblings
280 Returns an unordered resultset of all objects in the same group
281 excluding the object you called this method on.
282
283 _position
284 my $num_pos = $item->_position;
285
286 Returns the absolute numeric position of the current object, with the
287 first object being at position 1, its sibling at position 2 and so on.
288
289 _grouping_clause
290 This method returns one or more name=>value pairs for limiting a search
291 by the grouping column(s). If the grouping column is not defined then
292 this will return an empty list.
293
294 _get_grouping_columns
295 Returns a list of the column names used for grouping, regardless of
296 whether they were specified as an arrayref or a single string, and
297 returns () if there is no grouping.
298
299 _is_in_group
300 $item->_is_in_group( {user => 'fred', list => 'work'} )
301
302 Returns true if the object is in the group represented by hashref
303 $other
304
305 _ordered_internal_update
306 This is a short-circuited method, that is used internally by this
307 module to update positioning values in isolation (i.e. without
308 triggering any of the positioning integrity code).
309
310 Some day you might get confronted by datasets that have ambiguous
311 positioning data (e.g. duplicate position values within the same group,
312 in a table without unique constraints). When manually fixing such data
313 keep in mind that you can not invoke "update" in DBIx::Class::Row like
314 you normally would, as it will get confused by the wrong data before
315 having a chance to update the ill-defined row. If you really know what
316 you are doing use this method which bypasses any hooks introduced by
317 this module.
318
320 Race Condition on Insert
321 If a position is not specified for an insert than a position will be
322 chosen based either on "_initial_position_value" or
323 "_next_position_value", depending if there are already some items in
324 the current group. The space of time between the necessary selects and
325 insert introduces a race condition. Having unique constraints on your
326 position/group columns, and using transactions (see "txn_do" in
327 DBIx::Class::Storage) will prevent such race conditions going
328 undetected.
329
330 Multiple Moves
331 Be careful when issuing move_* methods to multiple objects. If you've
332 pre-loaded the objects then when you move one of the objects the
333 position of the other object will not reflect their new value until you
334 reload them from the database - see "discard_changes" in
335 DBIx::Class::Row.
336
337 There are times when you will want to move objects as groups, such as
338 changing the parent of several objects at once - this directly
339 conflicts with this problem. One solution is for us to write a
340 ResultSet class that supports a parent() method, for example. Another
341 solution is to somehow automagically modify the objects that exist in
342 the current object's result set to have the new position value.
343
344 Default Values
345 Using a database defined default_value on one of your group columns
346 could result in the position not being assigned correctly.
347
349 Original code framework
350 Aran Deltac <bluefeet@cpan.org>
351
352 Constraints support and code generalisation
353 Peter Rabbitson <ribasushi@cpan.org>
354
356 You may distribute this code under the same terms as Perl itself.
357
358
359
360perl v5.12.0 2010-05-12 DBIx::Class::Ordered(3)