File Coverage

lib/Google/Ads/AdWords/Utilities/PageProcessor.pm
Criterion Covered Total %
statement 21 83 25.3
branch 0 28 0.0
condition 0 12 0.0
subroutine 7 12 58.3
pod 3 4 75.0
total 31 139 22.3


line stmt bran cond sub pod time code
1             # Copyright 2015, Google Inc. All Rights Reserved.
2             #
3             # Licensed under the Apache License, Version 2.0 (the "License");
4             # you may not use this file except in compliance with the License.
5             # You may obtain a copy of the License at
6             #
7             # http://www.apache.org/licenses/LICENSE-2.0
8             #
9             # Unless required by applicable law or agreed to in writing, software
10             # distributed under the License is distributed on an "AS IS" BASIS,
11             # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12             # See the License for the specific language governing permissions and
13             # limitations under the License.
14             #
15             # Description: This is a utility that provides automatic paging of results.
16              
17             package Google::Ads::AdWords::Utilities::PageProcessor;
18              
19 1     1   1164 use strict;
  1         2  
  1         31  
20 1     1   4 use warnings;
  1         3  
  1         23  
21 1     1   4 use utf8;
  1         2  
  1         7  
22 1     1   23 use version;
  1         2  
  1         8  
23              
24             # The following needs to be on one line because CPAN uses a particularly hacky
25             # eval() to determine module versions.
26 1     1   78 use Google::Ads::AdWords::Constants; our $VERSION = ${Google::Ads::AdWords::Constants::VERSION};
  1         2  
  1         47  
27 1     1   7 use Google::Ads::Common::Utilities::AdsUtilityRegistry;
  1         2  
  1         25  
28              
29 1     1   5 use Class::Std::Fast;
  1         1  
  1         13  
