use strict;
use parent qw(Exporter);
-our @EXPORT = qw(move_position_up move_position_down add_to_list remove_from_list reorder_list configure_acts_as_list);
+our @EXPORT = qw(move_position_up move_position_down add_to_list remove_from_list reorder_list configure_acts_as_list
+ get_previous_in_list get_next_in_list);
use Carp;
return $self->db->in_transaction ? $worker->() : $self->db->do_transaction($worker);
}
+sub get_next_in_list {
+ my ($self) = @_;
+ return get_previous_or_next($self, 'next');
+}
+
+sub get_previous_in_list {
+ my ($self) = @_;
+ return get_previous_or_next($self, 'previous');
+}
+
sub reorder_list {
my ($class_or_self, @ids) = @_;
$self->update_attributes($column => $new_position);
}
+sub get_previous_or_next {
+ my ($self, $direction) = @_;
+
+ my $asc_desc = $direction eq 'next' ? 'ASC' : 'DESC';
+ my $comparator = $direction eq 'next' ? '>' : '<';
+ my $table = $self->meta->table;
+ my $column = column_name($self);
+ my $primary_key_col = ($self->meta->primary_key)[0];
+ my ($group_by, @values) = get_group_by_where($self);
+ $group_by = " AND ${group_by}" if $group_by;
+ my $sql = <<SQL;
+ SELECT ${primary_key_col}
+ FROM ${table}
+ WHERE (${column} ${comparator} ?)
+ ${group_by}
+ ORDER BY ${column} ${asc_desc}
+ LIMIT 1
+SQL
+
+ my $id = ($self->db->dbh->selectrow_arrayref($sql, undef, $self->$column, @values) || [])->[0];
+
+ return $id ? $self->_get_manager_class->find_by(id => $id) : undef;
+}
+
sub column_name {
my ($self) = @_;
my $column = get_spec(ref $self, 'column_name');
Sets this items positional column to C<-1>, saves it and moves all
following items up by 1.
+=item C<get_previous_in_list>
+
+Fetches the previous item in the list. Returns C<undef> if C<$self> is
+already the first one.
+
+=item C<get_next_in_list>
+
+Fetches the next item in the list. Returns C<undef> if C<$self> is
+already the last one.
+
=item C<reorder_list @ids>
Re-orders the objects given in C<@ids> by their position in C<@ids> by
-use Test::More tests => 44;
+use Test::More tests => 50;
use Test::Exception;
use strict;
$item = get_item(8); $item->remove_from_list; $item->parent_id(3); $item->add_to_list(position => 'first');
test_positions "add_to_list position 'first' in empty", [ 1, undef, 1 ], [ 2, undef, 2 ], [ 3, 1, 1 ], [ 4, 1, 2 ], [ 5, 1, 3 ], [ 6, 4, 1 ], [ 7, 4, 2 ], [ 8, 3, 1 ];
-
+reset_state();
+$item = get_item(4);
+is($item->get_next_in_list->id, 5, 'Next of 4 is 5');
+is($item->get_previous_in_list->id, 3, 'Previous of 4 is 5');
+is($item->get_next_in_list->get_previous_in_list->id, 4, 'Previous of Next of 4 is 4');
+is($item->get_previous_in_list->get_next_in_list->id, 4, 'Next of Previous of 4 is 4');
+is($item->get_next_in_list->get_next_in_list, undef, 'Next of Next of 4 is undef');
+is($item->get_previous_in_list->get_previous_in_list, undef, 'Previous of Previous of 4 is undef');
# Parametervalidierung
throws_ok { new_item()->move_position_up } qr/not.*been.*saved/i, 'move up not saved yet';