File Coverage

blib/lib/MongoDB/Cursor.pm
Criterion Covered Total %
statement 42 125 33.6
branch 0 52 0.0
condition 0 8 0.0
subroutine 14 35 40.0
pod 19 20 95.0
total 75 240 31.2


line stmt bran cond sub pod time code
1             # Copyright 2009 - present MongoDB, Inc.
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 59     59   458 use strict;
  59         123  
  59         2404  
16 59     59   291 use warnings;
  59         118  
  59         2067  
17             package MongoDB::Cursor;
18              
19              
20             # ABSTRACT: A lazy cursor for Mongo query results
21              
22 59     59   290 use version;
  59         108  
  59         445  
23             our $VERSION = 'v2.2.2';
24              
25 59     59   4350 use Moo;
  59         135  
  59         345  
26 59     59   19161 use MongoDB::Error;
  59         131  
  59         6937  
27 59     59   23221 use MongoDB::QueryResult;
  59         185  
  59         2239  
28 59     59   477 use MongoDB::ReadPreference;
  59         131  
  59         1470  
29 59     59   324 use MongoDB::_Protocol;
  59         111  
  59         1269  
30 59     59   26067 use MongoDB::Op::_Explain;
  59         173  
  59         2459  
31 59     59   413 use MongoDB::_Types -types, qw/to_IxHash is_OrderedDoc/;
  59         104  
  59         286  
32 59         268 use Types::Standard qw(
33             InstanceOf
34             is_Str
35 59     59   317266 );
  59         135  
36 59     59   44416 use boolean;
  59         145  
  59         457  
37 59     59   4198 use Tie::IxHash;
  59         123  
  59         1509  
38 59     59   281 use namespace::clean -except => 'meta';
  59         122  
  59         335  
