Commit 330e1e30 authored by Jeremy Mikola's avatar Jeremy Mikola

PHPLIB-138: Support typeMap option for Database::command()

This refactors the existing Database method to use an Operation class.
parent a3bf7021
......@@ -3,7 +3,6 @@
namespace MongoDB;
use MongoDB\Collection;
use MongoDB\Driver\Command;
use MongoDB\Driver\Cursor;
use MongoDB\Driver\Manager;
use MongoDB\Driver\Query;
......@@ -15,6 +14,7 @@ use MongoDB\Exception\InvalidArgumentException;
use MongoDB\Exception\InvalidArgumentTypeException;
use MongoDB\Model\CollectionInfoIterator;
use MongoDB\Operation\CreateCollection;
use MongoDB\Operation\DatabaseCommand;
use MongoDB\Operation\DropCollection;
use MongoDB\Operation\DropDatabase;
use MongoDB\Operation\ListCollections;
......@@ -116,27 +116,22 @@ class Database
/**
* Execute a command on this database.
*
* @see DatabaseCommand::__construct() for supported options
* @param array|object $command Command document
* @param ReadPreference|null $readPreference Read preference
* @param array $options Options for command execution
* @return Cursor
* @throws InvalidArgumentException
*/
public function command($command, ReadPreference $readPreference = null)
public function command($command, array $options = [])
{
if ( ! is_array($command) && ! is_object($command)) {
throw new InvalidArgumentTypeException('$command', $command, 'array or object');
}
if ( ! $command instanceof Command) {
$command = new Command($command);
if ( ! isset($options['readPreference'])) {
$options['readPreference'] = $this->readPreference;
}
if ( ! isset($readPreference)) {
$readPreference = $this->readPreference;
}
$server = $this->manager->selectServer($readPreference);
$operation = new DatabaseCommand($this->databaseName, $command, $options);
$server = $this->manager->selectServer($options['readPreference']);
return $server->executeCommand($this->databaseName, $command);
return $operation->execute($server);
}
/**
......
<?php
namespace MongoDB\Operation;
use MongoDB\Driver\Command;
use MongoDB\Driver\ReadPreference;
use MongoDB\Driver\Server;
use MongoDB\Exception\InvalidArgumentException;
use MongoDB\Exception\InvalidArgumentTypeException;
/**
* Operation for executing a database command.
*
* @api
* @see MongoDB\Database::command()
*/
class DatabaseCommand implements Executable
{
private $databaseName;
private $command;
private $options;
/**
* Constructs a command.
*
* Supported options:
*
* * readPreference (MongoDB\Driver\ReadPreference): The read preference to
* use when executing the command. This may be used when issuing the
* command to a replica set or mongos node to ensure that the driver sets
* the wire protocol accordingly or adds the read preference to the
* command document, respectively.
*
* * typeMap (array): Type map for BSON deserialization. This will be
* applied to the returned Cursor (it is not sent to the server).
*
* @param string $databaseName Database name
* @param array|object $command Command document
* @param array $options Options for command execution
* @throws InvalidArgumentException
*/
public function __construct($databaseName, $command, array $options = [])
{
if ( ! is_array($command) && ! is_object($command)) {
throw new InvalidArgumentTypeException('$command', $command, 'array or object');
}
if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) {
throw new InvalidArgumentTypeException('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference');
}
if (isset($options['typeMap']) && ! is_array($options['typeMap'])) {
throw new InvalidArgumentTypeException('"typeMap" option', $options['typeMap'], 'array');
}
$this->databaseName = (string) $databaseName;
$this->command = ($command instanceof Command) ? $command : new Command($command);
$this->options = $options;
}
/**
* Execute the operation.
*
* @see Executable::execute()
* @param Server $server
* @return integer
*/
public function execute(Server $server)
{
$readPreference = isset($this->options['readPreference']) ? $this->options['readPreference'] : null;
$cursor = $server->executeCommand($this->databaseName, $this->command, $readPreference);
if (isset($this->options['typeMap'])) {
$cursor->setTypeMap($this->options['typeMap']);
}
return $cursor;
}
}
......@@ -68,8 +68,11 @@ class DatabaseFunctionalTest extends FunctionalTestCase
public function testCommand()
{
$command = ['isMaster' => 1];
$readPreference = new ReadPreference(ReadPreference::RP_PRIMARY);
$cursor = $this->database->command($command, $readPreference);
$options = [
'readPreference' => new ReadPreference(ReadPreference::RP_PRIMARY),
];
$cursor = $this->database->command($command, $options);
$this->assertInstanceOf('MongoDB\Driver\Cursor', $cursor);
$commandResult = current($cursor->toArray());
......@@ -79,6 +82,25 @@ class DatabaseFunctionalTest extends FunctionalTestCase
$this->assertTrue($commandResult->ismaster);
}
public function testCommandAppliesTypeMapToCursor()
{
$command = ['isMaster' => 1];
$options = [
'readPreference' => new ReadPreference(ReadPreference::RP_PRIMARY),
'typeMap' => ['root' => 'array'],
];
$cursor = $this->database->command($command, $options);
$this->assertInstanceOf('MongoDB\Driver\Cursor', $cursor);
$commandResult = current($cursor->toArray());
$this->assertCommandSucceeded($commandResult);
$this->assertInternalType('array', $commandResult);
$this->assertTrue(isset($commandResult['ismaster']));
$this->assertTrue($commandResult['ismaster']);
}
/**
* @expectedException MongoDB\Exception\InvalidArgumentTypeException
* @dataProvider provideInvalidDocumentValues
......
<?php
namespace MongoDB\Tests\Operation;
use MongoDB\Operation\DatabaseCommand;
class DatabaseCommandTest extends TestCase
{
/**
* @expectedException MongoDB\Exception\InvalidArgumentTypeException
* @dataProvider provideInvalidDocumentValues
*/
public function testConstructorCommandArgumentTypeCheck($command)
{
new DatabaseCommand($this->getDatabaseName(), $command);
}
/**
* @expectedException MongoDB\Exception\InvalidArgumentTypeException
* @dataProvider provideInvalidConstructorOptions
*/
public function testConstructorOptionTypeChecks(array $options)
{
new DatabaseCommand($this->getDatabaseName(), ['ping' => 1], $options);
}
public function provideInvalidConstructorOptions()
{
$options = [];
foreach ($this->getInvalidReadPreferenceValues() as $value) {
$options[][] = ['readPreference' => $value];
}
foreach ($this->getInvalidArrayValues() as $value) {
$options[][] = ['typeMap' => $value];
}
return $options;
}
}
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