Commit 01df4415 authored by Jeremy Mikola's avatar Jeremy Mikola

PHPLIB-497: Allow passing hint to findAndModify update/replace ops

parent 23e32ddc
......@@ -10,6 +10,15 @@ source:
file: apiargs-MongoDBCollection-common-option.yaml
ref: collation
---
source:
file: apiargs-common-option.yaml
ref: hint
post: |
This option is available in MongoDB 4.4+ and will result in an exception at
execution time if specified for an older server version.
.. versionadded:: 1.7
---
source:
file: apiargs-common-option.yaml
ref: maxTimeMS
......
......@@ -16,6 +16,15 @@ source:
file: apiargs-MongoDBCollection-common-option.yaml
ref: collation
---
source:
file: apiargs-common-option.yaml
ref: hint
post: |
This option is available in MongoDB 4.4+ and will result in an exception at
execution time if specified for an older server version.
.. versionadded:: 1.7
---
source:
file: apiargs-common-option.yaml
ref: maxTimeMS
......
......@@ -30,6 +30,7 @@ use function is_array;
use function is_bool;
use function is_integer;
use function is_object;
use function is_string;
use function MongoDB\create_field_path_type_map;
use function MongoDB\is_pipeline;
use function MongoDB\server_supports_feature;
......@@ -54,6 +55,9 @@ class FindAndModify implements Executable, Explainable
/** @var integer */
private static $wireVersionForDocumentLevelValidation = 4;
/** @var integer */
private static $wireVersionForHintServerSideError = 8;
/** @var integer */
private static $wireVersionForWriteConcern = 4;
......@@ -91,6 +95,14 @@ class FindAndModify implements Executable, Explainable
* * fields (document): Limits the fields to return for the matching
* document.
*
* * 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.
*
* This is only supported for update and replace operations (i.e. remove
* option is false) on server versions >= 4.4. Using this option in
* other contexts will result in an exception at execution time.
*
* * maxTimeMS (integer): The maximum amount of time to allow the query to
* run.
*
......@@ -153,6 +165,10 @@ class FindAndModify implements Executable, Explainable
throw InvalidArgumentException::invalidType('"fields" option', $options['fields'], 'array or object');
}
if (isset($options['hint']) && ! is_string($options['hint']) && ! is_array($options['hint']) && ! is_object($options['hint'])) {
throw InvalidArgumentException::invalidType('"hint" option', $options['hint'], ['string', 'array', 'object']);
}
if (isset($options['maxTimeMS']) && ! is_integer($options['maxTimeMS'])) {
throw InvalidArgumentException::invalidType('"maxTimeMS" option', $options['maxTimeMS'], 'integer');
}
......@@ -226,6 +242,14 @@ class FindAndModify implements Executable, Explainable
throw UnsupportedException::collationNotSupported();
}
/* Server versions >= 4.1.10 raise errors for unknown findAndModify
* options (SERVER-40005), but the CRUD spec requires client-side errors
* for server versions < 4.2. For later versions, we'll rely on the
* server to either utilize the option or report its own error. */
if (isset($this->options['hint']) && ! server_supports_feature($server, self::$wireVersionForHintServerSideError)) {
throw UnsupportedException::hintNotSupported();
}
if (isset($this->options['writeConcern']) && ! server_supports_feature($server, self::$wireVersionForWriteConcern)) {
throw UnsupportedException::writeConcernNotSupported();
}
......@@ -280,12 +304,10 @@ class FindAndModify implements Executable, Explainable
: (object) $this->options['update'];
}
if (isset($this->options['arrayFilters'])) {
$cmd['arrayFilters'] = $this->options['arrayFilters'];
}
if (isset($this->options['maxTimeMS'])) {
$cmd['maxTimeMS'] = $this->options['maxTimeMS'];
foreach (['arrayFilters', 'hint', 'maxTimeMS'] as $option) {
if (isset($this->options[$option])) {
$cmd[$option] = $this->options[$option];
}
}
if (! empty($this->options['bypassDocumentValidation']) &&
......
......@@ -57,6 +57,13 @@ class FindOneAndReplace implements Executable, Explainable
* This is not supported for server versions < 3.4 and will result in an
* exception at execution time if used.
*
* * 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.
*
* This is not supported for server versions < 4.4 and will result in an
* exception at execution time if used.
*
* * maxTimeMS (integer): The maximum amount of time to allow the query to
* run.
*
......
......@@ -61,6 +61,13 @@ class FindOneAndUpdate implements Executable, Explainable
* This is not supported for server versions < 3.4 and will result in an
* exception at execution time if used.
*
* * 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.
*
* This is not supported for server versions < 4.4 and will result in an
* exception at execution time if used.
*
* * maxTimeMS (integer): The maximum amount of time to allow the query to
* run.
*
......
{
"runOn": [
{
"maxServerVersion": "4.0.99"
}
],
"data": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
}
],
"collection_name": "findOneAndReplace_hint",
"tests": [
{
"description": "FindOneAndReplace with hint string unsupported (client-side error)",
"operations": [
{
"object": "collection",
"name": "findOneAndReplace",
"arguments": {
"filter": {
"_id": 1
},
"replacement": {
"x": 33
},
"hint": "_id_"
},
"error": true
}
],
"expectations": [],
"outcome": {
"collection": {
"data": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
}
]
}
}
},
{
"description": "FindOneAndReplace with hint document unsupported (client-side error)",
"operations": [
{
"object": "collection",
"name": "findOneAndReplace",
"arguments": {
"filter": {
"_id": 1
},
"replacement": {
"x": 33
},
"hint": {
"_id": 1
}
},
"error": true
}
],
"expectations": [],
"outcome": {
"collection": {
"data": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
}
]
}
}
}
]
}
{
"runOn": [
{
"minServerVersion": "4.2.0",
"maxServerVersion": "4.3.0"
}
],
"data": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
}
],
"collection_name": "findOneAndReplace_hint",
"tests": [
{
"description": "FindOneAndReplace with hint string unsupported (server-side error)",
"operations": [
{
"object": "collection",
"name": "findOneAndReplace",
"arguments": {
"filter": {
"_id": 1
},
"replacement": {
"x": 33
},
"hint": "_id_"
},
"error": true
}
],
"expectations": [
{
"command_started_event": {
"command": {
"findAndModify": "findOneAndReplace_hint",
"query": {
"_id": 1
},
"update": {
"x": 33
},
"hint": "_id_"
}
}
}
],
"outcome": {
"collection": {
"data": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
}
]
}
}
},
{
"description": "FindOneAndReplace with hint document unsupported (server-side error)",
"operations": [
{
"object": "collection",
"name": "findOneAndReplace",
"arguments": {
"filter": {
"_id": 1
},
"replacement": {
"x": 33
},
"hint": {
"_id": 1
}
},
"error": true
}
],
"expectations": [
{
"command_started_event": {
"command": {
"findAndModify": "findOneAndReplace_hint",
"query": {
"_id": 1
},
"update": {
"x": 33
},
"hint": {
"_id": 1
}
}
}
}
],
"outcome": {
"collection": {
"data": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
}
]
}
}
}
]
}
{
"runOn": [
{
"minServerVersion": "4.3.1"
}
],
"data": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
}
],
"collection_name": "findOneAndReplace_hint",
"tests": [
{
"description": "FindOneAndReplace with hint string",
"operations": [
{
"object": "collection",
"name": "findOneAndReplace",
"arguments": {
"filter": {
"_id": 1
},
"replacement": {
"x": 33
},
"hint": "_id_"
},
"result": {
"_id": 1,
"x": 11
}
}
],
"expectations": [
{
"command_started_event": {
"command": {
"findAndModify": "findOneAndReplace_hint",
"query": {
"_id": 1
},
"update": {
"x": 33
},
"hint": "_id_"
}
}
}
],
"outcome": {
"collection": {
"data": [
{
"_id": 1,
"x": 33
},
{
"_id": 2,
"x": 22
}
]
}
}
},
{
"description": "FindOneAndReplace with hint document",
"operations": [
{
"object": "collection",
"name": "findOneAndReplace",
"arguments": {
"filter": {
"_id": 1
},
"replacement": {
"x": 33
},
"hint": {
"_id": 1
}
},
"result": {
"_id": 1,
"x": 11
}
}
],
"expectations": [
{
"command_started_event": {
"command": {
"findAndModify": "findOneAndReplace_hint",
"query": {
"_id": 1
},
"update": {
"x": 33
},
"hint": {
"_id": 1
}
}
}
}
],
"outcome": {
"collection": {
"data": [
{
"_id": 1,
"x": 33
},
{
"_id": 2,
"x": 22
}
]
}
}
}
]
}
{
"runOn": [
{
"maxServerVersion": "4.0.99"
}
],
"data": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
}
],
"collection_name": "findOneAndUpdate_hint",
"tests": [
{
"description": "FindOneAndUpdate with hint string unsupported (client-side error)",
"operations": [
{
"object": "collection",
"name": "findOneAndUpdate",
"arguments": {
"filter": {
"_id": 1
},
"update": {
"$inc": {
"x": 1
}
},
"hint": "_id_"
},
"error": true
}
],
"expectations": [],
"outcome": {
"collection": {
"data": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
}
]
}
}
},
{
"description": "FindOneAndUpdate with hint document unsupported (client-side error)",
"operations": [
{
"object": "collection",
"name": "findOneAndUpdate",
"arguments": {
"filter": {
"_id": 1
},
"update": {
"$inc": {
"x": 1
}
},
"hint": {
"_id": 1
}
},
"error": true
}
],
"expectations": [],
"outcome": {
"collection": {
"data": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
}
]
}
}
}
]
}
{
"runOn": [
{
"minServerVersion": "4.2.0",
"maxServerVersion": "4.3.0"
}
],
"data": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
}
],
"collection_name": "findOneAndUpdate_hint",
"tests": [
{
"description": "FindOneAndUpdate with hint string unsupported (server-side error)",
"operations": [
{
"object": "collection",
"name": "findOneAndUpdate",
"arguments": {
"filter": {
"_id": 1
},
"update": {
"$inc": {
"x": 1
}
},
"hint": "_id_"
},
"error": true
}
],
"expectations": [
{
"command_started_event": {
"command": {
"findAndModify": "findOneAndUpdate_hint",
"query": {
"_id": 1
},
"update": {
"$inc": {
"x": 1
}
},
"hint": "_id_"
}
}
}
],
"outcome": {
"collection": {
"data": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
}
]
}
}
},
{
"description": "FindOneAndUpdate with hint document unsupported (server-side error)",
"operations": [
{
"object": "collection",
"name": "findOneAndUpdate",
"arguments": {
"filter": {
"_id": 1
},
"update": {
"$inc": {
"x": 1
}
},
"hint": {
"_id": 1
}
},
"error": true
}
],
"expectations": [
{
"command_started_event": {
"command": {
"findAndModify": "findOneAndUpdate_hint",
"query": {
"_id": 1
},
"update": {
"$inc": {
"x": 1
}
},
"hint": {
"_id": 1
}
}
}
}
],
"outcome": {
"collection": {
"data": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
}
]
}
}
}
]
}
{
"runOn": [
{
"minServerVersion": "4.3.1"
}
],
"data": [
{
"_id": 1,
"x": 11
},
{
"_id": 2,
"x": 22
}
],
"collection_name": "findOneAndUpdate_hint",
"tests": [
{
"description": "FindOneAndUpdate with hint string",
"operations": [
{
"object": "collection",
"name": "findOneAndUpdate",
"arguments": {
"filter": {
"_id": 1
},
"update": {
"$inc": {
"x": 1
}
},
"hint": "_id_"
},
"result": {
"_id": 1,
"x": 11
}
}
],
"expectations": [
{
"command_started_event": {
"command": {
"findAndModify": "findOneAndUpdate_hint",
"query": {
"_id": 1
},
"update": {
"$inc": {
"x": 1
}
},
"hint": "_id_"
}
}
}
],
"outcome": {
"collection": {
"data": [
{
"_id": 1,
"x": 12
},
{
"_id": 2,
"x": 22
}
]
}
}
},
{
"description": "FindOneAndUpdate with hint document",
"operations": [
{
"object": "collection",
"name": "findOneAndUpdate",
"arguments": {
"filter": {
"_id": 1
},
"update": {
"$inc": {
"x": 1
}
},
"hint": {
"_id": 1
}
},
"result": {
"_id": 1,
"x": 11
}
}
],
"expectations": [
{
"command_started_event": {
"command": {
"findAndModify": "findOneAndUpdate_hint",
"query": {
"_id": 1
},
"update": {
"$inc": {
"x": 1
}
},
"hint": {
"_id": 1
}
}
}
}
],
"outcome": {
"collection": {
"data": [
{
"_id": 1,
"x": 12
},
{
"_id": 2,
"x": 22
}
]
}
}
}
]
}
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