File Coverage

blib/lib/MongoDB/IndexView.pm
Criterion Covered Total %
statement 36 96 37.5
branch 0 30 0.0
condition 0 6 0.0
subroutine 12 24 50.0
pod 5 5 100.0
total 53 161 32.9


line stmt bran cond sub pod time code
1             # Copyright 2015 - 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   382 use strict;
  59         121  
  59         1735  
16 59     59   278 use warnings;
  59         112  
  59         2091  
17             package MongoDB::IndexView;
18              
19             # ABSTRACT: Index management for a collection
20              
21 59     59   271 use version;
  59         116  
  59         414  
22             our $VERSION = 'v2.2.2';
23              
24 59     59   4472 use Moo;
  59         127  
  59         394  
25 59     59   18794 use MongoDB::Error;
  59         156  
  59         5329  
26 59     59   21767 use MongoDB::Op::_CreateIndexes;
  59         178  
  59         2177  
27 59     59   23699 use MongoDB::Op::_DropIndexes;
  59         193  
  59         3946  
28 59     59   436 use MongoDB::ReadPreference;
  59         112  
  59         1691  
29 59         339 use MongoDB::_Types qw(
30             BSONCodec
31             IxHash
32             is_IndexModelList
33             is_OrderedDoc
34 59     59   279 );
  59         107  
35 59         414 use Types::Standard qw(
36             InstanceOf
37             Str
38             is_Str
39 59     59   53501 );
  59         125  
40 59     59   48581 use boolean;
  59         135  
  59         481  
41 59     59   4304 use namespace::clean -except => 'meta';
  59         121  
  59         317  
