| 515 | | local @$args{qw( sort direction range_incl )} |
| 516 | | = ($by_field, $next ? 'ascend' : 'descend', { $by_field => 1 }); |
| 517 | | my $iter = $class->load_iter({ |
| | 515 | local @$args{qw( sort range_incl )} |
| | 516 | = ( [ { column => $by_field, desc => $next ? 'ASC' : 'DESC' }, |
| | 517 | { column => 'id', desc => $next ? 'ASC' : 'DESC' } ], |
| | 518 | { $by_field => 1 }); |
| | 519 | |
| | 520 | my $obj = $class->load({ |
| 520 | | }, $args); |
| 521 | | |
| 522 | | # This selection should always succeed, but handle situation if |
| 523 | | # it fails by returning undef. |
| 524 | | return unless $iter; |
| 525 | | |
| 526 | | # The 'same' array will hold any entries that have matching |
| 527 | | # timestamps; we will then sort those by id to find the correct |
| 528 | | # adjacent object. |
| 529 | | my @same; |
| 530 | | while (my $e = $iter->()) { |
| 531 | | # Don't consider the object that is 'current' |
| 532 | | next if $e->id == $id; |
| 533 | | my $e_ts = $e->$by_field(); |
| 534 | | if ($e_ts eq $ts) { |
| 535 | | # An object with the same timestamp should only be |
| 536 | | # considered if the id is in the scope we're looking for |
| 537 | | # (greater than for the 'next' object; less than for |
| 538 | | # the 'previous' object). |
| 539 | | push @same, $e |
| 540 | | if $next && $e->id > $id or !$next && $e->id < $id; |
| 541 | | } else { |
| 542 | | # We found an object with a timestamp different than |
| 543 | | # the 'current' object. |
| 544 | | if (!@same) { |
| 545 | | push @same, $e; |
| 546 | | # We should check to see if this new timestamped object also |
| 547 | | # has entries adjacent to _it_ that have the same timestamp. |
| 548 | | while (my $e = $iter->()) { |
| 549 | | push(@same, $e), next if $e->$by_field() eq $e_ts; |
| 550 | | $iter->('finish'), last; |
| 551 | | } |
| 552 | | } else { |
| 553 | | $iter->('finish'); |
| 554 | | } |
| 555 | | return $e unless @same; |
| 556 | | last; |
| 557 | | } |
| 558 | | } |
| 559 | | if (@same) { |
| 560 | | # If we only have 1 element in @same, return that. |
| 561 | | return $same[0] if @same == 1; |
| 562 | | # Sort remaining elements in @same by id. |
| 563 | | @same = sort { $a->id <=> $b->id } @same; |
| 564 | | # Return front of list (smallest id) if selecting 'next' |
| 565 | | # object. Return tail of list (largest id) if selection 'previous'. |
| 566 | | return $same[$next ? 0 : $#same]; |
| 567 | | } |
| 568 | | return; |
| | 524 | }, { not => { 'id' => 1 }, limit => 1, %$args }); |
| | 525 | |
| | 526 | return $obj; |