From: Brian Kirkbride Date: Tue, 4 Jul 2006 04:38:57 +0000 (+0000) Subject: local copy of DBIC ordered_handle_updates branch X-Git-Tag: v0.08010~150^2~110^2~4 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=dbsrgits%2FDBIx-Class.git;a=commitdiff_plain;h=79dc353af7198da731d16fec64970bc5c31e8a27 local copy of DBIC ordered_handle_updates branch r2107@home: bkirkbri | 2006-07-03 23:25:35 -0500 Added a new method, move_to_group r2108@home: bkirkbri | 2006-07-03 23:27:13 -0500 Overloaded update() to handle changes to position_column or group_column correctly r2109@home: bkirkbri | 2006-07-03 23:30:35 -0500 Added tests for new move_to_group method and overloaded update() --- diff --git a/lib/DBIx/Class/Ordered.pm b/lib/DBIx/Class/Ordered.pm index 8e2c74d..b77cc35 100644 --- a/lib/DBIx/Class/Ordered.pm +++ b/lib/DBIx/Class/Ordered.pm @@ -290,10 +290,55 @@ sub move_to { }); my $op = ($from_position>$to_position) ? '+' : '-'; $rs->update({ $position_column => \"$position_column $op 1" }); + $self->{_ORDERED_INTERNAL_UPDATE} = 1; $self->update({ $position_column => $to_position }); return 1; } +=head2 move_to_group + + $item->move_to_group( $group, $position ); + +Moves the object to the specified position of the specified +group, or to the end of the group if $position is undef. +1 is returned on success, and 0 is returned if the object is +already at the specified position of the specified group. + +=cut + +sub move_to_group { + my( $self, $to_group, $to_position ) = @_; + my $position_column = $self->position_column; + my $grouping_column = $self->grouping_column; + + return 0 if ( ! defined($to_group) ); + return 0 if ( defined($to_position) and $to_position < 1 ); + return 0 if ( $self->$grouping_column==$to_group and defined($to_position) and $self->$position_column==$to_position ); + + # Move to end of current group and adjust siblings + $self->move_last; + + $self->$grouping_column($to_group); + my $new_group_count = $self->result_source->resultset->search({$self->_grouping_clause()})->count(); + if (!defined($to_position) or $to_position > $new_group_count) { + $self->{_ORDERED_INTERNAL_UPDATE} = 1; + $self->update({ $position_column => $new_group_count + 1 }); + } + else { + my @between = ($to_position, $new_group_count); + + my $rs = $self->result_source->resultset->search({ + $position_column => { -between => [ @between ] }, + $self->_grouping_clause(), + }); + $rs->update({ $position_column => \"$position_column + 1" }); + $self->{_ORDERED_INTERNAL_UPDATE} = 1; + $self->update({ $position_column => $to_position }); + } + + return 1; +} + =head2 insert Overrides the DBIC insert() method by providing a default @@ -310,6 +355,42 @@ sub insert { return $self->next::method( @_ ); } +=head2 update + +Overrides the DBIC update() method by checking for a change +to the position and/or group columns. Movement within a +group or to another group is handled by repositioning +the appropriate siblings. Position defaults to the end +of a new group if it has been changed to undef. + +=cut + +sub update { + my $self = shift; + + if ($self->{_ORDERED_INTERNAL_UPDATE}) { + delete $self->{_ORDERED_INTERNAL_UPDATE}; + return $self->next::method( @_ ); + } + + $self->set_columns($_[0]) if @_ > 0; + my %changes = $self->get_dirty_columns; + $self->discard_changes; + + my $pos_col = $self->position_column; + my $grp_col = $self->grouping_column; + if (defined($grp_col) and exists $changes{$grp_col}) { + $self->move_to_group( + delete($changes{$grp_col}), + exists($changes{$pos_col}) ? delete($changes{$pos_col}) : $self->$pos_col + ); + } + elsif (exists $changes{$pos_col}) { + $self->move_to(delete $changes{$pos_col}); + } + return $self->next::method( \%changes ); +} + =head2 delete Overrides the DBIC delete() method by first moving the object diff --git a/t/87ordered.t b/t/87ordered.t index b1d484c..7843eee 100644 --- a/t/87ordered.t +++ b/t/87ordered.t @@ -8,7 +8,7 @@ use DBICTest; my $schema = DBICTest->init_schema(); -plan tests => 321; +plan tests => 417; my $employees = $schema->resultset('Employee'); $employees->delete(); @@ -23,20 +23,77 @@ hammer_rs( $employees ); DBICTest::Employee->grouping_column('group_id'); $employees->delete(); -foreach my $group_id (1..3) { +foreach my $group_id (1..4) { foreach (1..6) { $employees->create({ name=>'temp', group_id=>$group_id }); } } $employees = $employees->search(undef,{order_by=>'group_id,position'}); -foreach my $group_id (1..3) { +foreach my $group_id (1..4) { my $group_employees = $employees->search({group_id=>$group_id}); $group_employees->all(); ok( check_rs($group_employees), "group intial positions" ); hammer_rs( $group_employees ); } +my $group_3 = $employees->search({group_id=>3}); +my $to_group = 1; +my $to_pos = undef; +while (my $employee = $group_3->next) { + $employee->move_to_group($to_group, $to_pos); + $to_pos++; + $to_group = $to_group==1 ? 2 : 1; +} +foreach my $group_id (1..4) { + my $group_employees = $employees->search({group_id=>$group_id}); + $group_employees->all(); + ok( check_rs($group_employees), "group positions after move_to_group" ); +} + +my $employee = $employees->search({group_id=>4})->first; +$employee->position(2); +$employee->update; +ok( check_rs($employees->search_rs({group_id=>4})), "overloaded update 1" ); +$employee = $employees->search({group_id=>4})->first; +$employee->update({position=>3}); +ok( check_rs($employees->search_rs({group_id=>4})), "overloaded update 2" ); +$employee = $employees->search({group_id=>4})->first; +$employee->group_id(1); +$employee->update; +ok( + check_rs($employees->search_rs({group_id=>1})) && check_rs($employees->search_rs({group_id=>4})), + "overloaded update 3" +); +$employee = $employees->search({group_id=>4})->first; +$employee->update({group_id=>2}); +ok( + check_rs($employees->search_rs({group_id=>2})) && check_rs($employees->search_rs({group_id=>4})), + "overloaded update 4" +); +$employee = $employees->search({group_id=>4})->first; +$employee->group_id(1); +$employee->position(3); +$employee->update; +ok( + check_rs($employees->search_rs({group_id=>1})) && check_rs($employees->search_rs({group_id=>4})), + "overloaded update 5" +); +$employee = $employees->search({group_id=>4})->first; +$employee->group_id(2); +$employee->position(undef); +$employee->update; +ok( + check_rs($employees->search_rs({group_id=>2})) && check_rs($employees->search_rs({group_id=>4})), + "overloaded update 6" +); +$employee = $employees->search({group_id=>4})->first; +$employee->update({group_id=>1,position=>undef}); +ok( + check_rs($employees->search_rs({group_id=>1})) && check_rs($employees->search_rs({group_id=>4})), + "overloaded update 7" +); + sub hammer_rs { my $rs = shift; my $employee;