Skip to content
This repository was archived by the owner on Dec 22, 2021. It is now read-only.

Commit ed9378e

Browse files
committed
PERL-718 Add support for deprecated 'modifiers' fields
The latest CRUD spec deprecates the 'modifiers' field, but requires additional modifier fields. For all modifiers fields, find options must fall back to the corresponding modifier, if available. This commit also adds unit testing for all the find modifier fields.
1 parent 4bee7ab commit ed9378e

File tree

13 files changed

+1139
-346
lines changed

13 files changed

+1139
-346
lines changed

lib/MongoDB/Collection.pm

Lines changed: 38 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -695,36 +695,50 @@ Valid options include:
695695
* C<collation> - a L<document|/Document> defining the collation for this operation.
696696
See docs for the format of the collation document here:
697697
L<https://docs.mongodb.com/master/reference/collation/>.
698-
* C<comment> – attaches a comment to the query. If C<$comment> also exists in
699-
the C<modifiers> document, the comment field overwrites C<$comment>.
698+
* C<comment> – attaches a comment to the query.
700699
* C<cursorType> – indicates the type of cursor to use. It must be one of three
701700
string values: C<'non_tailable'> (the default), C<'tailable'>, and
702701
C<'tailable_await'>.
702+
* C<hint> – L<specify an index to
703+
use|http://docs.mongodb.org/manual/reference/command/count/#specify-the-index-to-use>;
704+
must be a string, array reference, hash reference or L<Tie::IxHash> object.
703705
* C<limit> – the maximum number of documents to return.
706+
* C<max>L<specify the B<exclusive> upper bound for a specific index|
707+
https://docs.mongodb.com/manual/reference/operator/meta/max/>.
704708
* C<maxAwaitTimeMS> – the maximum amount of time for the server to wait on
705709
new documents to satisfy a tailable cursor query. This only applies
706710
to a C<cursorType> of 'tailable_await'; the option is otherwise ignored.
707711
(Note, this will be ignored for servers before version 3.2.)
708-
* C<maxTimeMS> – the maximum amount of time to allow the query to run. If
709-
C<$maxTimeMS> also exists in the modifiers document, the C<maxTimeMS> field
710-
overwrites C<$maxTimeMS>. (Note, this will be ignored for servers before
711-
version 2.6.)
712-
* C<modifiers> – a hash reference of dollar-prefixed L<query
712+
* C<maxScan> – L<maximum number of documents or index keys to scan|
713+
https://docs.mongodb.com/manual/reference/operator/meta/maxScan/>.
714+
* C<maxTimeMS> – the maximum amount of time to allow the query to run.
715+
(Note, this will be ignored for servers before version 2.6.)
716+
* C<min>L<specify the B<inclusive> lower bound for a specific index|
717+
https://docs.mongodb.com/manual/reference/operator/meta/min/>.
718+
* C<modifiers> – (DEPRECATED) a hash reference of dollar-prefixed L<query
713719
modifiers|http://docs.mongodb.org/manual/reference/operator/query-modifier/>
714-
modifying the output or behavior of a query.
720+
modifying the output or behavior of a query. Top-level options will always
721+
take precedence over corresponding modifiers. Supported modifiers include
722+
$comment, $hint, $maxScan, $maxTimeMS, $max, $min, $orderby, $returnKey,
723+
$showDiskLoc, and $snapshot. Some options may not be supported by
724+
newer server versions.
715725
* C<noCursorTimeout> – if true, prevents the server from timing out a cursor
716-
after a period of inactivity
726+
after a period of inactivity.
717727
* C<projection> - a hash reference defining fields to return. See "L<limit
718-
fields to
719-
return|http://docs.mongodb.org/manual/tutorial/project-fields-from-query-results/>"
728+
fields to return|http://docs.mongodb.org/manual/tutorial/project-fields-from-query-results/>"
720729
in the MongoDB documentation for details.
721730
* C<session> - the session to use for these operations. If not supplied, will
722731
use an implicit session. For more information see L<MongoDB::ClientSession>
732+
* C<returnKey> – L<Only return the index field or fields for the results of
733+
the query|https://docs.mongodb.com/manual/reference/operator/meta/returnKey/>.
734+
* C<showRecordId> – modifies the output of a query by adding a field
735+
L<$recordId|https://docs.mongodb.com/manual/reference/method/cursor.showRecordId/>
736+
that uniquely identifies a document in a collection.
723737
* C<skip> – the number of documents to skip before returning.
724738
* C<sort> – an L<ordered document|/Ordered document> defining the order in which
725-
to return matching documents. If C<$orderby> also exists in the modifiers
726-
document, the sort field overwrites C<$orderby>. See docs for
727-
L<$orderby|http://docs.mongodb.org/manual/reference/operator/meta/orderby/>.
739+
to return matching documents. See the L<$orderby
740+
documentation|https://docs.mongodb.com/manual/reference/operator/meta/orderby/>
741+
for examples.
728742
729743
For more information, see the L<Read Operations
730744
Overview|http://docs.mongodb.org/manual/core/read-operations-introduction/> in
@@ -764,22 +778,9 @@ sub find {
764778
return MongoDB::Cursor->new(
765779
client => $self->{_client},
766780
query => MongoDB::Op::_Query->_new(
767-
modifiers => {},
768-
allowPartialResults => 0,
769-
batchSize => 0,
770-
comment => '',
771-
cursorType => 'non_tailable',
772-
limit => 0,
773-
maxAwaitTimeMS => 0,
774-
maxTimeMS => 0,
775-
noCursorTimeout => 0,
776-
oplogReplay => 0,
777-
projection => undef,
778-
skip => 0,
779-
sort => undef,
780-
session => $session,
781-
%$options,
782-
filter => $filter || {},
781+
filter => $filter || {},
782+
options => MongoDB::Op::_Query->precondition_options($options),
783+
session => $session,
783784
%{ $self->_op_args },
784785
)
785786
);
@@ -838,28 +839,17 @@ sub find_one {
838839

839840
# coerce to IxHash
840841
__ixhash( $options, 'sort' );
842+
# overide projection and limit
843+
$options->{projection} = $projection;
844+
$options->{limit} = -1;
841845

842846
return $self->client->send_read_op(
843847
MongoDB::Op::_Query->_new(
844-
modifiers => {},
845-
allowPartialResults => 0,
846-
batchSize => 0,
847-
comment => '',
848-
cursorType => 'non_tailable',
849-
limit => 0,
850-
maxAwaitTimeMS => 0,
851-
maxTimeMS => 0,
852-
noCursorTimeout => 0,
853-
oplogReplay => 0,
854-
skip => 0,
855-
sort => undef,
856-
session => $session,
857-
%$options,
858-
filter => $filter || {},
859-
projection => $projection || {},
860-
limit => -1,
848+
filter => $filter || {},
849+
options => MongoDB::Op::_Query->precondition_options($options),
850+
session => $session,
861851
%{ $self->_op_args },
862-
)
852+
)
863853
)->next;
864854
}
865855

