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 get_full_list);
use Carp;
croak "Invalid parameter 'position'" unless ($params{position} || '') =~ m/^ (?: before | after | first | last ) $/x;
+ my $column = column_name($self);
+
+ $self->remove_from_list if ($self->$column // -1) != -1;
+
if ($params{position} eq 'last') {
set_position($self);
$self->save;
my $table = $self->meta->table;
my $primary_key_col = ($self->meta->primary_key)[0];
- my $column = column_name($self);
my ($group_by, @values) = get_group_by_where($self);
$group_by = " AND ${group_by}" if $group_by;
my $new_position;
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 get_full_list {
+ my ($self) = @_;
+
+ my $group_by = get_spec(ref $self, 'group_by') || [];
+ $group_by = [ $group_by ] if $group_by && !ref $group_by;
+ my @where = map { ($_ => $self->$_) } @{ $group_by };
+
+ return $self->_get_manager_class->get_all(where => \@where, sort_by => column_name($self) . ' ASC');
+}
+
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');
referenced item by shifting all the appropriate item positions up by
one.
+If C<$self>'s positional column is already set when this function is
+called then L</remove_from_list> will be called first before anything
+else is done.
+
After this function C<$self>'s positional column has been set and
saved to the database.
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<get_full_list>
+
+Fetches all items in the same list as C<$self> and returns them as an
+array reference.
+
=item C<reorder_list @ids>
Re-orders the objects given in C<@ids> by their position in C<@ids> by