diff --git a/src/Collection.php b/src/Collection.php index 749163f33..a796d1e9a 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -5,6 +5,7 @@ use MongoDB\Driver\Command; use MongoDB\Driver\Cursor; use MongoDB\Driver\Manager; +use MongoDB\Driver\ReadConcern; use MongoDB\Driver\ReadPreference; use MongoDB\Driver\Server; use MongoDB\Driver\WriteConcern; @@ -42,6 +43,7 @@ class Collection private $collectionName; private $databaseName; private $manager; + private $readConcern; private $readPreference; private $writeConcern; @@ -53,6 +55,9 @@ class Collection * * Supported options: * + * * readConcern (MongoDB\Driver\ReadConcern): The default read concern to + * use for collection operations. Defaults to the Manager's read concern. + * * * readPreference (MongoDB\Driver\ReadPreference): The default read * preference to use for collection operations. Defaults to the Manager's * read preference. @@ -77,6 +82,10 @@ public function __construct(Manager $manager, $namespace, array $options = []) $this->databaseName = $parts[0]; $this->collectionName = $parts[1]; + if (isset($options['readConcern']) && ! $options['readConcern'] instanceof ReadConcern) { + throw new InvalidArgumentTypeException('"readConcern" option', $options['readConcern'], 'MongoDB\Driver\ReadConcern'); + } + if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) { throw new InvalidArgumentTypeException('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference'); } @@ -86,6 +95,7 @@ public function __construct(Manager $manager, $namespace, array $options = []) } $this->manager = $manager; + $this->readConcern = isset($options['readConcern']) ? $options['readConcern'] : $this->manager->getReadConcern(); $this->readPreference = isset($options['readPreference']) ? $options['readPreference'] : $this->manager->getReadPreference(); $this->writeConcern = isset($options['writeConcern']) ? $options['writeConcern'] : $this->manager->getWriteConcern(); } @@ -102,6 +112,7 @@ public function __debugInfo() 'collectionName' => $this->collectionName, 'databaseName' => $this->databaseName, 'manager' => $this->manager, + 'readConcern' => $this->readConcern, 'readPreference' => $this->readPreference, 'writeConcern' => $this->writeConcern, ]; @@ -132,11 +143,20 @@ public function __toString() */ public function aggregate(array $pipeline, array $options = []) { + $hasOutStage = \MongoDB\is_last_pipeline_operator_out($pipeline); + + /* A "majority" read concern is not compatible with the $out stage, so + * avoid providing the Collection's read concern if it would conflict. + */ + if ( ! isset($options['readConcern']) && ! ($hasOutStage && $this->readConcern->getLevel() === ReadConcern::MAJORITY)) { + $options['readConcern'] = $this->readConcern; + } + if ( ! isset($options['readPreference'])) { $options['readPreference'] = $this->readPreference; } - if (\MongoDB\is_last_pipeline_operator_out($pipeline)) { + if ($hasOutStage) { $options['readPreference'] = new ReadPreference(ReadPreference::RP_PRIMARY); } @@ -176,6 +196,10 @@ public function bulkWrite(array $operations, array $options = []) */ public function count($filter = [], array $options = []) { + if ( ! isset($options['readConcern'])) { + $options['readConcern'] = $this->readConcern; + } + if ( ! isset($options['readPreference'])) { $options['readPreference'] = $this->readPreference; } @@ -284,6 +308,10 @@ public function deleteOne($filter, array $options = []) */ public function distinct($fieldName, $filter = [], array $options = []) { + if ( ! isset($options['readConcern'])) { + $options['readConcern'] = $this->readConcern; + } + if ( ! isset($options['readPreference'])) { $options['readPreference'] = $this->readPreference; } @@ -352,6 +380,10 @@ public function dropIndexes() */ public function find($filter = [], array $options = []) { + if ( ! isset($options['readConcern'])) { + $options['readConcern'] = $this->readConcern; + } + if ( ! isset($options['readPreference'])) { $options['readPreference'] = $this->readPreference; } @@ -373,6 +405,10 @@ public function find($filter = [], array $options = []) */ public function findOne($filter = [], array $options = []) { + if ( ! isset($options['readConcern'])) { + $options['readConcern'] = $this->readConcern; + } + if ( ! isset($options['readPreference'])) { $options['readPreference'] = $this->readPreference; } @@ -621,6 +657,10 @@ public function updateOne($filter, $update, array $options = []) * * Supported options: * + * * readConcern (MongoDB\Driver\ReadConcern): The default read concern to + * use for collection operations. Defaults to this Collection's read + * concern. + * * * readPreference (MongoDB\Driver\ReadPreference): The default read * preference to use for collection operations. Defaults to this * Collection's read preference. @@ -634,6 +674,10 @@ public function updateOne($filter, $update, array $options = []) */ public function withOptions(array $options = []) { + if ( ! isset($options['readConcern'])) { + $options['readConcern'] = $this->readConcern; + } + if ( ! isset($options['readPreference'])) { $options['readPreference'] = $this->readPreference; } diff --git a/src/Database.php b/src/Database.php index 038120b3f..4261df9ee 100644 --- a/src/Database.php +++ b/src/Database.php @@ -7,6 +7,7 @@ use MongoDB\Driver\Cursor; use MongoDB\Driver\Manager; use MongoDB\Driver\Query; +use MongoDB\Driver\ReadConcern; use MongoDB\Driver\ReadPreference; use MongoDB\Driver\Server; use MongoDB\Driver\WriteConcern; @@ -22,6 +23,7 @@ class Database { private $databaseName; private $manager; + private $readConcern; private $readPreference; private $writeConcern; @@ -33,6 +35,10 @@ class Database * * Supported options: * + * * readConcern (MongoDB\Driver\ReadConcern): The default read concern to + * use for database operations and selected collections. Defaults to the + * Manager's read concern. + * * * readPreference (MongoDB\Driver\ReadPreference): The default read * preference to use for database operations and selected collections. * Defaults to the Manager's read preference. @@ -52,6 +58,10 @@ public function __construct(Manager $manager, $databaseName, array $options = [] throw new InvalidArgumentException('$databaseName is invalid: ' . $databaseName); } + if (isset($options['readConcern']) && ! $options['readConcern'] instanceof ReadConcern) { + throw new InvalidArgumentTypeException('"readConcern" option', $options['readConcern'], 'MongoDB\Driver\ReadConcern'); + } + if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) { throw new InvalidArgumentTypeException('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference'); } @@ -62,6 +72,7 @@ public function __construct(Manager $manager, $databaseName, array $options = [] $this->manager = $manager; $this->databaseName = (string) $databaseName; + $this->readConcern = isset($options['readConcern']) ? $options['readConcern'] : $this->manager->getReadConcern(); $this->readPreference = isset($options['readPreference']) ? $options['readPreference'] : $this->manager->getReadPreference(); $this->writeConcern = isset($options['writeConcern']) ? $options['writeConcern'] : $this->manager->getWriteConcern(); } @@ -77,6 +88,7 @@ public function __debugInfo() return [ 'databaseName' => $this->databaseName, 'manager' => $this->manager, + 'readConcern' => $this->readConcern, 'readPreference' => $this->readPreference, 'writeConcern' => $this->writeConcern, ]; @@ -191,6 +203,10 @@ public function listCollections(array $options = []) * * Supported options: * + * * readConcern (MongoDB\Driver\ReadConcern): The default read concern to + * use for collection operations. Defaults to the Database's read + * concern. + * * * readPreference (MongoDB\Driver\ReadPreference): The default read * preference to use for collection operations. Defaults to the * Database's read preference. @@ -205,6 +221,10 @@ public function listCollections(array $options = []) */ public function selectCollection($collectionName, array $options = []) { + if ( ! isset($options['readConcern'])) { + $options['readConcern'] = $this->readConcern; + } + if ( ! isset($options['readPreference'])) { $options['readPreference'] = $this->readPreference; } @@ -221,6 +241,10 @@ public function selectCollection($collectionName, array $options = []) * * Supported options: * + * * readConcern (MongoDB\Driver\ReadConcern): The default read concern to + * use for database operations and selected collections. Defaults to this + * Database's read concern. + * * * readPreference (MongoDB\Driver\ReadPreference): The default read * preference to use for database operations and selected collections. * Defaults to this Database's read preference. @@ -234,6 +258,10 @@ public function selectCollection($collectionName, array $options = []) */ public function withOptions(array $options = []) { + if ( ! isset($options['readConcern'])) { + $options['readConcern'] = $this->readConcern; + } + if ( ! isset($options['readPreference'])) { $options['readPreference'] = $this->readPreference; } diff --git a/src/Operation/Aggregate.php b/src/Operation/Aggregate.php index 01bc57880..fa47a38c5 100644 --- a/src/Operation/Aggregate.php +++ b/src/Operation/Aggregate.php @@ -3,6 +3,7 @@ namespace MongoDB\Operation; use MongoDB\Driver\Command; +use MongoDB\Driver\ReadConcern; use MongoDB\Driver\ReadPreference; use MongoDB\Driver\Server; use MongoDB\Exception\InvalidArgumentException; @@ -23,6 +24,7 @@ class Aggregate implements Executable { private static $wireVersionForCursor = 2; private static $wireVersionForDocumentLevelValidation = 4; + private static $wireVersionForReadConcern = 4; private $databaseName; private $collectionName; @@ -50,6 +52,12 @@ class Aggregate implements Executable * * maxTimeMS (integer): The maximum amount of time to allow the query to * run. * + * * readConcern (MongoDB\Driver\ReadConcern): Read concern. Note that a + * "majority" read concern is not compatible with the $out stage. + * + * For servers < 3.2, this option is ignored as read concern is not + * available. + * * * readPreference (MongoDB\Driver\ReadPreference): Read preference. * * * useCursor (boolean): Indicates whether the command will request that @@ -108,6 +116,10 @@ public function __construct($databaseName, $collectionName, array $pipeline, arr throw new InvalidArgumentTypeException('"maxTimeMS" option', $options['maxTimeMS'], 'integer'); } + if (isset($options['readConcern']) && ! $options['readConcern'] instanceof ReadConcern) { + throw new InvalidArgumentTypeException('"readConcern" option', $options['readConcern'], 'MongoDB\Driver\ReadConcern'); + } + if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) { throw new InvalidArgumentTypeException('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference'); } @@ -183,6 +195,10 @@ private function createCommand(Server $server, $isCursorSupported) $cmd['maxTimeMS'] = $this->options['maxTimeMS']; } + if (isset($this->options['readConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) { + $cmd['readConcern'] = \MongoDB\read_concern_as_document($this->options['readConcern']); + } + if ($this->options['useCursor']) { $cmd['cursor'] = isset($this->options["batchSize"]) ? ['batchSize' => $this->options["batchSize"]] diff --git a/src/Operation/Count.php b/src/Operation/Count.php index 2d3a7dadd..b614e6292 100644 --- a/src/Operation/Count.php +++ b/src/Operation/Count.php @@ -3,6 +3,7 @@ namespace MongoDB\Operation; use MongoDB\Driver\Command; +use MongoDB\Driver\ReadConcern; use MongoDB\Driver\ReadPreference; use MongoDB\Driver\Server; use MongoDB\Exception\InvalidArgumentException; @@ -18,6 +19,8 @@ */ class Count implements Executable { + private static $wireVersionForReadConcern = 4; + private $databaseName; private $collectionName; private $filter; @@ -36,6 +39,11 @@ class Count implements Executable * * maxTimeMS (integer): The maximum amount of time to allow the query to * run. * + * * readConcern (MongoDB\Driver\ReadConcern): Read concern. + * + * For servers < 3.2, this option is ignored as read concern is not + * available. + * * * readPreference (MongoDB\Driver\ReadPreference): Read preference. * * * skip (integer): The number of documents to skip before returning the @@ -71,6 +79,10 @@ public function __construct($databaseName, $collectionName, $filter = [], array throw new InvalidArgumentTypeException('"maxTimeMS" option', $options['maxTimeMS'], 'integer'); } + if (isset($options['readConcern']) && ! $options['readConcern'] instanceof ReadConcern) { + throw new InvalidArgumentTypeException('"readConcern" option', $options['readConcern'], 'MongoDB\Driver\ReadConcern'); + } + if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) { throw new InvalidArgumentTypeException('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference'); } @@ -96,7 +108,7 @@ public function execute(Server $server) { $readPreference = isset($this->options['readPreference']) ? $this->options['readPreference'] : null; - $cursor = $server->executeCommand($this->databaseName, $this->createCommand(), $readPreference); + $cursor = $server->executeCommand($this->databaseName, $this->createCommand($server), $readPreference); $result = current($cursor->toArray()); // Older server versions may return a float @@ -110,9 +122,10 @@ public function execute(Server $server) /** * Create the count command. * + * @param Server $server * @return Command */ - private function createCommand() + private function createCommand(Server $server) { $cmd = ['count' => $this->collectionName]; @@ -126,6 +139,10 @@ private function createCommand() } } + if (isset($this->options['readConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) { + $cmd['readConcern'] = \MongoDB\read_concern_as_document($this->options['readConcern']); + } + return new Command($cmd); } } diff --git a/src/Operation/Distinct.php b/src/Operation/Distinct.php index 01ae8b7de..14435cc23 100644 --- a/src/Operation/Distinct.php +++ b/src/Operation/Distinct.php @@ -3,6 +3,7 @@ namespace MongoDB\Operation; use MongoDB\Driver\Command; +use MongoDB\Driver\ReadConcern; use MongoDB\Driver\ReadPreference; use MongoDB\Driver\Server; use MongoDB\Exception\InvalidArgumentException; @@ -18,6 +19,8 @@ */ class Distinct implements Executable { + private static $wireVersionForReadConcern = 4; + private $databaseName; private $collectionName; private $fieldName; @@ -32,6 +35,11 @@ class Distinct implements Executable * * maxTimeMS (integer): The maximum amount of time to allow the query to * run. * + * * readConcern (MongoDB\Driver\ReadConcern): Read concern. + * + * For servers < 3.2, this option is ignored as read concern is not + * available. + * * * readPreference (MongoDB\Driver\ReadPreference): Read preference. * * @param string $databaseName Database name @@ -51,6 +59,10 @@ public function __construct($databaseName, $collectionName, $fieldName, $filter throw new InvalidArgumentTypeException('"maxTimeMS" option', $options['maxTimeMS'], 'integer'); } + if (isset($options['readConcern']) && ! $options['readConcern'] instanceof ReadConcern) { + throw new InvalidArgumentTypeException('"readConcern" option', $options['readConcern'], 'MongoDB\Driver\ReadConcern'); + } + if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) { throw new InvalidArgumentTypeException('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference'); } @@ -73,7 +85,7 @@ public function execute(Server $server) { $readPreference = isset($this->options['readPreference']) ? $this->options['readPreference'] : null; - $cursor = $server->executeCommand($this->databaseName, $this->createCommand(), $readPreference); + $cursor = $server->executeCommand($this->databaseName, $this->createCommand($server), $readPreference); $result = current($cursor->toArray()); if ( ! isset($result->values) || ! is_array($result->values)) { @@ -86,9 +98,10 @@ public function execute(Server $server) /** * Create the distinct command. * + * @param Server $server * @return Command */ - private function createCommand() + private function createCommand(Server $server) { $cmd = [ 'distinct' => $this->collectionName, @@ -103,6 +116,10 @@ private function createCommand() $cmd['maxTimeMS'] = $this->options['maxTimeMS']; } + if (isset($this->options['readConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) { + $cmd['readConcern'] = \MongoDB\read_concern_as_document($this->options['readConcern']); + } + return new Command($cmd); } } diff --git a/src/Operation/Find.php b/src/Operation/Find.php index a4011879e..a4c0554ac 100644 --- a/src/Operation/Find.php +++ b/src/Operation/Find.php @@ -3,6 +3,7 @@ namespace MongoDB\Operation; use MongoDB\Driver\Query; +use MongoDB\Driver\ReadConcern; use MongoDB\Driver\ReadPreference; use MongoDB\Driver\Server; use MongoDB\Exception\InvalidArgumentException; @@ -65,6 +66,11 @@ class Find implements Executable * * projection (document): Limits the fields to return for the matching * document. * + * * readConcern (MongoDB\Driver\ReadConcern): Read concern. + * + * For servers < 3.2, this option is ignored as read concern is not + * available. + * * * readPreference (MongoDB\Driver\ReadPreference): Read preference. * * * skip (integer): The number of documents to skip before returning. @@ -133,6 +139,10 @@ public function __construct($databaseName, $collectionName, $filter, array $opti throw new InvalidArgumentTypeException('"projection" option', $options['projection'], 'array or object'); } + if (isset($options['readConcern']) && ! $options['readConcern'] instanceof ReadConcern) { + throw new InvalidArgumentTypeException('"readConcern" option', $options['readConcern'], 'MongoDB\Driver\ReadConcern'); + } + if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) { throw new InvalidArgumentTypeException('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference'); } @@ -188,7 +198,7 @@ private function createQuery() } } - foreach (['batchSize', 'limit', 'skip', 'sort', 'noCursorTimeout', 'oplogReplay', 'projection'] as $option) { + foreach (['batchSize', 'limit', 'skip', 'sort', 'noCursorTimeout', 'oplogReplay', 'projection', 'readConcern'] as $option) { if (isset($this->options[$option])) { $options[$option] = $this->options[$option]; } diff --git a/src/Operation/FindOne.php b/src/Operation/FindOne.php index 48b1c80ed..58fb884d9 100644 --- a/src/Operation/FindOne.php +++ b/src/Operation/FindOne.php @@ -36,6 +36,11 @@ class FindOne implements Executable * * projection (document): Limits the fields to return for the matching * document. * + * * readConcern (MongoDB\Driver\ReadConcern): Read concern. + * + * For servers < 3.2, this option is ignored as read concern is not + * available. + * * * readPreference (MongoDB\Driver\ReadPreference): Read preference. * * * skip (integer): The number of documents to skip before returning. diff --git a/src/functions.php b/src/functions.php index d66cf1e3b..26c72d169 100644 --- a/src/functions.php +++ b/src/functions.php @@ -2,8 +2,10 @@ namespace MongoDB; +use MongoDB\Driver\ReadConcern; use MongoDB\Driver\Server; use MongoDB\Exception\InvalidArgumentTypeException; +use stdClass; /** * Return whether the first key in the document starts with a "$" character. @@ -81,6 +83,25 @@ function generate_index_name($document) return $name; } +/** + * Converts a ReadConcern instance to a stdClass for use in a BSON document. + * + * @internal + * @see https://jira.mongodb.org/browse/PHPC-498 + * @param ReadConcern $readConcern Read concern + * @return stdClass + */ +function read_concern_as_document(ReadConcern $readConcern) +{ + $document = []; + + if ($readConcern->getLevel() !== null) { + $document['level'] = $readConcern->getLevel(); + } + + return (object) $document; +} + /** * Return whether the server supports a particular feature. * diff --git a/tests/Collection/CollectionFunctionalTest.php b/tests/Collection/CollectionFunctionalTest.php index 6b94ec245..ed24e096c 100644 --- a/tests/Collection/CollectionFunctionalTest.php +++ b/tests/Collection/CollectionFunctionalTest.php @@ -4,6 +4,7 @@ use MongoDB\Collection; use MongoDB\Driver\BulkWrite; +use MongoDB\Driver\ReadConcern; use MongoDB\Driver\ReadPreference; use MongoDB\Driver\WriteConcern; @@ -114,6 +115,7 @@ public function testFindOne() public function testWithOptionsInheritsReadPreferenceAndWriteConcern() { $collectionOptions = [ + 'readConcern' => new ReadConcern(ReadConcern::LOCAL), 'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED), 'writeConcern' => new WriteConcern(WriteConcern::MAJORITY), ]; @@ -122,6 +124,8 @@ public function testWithOptionsInheritsReadPreferenceAndWriteConcern() $clone = $collection->withOptions(); $debug = $clone->__debugInfo(); + $this->assertInstanceOf('MongoDB\Driver\ReadConcern', $debug['readConcern']); + $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel()); $this->assertInstanceOf('MongoDB\Driver\ReadPreference', $debug['readPreference']); $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode()); $this->assertInstanceOf('MongoDB\Driver\WriteConcern', $debug['writeConcern']); @@ -131,6 +135,7 @@ public function testWithOptionsInheritsReadPreferenceAndWriteConcern() public function testWithOptionsPassesReadPreferenceAndWriteConcern() { $collectionOptions = [ + 'readConcern' => new ReadConcern(ReadConcern::LOCAL), 'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED), 'writeConcern' => new WriteConcern(WriteConcern::MAJORITY), ]; @@ -138,6 +143,8 @@ public function testWithOptionsPassesReadPreferenceAndWriteConcern() $clone = $this->collection->withOptions($collectionOptions); $debug = $clone->__debugInfo(); + $this->assertInstanceOf('MongoDB\Driver\ReadConcern', $debug['readConcern']); + $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel()); $this->assertInstanceOf('MongoDB\Driver\ReadPreference', $debug['readPreference']); $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode()); $this->assertInstanceOf('MongoDB\Driver\WriteConcern', $debug['writeConcern']); diff --git a/tests/Database/DatabaseFunctionalTest.php b/tests/Database/DatabaseFunctionalTest.php index 61bd6e255..267e2aaf4 100644 --- a/tests/Database/DatabaseFunctionalTest.php +++ b/tests/Database/DatabaseFunctionalTest.php @@ -4,6 +4,7 @@ use MongoDB\Database; use MongoDB\Driver\BulkWrite; +use MongoDB\Driver\ReadConcern; use MongoDB\Driver\ReadPreference; use MongoDB\Driver\WriteConcern; @@ -100,9 +101,10 @@ public function testDrop() $this->assertCollectionCount($this->getNamespace(), 0); } - public function testSelectCollectionInheritsReadPreferenceAndWriteConcern() + public function testSelectCollectionInheritsOptions() { $databaseOptions = [ + 'readConcern' => new ReadConcern(ReadConcern::LOCAL), 'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED), 'writeConcern' => new WriteConcern(WriteConcern::MAJORITY), ]; @@ -111,15 +113,18 @@ public function testSelectCollectionInheritsReadPreferenceAndWriteConcern() $collection = $database->selectCollection($this->getCollectionName()); $debug = $collection->__debugInfo(); + $this->assertInstanceOf('MongoDB\Driver\ReadConcern', $debug['readConcern']); + $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel()); $this->assertInstanceOf('MongoDB\Driver\ReadPreference', $debug['readPreference']); $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode()); $this->assertInstanceOf('MongoDB\Driver\WriteConcern', $debug['writeConcern']); $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); } - public function testSelectCollectionPassesReadPreferenceAndWriteConcern() + public function testSelectCollectionPassesOptions() { $collectionOptions = [ + 'readConcern' => new ReadConcern(ReadConcern::LOCAL), 'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED), 'writeConcern' => new WriteConcern(WriteConcern::MAJORITY), ]; @@ -127,15 +132,18 @@ public function testSelectCollectionPassesReadPreferenceAndWriteConcern() $collection = $this->database->selectCollection($this->getCollectionName(), $collectionOptions); $debug = $collection->__debugInfo(); + $this->assertInstanceOf('MongoDB\Driver\ReadConcern', $debug['readConcern']); + $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel()); $this->assertInstanceOf('MongoDB\Driver\ReadPreference', $debug['readPreference']); $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode()); $this->assertInstanceOf('MongoDB\Driver\WriteConcern', $debug['writeConcern']); $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); } - public function testWithOptionsInheritsReadPreferenceAndWriteConcern() + public function testWithOptionsInheritsOptions() { $databaseOptions = [ + 'readConcern' => new ReadConcern(ReadConcern::LOCAL), 'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED), 'writeConcern' => new WriteConcern(WriteConcern::MAJORITY), ]; @@ -144,15 +152,18 @@ public function testWithOptionsInheritsReadPreferenceAndWriteConcern() $clone = $database->withOptions(); $debug = $clone->__debugInfo(); + $this->assertInstanceOf('MongoDB\Driver\ReadConcern', $debug['readConcern']); + $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel()); $this->assertInstanceOf('MongoDB\Driver\ReadPreference', $debug['readPreference']); $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode()); $this->assertInstanceOf('MongoDB\Driver\WriteConcern', $debug['writeConcern']); $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); } - public function testWithOptionsPassesReadPreferenceAndWriteConcern() + public function testWithOptionsPassesOptions() { $databaseOptions = [ + 'readConcern' => new ReadConcern(ReadConcern::LOCAL), 'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED), 'writeConcern' => new WriteConcern(WriteConcern::MAJORITY), ]; @@ -160,6 +171,8 @@ public function testWithOptionsPassesReadPreferenceAndWriteConcern() $clone = $this->database->withOptions($databaseOptions); $debug = $clone->__debugInfo(); + $this->assertInstanceOf('MongoDB\Driver\ReadConcern', $debug['readConcern']); + $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel()); $this->assertInstanceOf('MongoDB\Driver\ReadPreference', $debug['readPreference']); $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode()); $this->assertInstanceOf('MongoDB\Driver\WriteConcern', $debug['writeConcern']); diff --git a/tests/FunctionsTest.php b/tests/FunctionsTest.php new file mode 100644 index 000000000..176a3b934 --- /dev/null +++ b/tests/FunctionsTest.php @@ -0,0 +1,28 @@ +assertEquals($expectedDocument, \MongoDB\read_concern_as_document($readConcern)); + } + + public function provideReadConcernsAndDocuments() + { + return [ + [ new ReadConcern, (object) [] ], + [ new ReadConcern(ReadConcern::LOCAL), (object) ['level' => ReadConcern::LOCAL] ], + [ new ReadConcern(ReadConcern::MAJORITY), (object) ['level' => ReadConcern::MAJORITY] ], + ]; + } +} diff --git a/tests/Operation/AggregateTest.php b/tests/Operation/AggregateTest.php index 287cfc06b..ed53920f7 100644 --- a/tests/Operation/AggregateTest.php +++ b/tests/Operation/AggregateTest.php @@ -53,6 +53,10 @@ public function provideInvalidConstructorOptions() $options[][] = ['maxTimeMS' => $value]; } + foreach ($this->getInvalidReadConcernValues() as $value) { + $options[][] = ['readConcern' => $value]; + } + foreach ($this->getInvalidReadPreferenceValues() as $value) { $options[][] = ['readPreference' => $value]; } diff --git a/tests/Operation/CountTest.php b/tests/Operation/CountTest.php index a3e5abde4..5094a30a3 100644 --- a/tests/Operation/CountTest.php +++ b/tests/Operation/CountTest.php @@ -40,6 +40,10 @@ public function provideInvalidConstructorOptions() $options[][] = ['maxTimeMS' => $value]; } + foreach ($this->getInvalidReadConcernValues() as $value) { + $options[][] = ['readConcern' => $value]; + } + foreach ($this->getInvalidReadPreferenceValues() as $value) { $options[][] = ['readPreference' => $value]; } diff --git a/tests/Operation/DistinctTest.php b/tests/Operation/DistinctTest.php index b4ba88cfc..9a200323f 100644 --- a/tests/Operation/DistinctTest.php +++ b/tests/Operation/DistinctTest.php @@ -32,6 +32,10 @@ public function provideInvalidConstructorOptions() $options[][] = ['maxTimeMS' => $value]; } + foreach ($this->getInvalidReadConcernValues() as $value) { + $options[][] = ['readConcern' => $value]; + } + foreach ($this->getInvalidReadPreferenceValues() as $value) { $options[][] = ['readPreference' => $value]; } diff --git a/tests/Operation/FindTest.php b/tests/Operation/FindTest.php index 649016b8b..57ef09914 100644 --- a/tests/Operation/FindTest.php +++ b/tests/Operation/FindTest.php @@ -64,6 +64,10 @@ public function provideInvalidConstructorOptions() $options[][] = ['projection' => $value]; } + foreach ($this->getInvalidReadConcernValues() as $value) { + $options[][] = ['readConcern' => $value]; + } + foreach ($this->getInvalidReadPreferenceValues() as $value) { $options[][] = ['readPreference' => $value]; } diff --git a/tests/TestCase.php b/tests/TestCase.php index d1891df04..6ebaa3b60 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -2,6 +2,9 @@ namespace MongoDB\Tests; +use MongoDB\Driver\ReadConcern; +use MongoDB\Driver\ReadPreference; +use MongoDB\Driver\WriteConcern; use ReflectionClass; use stdClass; @@ -74,6 +77,16 @@ protected function getInvalidIntegerValues() return [3.14, 'foo', true, [], new stdClass]; } + /** + * Return a list of invalid ReadPreference values. + * + * @return array + */ + protected function getInvalidReadConcernValues() + { + return [123, 3.14, 'foo', true, [], new stdClass, new ReadPreference(ReadPreference::RP_PRIMARY), new WriteConcern(1)]; + } + /** * Return a list of invalid ReadPreference values. * @@ -81,7 +94,7 @@ protected function getInvalidIntegerValues() */ protected function getInvalidReadPreferenceValues() { - return [123, 3.14, 'foo', true, [], new stdClass]; + return [123, 3.14, 'foo', true, [], new stdClass, new ReadConcern, new WriteConcern(1)]; } /** @@ -101,7 +114,7 @@ protected function getInvalidStringValues() */ protected function getInvalidWriteConcernValues() { - return [123, 3.14, 'foo', true, [], new stdClass]; + return [123, 3.14, 'foo', true, [], new stdClass, new ReadConcern, new ReadPreference(ReadPreference::RP_PRIMARY)]; } /**