DBIx-Class

 view release on metacpan or  search on metacpan

lib/DBIx/Class/Ordered.pm  view on Meta::CPAN

=cut

__PACKAGE__->mk_classdata( '_initial_position_value' => 1 );

=head2 _next_position_value

  my $new_value = $item->_next_position_value ( $position_value )

Returns a position B<value> that would be considered C<next> with
regards to C<$position_value>. Can be pretty much anything, given
that C<< $position_value < $new_value >> where C<< < >> is the
SQL comparison operator (usually works fine on strings). The
default method expects C<$position_value> to be numeric, and
returns C<$position_value + 1>

=cut
sub _next_position_value {
    return $_[1] + 1;
}

=head2 _shift_siblings

  $item->_shift_siblings ($direction, @between)

Shifts all siblings with B<positions values> in the range @between
(inclusive) by one position as specified by $direction (left if < 0,
 right if > 0). By default simply increments/decrements each
L</position_column> value by 1, doing so in a way as to not violate
any existing constraints.

Note that if you override this method and have unique constraints
including the L</position_column> the shift is not a trivial task.
Refer to the implementation source of the default method for more
information.

=cut
sub _shift_siblings {
    my ($self, $direction, @between) = @_;
    return 0 unless $direction;

    my $position_column = $self->position_column;

    my ($op, $ord);
    if ($direction < 0) {
        $op = '-';
        $ord = 'asc';
    }
    else {
        $op = '+';
        $ord = 'desc';
    }

    my $shift_rs = $self->_group_rs-> search ({ $position_column => { -between => \@between } });

    # some databases (sqlite, pg, perhaps others) are dumb and can not do a
    # blanket increment/decrement without violating a unique constraint.
    # 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;

    # set in case there are more cascades combined with $rs->update => $rs_update_all overrides
    local $rsrc->schema->{_ORDERED_INTERNAL_UPDATE} = 1;
    my @pcols = $rsrc->primary_columns;
    if (
      grep { $_ eq $position_column } ( map { @$_ } (values %{{ $rsrc->unique_constraints }} ) )
    ) {
        my $clean_rs = $rsrc->resultset;

        for ( $shift_rs->search (
          {}, { order_by => { "-$ord", $position_column }, select => [$position_column, @pcols] }
        )->cursor->all ) {
          my $pos = shift @$_;
          $clean_rs->find(@$_)->update ({ $position_column => $pos + ( ($op eq '+') ? 1 : -1 ) });
        }
    }
    else {
        $shift_rs->update ({ $position_column => \ "$position_column $op 1" } );
    }
}


# This method returns a resultset containing all members of the row
# group (including the row itself).
sub _group_rs {
    my $self = shift;
    return $self->result_source->resultset->search({$self->_grouping_clause()});
}

# Returns an unordered resultset of all objects in the same group
# excluding the object you called this method on.
sub _siblings {
    my $self = shift;
    my $position_column = $self->position_column;
    my $pos;
    return defined ($pos = $self->get_column($position_column))
        ? $self->_group_rs->search(
            { $position_column => { '!=' => $pos } },
          )
        : $self->_group_rs
    ;
}

# Returns the B<absolute numeric position> of the current object, with the
# first object being at position 1, its sibling at position 2 and so on.
sub _position {
    my $self = shift;
    return $self->_position_from_value ($self->get_column ($self->position_column) );
}

# 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
# this will return an empty list.
sub _grouping_clause {
    my( $self ) = @_;
    return map {  $_ => $self->get_column($_)  } $self->_grouping_columns();
}

# Returns a list of the column names used for grouping, regardless of whether
# they were specified as an arrayref or a single string, and returns ()
# if there is no grouping.
sub _grouping_columns {



( run in 1.208 second using v1.01-cache-2.11-cpan-d8267643d1d )