package GitLab::API::v3::Paginator; $GitLab::API::v3::Paginator::VERSION = '1.00'; =head1 NAME GitLab::API::v3::Paginator - Iterate through paginated GitLab v3 API records. =head1 DESCRIPTION There should be no need to create objects of this type directly, instead use L<GitLab::API::v3/paginator> which simplifies things a bit. =cut use Types::Standard -types; use Types::Common::String -types; use Carp qw( croak ); use Moo; use strictures 1; use namespace::clean; =head1 REQUIRED ARGUMENTS =head2 method The name of the method subroutine to call on the L</api> object to get records from. This method must accept a hash ref of parameters as the last argument, adhere to the C<page> and C<per_page> parameters, and return an array ref. =cut has method => ( is => 'ro', isa => NonEmptySimpleStr, required => 1, ); =head2 api The L<GitLab::API::v3> object. =cut has api => ( is => 'ro', isa => InstanceOf[ 'GitLab::API::v3' ], required => 1, ); =head1 OPTIONAL ARGUMENTS =head2 args The arguments to use when calling the L</method>, the same arguments you would use when you call the method yourself on the L</api> object, minus the C<\%params> hash ref. =cut has args => ( is => 'ro', isa => ArrayRef, default => sub{ [] }, ); =head2 params The C<\%params> hash ref argument. =cut has params => ( is => 'ro', isa => HashRef, default => sub{ {} }, ); =head1 METHODS =cut has _records => ( is => 'rw', init_arg => undef, default => sub{ [] }, ); has _page => ( is => 'rw', init_arg => undef, default => 0, ); has _last_page => ( is => 'rw', init_arg => undef, default => 0, ); =head2 next_page while (my $records = $paginator->next_page()) { ... } Returns an array ref of records for the next page. =cut sub next_page { my ($self) = @_; return if $self->_last_page(); my $page = $self->_page() + 1; my $params = $self->params(); my $per_page = $params->{per_page} || 20; $params = { %$params, page => $page, per_page => $per_page, }; my $method = $self->method(); my $records = $self->api->$method( @{ $self->args() }, $params, ); croak("The $method method returned a non array ref value") if ref($records) ne 'ARRAY'; $self->_page( $page ); $self->_last_page( 1 ) if @$records < $per_page; $self->_records( [ @$records ] ); return if !@$records; return $records; } =head2 next while (my $record = $paginator->next()) { ... } Returns the next record in the current page. If all records have been exhausted then L</next_page> will automatically be called. This way if you want to ignore pagination you can just call C<next> over and over again to walk through all the records. =cut sub next { my ($self) = @_; my $records = $self->_records(); return shift(@$records) if @$records; return if $self->_last_page(); $self->next_page(); $records = $self->_records(); return shift(@$records) if @$records; return; } =head2 all my $records = $paginator->all(); This is just an alias for calling L</next_page> over and over again to build an array ref of all records. =cut sub all { my ($self) = @_; $self->reset(); my @records; while (my $page = $self->next_page()) { push @records, @$page; } return \@records; } =head2 reset $paginator->reset(); Reset the paginator back to its original state on the first page with no records retrieved yet. =cut sub reset { my ($self) = @_; $self->_records( [] ); $self->_page( 0 ); $self->_last_page( 0 ); return; } 1; __END__ =head1 AUTHOR Aran Clary Deltac <bluefeetE<64>gmail.com> =head1 LICENSE This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.