Commit 62397f02 authored by Jeremy Mikola's avatar Jeremy Mikola

PHPLIB-109: Extract ReplaceOne, UpdateOne, and UpdateMany operation classes

parent 70c6e6e4
......@@ -29,6 +29,9 @@ use MongoDB\Operation\FindOneAndUpdate;
use MongoDB\Operation\InsertMany;
use MongoDB\Operation\InsertOne;
use MongoDB\Operation\ListIndexes;
use MongoDB\Operation\ReplaceOne;
use MongoDB\Operation\UpdateMany;
use MongoDB\Operation\UpdateOne;
use Traversable;
class Collection
......@@ -609,79 +612,68 @@ class Collection
}
/**
* Replace one document
* Replaces at most one document matching the filter.
*
* @see ReplaceOne::__construct() for supported options
* @see http://docs.mongodb.org/manual/reference/command/update/
* @see Collection::getWriteOptions() for supported $options
*
* @param array $filter The document to be replaced
* @param array $update The document to replace with
* @param array $options Additional options
* @param array|object $filter Query by which to filter documents
* @param array|object $replacement Replacement document
* @param array $options Command options
* @return UpdateResult
*/
public function replaceOne(array $filter, array $update, array $options = array())
public function replaceOne($filter, $replacement, array $options = array())
{
$firstKey = key($update);
if (isset($firstKey[0]) && $firstKey[0] == '$') {
throw new InvalidArgumentException("First key in \$update must NOT be a \$operator");
if ( ! isset($options['writeConcern']) && isset($this->wc)) {
$options['writeConcern'] = $this->wc;
}
$wr = $this->_update($filter, $update, $options + array("multi" => false));
return new UpdateResult($wr);
$operation = new ReplaceOne($this->dbname, $this->collname, $filter, $replacement, $options);
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
return $operation->execute($server);
}
/**
* Update one document
* NOTE: Will update ALL documents matching $filter
* Updates all documents matching the filter.
*
* @see UpdateMany::__construct() for supported options
* @see http://docs.mongodb.org/manual/reference/command/update/
* @see Collection::getWriteOptions() for supported $options
*
* @param array $filter The document to be replaced
* @param array $update An array of update operators to apply to the document
* @param array $options Additional options
* @param array|object $filter Query by which to filter documents
* @param array|object $replacement Update to apply to the matched documents
* @param array $options Command options
* @return UpdateResult
*/
public function updateMany(array $filter, $update, array $options = array())
public function updateMany($filter, $update, array $options = array())
{
$wr = $this->_update($filter, $update, $options + array("multi" => true));
if ( ! isset($options['writeConcern']) && isset($this->wc)) {
$options['writeConcern'] = $this->wc;
}
return new UpdateResult($wr);
$operation = new UpdateMany($this->dbname, $this->collname, $filter, $update, $options);
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
return $operation->execute($server);
}
/**
* Update one document
* NOTE: Will update at most ONE document matching $filter
* Updates at most one document matching the filter.
*
* @see ReplaceOne::__construct() for supported options
* @see http://docs.mongodb.org/manual/reference/command/update/
* @see Collection::getWriteOptions() for supported $options
*
* @param array $filter The document to be replaced
* @param array $update An array of update operators to apply to the document
* @param array $options Additional options
* @param array|object $filter Query by which to filter documents
* @param array|object $replacement Update to apply to the matched document
* @param array $options Command options
* @return UpdateResult
*/
public function updateOne(array $filter, array $update, array $options = array())
public function updateOne($filter, $update, array $options = array())
{
$firstKey = key($update);
if (!isset($firstKey[0]) || $firstKey[0] != '$') {
throw new InvalidArgumentException("First key in \$update must be a \$operator");
if ( ! isset($options['writeConcern']) && isset($this->wc)) {
$options['writeConcern'] = $this->wc;
}
$wr = $this->_update($filter, $update, $options + array("multi" => false));
return new UpdateResult($wr);
}
/**
* Internal helper for replacing/updating one/many documents
* @internal
*/
protected function _update($filter, $update, $options)
{
$options = array_merge($this->getWriteOptions(), $options);
$operation = new UpdateOne($this->dbname, $this->collname, $filter, $update, $options);
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
$bulk = new BulkWrite($options["ordered"]);
$bulk->update($filter, $update, $options);
return $this->manager->executeBulkWrite($this->ns, $bulk, $this->wc);
return $operation->execute($server);
}
}
<?php
namespace MongoDB\Operation;
use MongoDB\UpdateResult;
use MongoDB\Driver\Server;
use MongoDB\Exception\InvalidArgumentException;
use MongoDB\Exception\InvalidArgumentTypeException;
/**
* Operation for replacing a single document with the update command.
*
* @api
* @see MongoDB\Collection::replaceOne()
* @see http://docs.mongodb.org/manual/reference/command/update/
*/
class ReplaceOne implements Executable
{
private $update;
/**
* Constructs an update command.
*
* Supported options:
*
* * upsert (boolean): When true, a new document is created if no document
* matches the query. The default is false.
*
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
*
* @param string $databaseName Database name
* @param string $collectionName Collection name
* @param array|object $filter Query by which to filter documents
* @param array|object $replacement Replacement document
* @param array $options Command options
* @throws InvalidArgumentException
*/
public function __construct($databaseName, $collectionName, $filter, $replacement, array $options = array())
{
if ( ! is_array($replacement) && ! is_object($replacement)) {
throw new InvalidArgumentTypeException('$replacement', $replacement, 'array or object');
}
if (\MongoDB\is_first_key_operator($replacement)) {
throw new InvalidArgumentException('First key in $replacement argument is an update operator');
}
$this->update = new Update(
$databaseName,
$collectionName,
$filter,
$replacement,
array('multi' => false) + $options
);
}
/**
* Execute the operation.
*
* @see Executable::execute()
* @param Server $server
* @return UpdateResult
*/
public function execute(Server $server)
{
return $this->update->execute($server);
}
}
<?php
namespace MongoDB\Operation;
use MongoDB\UpdateResult;
use MongoDB\Driver\BulkWrite;
use MongoDB\Driver\Server;
use MongoDB\Driver\WriteConcern;
use MongoDB\Exception\InvalidArgumentException;
use MongoDB\Exception\InvalidArgumentTypeException;
/**
* Operation for the update command.
*
* This class is used internally by the ReplaceOne, UpdateMany, and UpdateOne
* operation classes.
*
* @internal
* @see http://docs.mongodb.org/manual/reference/command/update/
*/
class Update implements Executable
{
private $databaseName;
private $collectionName;
private $filter;
private $update;
private $options;
/**
* Constructs a update command.
*
* Supported options:
*
* * multi (boolean): When true, updates all documents matching the query.
* This option cannot be true if the $update argument is a replacement
* document (i.e. contains no update operators). The default is false.
*
* * upsert (boolean): When true, a new document is created if no document
* matches the query. The default is false.
*
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
*
* @param string $databaseName Database name
* @param string $collectionName Collection name
* @param array|object $filter Query by which to delete documents
* @param array|object $update Update to apply to the matched
* document(s) or a replacement document
* @param array $options Command options
* @throws InvalidArgumentException
*/
public function __construct($databaseName, $collectionName, $filter, $update, array $options = array())
{
if ( ! is_array($filter) && ! is_object($filter)) {
throw new InvalidArgumentTypeException('$filter', $filter, 'array or object');
}
if ( ! is_array($update) && ! is_object($update)) {
throw new InvalidArgumentTypeException('$update', $filter, 'array or object');
}
$options += array(
'multi' => false,
'upsert' => false,
);
if ( ! is_bool($options['multi'])) {
throw new InvalidArgumentTypeException('"multi" option', $options['multi'], 'boolean');
}
if ($options['multi'] && ! \MongoDB\is_first_key_operator($update)) {
throw new InvalidArgumentException('"multi" option cannot be true if $update is a replacement document');
}
if ( ! is_bool($options['upsert'])) {
throw new InvalidArgumentTypeException('"upsert" option', $options['upsert'], 'boolean');
}
if (array_key_exists('writeConcern', $options) && ! $options['writeConcern'] instanceof WriteConcern) {
throw new InvalidArgumentTypeException('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
}
$this->databaseName = (string) $databaseName;
$this->collectionName = (string) $collectionName;
$this->filter = $filter;
$this->update = $update;
$this->options = $options;
}
/**
* Execute the operation.
*
* @see Executable::execute()
* @param Server $server
* @return UpdateResult
*/
public function execute(Server $server)
{
$options = array(
'multi' => $this->options['multi'],
'upsert' => $this->options['upsert'],
);
$bulk = new BulkWrite();
$bulk->update($this->filter, $this->update, $options);
$writeConcern = isset($this->options['writeConcern']) ? $this->options['writeConcern'] : null;
$writeResult = $server->executeBulkWrite($this->databaseName . '.' . $this->collectionName, $bulk, $writeConcern);
return new UpdateResult($writeResult);
}
}
<?php
namespace MongoDB\Operation;
use MongoDB\UpdateResult;
use MongoDB\Driver\Server;
use MongoDB\Exception\InvalidArgumentException;
use MongoDB\Exception\InvalidArgumentTypeException;
/**
* Operation for updating multiple documents with the update command.
*
* @api
* @see MongoDB\Collection::updateMany()
* @see http://docs.mongodb.org/manual/reference/command/update/
*/
class UpdateMany implements Executable
{
private $update;
/**
* Constructs an update command.
*
* Supported options:
*
* * upsert (boolean): When true, a new document is created if no document
* matches the query. The default is false.
*
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
*
* @param string $databaseName Database name
* @param string $collectionName Collection name
* @param array|object $filter Query by which to filter documents
* @param array|object $update Update to apply to the matched documents
* @param array $options Command options
* @throws InvalidArgumentException
*/
public function __construct($databaseName, $collectionName, $filter, $update, array $options = array())
{
if ( ! is_array($update) && ! is_object($update)) {
throw new InvalidArgumentTypeException('$update', $update, 'array or object');
}
if ( ! \MongoDB\is_first_key_operator($update)) {
throw new InvalidArgumentException('First key in $update argument is not an update operator');
}
$this->update = new Update(
$databaseName,
$collectionName,
$filter,
$update,
array('multi' => true) + $options
);
}
/**
* Execute the operation.
*
* @see Executable::execute()
* @param Server $server
* @return UpdateResult
*/
public function execute(Server $server)
{
return $this->update->execute($server);
}
}
<?php
namespace MongoDB\Operation;
use MongoDB\UpdateResult;
use MongoDB\Driver\Server;
use MongoDB\Exception\InvalidArgumentException;
use MongoDB\Exception\InvalidArgumentTypeException;
/**
* Operation for updating a single document with the update command.
*
* @api
* @see MongoDB\Collection::updateOne()
* @see http://docs.mongodb.org/manual/reference/command/update/
*/
class UpdateOne implements Executable
{
private $update;
/**
* Constructs an update command.
*
* Supported options:
*
* * upsert (boolean): When true, a new document is created if no document
* matches the query. The default is false.
*
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
*
* @param string $databaseName Database name
* @param string $collectionName Collection name
* @param array|object $filter Query by which to filter documents
* @param array|object $update Update to apply to the matched document
* @param array $options Command options
* @throws InvalidArgumentException
*/
public function __construct($databaseName, $collectionName, $filter, $update, array $options = array())
{
if ( ! is_array($update) && ! is_object($update)) {
throw new InvalidArgumentTypeException('$update', $update, 'array or object');
}
if ( ! \MongoDB\is_first_key_operator($update)) {
throw new InvalidArgumentException('First key in $update argument is not an update operator');
}
$this->update = new Update(
$databaseName,
$collectionName,
$filter,
$update,
array('multi' => false) + $options
);
}
/**
* Execute the operation.
*
* @see Executable::execute()
* @param Server $server
* @return UpdateResult
*/
public function execute(Server $server)
{
return $this->update->execute($server);
}
}
<?php
namespace MongoDB\Tests\Operation;
use MongoDB\Operation\ReplaceOne;
class ReplaceOneTest extends TestCase
{
/**
* @expectedException MongoDB\Exception\InvalidArgumentTypeException
* @dataProvider provideInvalidDocumentArguments
*/
public function testConstructorFilterArgumentType($filter)
{
new ReplaceOne($this->getDatabaseName(), $this->getCollectionName(), $filter, array('y' => 1));
}
/**
* @expectedException MongoDB\Exception\InvalidArgumentTypeException
* @dataProvider provideInvalidDocumentArguments
*/
public function testConstructorReplacementArgumentType($replacement)
{
new ReplaceOne($this->getDatabaseName(), $this->getCollectionName(), array('x' => 1), $replacement);
}
/**
* @expectedException MongoDB\Exception\InvalidArgumentException
*/
public function testConstructorReplacementArgumentRequiresNoOperators()
{
new ReplaceOne($this->getDatabaseName(), $this->getCollectionName(), array('x' => 1), array('$set' => array('x' => 1)));
}
}
<?php
namespace MongoDB\Tests\Operation;
use MongoDB\Operation\UpdateMany;
class UpdateManyTest extends TestCase
{
/**
* @expectedException MongoDB\Exception\InvalidArgumentTypeException
* @dataProvider provideInvalidDocumentArguments
*/
public function testConstructorFilterArgumentType($filter)
{
new UpdateMany($this->getDatabaseName(), $this->getCollectionName(), $filter, array('$set' => array('x' => 1)));
}
/**
* @expectedException MongoDB\Exception\InvalidArgumentTypeException
* @dataProvider provideInvalidDocumentArguments
*/
public function testConstructorUpdateArgumentType($update)
{
new UpdateMany($this->getDatabaseName(), $this->getCollectionName(), array('x' => 1), $update);
}
/**
* @expectedException MongoDB\Exception\InvalidArgumentException
*/
public function testConstructorUpdateArgumentRequiresOperators()
{
new UpdateMany($this->getDatabaseName(), $this->getCollectionName(), array('x' => 1), array('y' => 1));
}
}
<?php
namespace MongoDB\Tests\Operation;
use MongoDB\Operation\UpdateOne;
class UpdateOneTest extends TestCase
{
/**
* @expectedException MongoDB\Exception\InvalidArgumentTypeException
* @dataProvider provideInvalidDocumentArguments
*/
public function testConstructorFilterArgumentType($filter)
{
new UpdateOne($this->getDatabaseName(), $this->getCollectionName(), $filter, array('$set' => array('x' => 1)));
}
/**
* @expectedException MongoDB\Exception\InvalidArgumentTypeException
* @dataProvider provideInvalidDocumentArguments
*/
public function testConstructorUpdateArgumentType($update)
{
new UpdateOne($this->getDatabaseName(), $this->getCollectionName(), array('x' => 1), $update);
}
/**
* @expectedException MongoDB\Exception\InvalidArgumentException
*/
public function testConstructorUpdateArgumentRequiresOperators()
{
new UpdateOne($this->getDatabaseName(), $this->getCollectionName(), array('x' => 1), array('y' => 1));
}
}
<?php
namespace MongoDB\Tests\Operation;
use MongoDB\Operation\Update;
class UpdateTest extends TestCase
{
/**
* @expectedException MongoDB\Exception\InvalidArgumentTypeException
* @dataProvider provideInvalidDocumentArguments
*/
public function testConstructorFilterArgumentType($filter)
{
new Update($this->getDatabaseName(), $this->getCollectionName(), $filter, array('$set' => array('x' => 1)));
}
/**
* @expectedException MongoDB\Exception\InvalidArgumentTypeException
* @dataProvider provideInvalidDocumentArguments
*/
public function testConstructorUpdateArgumentType($update)
{
new Update($this->getDatabaseName(), $this->getCollectionName(), array('x' => 1), $update);
}
/**
* @expectedException MongoDB\Exception\InvalidArgumentTypeException
* @dataProvider provideInvalidBooleanArguments
*/
public function testConstructorMultiOptionType($multi)
{
new Update($this->getDatabaseName(), $this->getCollectionName(), array('x' => 1), array('y' => 1), array('multi' => $multi));
}
/**
* @expectedException MongoDB\Exception\InvalidArgumentTypeException
* @dataProvider provideInvalidBooleanArguments
*/
public function testConstructorUpsertOptionType($upsert)
{
new Update($this->getDatabaseName(), $this->getCollectionName(), array('x' => 1), array('y' => 1), array('upsert' => $upsert));
}
/**
* @expectedException MongoDB\Exception\InvalidArgumentTypeException
*/
public function testConstructorWriteConcernOptionType()
{
new Update($this->getDatabaseName(), $this->getCollectionName(), array('x' => 1), array('y' => 1), array('writeConcern' => null));
}
}
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