lib/MongoDB/Cursor.pm

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,10 @@ use MongoDB::QueryResult;
3232
use MongoDB::ReadPreference;
3333
use MongoDB::_Protocol;
3434
use MongoDB::Op::_Explain;
35-
use MongoDB::_Types -types, 'to_IxHash';
35+
use MongoDB::_Types -types, qw/to_IxHash is_OrderedDoc/;
3636
use Types::Standard qw(
3737
InstanceOf
38+
is_Str
3839
);
3940
use boolean;
4041
use Tie::IxHash;
@@ -118,7 +119,7 @@ sub immortal {
118119
MongoDB::UsageError->throw("cannot set immortal after querying")
119120
if $self->started_iterating;
120121

121-
$self->_query->noCursorTimeout(!!$bool);
122+
$self->_query->set_noCursorTimeout($bool);
122123
return $self;
123124
}
124125

@@ -150,7 +151,7 @@ sub fields {
150151
MongoDB::UsageError->throw("not a hash reference")
151152
unless ref $f eq 'HASH' || ref $f eq 'Tie::IxHash';
152153

153-
$self->_query->projection($f);
154+
$self->_query->set_projection($f);
154155
return $self;
155156
}
156157

@@ -172,7 +173,7 @@ sub sort {
172173
MongoDB::UsageError->throw("cannot set sort after querying")
173174
if $self->started_iterating;
174175

175-
$self->_query->sort( to_IxHash($order) );
176+
$self->_query->set_sort($order);
176177
return $self;
177178
}
178179

@@ -191,7 +192,7 @@ sub limit {
191192
my ( $self, $num ) = @_;
192193
MongoDB::UsageError->throw("cannot set limit after querying")
193194
if $self->started_iterating;
194-
$self->_query->limit($num);
195+
$self->_query->set_limit($num);
195196
return $self;
196197
}
197198