39              
40             #pod =attr started_iterating
41             #pod
42             #pod A boolean indicating if this cursor has queried the database yet. Methods
43             #pod modifying the query will complain if they are called after the database is
44             #pod queried.
45             #pod
46             #pod =cut
47              
48             with $_ for qw(
49             MongoDB::Role::_CursorAPI
50             MongoDB::Role::_DeprecationWarner
51             );
52              
53             # attributes for sending a query
54             has client => (
55             is => 'ro',
56             required => 1,
57             isa => InstanceOf ['MongoDB::MongoClient'],
58             );
59              
60             has _query => (
61             is => 'ro',
62             isa => InstanceOf['MongoDB::Op::_Query'],
63             required => 1,
64             init_arg => 'query',
65             );
66              
67             # lazy result attribute
68             has result => (
69             is => 'lazy',
70             isa => InstanceOf['MongoDB::QueryResult'],
71             builder => '_build_result',
72             predicate => 'started_iterating',
73             clearer => '_clear_result',
74             );
75              
76             # this does the query if it hasn't been done yet
77             sub _build_result {
78 0     0     my ($self) = @_;
79              
80 0           return $self->{client}->send_retryable_read_op( $self->_query );
81             }
82              
83             #--------------------------------------------------------------------------#
84             # methods that modify the query
85             #--------------------------------------------------------------------------#
86              
87             #pod =head1 QUERY MODIFIERS
88             #pod
89             #pod These methods modify the query to be run. An exception will be thrown if
90             #pod they are called after results are iterated.
91             #pod
92             #pod =head2 immortal
93             #pod
94             #pod $cursor->immortal(1);
95             #pod
96             #pod Ordinarily, a cursor "dies" on the database server after a certain length of
97             #pod time (approximately 10 minutes), to prevent inactive cursors from hogging
98             #pod resources. This option indicates that a cursor should not die until all of its
99             #pod results have been fetched or it goes out of scope in Perl.
100             #pod
101             #pod Boolean value, defaults to 0.
102             #pod
103             #pod Note: C only affects the server-side timeout. If you are getting
104             #pod client-side timeouts you will need to change your client configuration.
105             #pod See L and
106             #pod L.
107             #pod
108             #pod Returns this cursor for chaining operations.
109             #pod
110             #pod =cut
111              
112             sub immortal {
113 0     0 1   my ( $self, $bool ) = @_;
114 0 0         MongoDB::UsageError->throw("cannot set immortal after querying")
115             if $self->started_iterating;
116              
117 0           $self->_query->set_noCursorTimeout($bool);
118 0           return $self;
119             }
120              
121             #pod =head2 fields
122             #pod
123             #pod $coll->insert({name => "Fred", age => 20});
124             #pod my $cursor = $coll->find->fields({ name => 1 });
125             #pod my $obj = $cursor->next;
126             #pod $obj->{name}; "Fred"
127             #pod $obj->{age}; # undef
128             #pod
129             #pod Selects which fields are returned. The default is all fields. When fields
130             #pod are specified, _id is returned by default, but this can be disabled by
131             #pod explicitly setting it to "0". E.g. C<< _id => 0 >>. Argument must be either a
132             #pod hash reference or a L object.
133             #pod
134             #pod See L
135             #pod return|http://docs.mongodb.org/manual/tutorial/project-fields-from-query-results/>
136             #pod in the MongoDB documentation for details.
137             #pod
138             #pod Returns this cursor for chaining operations.
139             #pod
140             #pod =cut
141              
142             sub fields {
143 0     0 1   my ($self, $f) = @_;
144 0 0         MongoDB::UsageError->throw("cannot set fields after querying")
145             if $self->started_iterating;
146 0 0 0       MongoDB::UsageError->throw("not a hash reference")
147             unless ref $f eq 'HASH' || ref $f eq 'Tie::IxHash';
148              
149 0           $self->_query->set_projection($f);
150 0           return $self;
151             }
152              
153             #pod =head2 sort
154             #pod
155             #pod # sort by name, descending
156             #pod $cursor->sort([name => -1]);
157             #pod
158             #pod Adds a sort to the query. Argument is either a hash reference or a
159             #pod L or an array reference of key/value pairs. Because hash
160             #pod references are not ordered, do not use them for more than one key.
161             #pod
162             #pod Returns this cursor for chaining operations.
163             #pod
164             #pod =cut
165              
166             sub sort {
167 0     0 1   my ( $self, $order ) = @_;
168 0 0         MongoDB::UsageError->throw("cannot set sort after querying")
169             if $self->started_iterating;
170              
171 0           $self->_query->set_sort($order);
172 0           return $self;
173             }
174              
175              
176             #pod =head2 limit
177             #pod
178             #pod $cursor->limit(20);
179             #pod
180             #pod Sets cursor to return a maximum of N results.
181             #pod
182             #pod Returns this cursor for chaining operations.
183             #pod
184             #pod =cut
185              
186             sub limit {
187 0     0 1   my ( $self, $num ) = @_;
188 0 0         MongoDB::UsageError->throw("cannot set limit after querying")
189             if $self->started_iterating;
190 0           $self->_query->set_limit($num);
191 0           return $self;
192             }
193              
194              
195             #pod =head2 max_await_time_ms
196             #pod
197             #pod $cursor->max_await_time_ms( 500 );
198             #pod
199             #pod The maximum amount of time in milliseconds for the server to wait on new
200             #pod documents to satisfy a tailable cursor query. This only applies to a
201             #pod cursor of type 'tailble_await'. This is ignored if the cursor is not
202             #pod a 'tailable_await' cursor or the server version is less than version 3.2.
203             #pod
204             #pod Returns this cursor for chaining operations.
205             #pod
206             #pod =cut
207              
208             sub max_await_time_ms {
209 0     0 1   my ( $self, $num ) = @_;
210 0 0         $num = 0 unless defined $num;
211 0 0         MongoDB::UsageError->throw("max_await_time_ms must be non-negative")
212             if $num < 0;
213 0 0         MongoDB::UsageError->throw("can not set max_await_time_ms after querying")
214             if $self->started_iterating;
215              
216 0           $self->_query->set_maxAwaitTimeMS( $num );
217 0           return $self;
218             }
219              
220             #pod =head2 max_time_ms
221             #pod
222             #pod $cursor->max_time_ms( 500 );
223             #pod
224             #pod Causes the server to abort the operation if the specified time in milliseconds
225             #pod is exceeded.
226             #pod
227             #pod Returns this cursor for chaining operations.
228             #pod
229             #pod =cut
230              
231             sub max_time_ms {
232 0     0 1   my ( $self, $num ) = @_;
233 0 0         $num = 0 unless defined $num;
234 0 0         MongoDB::UsageError->throw("max_time_ms must be non-negative")
235             if $num < 0;
236 0 0         MongoDB::UsageError->throw("can not set max_time_ms after querying")
237             if $self->started_iterating;
238              
239 0           $self->_query->set_maxTimeMS( $num );
240 0           return $self;
241              
242             }
243              
244             #pod =head2 tailable
245             #pod
246             #pod $cursor->tailable(1);
247             #pod
248             #pod If a cursor should be tailable. Tailable cursors can only be used on capped
249             #pod collections and are similar to the C command: they never die and keep
250             #pod returning new results as more is added to a collection.
251             #pod
252             #pod They are often used for getting log messages.
253             #pod
254             #pod Boolean value, defaults to 0.
255             #pod
256             #pod If you want the tailable cursor to block for a few seconds, use
257             #pod L instead. B calling this with a false value
258             #pod disables tailing, even if C was previously called.
259             #pod
260             #pod Returns this cursor for chaining operations.
261             #pod
262             #pod =cut
263              
264             sub tailable {
265 0     0 1   my ( $self, $bool ) = @_;
266 0 0         MongoDB::UsageError->throw("cannot set tailable after querying")
267             if $self->started_iterating;
268              
269 0 0         $self->_query->set_cursorType($bool ? 'tailable' : 'non_tailable');
270 0           return $self;
271             }
272              
273             #pod =head2 tailable_await
274             #pod
275             #pod $cursor->tailable_await(1);
276             #pod
277             #pod Sets a cursor to be tailable and block for a few seconds if no data
278             #pod is immediately available.
279             #pod
280             #pod Boolean value, defaults to 0.
281             #pod
282             #pod If you want the tailable cursor without blocking, use L instead.
283             #pod B calling this with a false value disables tailing, even if C
284             #pod was previously called.
285             #pod
286             #pod =cut
287              
288             sub tailable_await {
289 0     0 1   my ( $self, $bool ) = @_;
290 0 0         MongoDB::UsageError->throw("cannot set tailable_await after querying")
291             if $self->started_iterating;
292              
293 0 0         $self->_query->set_cursorType($bool ? 'tailable_await' : 'non_tailable');
294 0           return $self;
295             }
296              
297             #pod =head2 skip
298             #pod
299             #pod $cursor->skip( 50 );
300             #pod
301             #pod Skips the first N results.
302             #pod
303             #pod Returns this cursor for chaining operations.
304             #pod
305             #pod =cut
306              
307             sub skip {
308 0     0 1   my ( $self, $num ) = @_;
309 0 0         MongoDB::UsageError->throw("skip must be non-negative")
310             if $num < 0;
311 0 0         MongoDB::UsageError->throw("cannot set skip after querying")
312             if $self->started_iterating;
313              
314 0           $self->_query->set_skip($num);
315 0           return $self;
316             }
317              
318             #pod =head2 hint
319             #pod
320             #pod Hint the query to use a specific index by name:
321             #pod
322             #pod $cursor->hint("index_name");
323             #pod
324             #pod Hint the query to use index based on individual keys and direction:
325             #pod
326             #pod $cursor->hint([field_1 => 1, field_2 => -1, field_3 => 1]);
327             #pod
328             #pod Use of a hash reference should be avoided except for single key indexes.
329             #pod
330             #pod The hint must be a string or L
331             #pod document>.
332             #pod
333             #pod Returns this cursor for chaining operations.
334             #pod
335             #pod =cut
336              
337             sub hint {
338 0     0 1   my ( $self, $index ) = @_;
339 0 0         MongoDB::UsageError->throw("cannot set hint after querying")
340             if $self->started_iterating;
341 0 0 0       MongoDB::UsageError->throw("hint must be string or ordered document, not '$index'")
342             if ! (is_Str($index) || is_OrderedDoc($index));
343              
344 0           $self->_query->set_hint( $index );
345              
346 0           return $self;
347             }
348              
349             #pod =head2 partial
350             #pod
351             #pod $cursor->partial(1);
352             #pod
353             #pod If a shard is down, mongos will return an error when it tries to query that
354             #pod shard. If this is set, mongos will just skip that shard, instead.
355             #pod
356             #pod Boolean value, defaults to 0.
357             #pod
358             #pod Returns this cursor for chaining operations.
359             #pod
360             #pod =cut
361              
362             sub partial {
363 0     0 1   my ($self, $value) = @_;
364 0 0         MongoDB::UsageError->throw("cannot set partial after querying")
365             if $self->started_iterating;
366              
367 0           $self->_query->set_allowPartialResults( $value );
368              
369             # returning self is an API change but more consistent with other cursor methods
370 0           return $self;
371             }
372              
373             #pod =head2 read_preference
374             #pod
375             #pod $cursor->read_preference($read_preference_object);
376             #pod $cursor->read_preference('secondary', [{foo => 'bar'}]);
377             #pod
378             #pod Sets read preference for the cursor's connection.
379             #pod
380             #pod If given a single argument that is a L object, the
381             #pod read preference is set to that object. Otherwise, it takes positional
382             #pod arguments: the read preference mode and a tag set list, which must be a valid
383             #pod mode and tag set list as described in the L
384             #pod documentation.
385             #pod
386             #pod Returns this cursor for chaining operations.
387             #pod
388             #pod =cut
389              
390             sub read_preference {
391 0     0 1   my $self = shift;
392 0 0         MongoDB::UsageError->throw("cannot set read preference after querying")
393             if $self->started_iterating;
394              
395 0           my $type = ref $_[0];
396 0 0         if ( $type eq 'MongoDB::ReadPreference' ) {
397 0           $self->_query->read_preference( $_[0] );
398             }
399             else {
400 0   0       my $mode = shift || 'primary';
401 0           my $tag_sets = shift;
402 0 0         my $rp = MongoDB::ReadPreference->new(
403             mode => $mode,
404             ( $tag_sets ? ( tag_sets => $tag_sets ) : () )
405             );
406 0           $self->_query->read_preference($rp);
407             }
408              
409 0           return $self;
410             }
411              
412             #pod =head1 QUERY INTROSPECTION AND RESET
413             #pod
414             #pod These methods run introspection methods on the query conditions and modifiers
415             #pod stored within the cursor object.
416             #pod
417             #pod =head2 explain
418             #pod
419             #pod my $explanation = $cursor->explain;
420             #pod
421             #pod This will tell you the type of cursor used, the number of records the DB had to
422             #pod examine as part of this query, the number of records returned by the query, and
423             #pod the time in milliseconds the query took to execute.
424             #pod
425             #pod See also core documentation on explain:
426             #pod L.
427             #pod
428             #pod =cut
429              
430             sub explain {
431 0     0 1   my ($self) = @_;
432              
433 0           my $explain_op = MongoDB::Op::_Explain->_new(
434             db_name => $self->_query->db_name,
435             coll_name => $self->_query->coll_name,
436             full_name => $self->_query->full_name,
437             bson_codec => $self->_query->bson_codec,
438             query => $self->_query,
439             read_preference => $self->_query->read_preference,
440             read_concern => $self->_query->read_concern,
441             session => $self->_query->session,
442             monitoring_callback => $self->client->monitoring_callback,
443             );
444              
445 0           return $self->_query->client->send_retryable_read_op($explain_op);
446             }
447              
448             #pod =head1 QUERY ITERATION
449             #pod
450             #pod These methods allow you to iterate over results.
451             #pod
452             #pod =head2 result
453             #pod
454             #pod my $result = $cursor->result;
455             #pod
456             #pod This method will execute the query and return a L object
457             #pod with the results.
458             #pod
459             #pod The C, C, and C methods call C internally,
460             #pod which executes the query "on demand".
461             #pod
462             #pod Iterating with a MongoDB::QueryResult object directly instead of a
463             #pod L will be slightly faster, since the L
464             #pod methods below just internally call the corresponding method on the result
465             #pod object.
466             #pod
467             #pod =cut
468              
469             #--------------------------------------------------------------------------#
470             # methods delgated to result object
471             #--------------------------------------------------------------------------#
472              
473             #pod =head2 has_next
474             #pod
475             #pod while ($cursor->has_next) {
476             #pod ...
477             #pod }
478             #pod
479             #pod Checks if there is another result to fetch. Will automatically fetch more
480             #pod data from the server if necessary.
481             #pod
482             #pod =cut
483              
484 0     0 1   sub has_next { $_[0]->result->has_next }
485              
486             #pod =head2 next
487             #pod
488             #pod while (my $object = $cursor->next) {
489             #pod ...
490             #pod }
491             #pod
492             #pod Returns the next object in the cursor. Will automatically fetch more data from
493             #pod the server if necessary. Returns undef if no more data is available.
494             #pod
495             #pod =cut
496              
497 0     0 1   sub next { $_[0]->result->next }
498              
499             #pod =head2 batch
500             #pod
501             #pod while (my @batch = $cursor->batch) {
502             #pod ...
503             #pod }
504             #pod
505             #pod Returns the next batch of data from the cursor. Will automatically fetch more
506             #pod data from the server if necessary. Returns an empty list if no more data is available.
507             #pod
508             #pod =cut
509              
510 0     0 1   sub batch { $_[0]->result->batch }
511              
512             #pod =head2 all
513             #pod
514             #pod my @objects = $cursor->all;
515             #pod
516             #pod Returns a list of all objects in the result.
517             #pod
518             #pod =cut
519              
520 0     0 1   sub all { $_[0]->result->all }
521              
522             #pod =head2 reset
523             #pod
524             #pod Resets the cursor. After being reset, pre-query methods can be
525             #pod called on the cursor (sort, limit, etc.) and subsequent calls to
526             #pod result, next, has_next, or all will re-query the database.
527             #pod
528             #pod =cut
529              
530             sub reset {
531 0     0 1   my ($self) = @_;
532 0           $self->_clear_result;
533 0           return $self;
534             }
535              
536             #pod =head2 info
537             #pod
538             #pod Returns a hash of information about this cursor. This is intended for
539             #pod debugging purposes and users should not rely on the contents of this method for
540             #pod production use. Currently the fields are:
541             #pod
542             #pod =for :list
543             #pod * C -- the server-side id for this cursor. See below for details.
544             #pod * C -- the number of results received from the server so far
545             #pod * C -- the (zero-based) index of the document that will be returned next from L
546             #pod * C -- if the database could not find the cursor or another error occurred, C may
547             #pod contain a hash reference of flags set in the response (depending on the error). See
548             #pod L
549             #pod for a full list of flag values.
550             #pod * C -- the index of the result that the current batch of results starts at.
551             #pod
552             #pod If the cursor has not yet executed, only the C field will be returned with
553             #pod a value of 0.
554             #pod
555             #pod The C could appear in one of three forms:
556             #pod
557             #pod =for :list
558             #pod * MongoDB::CursorID object (a blessed reference to an 8-byte string)
559             #pod * A perl scalar (an integer)
560             #pod * A Math::BigInt object (64 bit integer on 32-bit perl)
561             #pod
562             #pod When the C is zero, there are no more results to fetch.
563             #pod
564             #pod =cut
565              
566             sub info {
567 0     0 1   my $self = shift;
568 0 0         if ( $self->started_iterating ) {
569 0           return $self->result->_info;
570             }
571             else {
572 0           return { num => 0 };
573             }
574             }
575              
576             #--------------------------------------------------------------------------#
577             # Deprecated methods
578             #--------------------------------------------------------------------------#
579              
580             sub snapshot {
581 0     0 0   my ($self, $bool) = @_;
582              
583 0           $self->_warn_deprecated_method(
584             'snapshot' => "Snapshot is deprecated as of MongoDB 3.6" );
585              
586 0 0         MongoDB::UsageError->throw("cannot set snapshot after querying")
587             if $self->started_iterating;
588              
589 0 0         MongoDB::UsageError->throw("snapshot requires a defined, boolean argument")
590             unless defined $bool;
591              
592 0           $self->_query->set_snapshot($bool);
593 0           return $self;
594             }
595              
596             1;
597              
598              
599              
600             # vim: ts=4 sts=4 sw=4 et tw=75:
601              
602             __END__