42              
43             #pod =attr collection
44             #pod
45             #pod The L for which indexes are being created or viewed.
46             #pod
47             #pod =cut
48              
49             #--------------------------------------------------------------------------#
50             # constructor attributes
51             #--------------------------------------------------------------------------#
52              
53             has collection => (
54             is => 'ro',
55             isa => InstanceOf( ['MongoDB::Collection'] ),
56             required => 1,
57             );
58              
59             #--------------------------------------------------------------------------#
60             # private attributes
61             #--------------------------------------------------------------------------#
62              
63             has _bson_codec => (
64             is => 'lazy',
65             isa => BSONCodec,
66             builder => '_build__bson_codec',
67             );
68              
69             sub _build__bson_codec {
70 0     0     my ($self) = @_;
71 0           return $self->collection->bson_codec->clone( ordered => 1 );
72             }
73              
74             has _client => (
75             is => 'lazy',
76             isa => InstanceOf( ['MongoDB::MongoClient'] ),
77             builder => '_build__client',
78             );
79              
80             sub _build__client {
81 0     0     my ($self) = @_;
82 0           return $self->collection->client;
83             }
84              
85             has _coll_name => (
86             is => 'lazy',
87             isa => Str,
88             builder => '_build__coll_name',
89             );
90              
91             sub _build__coll_name {
92 0     0     my ($self) = @_;
93 0           return $self->collection->name;
94             }
95              
96             has _db_name => (
97             is => 'lazy',
98             isa => Str,
99             builder => '_build__db_name',
100             );
101              
102             sub _build__db_name {
103 0     0     my ($self) = @_;
104 0           return $self->collection->database->name;
105             }
106              
107             has _write_concern => (
108             is => 'lazy',
109             isa => InstanceOf( ['MongoDB::WriteConcern'] ),
110             builder => '_build__write_concern',
111             );
112              
113             sub _build__write_concern {
114 0     0     my ($self) = @_;
115 0           return $self->collection->write_concern;
116             }
117              
118             #--------------------------------------------------------------------------#
119             # public methods
120             #--------------------------------------------------------------------------#
121              
122             #pod =method list
123             #pod
124             #pod $result = $indexes->list;
125             #pod
126             #pod while ( my $index = $result->next ) {
127             #pod ...
128             #pod }
129             #pod
130             #pod for my $index ( $result->all ) {
131             #pod ...
132             #pod }
133             #pod
134             #pod This method returns a L which can be used to
135             #pod retrieve index information either one at a time (with C) or
136             #pod all at once (with C).
137             #pod
138             #pod If the list can't be retrieved, an exception will be thrown.
139             #pod
140             #pod =cut
141              
142             my $list_args;
143              
144             sub list {
145 0     0 1   my ($self) = @_;
146              
147 0           my $op = MongoDB::Op::_ListIndexes->_new(
148             client => $self->_client,
149             db_name => $self->_db_name,
150             full_name => '', # unused
151             coll_name => $self->_coll_name,
152             bson_codec => $self->_bson_codec,
153             monitoring_callback => $self->_client->monitoring_callback,
154             read_preference => MongoDB::ReadPreference->new( mode => 'primary' ),
155             session => $self->_client->_maybe_get_implicit_session,
156             );
157              
158 0           return $self->_client->send_retryable_read_op($op);
159             }
160              
161             #pod =method create_one
162             #pod
163             #pod $name = $indexes->create_one( [ x => 1 ] );
164             #pod $name = $indexes->create_one( [ x => 1, y => 1 ] );
165             #pod $name = $indexes->create_one( [ z => 1 ], { unique => 1 } );
166             #pod
167             #pod This method takes an ordered index specification document and an optional
168             #pod hash reference of index options and returns the name of the index created.
169             #pod It will throw an exception on error.
170             #pod
171             #pod The index specification document is an ordered document (array reference,
172             #pod L object, or single-key hash reference) with index keys and
173             #pod direction/type.
174             #pod
175             #pod See L for important information about index specifications
176             #pod and options.
177             #pod
178             #pod The following additional options are recognized:
179             #pod
180             #pod =for :list
181             #pod * C — maximum time in milliseconds before the operation will
182             #pod time out.
183             #pod
184             #pod =cut
185              
186             my $create_one_args;
187              
188             sub create_one {
189 0     0 1   my ( $self, $keys, $opts ) = @_;
190              
191 0 0         MongoDB::UsageError->throw("Argument to create_one must be an ordered document")
192             unless is_OrderedDoc($keys);
193              
194 0           my $global_opts = {};
195 0 0         if (exists $opts->{maxTimeMS}) {
196 0           $global_opts->{maxTimeMS} = delete $opts->{maxTimeMS};
197             }
198              
199 0 0         my ($name) = $self->create_many(
200             { keys => $keys, ( $opts ? ( options => $opts ) : () ) },
201             $global_opts,
202             );
203 0           return $name;
204             }
205              
206             #pod =method create_many
207             #pod
208             #pod @names = $indexes->create_many(
209             #pod { keys => [ x => 1, y => 1 ] },
210             #pod { keys => [ z => 1 ], options => { unique => 1 } }
211             #pod );
212             #pod
213             #pod @names = $indexes->create_many(
214             #pod { keys => [ x => 1, y => 1 ] },
215             #pod { keys => [ z => 1 ], options => { unique => 1 } }
216             #pod \%global_options,
217             #pod );
218             #pod
219             #pod This method takes a list of index models (given as hash references)
220             #pod and returns a list of index names created. It will throw an exception
221             #pod on error.
222             #pod
223             #pod If the last value is a hash reference without a C entry, it will
224             #pod be assumed to be a set of global options. See below for a list of
225             #pod accepted global options.
226             #pod
227             #pod Each index module is described by the following fields:
228             #pod
229             #pod =for :list
230             #pod * C (required) — an index specification as an ordered document (array
231             #pod reference, L object, or single-key hash reference)
232             #pod with index keys and direction/type. See below for more.
233             #pod * C — an optional hash reference of index options.
234             #pod
235             #pod The C document needs to be ordered. You are B encouraged
236             #pod to get in the habit of specifying index keys with an array reference.
237             #pod Because Perl randomizes the order of hash keys, you may B use a hash
238             #pod reference if it contains a single key.
239             #pod
240             #pod The form of the C document differs based on the type of index (e.g.
241             #pod single-key, multi-key, text, geospatial, etc.).
242             #pod
243             #pod For single and multi-key indexes, the value is "1" for an ascending index
244             #pod and "-1" for a descending index.
245             #pod
246             #pod [ name => 1, votes => -1 ] # ascending on name, descending on votes
247             #pod
248             #pod See L in the
249             #pod MongoDB Manual for instructions for other index types.
250             #pod
251             #pod The C hash reference may have a mix of general-purpose and
252             #pod index-type-specific options. See L
253             #pod Options|http://docs.mongodb.org/manual/reference/method/db.collection.createIndex/#options>
254             #pod in the MongoDB Manual for specifics.
255             #pod
256             #pod Some of the more commonly used options include:
257             #pod
258             #pod =for :list
259             #pod * C — when true, index creation won't block but will run in the
260             #pod background; this is strongly recommended to avoid blocking other
261             #pod operations on the database.
262             #pod * C - a L defining the collation for this operation.
263             #pod See docs for the format of the collation document here:
264             #pod L.
265             #pod * C — enforce uniqueness when true; inserting a duplicate document
266             #pod (or creating one with update modifiers) will raise an error.
267             #pod * C — a name (string) for the index; one will be generated if this is
268             #pod omitted.
269             #pod
270             #pod Global options specified as the last value can contain the following
271             #pod keys:
272             #pod
273             #pod =for :list
274             #pod * C — maximum time in milliseconds before the operation will
275             #pod time out.
276             #pod
277             #pod =cut
278              
279             my $create_many_args;
280              
281             sub create_many {
282 0     0 1   my ( $self, @models ) = @_;
283              
284 0           my $opts;
285 0 0 0       if (@models and ref $models[-1] eq 'HASH' and not exists $models[-1]{keys}) {
      0        
286 0           $opts = pop @models;
287             }
288              
289 0 0         MongoDB::UsageError->throw("Argument to create_many must be a list of index models")
290             unless is_IndexModelList(\@models);
291              
292 0           my $indexes = [ map __flatten_index_model($_), @models ];
293             my $op = MongoDB::Op::_CreateIndexes->_new(
294             db_name => $self->_db_name,
295             coll_name => $self->_coll_name,
296             full_name => '', # unused
297             bson_codec => $self->_bson_codec,
298             indexes => $indexes,
299             write_concern => $self->_write_concern,
300             monitoring_callback => $self->_client->monitoring_callback,
301             (defined($opts->{maxTimeMS})
302             ? (max_time_ms => $opts->{maxTimeMS})
303 0 0         : ()
304             ),
305             );
306              
307             # succeed or die; we don't care about response document
308 0           $self->_client->send_write_op($op);
309              
310 0           return map $_->{name}, @$indexes;
311             }
312              
313             #pod =method drop_one
314             #pod
315             #pod $output = $indexes->drop_one( $name );
316             #pod $output = $indexes->drop_one( $name, \%options );
317             #pod
318             #pod This method takes the name of an index and drops it. It returns the output
319             #pod of the dropIndexes command (a hash reference) on success or throws a
320             #pod exception if the command errors. However, if the index does not exist, the
321             #pod command output will have the C field as a false value, but no exception
322             #pod will e thrown.
323             #pod
324             #pod Valid options are:
325             #pod
326             #pod =for :list
327             #pod * C — maximum time in milliseconds before the operation will
328             #pod time out.
329             #pod
330             #pod =cut
331              
332             my $drop_one_args;
333              
334             sub drop_one {
335 0     0 1   my ( $self, $name, $opts ) = @_;
336              
337 0 0         MongoDB::UsageError->throw("Argument to drop_one must be a string")
338             unless is_Str($name);
339              
340 0 0         if ( $name eq '*' ) {
341 0           MongoDB::UsageError->throw("Can't use '*' as an argument to drop_one");
342             }
343              
344             my $op = MongoDB::Op::_DropIndexes->_new(
345             db_name => $self->_db_name,
346             coll_name => $self->_coll_name,
347             full_name => '', # unused
348             bson_codec => $self->_bson_codec,
349             write_concern => $self->_write_concern,
350             index_name => $name,
351             monitoring_callback => $self->_client->monitoring_callback,
352             (defined($opts->{maxTimeMS})
353             ? (max_time_ms => $opts->{maxTimeMS})
354 0 0         : ()
355             ),
356             );
357              
358 0           $self->_client->send_write_op($op)->output;
359             }
360              
361             #pod =method drop_all
362             #pod
363             #pod $output = $indexes->drop_all;
364             #pod $output = $indexes->drop_all(\%options);
365             #pod
366             #pod This method drops all indexes (except the one on the C<_id> field). It
367             #pod returns the output of the dropIndexes command (a hash reference) on success
368             #pod or throws a exception if the command fails.
369             #pod
370             #pod Valid options are:
371             #pod
372             #pod =for :list
373             #pod * C — maximum time in milliseconds before the operation will
374             #pod time out.
375             #pod
376             #pod =cut
377              
378             my $drop_all_args;
379              
380             sub drop_all {
381 0     0 1   my ($self, $opts) = @_;
382              
383             my $op = MongoDB::Op::_DropIndexes->_new(
384             db_name => $self->_db_name,
385             coll_name => $self->_coll_name,
386             full_name => '', # unused
387             bson_codec => $self->_bson_codec,
388             write_concern => $self->_write_concern,
389             index_name => '*',
390             monitoring_callback => $self->_client->monitoring_callback,
391             (defined($opts->{maxTimeMS})
392             ? (max_time_ms => $opts->{maxTimeMS})
393 0 0         : ()
394             ),
395             );
396              
397 0           $self->_client->send_write_op($op)->output;
398             }
399              
400             #--------------------------------------------------------------------------#
401             # private functions
402             #--------------------------------------------------------------------------#
403              
404             sub __flatten_index_model {
405 0     0     my ($model) = @_;
406              
407 0           my ( $keys, $orig ) = @{$model}{qw/keys options/};
  0            
408              
409 0           $keys = IxHash->coerce($keys);
410              
411             # copy the original so we don't modify it
412 0 0         my $opts = { $orig ? %$orig : () };
413              
414 0           for my $k (qw/keys key/) {
415             MongoDB::UsageError->throw("Can't specify '$k' in options to index creation")
416 0 0         if exists $opts->{$k};
417             }
418              
419             # add name if not provided
420             $opts->{name} = __to_index_string($keys)
421 0 0         unless defined $opts->{name};
422              
423             # convert some things to booleans
424 0           for my $k (qw/unique background sparse dropDups/) {
425 0 0         next unless exists $opts->{$k};
426 0           $opts->{$k} = boolean( $opts->{$k} );
427             }
428              
429             # return is document ready for the createIndexes command
430 0           return { key => $keys, %$opts };
431             }
432              
433             # utility function to generate an index name by concatenating key/value pairs
434             sub __to_index_string {
435 0     0     my $keys = shift;
436              
437 0 0         if ( ref $keys eq 'Tie::IxHash' ) {
438 0           my @name;
439 0           my @ks = $keys->Keys;
440 0           my @vs = $keys->Values;
441              
442 0           for ( my $i = 0; $i < $keys->Length; $i++ ) {
443 0           push @name, $ks[$i];
444 0           push @name, $vs[$i];
445             }
446              
447 0           return join( "_", @name );
448             }
449             else {
450 0           MongoDB::InternalError->throw("expected Tie::IxHash for __to_index_string");
451             }
452              
453             }
454              
455              
456             1;
457              
458              
459             # vim: set ts=4 sts=4 sw=4 et tw=75:
460              
461             __END__