@@ -217,7 +218,7 @@ sub max_await_time_ms {
217218
MongoDB::UsageError->throw("can not set max_await_time_ms after querying")
218219
if $self->started_iterating;
219220

220-
$self->_query->maxAwaitTimeMS( $num );
221+
$self->_query->set_maxAwaitTimeMS( $num );
221222
return $self;
222223
}
223224

@@ -240,7 +241,7 @@ sub max_time_ms {
240241
MongoDB::UsageError->throw("can not set max_time_ms after querying")
241242
if $self->started_iterating;
242243

243-
$self->_query->maxTimeMS( $num );
244+
$self->_query->set_maxTimeMS( $num );
244245
return $self;
245246

246247
}
@@ -270,7 +271,7 @@ sub tailable {
270271
MongoDB::UsageError->throw("cannot set tailable after querying")
271272
if $self->started_iterating;
272273

273-
$self->_query->cursorType($bool ? 'tailable' : 'non_tailable');
274+
$self->_query->set_cursorType($bool ? 'tailable' : 'non_tailable');
274275
return $self;
275276
}
276277

@@ -294,7 +295,7 @@ sub tailable_await {
294295
MongoDB::UsageError->throw("cannot set tailable_await after querying")
295296
if $self->started_iterating;
296297

297-
$self->_query->cursorType($bool ? 'tailable_await' : 'non_tailable');
298+
$self->_query->set_cursorType($bool ? 'tailable_await' : 'non_tailable');
298299
return $self;
299300
}
300301

@@ -315,7 +316,7 @@ sub skip {
315316
MongoDB::UsageError->throw("cannot set skip after querying")
316317
if $self->started_iterating;
317318

318-
$self->_query->skip($num);
319+
$self->_query->set_skip($num);
319320
return $self;
320321
}
321322

@@ -331,6 +332,9 @@ Hint the query to use index based on individual keys and direction:
331332
332333
Use of a hash reference should be avoided except for single key indexes.
333334
335+
The hint must be a string or L<ordered document|MongoDB::Collection/Ordered
336+
document>.
337+
334338
Returns this cursor for chaining operations.
335339
336340
=cut
@@ -339,16 +343,11 @@ sub hint {
339343
my ( $self, $index ) = @_;
340344
MongoDB::UsageError->throw("cannot set hint after querying")
341345
if $self->started_iterating;
346+
MongoDB::UsageError->throw("hint must be string or ordered document, not '$index'")
347+
if ! (is_Str($index) || is_OrderedDoc($index));
342348

343-
# $index must either be a string or a reference to an array, hash, or IxHash
344-
if ( ref $index eq 'ARRAY' ) {
345-
$index = Tie::IxHash->new(@$index);
346-
}
347-
elsif ( ref $index && !( ref $index eq 'HASH' || ref $index eq 'Tie::IxHash' ) ) {
348-
MongoDB::UsageError->throw("not a hash reference");
349-
}
349+
$self->_query->set_hint( $index );
350350

351-
$self->_query->modifiers->{'$hint'} = $index;
352351
return $self;
353352
}
354353

