File Coverage

blib/lib/Elastic/Model/Results/Scrolled.pm
Criterion Covered Total %
statement 12 28 42.8
branch n/a
condition 0 11 0.0
subroutine 4 7 57.1
pod 1 2 50.0
total 17 48 35.4


line stmt bran cond sub pod time code
1             package Elastic::Model::Results::Scrolled;
2             $Elastic::Model::Results::Scrolled::VERSION = '0.51';
3 1     1   654 use Carp;
  1         1  
  1         61  
4 1     1   4 use Moose;
  1         3  
  1         6  
5             with 'Elastic::Model::Role::Results';
6 1     1   4816 use MooseX::Types::Moose qw(Int);
  1         2  
  1         8  
7              
8 1     1   3873 use namespace::autoclean;
  1         2  
  1         7  
9              
10             #===================================
11             has '_scroll' => (
12             #===================================
13                 isa => 'Search::Elasticsearch::Scroll',
14                 is => 'ro',
15                 writer => '_set_scroll',
16             );
17              
18             #===================================
19             has '_virtual_size' => (
20             #===================================
21                 isa => Int,
22                 is => 'ro',
23                 writer => '_set_virtual_size',
24             );
25              
26             #===================================
27             sub BUILD {
28             #===================================
29 0     0 0       my $self = shift;
30 0               my $scroll = $self->model->store->scrolled_search( $self->search );
31 0               $self->_set_scroll($scroll);
32              
33             # TODO: handle partial results if some shards failed?
34             # TODO: croak "Search timed out" if $result->{timed_out};
35              
36 0               $self->_set_total( $scroll->total );
37 0               $self->_set_virtual_size( $scroll->total );
38 0   0           $self->_set_facets( $scroll->facets || {} );
39 0   0           $self->_set_aggs( $scroll->aggregations || {} );
40 0   0           $self->_set_max_score( $scroll->max_score || 0 );
41             }
42              
43             #===================================
44 0     0 1   sub size { shift->_virtual_size }
45             #===================================
46              
47             #===================================
48             before '_i' => sub {
49             #===================================
50                 my $self = shift;
51                 if (@_) {
52                     my $i = shift;
53                     $self->_fetch_until($i) if $i > -1;
54                 }
55             };
56              
57             #===================================
58             before 'shift_element' => sub {
59             #===================================
60                 my $self = shift;
61                 $self->_fetch_until(0);
62                 my $size = $self->size;
63                 $self->_set_virtual_size( $size > 0 ? $size - 1 : 0 );
64             };
65              
66             #===================================
67             sub _fetch_until {
68             #===================================
69 0     0         my $self = shift;
70 0   0           my $i = shift || 0;
71 0               my $scroll = $self->_scroll;
72 0               my $elements = $self->elements;
73 0   0           while ( $i >= @$elements and not $scroll->is_finished ) {
74 0                   push @$elements, $scroll->drain_buffer;
75 0                   $scroll->refill_buffer;
76                 }
77             }
78              
79             1;
80              
81             =pod
82            
83             =encoding UTF-8
84            
85             =head1 NAME
86            
87             Elastic::Model::Results::Scrolled - An iterator over unbounded search results
88            
89             =head1 VERSION
90            
91             version 0.51
92            
93             =head1 SYNOPSIS
94            
95             All active users:
96            
97             $all_users = $model->view
98             ->index ( 'my_domain' )
99             ->type ( 'user' )
100             ->filterb( 'status' => 'active' )
101             ->size ( 100 )
102             ->scan
103            
104             while ( my $user = $users->next ) {
105             say $user->name;
106             }
107            
108             =head1 DESCRIPTION
109            
110             An L<Elastic::Model::Results::Scrolled> object is returned when you call
111             L<Elastic::Model::View/scroll()> or L<Elastic::Model::View/scan()>,
112             and is intended for searches that could potentially retrieve many results.
113             Results are retrieved from Elasticsearch in chunks.
114            
115             A C<$results> object can iterate through L<Elastic::Model::Result> objects
116             (with all the result metadata), or just the DocClass object itself
117             (eg C<MyApp::User>). For instance, you can do:
118            
119             $result = $results->next_result;
120             $object = $results->next_object;
121            
122             Or you can set the default type to return:
123            
124             $results->as_objects;
125             $object = $results->next;
126            
127             $results->as_results;
128             $result = $results->next;
129            
130             By default, L<scroll()|Elastic::Model::View/scroll()> will set the short accessors
131             to return L<Elastic::Model::Result> objects, and
132             L<scan()|Elastic::Model::View/scan()> will set them to default to the
133             original objects.
134            
135             Most attributes and accessors in this class come from
136             L<Elastic::Model::Role::Results> and L<Elastic::Model::Role::Iterator>.
137            
138             Also, see L<Elastic::Manual::Searching>.
139            
140             =head1 ATTRIBUTES
141            
142             =head2 size
143            
144             $size = $results->size;
145            
146             Initially the same as the L</total> attribute, as you can
147             potentially retrieve all matching results. (This is different from the
148             L<Elastic::Model::Results/size>.) If you use L</shift>, the L</size>
149             will decrease, while the L</total> will remain the same.
150            
151             =head2 total
152            
153             $total_matching = $results->total
154            
155             The total number of matching docs found by Elasticsearch.
156            
157             =head2 max_score
158            
159             $max_score = $results->max_score
160            
161             The highest score (relevance) found by Elasticsearch. B<Note:> if you
162             are sorting by a field other than C<_score> then you will need
163             to set L<Elastic::Model::View/track_scores> to true to retrieve the
164             L</max_score>.
165            
166             =head2 facets
167            
168             =head2 facet
169            
170             $facets = $results->facets
171             $facet = $results->facet($facet_name)
172            
173             Facet results, if any were requested with L<Elastic::Model::View/facets>.
174            
175             =head2 elements
176            
177             \@elements = $results->elements;
178            
179             An array ref containing all of the data structures that we can iterate over.
180            
181             =head2 search
182            
183             \%search_args = $results->search
184            
185             Contains the hash ref of the search request passed to
186             L<Elastic::Model::Role::Store/scrolled_search()>
187            
188             =head1 ITERATOR CONTROL
189            
190             =head2 index
191            
192             $index = $results->index; # index of the current element, or undef
193             $results->index(0); # set the current element to the first element
194             $results->index(-1); # set the current element to the last element
195             $results->index(undef); # resets the iterator, no current element
196            
197             L</index> contains the current index of the iterator. Before you start
198             iterating, it will return undef.
199            
200             =head2 reset
201            
202             $results->reset;
203            
204             Resets the iterator so that the next call to L</next> will return
205             the first element. B<Note:> any calls to L</shift> means that those
206             elements have been discarded. L</reset> will not reload these.
207            
208             =head1 INFORMATIONAL ACCESSORS
209            
210             =head2 size
211            
212             $size = $results->size;
213            
214             Returns the number of L</elements>.
215            
216             =head2 even
217            
218             $bool = $results->even
219            
220             Is the current L</index> even?
221            
222             =head2 odd
223            
224             $bool = $results->odd
225            
226             Is the current L</index> odd?
227            
228             =head2 parity
229            
230             $parity = $results->parity
231            
232             Returns C<'odd'> or C<'even'>. Useful for alternating the colour of rows:
233            
234             while ( my $el = $results->next ) {
235             my $css_class = $el->parity;
236             # display row
237             }
238            
239             =head2 is_first
240            
241             $bool = $results->is_first
242            
243             Is the L</current> element the first element?
244            
245             =head2 is_last
246            
247             $bool = $results->is_last
248            
249             Is the L</current> element the last element?
250            
251             =head2 has_next
252            
253             $bool = $results->has_next
254            
255             Is there a L</next> element?
256            
257             =head2 has_prev
258            
259             $bool = $results->has_prev
260            
261             Is there a L</prev> element?
262            
263             =head1 WRAPPERS
264            
265             =head2 as_results()
266            
267             $results = $results->as_results;
268            
269             Sets the "short" accessors (eg L</next>, L</prev>) to return
270             L<Elastic::Model::Result> objects.
271            
272             =head2 as_objects()
273            
274             $objects = $objects->as_objects;
275            
276             Sets the "short" accessors (eg L</next>, L</prev>) to return the object itself,
277             eg C<MyApp::User>
278            
279             =head2 as_elements()
280            
281             $results->as_elements()
282            
283             Sets the "short" accessors (eg L</next>, L</prev>) to return the raw result
284             returned by Elasticsearch.
285            
286             =head1 ELEMENT ACCESSORS
287            
288             All of the accessors below have 4 forms:
289            
290             =over
291            
292             =item *
293            
294             Result, eg C<next_result> which returns the full result metadata as an
295             L<Elastic::Model::Result> object.
296            
297             =item *
298            
299             Object, eg C<next_object> which returns the original matching object, eg
300             an instance of C<MyApp::User>
301            
302             =item *
303            
304             Element, eg C<next_element> which returns the raw hashref from Elasticsearch
305            
306             =item *
307            
308             Short, which can return any one of the above, depending on which
309             L<Wrapper|/WRAPPERS> is currently in effect.
310            
311             =back
312            
313             Typically you would select the type that you need, then use the short
314             accessors, eg:
315            
316             $results->as_objects;
317            
318             while (my $object = $result->next ) {...}
319            
320             =head2 first
321            
322             $el = $results->first
323            
324             Returns the first element, and resets the iterator so that a call
325             to L</next> will return the second element. If there is
326             no first element, it returns undef.
327            
328             Also C<first_result>, C<first_object>, C<first_element>
329            
330             =head2 next
331            
332             $el = $results->next;
333            
334             Returns the next element, and advances the iterator by one. If there is
335             no next element, it returns undef. If the next element is the last
336             element, then it will work like this:
337            
338             $results->next; # returns last element
339             $results->next; # returns undef, and resets iterator
340             $results->next; # returns first element
341            
342             Also C<next_result>, C<next_object>, C<next_element>
343            
344             =head2 prev
345            
346             $el = $results->prev
347            
348             Returns the previous element, and moves the iterator one step in reverse. If
349             there is no previous element, it returns undef. If the previous element is the
350             first element, then it will work like this:
351            
352             $results->prev; # returns prev element
353             $results->prev; # returns undef, and resets iterator to end
354             $results->prev; # returns last element
355            
356             Also C<prev_result>, C<prev_object>, C<prev_element>
357            
358             =head2 current
359            
360             $el = $results->current
361            
362             Returns the current element, or undef
363            
364             Also C<current_result>, C<current_object>, C<current_element>
365            
366             =head2 last
367            
368             $el = $results->last
369            
370             Returns the last element, and resets the iterator so that a call
371             to L</next> will return undef, and a second call to
372             L</next> will return the first element If there is
373             no last element, it returns undef.
374            
375             Also C<last_result>, C<last_object>, C<last_element>
376            
377             =head2 peek_next
378            
379             $el = $results->peek_next
380            
381             Returns the next element (or undef), but doesn't move the iterator.
382            
383             Also C<peek_next_result>, C<peek_next_object>, C<peek_next_element>
384            
385             =head2 peek_prev
386            
387             $el = $results->peek_prev
388            
389             Returns the previous element (or undef), but doesn't move the iterator.
390            
391             Also C<peek_prev_result>, C<peek_prev_object>, C<peek_prev_element>
392            
393             =head2 shift
394            
395             $el = $results->shift
396            
397             Returns the L</first> element and removes it from from the list. L</size>
398             will decrease by 1. Returns undef if there are no more elements.
399            
400             Also C<shift_result>, C<shift_object>, C<shift_element>
401            
402             =head2 slice
403            
404             @els = $results->slice($offset,$length);
405            
406             Returns a list of (max) C<$length> elements, starting at C<$offset> (which
407             is zero-based):
408            
409             $results->slice(); # all elements;
410             $results->slice(5); # elements 5..size
411             $results->slice(-5); # elements size-5..size
412             $results->slice(0,10); # elements 0..9
413             $results->slice(5,10); # elements 5..14
414            
415             If your iterator only contains 5 elements:
416            
417             $results->slice(3,10); # elements 3..4
418             $results->slice(10,10); # an empty list
419            
420             Also C<slice_results>, C<slice_objects>, C<slice_elements>
421            
422             =head2 all
423            
424             @els = $results->all
425            
426             Returns all L</elements> as a list.
427            
428             Also C<all_results>, C<all_objects>, C<all_elements>
429            
430             =head1 AUTHOR
431            
432             Clinton Gormley <drtech@cpan.org>
433            
434             =head1 COPYRIGHT AND LICENSE
435            
436             This software is copyright (c) 2015 by Clinton Gormley.
437            
438             This is free software; you can redistribute it and/or modify it under
439             the same terms as the Perl 5 programming language system itself.
440            
441             =cut
442              
443             __END__
444            
445             # ABSTRACT: An iterator over unbounded search results
446            
447