Skip to content

PHPLIB-130: Support readConcern option #68

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 23, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 45 additions & 1 deletion src/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -42,6 +43,7 @@ class Collection
private $collectionName;
private $databaseName;
private $manager;
private $readConcern;
private $readPreference;
private $writeConcern;

Expand All @@ -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.
Expand All @@ -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');
}
Expand All @@ -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();
}
Expand All @@ -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,
];
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand Down Expand Up @@ -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.
Expand All @@ -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;
}
Expand Down
28 changes: 28 additions & 0 deletions src/Database.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -22,6 +23,7 @@ class Database
{
private $databaseName;
private $manager;
private $readConcern;
private $readPreference;
private $writeConcern;

Expand All @@ -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.
Expand All @@ -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');
}
Expand All @@ -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();
}
Expand All @@ -77,6 +88,7 @@ public function __debugInfo()
return [
'databaseName' => $this->databaseName,
'manager' => $this->manager,
'readConcern' => $this->readConcern,
'readPreference' => $this->readPreference,
'writeConcern' => $this->writeConcern,
];
Expand Down Expand Up @@ -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.
Expand All @@ -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;
}
Expand All @@ -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.
Expand All @@ -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;
}
Expand Down
16 changes: 16 additions & 0 deletions src/Operation/Aggregate.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -23,6 +24,7 @@ class Aggregate implements Executable
{
private static $wireVersionForCursor = 2;
private static $wireVersionForDocumentLevelValidation = 4;
private static $wireVersionForReadConcern = 4;

private $databaseName;
private $collectionName;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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');
}
Expand Down Expand Up @@ -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"]]
Expand Down
21 changes: 19 additions & 2 deletions src/Operation/Count.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -18,6 +19,8 @@
*/
class Count implements Executable
{
private static $wireVersionForReadConcern = 4;

private $databaseName;
private $collectionName;
private $filter;
Expand All @@ -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
Expand Down Expand Up @@ -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');
}
Expand All @@ -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
Expand All @@ -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];

Expand All @@ -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);
}
}
Loading