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   122129 use strict;
  23         103  
  23         756  
2 23     23   108 use warnings;
  23         45  
  23         1319  
3             package MetaCPAN::Client::Scroll;
4             # ABSTRACT: A MetaCPAN::Client scroller
5             $MetaCPAN::Client::Scroll::VERSION = '2.043000';
6 23     23   486 use Moo;
  23         5700  
  23         167  
7 23     23   7227 use Carp;
  23         38  
  23         1395  
8 23     23   134 use Ref::Util qw< is_hashref >;
  23         48  
  23         910  
9 23     23   798 use JSON::MaybeXS qw< decode_json encode_json >;
  23         19015  
  23         990  
10              
11 23     23   7962 use MetaCPAN::Client::Types qw< Str Int Time ArrayRef HashRef Bool >;
  23         70  
  23         18795  
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 index => (
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 272451 my ( $class, %args ) = @_;
76 11   100     58 $args{time} //= '5m';
77 11   50     35 $args{size} //= '100';
78              
79             my ( $ua, $base_url, $index, $body, $time, $size ) =
80 11         95 @args{qw< ua base_url index body time size >};
81              
82             # fetch scroller from server
83              
84 11         490 my $res = $ua->post(
85             sprintf( '%s/%s/_search?scroll=%s&size=%s', $base_url, $index, $time, $size ),
86             { content => encode_json $body }
87             );
88              
89 11 50       3140696 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         92474 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       108 : $content->{hits}{total};
102              
103 11         48 $args{_remaining} = $total;
104 11         33 $args{total} = $total;
105              
106 11         41 $args{_id} = $content->{_scroll_id};
107 11         51 $args{_buffer} = $content->{hits}{hits};
108              
109             $args{aggregations} = $content->{aggregations}
110 11 50 33     69 if exists $content->{aggregations} and is_hashref( $content->{aggregations} );
111              
112 11         3889 return \%args;
113             }
114              
115             sub next {
116 107     107 1 5525 my $self = shift;
117 107         169 my $buffer = $self->_buffer;
118 107         13799 my $remaining = $self->_remaining;
119              
120 107 100       541 if (!$remaining) {
    100          
121             # We're exhausted and will do no more.
122 3         9 return undef;
123             }
124             elsif (!@$buffer) {
125             # Refill the buffer if it's empty.
126 1         507 @$buffer = @{ $self->_fetch_next };
  1         5  
127              
128 1 50       6 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 104         1260 $self->_remaining($remaining - 1);
137             # Return the next result
138 104         1819 return shift @$buffer;
139             }
140              
141             sub _fetch_next {
142 1     1   2 my $self = shift;
143              
144 1         51 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       252893 unless $res->{status} == 200;
151              
152 1         10749 my $content = decode_json $res->{content};
153              
154 1         122 return $content->{hits}{hits};
155             }
156              
157             sub DEMOLISH {
158 11     11 1 119303 my ( $self, $gd ) = @_;
159             return
160 11 50       46 if $gd;
161 11 50       95 my $ua = $self->ua
162             or return;
163 11 50       68 my $base_url = $self->base_url
164             or return;
165 11 50       55 my $id = $self->_id
166             or return;
167 11 50       55 my $time = $self->time
168             or return;
169              
170 11         291 $ua->delete(
171             sprintf( '%s/_search/scroll?scroll=%s', $base_url, $time ),
172             { content => $id }
173             );
174             }
175              
176             1;
177              
178             __END__