30              
31             my %client_of : ATTR(:name :default<>);
32             my %service_of : ATTR(:name :default<>);
33             my %selector_of : ATTR(:name :default<>);
34             my %query_of : ATTR(:name :default<>);
35             my %page_size_of : ATTR(:name
36             :default);
37             my $end_of_page = 0;
38              
39             # Verify that all the variables are correctly defined.
40             # Either 'selector' or 'query' needs to be defined.
41             # Page size needs to be greater than 0.
42             sub START {
43 0     0 0   my ($self) = @_;
44              
45 0           Google::Ads::Common::Utilities::AdsUtilityRegistry->add_ads_utilities(
46             "PageProcessor");
47              
48 0 0         if (!defined($self->get_client())) {
49 0           die("Argument 'client' is required.");
50             }
51 0           my $die_on_faults = $self->get_client()->get_die_on_faults();
52 0 0         if (!defined($self->get_service())) {
53 0           my $service_arg_required = "Argument 'service' is required.";
54 0 0         if ($die_on_faults) {
55 0           die($service_arg_required);
56             } else {
57 0           warn($service_arg_required);
58             }
59             }
60 0 0 0       if ( (!defined($self->get_selector()) && !defined($self->get_query()))
      0        
      0        
61             || (defined($self->get_selector()) && defined($self->get_query())))
62             {
63 0           my $query_or_selector_arg_required =
64             "Argument 'selector' OR 'query' is required.";
65 0 0         if ($die_on_faults) {
66 0           die($query_or_selector_arg_required);
67             } else {
68 0           warn($query_or_selector_arg_required);
69             }
70             }
71 0 0         if ($self->get_page_size() <= 0) {
72 0           my $page_size_arg =
73             "Argument 'page_size'=>{$self->get_page_size()} must " .
74             "be greater than 0.";
75 0 0         if ($die_on_faults) {
76 0           die($page_size_arg);
77             } else {
78 0           warn($page_size_arg);
79             }
80             }
81             }
82              
83             # Process the entries that were retrieved from the service. For each entry,
84             # execute the subroutine that was passed in as an argument. Return the results
85             # of the subroutines as an array of results.
86             sub process_entries {
87 0     0 1   my ($self, $process_entry_subroutine) = @_;
88 0           my @results = ();
89 0           my $service = $self->get_service();
90 0           my $selector = $self->get_selector();
91 0           my $query = $self->get_query();
92 0           my $page_size = $self->get_page_size();
93             # Some services have serviceSelector as the arg while others have selector
94             # as the arg to the get subroutine.
95 0           my $selector_arg = 'selector';
96 0 0         if (
97             exists $service->get_class_resolver()->get_typemap->{'get/serviceSelector'})
98             {
99 0           $selector_arg = 'serviceSelector';
100             }
101             # If the query includes a LIMIT clause, extrapolate the offset and the page
102             # size because the offset will need to be dynamically increased when
103             # processing the pages.
104             # Example: query => 'SELECT Id, Name, Status ORDER BY Name LIMIT 0,10'
105 0           my $offset = 0;
106 0           my $page;
107 0 0 0       if (defined($query)
108 0           && $query =~ m/${\(Google::Ads::AdWords::Constants::QUERY_LIMIT_REGEX)}/i)
109             {
110 0           $query = $1;
111 0           $offset = $2;
112 0           $page_size = $3;
113             }
114              
115 0           do {
116 0 0         if (defined($selector)) {
117 0           $page = $service->get({$selector_arg => $selector});
118             } else {
119 0           $page =
120             $service->query({query => "${query} LIMIT ${offset},${page_size}"});
121             }
122 0 0         if ($page->get_entries()) {
123 0           $end_of_page = 0;
124             my @entries =
125             ref $page->get_entries() eq 'ARRAY'
126 0 0         ? @{$page->get_entries()}
  0            
127             : $page->get_entries();
128             # Before the last entry in the page, set a boolean indicating that
129             # the end of the page has been reached.
130 0           my $last_entry = pop @entries;
131 0           foreach my $entry (@entries) {
132 0           push(@results, $process_entry_subroutine->($entry));
133             }
134 0           $end_of_page = 1;
135 0           push(@results, $process_entry_subroutine->($last_entry));
136             my $page_size =
137 0 0         ref $page->get_entries() eq 'ARRAY' ? @{$page->get_entries()} : 1;
  0            
138 0 0         if (defined($selector)) {
139 0           my $paging = $selector->get_paging();
140 0           $paging->set_startIndex($paging->get_startIndex() + $page_size);
141             }
142 0           $offset += $page_size;
143             }
144             } while ($offset < $page->get_totalNumEntries());
145 0           return @results;
146             }
147              
148             # Retrieve all the entries from all the pages as an array of entries.
149             sub get_entries {
150 0     0 1   my ($self) = @_;
151             my $processEntrySubroutine = sub {
152 0     0     my ($entry) = @_;
153 0           return $entry;
154 0           };
155 0           return $self->process_entries($processEntrySubroutine);
156             }
157              
158             # Returns a 1 if we have reached the end of a page and 0 otherwise.
159             sub is_end_of_page {
160 0     0 1   return $end_of_page;
161             }
162              
163             1;
164              
165             =pod
166              
167             =head1 NAME
168              
169             Google::Ads::AdWords::Utilities::PageProcessor
170              
171             =head1 DESCRIPTION
172              
173             This is a utility that provides automatic paging of results.
174              
175             =head2 PROPERTIES
176              
177             The following properties may be accessed using get_PROPERTY methods:
178              
179             =head1 METHODS
180              
181             =head2 new
182              
183             Constructor. The following data structure may be passed to new():
184              
185             { # Google::Ads::AdWords::Utilities::PageProcessor
186             service => $service, # A service e.g.
187             Google::Ads::AdWords::v201702::TypeMaps::CampaignService object
188             selector => $selector, # A reference to a selector e.g.
189             Google::Ads::AdWords::v201702::Selector. When 'selector' is defined,
190             'query' cannot be defined.
191             query => $query, # A string representing a query e.g.
192             SELECT Id, Name, Status ORDER BY Name. When 'query' is defined, 'selector'
193             cannot be defined.
194             page_size => $page_size, # The size of the page (only used when 'query' is
195             defined in the constructor).
196             If not defined, the default of
197             L will be used.
198             },
199              
200             =head1 METHODS
201              
202             =head2 process_entries
203              
204             Process the entries that were retrieved from the service. For each entry,
205             execute the subroutine that was passed in as an argument. Return the results
206             of the subroutines as an array of results.
207              
208             =head3 Parameters
209              
210             =over
211              
212             =item *
213              
214             A reference to the subroutine that will be executed on each entry.
215              
216             =back
217              
218             =head3 Returns
219              
220             An array of all subroutine results (one per entry).
221              
222             =head2 get_entries
223              
224             Returns all the entries from all the pages in an array.
225              
226             =head3 Returns
227              
228             An array of entries from all the pages.
229              
230             =head2 is_end_of_page
231              
232             Returns whether or not processing has reached the end of a page boundary.
233              
234             =head3 Returns
235              
236             Returns a 1 if processing reached the end of a page and 0 otherwise.
237              
238             =cut