File Coverage

blib/lib/MetaCPAN/Client/Scroll.pm
Criterion Covered Total %
statement 57 62 91.9
branch 14 26 53.8
condition 4 7 57.1
subroutine 11 11 100.0
pod 3 3 100.0
total 89 109 81.6


line stmt bran cond sub pod time code
1 23     23   139808 use strict;
  23         84  
  23         950  
2 23     23   150 use warnings;
  23         49  
  23         1822  
3             package MetaCPAN::Client::Scroll;
4             # ABSTRACT: A MetaCPAN::Client scroller
5             $MetaCPAN::Client::Scroll::VERSION = '2.040000';
6 23     23   714 use Moo;
  23         8868  
  23         125  
7 23     23   10959 use Carp;
  23         81  
  23         2561  
8 23     23   153 use Ref::Util qw< is_hashref >;
  23         56  
  23         1445  
9 23     23   1219 use JSON::MaybeXS qw< decode_json encode_json >;
  23         28216  
  23         1612  
10              
11 23     23   11194 use MetaCPAN::Client::Types qw< Str Int Time ArrayRef HashRef Bool >;
  23         125  
  23         26135  
12              
13             has ua => (
14             is => 'ro',
15             required => 1,
16             );
17              
18             has size => (
19             is => 'ro',
20             isa => Str,
21             );
22              
23             has time => (
24             is => 'ro',
25             isa => Time,
26             );
27              
28             has base_url => (
29             is => 'ro',
30             isa => Str,
31             required => 1,
32             );
33              
34             has type => (
35             is => 'ro',
36             isa => Str,
37             required => 1,
38             );
39              
40             has body => (
41             is => 'ro',
42             isa => HashRef,
43             required => 1,
44             );
45              
46             has _id => (
47             is => 'ro',
48             isa => Str,
49             );
50              
51             has _buffer => (
52             is => 'ro',
53             isa => ArrayRef,
54             default => sub { [] },
55             );
56              
57             has _remaining => (
58             is => 'rw',
59             isa => Int,
60             default => sub { 0 },
61             );
62              
63             has total => (
64             is => 'ro',
65             isa => Int,
66             );
67              
68             has aggregations => (
69             is => 'ro',
70             isa => HashRef,
71             default => sub { +{} },
72             );
73              
74             sub BUILDARGS {
75 11     11 1 427820 my ( $class, %args ) = @_;
76 11   100     74 $args{time} //= '5m';
77 11   50     96 $args{size} //= '100';
78              
79             my ( $ua, $base_url, $type, $body, $time, $size ) =
80 11         64 @args{qw< ua base_url type body time size >};
81              
82             # fetch scroller from server
83              
84 11         531 my $res = $ua->post(
85             sprintf( '%s/%s/_search?scroll=%s&size=%s', $base_url, $type, $time, $size ),
86             { content => encode_json $body }
87             );
88              
89 11 50       4151127 if ( $res->{status} != 200 ) {
90 0         0 my $msg = "failed to create a scrolled search";
91 0 0       0 $args{debug} and $msg .= "\n(" . $res->{content} . ")";
92 0         0 croak $msg;
93             }
94              
95 11         140707 my $content = decode_json $res->{content};
96              
97             # read response content --> object params
98              
99             my $total = is_hashref($content->{hits}{total})
100             ? $content->{hits}{total}{value}
101 11 50       144 : $content->{hits}{total};
102              
103 11         57 $args{_remaining} = $total;
104 11         37 $args{total} = $total;
105              
106 11         45 $args{_id} = $content->{_scroll_id};
107 11         48 $args{_buffer} = $content->{hits}{hits};
108              
109             $args{aggregations} = $content->{aggregations}
110 11 50 33     66 if $content->{aggregations} and is_hashref( $content->{aggregations} );
111              
112 11         3043 return \%args;
113             }
114              
115             sub next {
116 103     103 1 15942 my $self = shift;
117 103         310 my $buffer = $self->_buffer;
118 103         3145 my $remaining = $self->_remaining;
119              
120 103 100       1123 if (!$remaining) {
    100          
121             # We're exhausted and will do no more.
122 3         12 return undef;
123             }
124             elsif (!@$buffer) {
125             # Refill the buffer if it's empty.
126 1         1030 @$buffer = @{ $self->_fetch_next };
  1         13  
127              
128 1 50       8 if (!@$buffer) {
129             # we weren't able to refill for some reason
130 0         0 $self->_remaining(0);
131 0         0 return undef;
132             }
133             }
134              
135             # One less result to return
136 100         2291 $self->_remaining($remaining - 1);
137             # Return the next result
138 100         5431 return shift @$buffer;
139             }
140              
141             sub _fetch_next {
142 1     1   3 my $self = shift;
143              
144 1         104 my $res = $self->ua->post(
145             sprintf( '%s/_search/scroll?scroll=%s&size=%s', $self->base_url, $self->time, $self->size ),
146             { content => encode_json { scroll_id => $self->_id } }
147             );
148              
149             croak "failed to fetch next scrolled batch"
150 1 50       281174 unless $res->{status} == 200;
151              
152 1         10158 my $content = decode_json $res->{content};
153              
154 1         193 return $content->{hits}{hits};
155             }
156              
157             sub DEMOLISH {
158 11     11 1 174505 my ( $self, $gd ) = @_;
159             return
160 11 50       50 if $gd;
161 11 50       207 my $ua = $self->ua
162             or return;
163 11 50       208 my $base_url = $self->base_url
164             or return;
165 11 50       64 my $id = $self->_id
166             or return;
167 11 50       80 my $time = $self->time
168             or return;
169              
170 11         376 $ua->delete(
171             sprintf( '%s/_search/scroll?scroll=%s', $base_url, $time ),
172             { content => $id }
173             );
174             }
175              
176             1;
177              
178             __END__