Commit d960f5f9 authored by Jeremy Mikola's avatar Jeremy Mikola

PHPLIB-286: Support hint option for Find and FindOne

parent 5731a023
...@@ -80,6 +80,19 @@ interface: phpmethod ...@@ -80,6 +80,19 @@ interface: phpmethod
operation: ~ operation: ~
optional: true optional: true
--- ---
arg_name: option
name: hint
type: string|array|object
description: |
The index to use. Specify either the index name as a string or the index key
pattern as a document. If specified, then the query system will only consider
plans using the hinted index.
.. versionadded:: 1.2
interface: phpmethod
operation: ~
optional: true
---
source: source:
file: apiargs-common-option.yaml file: apiargs-common-option.yaml
ref: maxTimeMS ref: maxTimeMS
......
...@@ -18,6 +18,10 @@ source: ...@@ -18,6 +18,10 @@ source:
file: apiargs-MongoDBCollection-method-find-option.yaml file: apiargs-MongoDBCollection-method-find-option.yaml
ref: comment ref: comment
--- ---
source:
file: apiargs-MongoDBCollection-method-find-option.yaml
ref: hint
---
source: source:
file: apiargs-common-option.yaml file: apiargs-common-option.yaml
ref: maxTimeMS ref: maxTimeMS
......
...@@ -70,6 +70,10 @@ class Find implements Executable ...@@ -70,6 +70,10 @@ class Find implements Executable
* NON_TAILABLE, TAILABLE, or TAILABLE_AWAIT. The default is * NON_TAILABLE, TAILABLE, or TAILABLE_AWAIT. The default is
* NON_TAILABLE. * NON_TAILABLE.
* *
* * hint (string|document): The index to use. Specify either the index
* name as a string or the index key pattern as a document. If specified,
* then the query system will only consider plans using the hinted index.
*
* * limit (integer): The maximum number of documents to return. * * limit (integer): The maximum number of documents to return.
* *
* * maxTimeMS (integer): The maximum amount of time to allow the query to * * maxTimeMS (integer): The maximum amount of time to allow the query to
...@@ -146,6 +150,10 @@ class Find implements Executable ...@@ -146,6 +150,10 @@ class Find implements Executable
} }
} }
if (isset($options['hint']) && ! is_string($options['hint']) && ! is_array($options['hint']) && ! is_object($options['hint'])) {
throw InvalidArgumentException::invalidType('"hint" option', $options['hint'], 'string or array or object');
}
if (isset($options['limit']) && ! is_integer($options['limit'])) { if (isset($options['limit']) && ! is_integer($options['limit'])) {
throw InvalidArgumentException::invalidType('"limit" option', $options['limit'], 'integer'); throw InvalidArgumentException::invalidType('"limit" option', $options['limit'], 'integer');
} }
...@@ -249,7 +257,7 @@ class Find implements Executable ...@@ -249,7 +257,7 @@ class Find implements Executable
} }
} }
foreach (['allowPartialResults', 'batchSize', 'comment', 'limit', 'maxTimeMS', 'noCursorTimeout', 'oplogReplay', 'projection', 'readConcern', 'skip', 'sort'] as $option) { foreach (['allowPartialResults', 'batchSize', 'comment', 'hint', 'limit', 'maxTimeMS', 'noCursorTimeout', 'oplogReplay', 'projection', 'readConcern', 'skip', 'sort'] as $option) {
if (isset($this->options[$option])) { if (isset($this->options[$option])) {
$options[$option] = $this->options[$option]; $options[$option] = $this->options[$option];
} }
......
...@@ -48,6 +48,10 @@ class FindOne implements Executable ...@@ -48,6 +48,10 @@ class FindOne implements Executable
* * comment (string): Attaches a comment to the query. If "$comment" also * * comment (string): Attaches a comment to the query. If "$comment" also
* exists in the modifiers document, this option will take precedence. * exists in the modifiers document, this option will take precedence.
* *
* * hint (string|document): The index to use. Specify either the index
* name as a string or the index key pattern as a document. If specified,
* then the query system will only consider plans using the hinted index.
*
* * maxTimeMS (integer): The maximum amount of time to allow the query to * * maxTimeMS (integer): The maximum amount of time to allow the query to
* run. If "$maxTimeMS" also exists in the modifiers document, this * run. If "$maxTimeMS" also exists in the modifiers document, this
* option will take precedence. * option will take precedence.
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
namespace MongoDB\Tests\Operation; namespace MongoDB\Tests\Operation;
use MongoDB\Driver\BulkWrite; use MongoDB\Driver\BulkWrite;
use MongoDB\Operation\CreateIndexes;
use MongoDB\Operation\Find; use MongoDB\Operation\Find;
use MongoDB\Tests\CommandObserver; use MongoDB\Tests\CommandObserver;
use stdClass; use stdClass;
...@@ -28,6 +29,57 @@ class FindFunctionalTest extends FunctionalTestCase ...@@ -28,6 +29,57 @@ class FindFunctionalTest extends FunctionalTestCase
); );
} }
public function testHintOption()
{
$bulkWrite = new BulkWrite;
$bulkWrite->insert(['_id' => 1, 'x' => 1]);
$bulkWrite->insert(['_id' => 2, 'x' => 2]);
$bulkWrite->insert(['_id' => 3, 'y' => 3]);
$this->manager->executeBulkWrite($this->getNamespace(), $bulkWrite);
$createIndexes = new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), [
['key' => ['x' => 1], 'sparse' => true, 'name' => 'sparse_x'],
['key' => ['y' => 1]],
]);
$createIndexes->execute($this->getPrimaryServer());
$hintsUsingSparseIndex = [
['x' => 1],
'sparse_x',
];
foreach ($hintsUsingSparseIndex as $hint) {
$operation = new Find($this->getDatabaseName(), $this->getCollectionName(), [], ['hint' => $hint]);
$cursor = $operation->execute($this->getPrimaryServer());
$expectedDocuments = [
(object) ['_id' => 1, 'x' => 1],
(object) ['_id' => 2, 'x' => 2],
];
$this->assertEquals($expectedDocuments, $cursor->toArray());
}
$hintsNotUsingSparseIndex = [
['_id' => 1],
['y' => 1],
'y_1',
];
foreach ($hintsNotUsingSparseIndex as $hint) {
$operation = new Find($this->getDatabaseName(), $this->getCollectionName(), [], ['hint' => $hint]);
$cursor = $operation->execute($this->getPrimaryServer());
$expectedDocuments = [
(object) ['_id' => 1, 'x' => 1],
(object) ['_id' => 2, 'x' => 2],
(object) ['_id' => 3, 'y' => 3],
];
$this->assertEquals($expectedDocuments, $cursor->toArray());
}
}
/** /**
* @dataProvider provideTypeMapOptionsAndExpectedDocuments * @dataProvider provideTypeMapOptionsAndExpectedDocuments
*/ */
......
...@@ -48,6 +48,10 @@ class FindTest extends TestCase ...@@ -48,6 +48,10 @@ class FindTest extends TestCase
$options[][] = ['cursorType' => $value]; $options[][] = ['cursorType' => $value];
} }
foreach ($this->getInvalidHintValues() as $value) {
$options[][] = ['hint' => $value];
}
foreach ($this->getInvalidIntegerValues() as $value) { foreach ($this->getInvalidIntegerValues() as $value) {
$options[][] = ['limit' => $value]; $options[][] = ['limit' => $value];
} }
...@@ -91,6 +95,11 @@ class FindTest extends TestCase ...@@ -91,6 +95,11 @@ class FindTest extends TestCase
return $options; return $options;
} }
private function getInvalidHintValues()
{
return [123, 3.14, true];
}
/** /**
* @expectedException MongoDB\Exception\InvalidArgumentException * @expectedException MongoDB\Exception\InvalidArgumentException
* @dataProvider provideInvalidConstructorCursorTypeOptions * @dataProvider provideInvalidConstructorCursorTypeOptions
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment