position INTEGER NOT NULL
);
-Optionally, add one or more columns to specify groupings, allowing you
+Optionally, add one or more columns to specify groupings, allowing you
to maintain independent ordered lists within one table:
CREATE TABLE items (
other_group_id INTEGER NOT NULL
);
-In your Schema or DB class add "Ordered" to the top
+In your Schema or DB class add "Ordered" to the top
of the component list.
__PACKAGE__->load_components(qw( Ordered ... ));
-Specify the column that stores the position number for
+Specify the column that stores the position number for
each row.
package My::Item;
=head1 DESCRIPTION
-This module provides a simple interface for modifying the ordered
+This module provides a simple interface for modifying the ordered
position of DBIx::Class objects.
=head1 AUTO UPDATE
-All of the move_* methods automatically update the rows involved in
-the query. This is not configurable and is due to the fact that if you
+All of the move_* methods automatically update the rows involved in
+the query. This is not configurable and is due to the fact that if you
move a record it always causes other records in the list to be updated.
=head1 METHODS
__PACKAGE__->position_column('position');
-Sets and retrieves the name of the column that stores the
+Sets and retrieves the name of the column that stores the
positional value of each record. Defaults to "position".
=cut
__PACKAGE__->grouping_column('group_id');
-This method specifies a column to limit all queries in
-this module by. This effectively allows you to have multiple
+This method specifies a column to limit all queries in
+this module by. This effectively allows you to have multiple
ordered lists within the same table.
=cut
my $sibling = $item->first_sibling();
-Returns the first sibling object, or 0 if the first sibling
+Returns the first sibling object, or 0 if the first sibling
is this sibling.
=cut
my $sibling = $item->last_sibling();
-Returns the last sibling, or 0 if the last sibling is this
+Returns the last sibling, or 0 if the last sibling is this
sibling.
=cut
1 is returned on success, and 0 is returned if the object is
already at the specified position of the specified group.
-$group may be specified as a single scalar if only one
+$group may be specified as a single scalar if only one
grouping column is in use, or as a hashref of column => value pairs
if multiple grouping columns are in use.
=head2 insert
-Overrides the DBIC insert() method by providing a default
-position number. The default will be the number of rows in
+Overrides the DBIC insert() method by providing a default
+position number. The default will be the number of rows in
the table +1, thus positioning the new record at the last position.
=cut
my $self = shift;
# this is set by _ordered_internal_update()
- return $self->next::method(@_) if $self->{_ORDERED_INTERNAL_UPDATE};
+ return $self->next::method(@_) if $self->result_source->schema->{_ORDERED_INTERNAL_UPDATE};
my $upd = shift;
$self->set_inflated_columns($upd) if $upd;
$ord = 'desc';
}
- my $shift_rs = $self->_group_rs-> search ({ $position_column => { -between => \@between } });
-
- # some databases (sqlite) are dumb and can not do a blanket
- # increment/decrement. So what we do here is check if the
- # position column is part of a unique constraint, and do a
- # one-by-one update if this is the case
-
- my $rsrc = $self->result_source;
-
- if (grep { $_ eq $position_column } ( map { @$_ } (values %{{ $rsrc->unique_constraints }} ) ) ) {
-
- my @pcols = $rsrc->_pri_cols;
- my $cursor = $shift_rs->search ({}, { order_by => { "-$ord", $position_column }, columns => \@pcols } )->cursor;
- my $rs = $self->result_source->resultset;
-
- my @all_pks = $cursor->all;
- while (my $pks = shift @all_pks) {
- my $cond;
- for my $i (0.. $#pcols) {
- $cond->{$pcols[$i]} = $pks->[$i];
- }
-
- $rs->search($cond)->update ({ $position_column => \ "$position_column $op 1" } );
- }
- }
- else {
- $shift_rs->update ({ $position_column => \ "$position_column $op 1" } );
- }
+ $self->_group_rs
+ ->search ({ $position_column => { -between => \@between } })
+ ->update ({ $position_column => \ "$position_column $op 1" } );
}
=head1 PRIVATE METHODS
-These methods are used internally. You should never have the
+These methods are used internally. You should never have the
need to use them.
=head2 _group_rs
=head2 _grouping_clause
This method returns one or more name=>value pairs for limiting a search
-by the grouping column(s). If the grouping column is not defined then
+by the grouping column(s). If the grouping column is not defined then
this will return an empty list.
=cut
sub _ordered_internal_update {
my $self = shift;
- local $self->{_ORDERED_INTERNAL_UPDATE} = 1;
+ local $self->result_source->schema->{_ORDERED_INTERNAL_UPDATE} = 1;
return $self->update (@_);
}
=head2 Multiple Moves
-Be careful when issuing move_* methods to multiple objects. If
-you've pre-loaded the objects then when you move one of the objects
-the position of the other object will not reflect their new value
+Be careful when issuing move_* methods to multiple objects. If
+you've pre-loaded the objects then when you move one of the objects
+the position of the other object will not reflect their new value
until you reload them from the database - see
L<DBIx::Class::Row/discard_changes>.
-There are times when you will want to move objects as groups, such
-as changing the parent of several objects at once - this directly
-conflicts with this problem. One solution is for us to write a
-ResultSet class that supports a parent() method, for example. Another
-solution is to somehow automagically modify the objects that exist
+There are times when you will want to move objects as groups, such
+as changing the parent of several objects at once - this directly
+conflicts with this problem. One solution is for us to write a
+ResultSet class that supports a parent() method, for example. Another
+solution is to somehow automagically modify the objects that exist
in the current object's result set to have the new position value.
=head2 Default Values