@@ -370,7 +369,7 @@ sub partial {
370369
MongoDB::UsageError->throw("cannot set partial after querying")
371370
if $self->started_iterating;
372371

373-
$self->_query->allowPartialResults( !! $value );
372+
$self->_query->set_allowPartialResults( $value );
374373

375374
# returning self is an API change but more consistent with other cursor methods
376375
return $self;
@@ -441,7 +440,7 @@ sub explain {
441440
coll_name => $self->_query->coll_name,
442441
full_name => $self->_query->full_name,
443442
bson_codec => $self->_query->bson_codec,
444-
query => $self->_query->clone,
443+
query => $self->_query,
445444
read_preference => $self->_query->read_preference,
446445
read_concern => $self->_query->read_concern,
447446
monitoring_callback => $self->client->monitoring_callback,
@@ -593,12 +592,16 @@ sub count {
593592
$cmd->Push(query => $self->_query->filter);
594593

595594
if ($limit_skip) {
596-
$cmd->Push(limit => $self->_query->limit) if $self->_query->limit;
597-
$cmd->Push(skip => $self->_query->skip) if $self->_query->skip;
595+
my $limit = $self->_query->options->{limit};
596+
my $skip = $self->_query->options->{skip};
597+
$cmd->Push(limit => $limit) if $limit;
598+
$cmd->Push(skip => $skip) if $skip;
598599
}
599600

600-
if (my $hint = $self->_query->modifiers->{'$hint'}) {
601-
$cmd->Push(hint => $hint);
601+
# XXX Allow this manual use of query internals, as this deprecated
602+
# count method will be removed eventually anyway.
603+
if ($self->_query->has_hint) {
604+
$cmd->Push(hint => $self->_query->options->{hint});
602605
}
603606

604607
my $result = try {
@@ -652,7 +655,7 @@ sub snapshot {
652655
MongoDB::UsageError->throw("snapshot requires a defined, boolean argument")
653656
unless defined $bool;
654657

655-
$self->_query->modifiers->{'$snapshot'} = $bool;
658+
$self->_query->set_snapshot($bool);
656659
return $self;
657660
}
658661

lib/MongoDB/Op/_Explain.pm

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,10 @@ sub execute {
6060
sub _command_explain {
6161
my ( $self, $link, $topology ) = @_;
6262

63-
my $cmd = Tie::IxHash->new( @{ $self->query->as_command } );
63+
my $cmd = Tie::IxHash->new( @{ $self->query->_as_command } );
6464

6565
# XXX need to standardize error here
66-
if (defined $self->query->modifiers->{hint}) {
66+
if ($self->query->has_hint) {
6767
# cannot use hint on explain, throw error
6868
MongoDB::Error->throw(
6969
message => "cannot use 'hint' with 'explain'",
@@ -89,13 +89,20 @@ sub _command_explain {
8989
sub _legacy_explain {
9090
my ( $self, $link, $topology ) = @_;
9191

92-
my $new_query = $self->query->clone;
93-
$new_query->modifiers->{'$explain'} = true;
92+
my $orig_query = $self->query;
93+
my $cloned_opts = { %{ $orig_query->options } };
94+
$cloned_opts->{explain} = 1;
9495

9596
# per David Storch, drivers *must* send a negative limit to instruct
9697
# the query planner analysis module to add a LIMIT stage. For older
9798
# explain implementations, it also ensures a cursor isn't left open.
98-
$new_query->limit( -1 * abs( $new_query->limit ) );
99+
$cloned_opts->{limit} = ( -1 * abs( $cloned_opts->{limit} ) );
100+
101+
my $new_query = MongoDB::Op::_Query->_new(
102+
%$orig_query,
103+
# override options from original
104+
options => $cloned_opts
105+
);
99106

100107
return $new_query->execute( $link, $topology )->next;
101108
}

lib/MongoDB/Op/_FSyncUnlock.pm

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -87,27 +87,15 @@ sub _legacy_fsync_unlock {
8787
my ( $self, $link, $topology ) = @_;
8888

8989
my $op = MongoDB::Op::_Query->_new(
90-
modifiers => {},
91-
filter => {},
92-
allowPartialResults => 0,
93-
batchSize => 0,
94-
comment => '',
95-
cursorType => 'non_tailable',
96-
maxAwaitTimeMS => 0,
97-
maxTimeMS => 0,
98-
noCursorTimeout => 0,
99-
oplogReplay => 0,
100-
projection => undef,
101-
skip => 0,
102-
sort => undef,
103-
db_name => 'admin',
104-
coll_name => '$cmd.sys.unlock',
105-
full_name => 'admin.$cmd.sys.unlock',
106-
limit => -1,
107-
bson_codec => $self->bson_codec,
108-
client => $self->client,
109-
read_preference => MongoDB::ReadPreference->new,
110-
read_concern => MongoDB::ReadConcern->new,
90+
bson_codec => $self->bson_codec,
91+
client => $self->client,
92+
coll_name => '$cmd.sys.unlock',
93+
db_name => 'admin',
94+
filter => {},
95+
full_name => 'admin.$cmd.sys.unlock',
96+
options => MongoDB::Op::_Query->precondition_options( { limit => -1 } ),
97+
read_concern => MongoDB::ReadConcern->new,
98+
read_preference => MongoDB::ReadPreference->new,
11199
monitoring_callback => $self->monitoring_callback,
112100
);
113101

lib/MongoDB/Op/_GetMore.pm

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ sub _command_get_more {
7676

7777
my $op = MongoDB::Op::_Command->_new(
7878
db_name => $self->db_name,
79-
query => $self->as_command,
79+
query => $self->_as_command,
8080
query_flags => {},
8181
bson_codec => $self->bson_codec,
8282
session => $self->session,
@@ -95,7 +95,7 @@ sub _command_get_more {
9595
};
9696
}
9797

98-
sub as_command {
98+
sub _as_command {
9999
my ($self) = @_;
100100
return [
101101
getMore => $self->cursor_id,

0 commit comments

Comments
 (0)