File Coverage

blib/lib/GitLab/API/v3/Paginator.pm
Criterion Covered Total %
statement 18 52 34.6
branch 0 14 0.0
condition 0 2 0.0
subroutine 6 10 60.0
pod 4 4 100.0
total 28 82 34.1


line stmt bran cond sub pod time code
1             package GitLab::API::v3::Paginator;
2              
3             =head1 NAME
4              
5             GitLab::API::v3::Paginator - Iterate through paginated GitLab v3 API records.
6              
7             =head1 DESCRIPTION
8              
9             There should be no need to create objects of this type
10             directly, instead use L<GitLab::API::v3/paginator> which
11             simplifies things a bit.
12              
13             =cut
14              
15 1     1   9 use Types::Standard -types;
  1         3  
  1         13  
16 1     1   5525 use Types::Common::String -types;
  1         47675  
  1         18  
17 1     1   1767 use Carp qw( croak );
  1         2  
  1         72  
18              
19 1     1   6 use Moo;
  1         2  
  1         11  
20 1     1   512 use strictures 1;
  1         11  
  1         69  
21 1     1   116 use namespace::clean;
  1         3  
  1         10  
22              
23             =head1 REQUIRED ARGUMENTS
24              
25             =head2 method
26              
27             The name of the method subroutine to call on the L</api> object
28             to get records from.
29              
30             This method must accept a hash ref of parameters as the last
31             argument, adhere to the C<page> and C<per_page> parameters, and
32             return an array ref.
33              
34             =cut
35              
36             has method => (
37             is => 'ro',
38             isa => NonEmptySimpleStr,
39             required => 1,
40             );
41              
42             =head2 api
43              
44             The L<GitLab::API::v3> object.
45              
46             =cut
47              
48             has api => (
49             is => 'ro',
50             isa => InstanceOf[ 'GitLab::API::v3' ],
51             required => 1,
52             );
53              
54             =head1 OPTIONAL ARGUMENTS
55              
56             =head2 args
57              
58             The arguments to use when calling the L</method>, the same arguments
59             you would use when you call the method yourself on the L</api>
60             object, minus the C<\%params> hash ref.
61              
62             =cut
63              
64             has args => (
65             is => 'ro',
66             isa => ArrayRef,
67             default => sub{ [] },
68             );
69              
70             =head2 params
71              
72             The C<\%params> hash ref argument.
73              
74             =cut
75              
76             has params => (
77             is => 'ro',
78             isa => HashRef,
79             default => sub{ {} },
80             );
81              
82             =head1 METHODS
83              
84             =cut
85              
86             has _records => (
87             is => 'rw',
88             init_arg => undef,
89             default => sub{ [] },
90             );
91              
92             has _page => (
93             is => 'rw',
94             init_arg => undef,
95             default => 0,
96             );
97              
98             has _last_page => (
99             is => 'rw',
100             init_arg => undef,
101             default => 0,
102             );
103              
104             =head2 next_page
105              
106             while (my $records = $paginator->next_page()) { ... }
107              
108             Returns an array ref of records for the next page.
109              
110             =cut
111              
112             sub next_page {
113 0     0 1   my ($self) = @_;
114              
115 0 0         return if $self->_last_page();
116              
117 0           my $page = $self->_page() + 1;
118 0           my $params = $self->params();
119 0   0       my $per_page = $params->{per_page} || 20;
120              
121 0           $params = {
122             %$params,
123             page => $page,
124             per_page => $per_page,
125             };
126              
127 0           my $method = $self->method();
128             my $records = $self->api->$method(
129 0           @{ $self->args() },
  0            
130             $params,
131             );
132              
133 0 0         croak("The $method method returned a non array ref value")
134             if ref($records) ne 'ARRAY';
135              
136 0           $self->_page( $page );
137 0 0         $self->_last_page( 1 ) if @$records < $per_page;
138 0           $self->_records( [ @$records ] );
139              
140 0 0         return if !@$records;
141              
142 0           return $records;
143             }
144              
145             =head2 next
146              
147             while (my $record = $paginator->next()) { ... }
148              
149             Returns the next record in the current page. If all records have
150             been exhausted then L</next_page> will automatically be called.
151             This way if you want to ignore pagination you can just call C<next>
152             over and over again to walk through all the records.
153              
154             =cut
155              
156             sub next {
157 0     0 1   my ($self) = @_;
158              
159 0           my $records = $self->_records();
160 0 0         return shift(@$records) if @$records;
161              
162 0 0         return if $self->_last_page();
163              
164 0           $self->next_page();
165              
166 0           $records = $self->_records();
167 0 0         return shift(@$records) if @$records;
168              
169 0           return;
170             }
171              
172             =head2 all
173              
174             my $records = $paginator->all();
175              
176             This is just an alias for calling L</next_page> over and over
177             again to build an array ref of all records.
178              
179             =cut
180              
181             sub all {
182 0     0 1   my ($self) = @_;
183              
184 0           $self->reset();
185              
186 0           my @records;
187 0           while (my $page = $self->next_page()) {
188 0           push @records, @$page;
189             }
190              
191 0           return \@records;
192             }
193              
194             =head2 reset
195              
196             $paginator->reset();
197              
198             Reset the paginator back to its original state on the first page
199             with no records retrieved yet.
200              
201             =cut
202              
203             sub reset {
204 0     0 1   my ($self) = @_;
205 0           $self->_records( [] );
206 0           $self->_page( 0 );
207 0           $self->_last_page( 0 );
208 0           return;
209             }
210              
211             1;
212             __END__
213              
214             =head1 SUPPORT
215              
216             See L<GitLab::API::v3/SUPPORT>.
217              
218             =head1 AUTHORS
219              
220             See L<GitLab::API::v3/AUTHORS>.
221              
222             =head1 LICENSE
223              
224             See L<GitLab::API::v3/LICENSE>.
225              
226             =cut
227