From 7f67f2647044c8077798efddf926bde82726d2a0 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Mon, 23 Sep 2024 14:09:45 +0200 Subject: [PATCH] PHPLIB-1511: Remove deprecated query options --- UPGRADE-2.0.md | 2 + psalm-baseline.xml | 4 -- src/Operation/Find.php | 71 +---------------------- src/Operation/FindOne.php | 15 +---- tests/Operation/ExplainFunctionalTest.php | 24 -------- tests/Operation/FindFunctionalTest.php | 36 ------------ tests/Operation/FindTest.php | 8 --- tests/UnifiedSpecTests/Util.php | 6 +- 8 files changed, 10 insertions(+), 156 deletions(-) diff --git a/UPGRADE-2.0.md b/UPGRADE-2.0.md index 98b8e3bd9..6014e7003 100644 --- a/UPGRADE-2.0.md +++ b/UPGRADE-2.0.md @@ -7,6 +7,8 @@ UPGRADE FROM 1.x to 2.0 * The `MongoDB\Operation\Watch::FULL_DOCUMENT_DEFAULT` constant has been removed. * The `MongoDB\Model\IndexInfo::isGeoHaystack` method has been removed. + * The `maxScan`, `modifiers`, `oplogReplay`, and `snapshot` options for `find` + and `findOne` operations have been removed. GridFS ------ diff --git a/psalm-baseline.xml b/psalm-baseline.xml index ebd214b86..c9376a240 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -708,11 +708,7 @@ options['codec']]]> options['typeMap']]]> - - - - diff --git a/src/Operation/Find.php b/src/Operation/Find.php index 244867dd0..017634c23 100644 --- a/src/Operation/Find.php +++ b/src/Operation/Find.php @@ -34,7 +34,6 @@ use function is_integer; use function is_object; use function is_string; -use function MongoDB\document_to_array; use function MongoDB\is_document; /** @@ -88,28 +87,15 @@ final class Find implements Executable, Explainable * * maxAwaitTimeMS (integer): The maxium amount of time for the server to wait * on new documents to satisfy a query, if cursorType is TAILABLE_AWAIT. * - * * maxScan (integer): Maximum number of documents or index keys to scan - * when executing the query. - * - * This option has been deprecated since version 1.4. - * * * maxTimeMS (integer): The maximum amount of time to allow the query to - * run. If "$maxTimeMS" also exists in the modifiers document, this - * option will take precedence. + * run. * * * min (document): The inclusive upper bound for a specific index. * - * * modifiers (document): Meta operators that modify the output or - * behavior of a query. Use of these operators is deprecated in favor of - * named options. - * * * noCursorTimeout (boolean): The server normally times out idle cursors * after an inactivity period (10 minutes) to prevent excess memory use. * Set this option to prevent that. * - * * oplogReplay (boolean): Internal replication use only. The driver - * should not set this. This option is deprecated as of MongoDB 4.4. - * * * projection (document): Limits the fields to return for the matching * document. * @@ -128,14 +114,7 @@ final class Find implements Executable, Explainable * * * skip (integer): The number of documents to skip before returning. * - * * snapshot (boolean): Prevents the cursor from returning a document more - * than once because of an intervening write operation. - * - * This options has been deprecated since version 1.4. - * - * * sort (document): The order in which to return matching documents. If - * "$orderby" also exists in the modifiers document, this option will - * take precedence. + * * sort (document): The order in which to return matching documents. * * * let (document): Map of parameter names and values. Values must be * constant or closed expressions that do not reference document fields. @@ -207,10 +186,6 @@ public function __construct(private string $databaseName, private string $collec throw InvalidArgumentException::invalidType('"maxAwaitTimeMS" option', $this->options['maxAwaitTimeMS'], 'integer'); } - if (isset($this->options['maxScan']) && ! is_integer($this->options['maxScan'])) { - throw InvalidArgumentException::invalidType('"maxScan" option', $this->options['maxScan'], 'integer'); - } - if (isset($this->options['maxTimeMS']) && ! is_integer($this->options['maxTimeMS'])) { throw InvalidArgumentException::invalidType('"maxTimeMS" option', $this->options['maxTimeMS'], 'integer'); } @@ -219,18 +194,10 @@ public function __construct(private string $databaseName, private string $collec throw InvalidArgumentException::expectedDocumentType('"min" option', $this->options['min']); } - if (isset($this->options['modifiers']) && ! is_document($this->options['modifiers'])) { - throw InvalidArgumentException::expectedDocumentType('"modifiers" option', $this->options['modifiers']); - } - if (isset($this->options['noCursorTimeout']) && ! is_bool($this->options['noCursorTimeout'])) { throw InvalidArgumentException::invalidType('"noCursorTimeout" option', $this->options['noCursorTimeout'], 'boolean'); } - if (isset($this->options['oplogReplay']) && ! is_bool($this->options['oplogReplay'])) { - throw InvalidArgumentException::invalidType('"oplogReplay" option', $this->options['oplogReplay'], 'boolean'); - } - if (isset($this->options['projection']) && ! is_document($this->options['projection'])) { throw InvalidArgumentException::expectedDocumentType('"projection" option', $this->options['projection']); } @@ -259,10 +226,6 @@ public function __construct(private string $databaseName, private string $collec throw InvalidArgumentException::invalidType('"skip" option', $this->options['skip'], 'integer'); } - if (isset($this->options['snapshot']) && ! is_bool($this->options['snapshot'])) { - throw InvalidArgumentException::invalidType('"snapshot" option', $this->options['snapshot'], 'boolean'); - } - if (isset($this->options['sort']) && ! is_document($this->options['sort'])) { throw InvalidArgumentException::expectedDocumentType('"sort" option', $this->options['sort']); } @@ -329,28 +292,6 @@ public function getCommandDocument(): array // maxAwaitTimeMS is a Query level option so should not be considered here unset($options['maxAwaitTimeMS']); - $modifierFallback = [ - ['allowPartialResults', 'partial'], - ['comment', '$comment'], - ['hint', '$hint'], - ['maxScan', '$maxScan'], - ['max', '$max'], - ['maxTimeMS', '$maxTimeMS'], - ['min', '$min'], - ['returnKey', '$returnKey'], - ['showRecordId', '$showDiskLoc'], - ['sort', '$orderby'], - ['snapshot', '$snapshot'], - ]; - - foreach ($modifierFallback as $modifier) { - if (! isset($options[$modifier[0]]) && isset($options['modifiers'][$modifier[1]])) { - $options[$modifier[0]] = $options['modifiers'][$modifier[1]]; - } - } - - unset($options['modifiers']); - return $cmd + $options; } @@ -395,7 +336,7 @@ private function createQueryOptions(): array } } - foreach (['allowDiskUse', 'allowPartialResults', 'batchSize', 'comment', 'hint', 'limit', 'maxAwaitTimeMS', 'maxScan', 'maxTimeMS', 'noCursorTimeout', 'oplogReplay', 'projection', 'readConcern', 'returnKey', 'showRecordId', 'skip', 'snapshot', 'sort'] as $option) { + foreach (['allowDiskUse', 'allowPartialResults', 'batchSize', 'comment', 'hint', 'limit', 'maxAwaitTimeMS', 'maxTimeMS', 'noCursorTimeout', 'projection', 'readConcern', 'returnKey', 'showRecordId', 'skip', 'sort'] as $option) { if (isset($this->options[$option])) { $options[$option] = $this->options[$option]; } @@ -407,12 +348,6 @@ private function createQueryOptions(): array } } - if (! empty($this->options['modifiers'])) { - /** @psalm-var array|object */ - $modifiers = $this->options['modifiers']; - $options['modifiers'] = is_object($modifiers) ? document_to_array($modifiers) : $modifiers; - } - return $options; } } diff --git a/src/Operation/FindOne.php b/src/Operation/FindOne.php index 0290356ee..96ddaeb62 100644 --- a/src/Operation/FindOne.php +++ b/src/Operation/FindOne.php @@ -55,20 +55,11 @@ final class FindOne implements Executable, Explainable * * * max (document): The exclusive upper bound for a specific index. * - * * maxScan (integer): Maximum number of documents or index keys to scan - * when executing the query. - * - * This option has been deprecated since version 1.4. - * * * maxTimeMS (integer): The maximum amount of time to allow the query to - * run. If "$maxTimeMS" also exists in the modifiers document, this - * option will take precedence. + * run. * * * min (document): The inclusive upper bound for a specific index. * - * * modifiers (document): Meta-operators modifying the output or behavior - * of a query. - * * * projection (document): Limits the fields to return for the matching * document. * @@ -87,9 +78,7 @@ final class FindOne implements Executable, Explainable * * * skip (integer): The number of documents to skip before returning. * - * * sort (document): The order in which to return matching documents. If - * "$orderby" also exists in the modifiers document, this option will - * take precedence. + * * sort (document): The order in which to return matching documents. * * * let (document): Map of parameter names and values. Values must be * constant or closed expressions that do not reference document fields. diff --git a/tests/Operation/ExplainFunctionalTest.php b/tests/Operation/ExplainFunctionalTest.php index 486ee4095..adfa35167 100644 --- a/tests/Operation/ExplainFunctionalTest.php +++ b/tests/Operation/ExplainFunctionalTest.php @@ -157,30 +157,6 @@ function (array $event): void { ); } - public function testFindModifiers(): void - { - $this->createFixtures(3); - - $operation = new Find( - $this->getDatabaseName(), - $this->getCollectionName(), - [], - ['modifiers' => ['$orderby' => ['_id' => 1]]], - ); - - (new CommandObserver())->observe( - function () use ($operation): void { - $explainOperation = new Explain($this->getDatabaseName(), $operation, ['typeMap' => ['root' => 'array', 'document' => 'array']]); - $explainOperation->execute($this->getPrimaryServer()); - }, - function (array $event): void { - $command = $event['started']->getCommand(); - $this->assertObjectHasProperty('sort', $command->explain); - $this->assertObjectNotHasProperty('modifiers', $command->explain); - }, - ); - } - /** @dataProvider provideVerbosityInformation */ public function testFindOne($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void { diff --git a/tests/Operation/FindFunctionalTest.php b/tests/Operation/FindFunctionalTest.php index 2a64a7d71..6433c025a 100644 --- a/tests/Operation/FindFunctionalTest.php +++ b/tests/Operation/FindFunctionalTest.php @@ -2,10 +2,8 @@ namespace MongoDB\Tests\Operation; -use MongoDB\BSON\Document; use MongoDB\Driver\BulkWrite; use MongoDB\Driver\ReadPreference; -use MongoDB\Model\BSONDocument; use MongoDB\Operation\CreateIndexes; use MongoDB\Operation\Find; use MongoDB\Tests\CommandObserver; @@ -36,40 +34,6 @@ function (array $event) use ($expectedQuery): void { ); } - /** @dataProvider provideModifierDocuments */ - public function testModifierDocuments($modifiers, stdClass $expectedSort): void - { - (new CommandObserver())->observe( - function () use ($modifiers): void { - $operation = new Find( - $this->getDatabaseName(), - $this->getCollectionName(), - [], - ['modifiers' => $modifiers], - ); - - $this->assertDeprecated( - fn () => $operation->execute($this->getPrimaryServer()), - ); - }, - function (array $event) use ($expectedSort): void { - $this->assertEquals($expectedSort, $event['started']->getCommand()->sort ?? null); - }, - ); - } - - public static function provideModifierDocuments(): array - { - $expectedSort = (object) ['x' => 1]; - - return [ - 'array' => [['$orderby' => ['x' => 1]], $expectedSort], - 'object' => [(object) ['$orderby' => ['x' => 1]], $expectedSort], - 'Serializable' => [new BSONDocument(['$orderby' => ['x' => 1]]), $expectedSort], - 'Document' => [Document::fromPHP(['$orderby' => ['x' => 1]]), $expectedSort], - ]; - } - public function testDefaultReadConcernIsOmitted(): void { (new CommandObserver())->observe( diff --git a/tests/Operation/FindTest.php b/tests/Operation/FindTest.php index 1a88cd6a2..58c4af880 100644 --- a/tests/Operation/FindTest.php +++ b/tests/Operation/FindTest.php @@ -37,11 +37,8 @@ public static function provideInvalidConstructorOptions() 'limit' => self::getInvalidIntegerValues(), 'max' => self::getInvalidDocumentValues(), 'maxAwaitTimeMS' => self::getInvalidIntegerValues(), - 'maxScan' => self::getInvalidIntegerValues(), 'maxTimeMS' => self::getInvalidIntegerValues(), 'min' => self::getInvalidDocumentValues(), - 'modifiers' => self::getInvalidDocumentValues(), - 'oplogReplay' => self::getInvalidBooleanValues(), 'projection' => self::getInvalidDocumentValues(), 'readConcern' => self::getInvalidReadConcernValues(), 'readPreference' => self::getInvalidReadPreferenceValues(), @@ -49,7 +46,6 @@ public static function provideInvalidConstructorOptions() 'session' => self::getInvalidSessionValues(), 'showRecordId' => self::getInvalidBooleanValues(), 'skip' => self::getInvalidIntegerValues(), - 'snapshot' => self::getInvalidBooleanValues(), 'sort' => self::getInvalidDocumentValues(), 'typeMap' => self::getInvalidArrayValues(), ]); @@ -69,7 +65,6 @@ public static function provideInvalidConstructorCursorTypeOptions() public function testExplainableCommandDocument(): void { - // all options except deprecated "snapshot" and "maxScan" $options = [ 'allowDiskUse' => true, 'allowPartialResults' => true, @@ -82,7 +77,6 @@ public function testExplainableCommandDocument(): void 'maxTimeMS' => 100, 'min' => ['x' => 10], 'noCursorTimeout' => true, - 'oplogReplay' => true, 'projection' => ['_id' => 0], 'readConcern' => new ReadConcern(ReadConcern::LOCAL), 'returnKey' => true, @@ -93,7 +87,6 @@ public function testExplainableCommandDocument(): void // Intentionally omitted options 'cursorType' => Find::NON_TAILABLE, 'maxAwaitTimeMS' => 500, - 'modifiers' => ['foo' => 'bar'], 'readPreference' => new ReadPreference(ReadPreference::SECONDARY_PREFERRED), 'typeMap' => ['root' => 'array'], ]; @@ -110,7 +103,6 @@ public function testExplainableCommandDocument(): void 'limit' => 15, 'maxTimeMS' => 100, 'noCursorTimeout' => true, - 'oplogReplay' => true, 'projection' => ['_id' => 0], 'readConcern' => new ReadConcern(ReadConcern::LOCAL), 'returnKey' => true, diff --git a/tests/UnifiedSpecTests/Util.php b/tests/UnifiedSpecTests/Util.php index d817d61d3..5d758ab6a 100644 --- a/tests/UnifiedSpecTests/Util.php +++ b/tests/UnifiedSpecTests/Util.php @@ -87,7 +87,7 @@ final class Util 'aggregate' => ['pipeline', 'session', 'allowDiskUse', 'batchSize', 'bypassDocumentValidation', 'collation', 'comment', 'explain', 'hint', 'let', 'maxAwaitTimeMS', 'maxTimeMS'], 'bulkWrite' => ['let', 'requests', 'session', 'ordered', 'bypassDocumentValidation', 'comment'], 'createChangeStream' => ['pipeline', 'session', 'fullDocument', 'fullDocumentBeforeChange', 'resumeAfter', 'startAfter', 'startAtOperationTime', 'batchSize', 'collation', 'maxAwaitTimeMS', 'comment', 'showExpandedEvents'], - 'createFindCursor' => ['filter', 'session', 'allowDiskUse', 'allowPartialResults', 'batchSize', 'collation', 'comment', 'cursorType', 'hint', 'limit', 'max', 'maxAwaitTimeMS', 'maxScan', 'maxTimeMS', 'min', 'modifiers', 'noCursorTimeout', 'oplogReplay', 'projection', 'returnKey', 'showRecordId', 'skip', 'snapshot', 'sort'], + 'createFindCursor' => ['filter', 'session', 'allowDiskUse', 'allowPartialResults', 'batchSize', 'collation', 'comment', 'cursorType', 'hint', 'limit', 'max', 'maxAwaitTimeMS', 'maxTimeMS', 'min', 'noCursorTimeout', 'projection', 'returnKey', 'showRecordId', 'skip', 'sort'], 'createIndex' => ['keys', 'comment', 'commitQuorum', 'maxTimeMS', 'name', 'session', 'unique'], 'createSearchIndex' => ['model'], 'createSearchIndexes' => ['models'], @@ -101,8 +101,8 @@ final class Util 'distinct' => ['fieldName', 'filter', 'session', 'collation', 'maxTimeMS', 'comment'], 'drop' => ['session', 'comment'], 'dropSearchIndex' => ['name'], - 'find' => ['let', 'filter', 'session', 'allowDiskUse', 'allowPartialResults', 'batchSize', 'collation', 'comment', 'cursorType', 'hint', 'limit', 'max', 'maxAwaitTimeMS', 'maxScan', 'maxTimeMS', 'min', 'modifiers', 'noCursorTimeout', 'oplogReplay', 'projection', 'returnKey', 'showRecordId', 'skip', 'snapshot', 'sort'], - 'findOne' => ['let', 'filter', 'session', 'allowDiskUse', 'allowPartialResults', 'batchSize', 'collation', 'comment', 'cursorType', 'hint', 'max', 'maxAwaitTimeMS', 'maxScan', 'maxTimeMS', 'min', 'modifiers', 'noCursorTimeout', 'oplogReplay', 'projection', 'returnKey', 'showRecordId', 'skip', 'snapshot', 'sort'], + 'find' => ['let', 'filter', 'session', 'allowDiskUse', 'allowPartialResults', 'batchSize', 'collation', 'comment', 'cursorType', 'hint', 'limit', 'max', 'maxAwaitTimeMS', 'maxTimeMS', 'min', 'noCursorTimeout', 'projection', 'returnKey', 'showRecordId', 'skip', 'sort'], + 'findOne' => ['let', 'filter', 'session', 'allowDiskUse', 'allowPartialResults', 'batchSize', 'collation', 'comment', 'cursorType', 'hint', 'max', 'maxAwaitTimeMS', 'maxTimeMS', 'min', 'noCursorTimeout', 'projection', 'returnKey', 'showRecordId', 'skip', 'sort'], 'findOneAndReplace' => ['let', 'returnDocument', 'filter', 'replacement', 'session', 'projection', 'returnDocument', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint', 'maxTimeMS', 'new', 'remove', 'sort', 'comment'], 'rename' => ['to', 'comment', 'dropTarget'], 'replaceOne' => ['let', 'filter', 'replacement', 'session', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint', 'comment'],