Commit 11ab5dac authored by Jeremy Mikola's avatar Jeremy Mikola

Merge pull request #467

parents 9b925197 746bbff6
...@@ -10,54 +10,48 @@ addons: ...@@ -10,54 +10,48 @@ addons:
packages: &common_packages packages: &common_packages
- gdb - gdb
env:
global:
- DRIVER_VERSION=1.4.0RC1
- SERVER_VERSION=3.4
matrix: matrix:
fast_finish: true fast_finish: true
include: include:
- php: 5.5 - php: 5.5
env: &common_env DRIVER_VERSION=1.3.3 SERVER_VERSION=3.4
addons: &common_addons addons: &common_addons
apt: apt:
sources: [ mongodb-3.4-precise ] sources: [ mongodb-3.4-precise ]
packages: [ mongodb-org, *common_packages ] packages: [ mongodb-org, *common_packages ]
- php: 5.6 - php: 5.6
env: *common_env
addons: *common_addons addons: *common_addons
- php: 7.0 - php: 7.0
env: *common_env
addons: *common_addons addons: *common_addons
- php: 7.1 - php: 7.1
env: *common_env
addons: *common_addons addons: *common_addons
- php: 7.2 - php: 7.2
env: *common_env
addons: *common_addons addons: *common_addons
- php: 7.0 - php: 7.0
env: DRIVER_VERSION=1.3.3 SERVER_VERSION=2.4 env:
addons: - SERVER_VERSION=2.6
apt:
sources: [ mongodb-upstart ]
packages: [ mongodb-10gen, *common_packages ]
- php: 7.0
env: DRIVER_VERSION=1.3.3 SERVER_VERSION=2.6
addons: addons:
apt: apt:
sources: [ mongodb-upstart ] sources: [ mongodb-upstart ]
packages: [ mongodb-org, *common_packages ] packages: [ mongodb-org, *common_packages ]
- php: 7.0 - php: 7.0
env: DRIVER_VERSION=1.3.3 SERVER_VERSION=3.0 env:
- SERVER_VERSION=3.0
addons: addons:
apt: apt:
sources: [ mongodb-3.0-precise ] sources: [ mongodb-3.0-precise ]
packages: [ mongodb-org, *common_packages ] packages: [ mongodb-org, *common_packages ]
- php: 7.0 - php: 7.0
env: DRIVER_VERSION=1.3.3 SERVER_VERSION=3.2 env:
- SERVER_VERSION=3.2
addons: addons:
apt: apt:
sources: [ mongodb-3.2-precise ] sources: [ mongodb-3.2-precise ]
packages: [ mongodb-org, *common_packages ] packages: [ mongodb-org, *common_packages ]
- php: 7.0
env: DRIVER_VERSION=devel SERVER_VERSION=3.4
addons: *common_addons
before_script: before_script:
- mongod --version - mongod --version
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
"php": ">=5.5", "php": ">=5.5",
"ext-hash": "*", "ext-hash": "*",
"ext-json": "*", "ext-json": "*",
"ext-mongodb": "^1.3.0" "ext-mongodb": "^1.4.0"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^4.8.36" "phpunit/phpunit": "^4.8.36"
......
...@@ -70,6 +70,8 @@ source: ...@@ -70,6 +70,8 @@ source:
source: source:
file: apiargs-MongoDBCollection-common-option.yaml file: apiargs-MongoDBCollection-common-option.yaml
ref: readPreference ref: readPreference
post: |
This option will be ignored when using the :ref:`$out <agg-out>` stage.
--- ---
source: source:
file: apiargs-MongoDBCollection-common-option.yaml file: apiargs-MongoDBCollection-common-option.yaml
......
source: source:
file: apiargs-MongoDBCollection-common-option.yaml file: apiargs-MongoDBCollection-common-option.yaml
ref: bypassDocumentValidation ref: bypassDocumentValidation
post: |
This only applies when results are output to a collection.
--- ---
source: source:
file: apiargs-MongoDBCollection-common-option.yaml file: apiargs-MongoDBCollection-common-option.yaml
...@@ -55,6 +57,8 @@ source: ...@@ -55,6 +57,8 @@ source:
source: source:
file: apiargs-MongoDBCollection-common-option.yaml file: apiargs-MongoDBCollection-common-option.yaml
ref: readPreference ref: readPreference
post: |
This option will be ignored when results are output to a collection.
--- ---
arg_name: option arg_name: option
name: scope name: scope
......
...@@ -831,7 +831,7 @@ class Collection ...@@ -831,7 +831,7 @@ class Collection
*/ */
public function mapReduce(JavascriptInterface $map, JavascriptInterface $reduce, $out, array $options = []) public function mapReduce(JavascriptInterface $map, JavascriptInterface $reduce, $out, array $options = [])
{ {
$hasOutputCollection = ! $this->isMapReduceOutputInline($out); $hasOutputCollection = ! \MongoDB\is_mapreduce_output_inline($out);
if ( ! isset($options['readPreference'])) { if ( ! isset($options['readPreference'])) {
$options['readPreference'] = $this->readPreference; $options['readPreference'] = $this->readPreference;
...@@ -984,38 +984,4 @@ class Collection ...@@ -984,38 +984,4 @@ class Collection
return new Collection($this->manager, $this->databaseName, $this->collectionName, $options); return new Collection($this->manager, $this->databaseName, $this->collectionName, $options);
} }
/**
* Return whether the "out" option for a mapReduce operation is "inline".
*
* This is used to determine if a mapReduce command requires a primary.
*
* @see https://docs.mongodb.com/manual/reference/command/mapReduce/#output-inline
* @param string|array|object $out Output specification
* @return boolean
* @throws InvalidArgumentException
*/
private function isMapReduceOutputInline($out)
{
if ( ! is_array($out) && ! is_object($out)) {
return false;
}
if ($out instanceof Serializable) {
$out = $out->bsonSerialize();
}
if (is_object($out)) {
$out = get_object_vars($out);
}
if ( ! is_array($out)) {
throw InvalidArgumentException::invalidType('$out', $out, 'array or object');
}
reset($out);
$firstKey = (string) key($out);
return $firstKey === 'inline';
}
} }
...@@ -92,6 +92,8 @@ class Aggregate implements Executable ...@@ -92,6 +92,8 @@ class Aggregate implements Executable
* *
* * readPreference (MongoDB\Driver\ReadPreference): Read preference. * * readPreference (MongoDB\Driver\ReadPreference): Read preference.
* *
* This option is ignored if the $out stage is specified.
*
* * typeMap (array): Type map for BSON deserialization. This will be * * typeMap (array): Type map for BSON deserialization. This will be
* applied to the returned Cursor (it is not sent to the server). * applied to the returned Cursor (it is not sent to the server).
* *
...@@ -231,11 +233,15 @@ class Aggregate implements Executable ...@@ -231,11 +233,15 @@ class Aggregate implements Executable
throw UnsupportedException::writeConcernNotSupported(); throw UnsupportedException::writeConcernNotSupported();
} }
$hasOutStage = \MongoDB\is_last_pipeline_operator_out($this->pipeline);
$isCursorSupported = \MongoDB\server_supports_feature($server, self::$wireVersionForCursor); $isCursorSupported = \MongoDB\server_supports_feature($server, self::$wireVersionForCursor);
$readPreference = isset($this->options['readPreference']) ? $this->options['readPreference'] : null;
$command = $this->createCommand($server, $isCursorSupported); $command = $this->createCommand($server, $isCursorSupported);
$cursor = $server->executeCommand($this->databaseName, $command, $readPreference); $options = $this->createOptions($hasOutStage);
$cursor = $hasOutStage
? $server->executeReadWriteCommand($this->databaseName, $command, $options)
: $server->executeReadCommand($this->databaseName, $command, $options);
if ($isCursorSupported && $this->options['useCursor']) { if ($isCursorSupported && $this->options['useCursor']) {
if (isset($this->options['typeMap'])) { if (isset($this->options['typeMap'])) {
...@@ -297,14 +303,6 @@ class Aggregate implements Executable ...@@ -297,14 +303,6 @@ class Aggregate implements Executable
$cmd['hint'] = is_array($this->options['hint']) ? (object) $this->options['hint'] : $this->options['hint']; $cmd['hint'] = is_array($this->options['hint']) ? (object) $this->options['hint'] : $this->options['hint'];
} }
if (isset($this->options['readConcern'])) {
$cmd['readConcern'] = \MongoDB\read_concern_as_document($this->options['readConcern']);
}
if (isset($this->options['writeConcern'])) {
$cmd['writeConcern'] = \MongoDB\write_concern_as_document($this->options['writeConcern']);
}
if ($this->options['useCursor']) { if ($this->options['useCursor']) {
$cmd['cursor'] = isset($this->options["batchSize"]) $cmd['cursor'] = isset($this->options["batchSize"])
? ['batchSize' => $this->options["batchSize"]] ? ['batchSize' => $this->options["batchSize"]]
...@@ -313,4 +311,31 @@ class Aggregate implements Executable ...@@ -313,4 +311,31 @@ class Aggregate implements Executable
return new Command($cmd); return new Command($cmd);
} }
/**
* Create options for executing the command.
*
* @see http://php.net/manual/en/mongodb-driver-server.executereadcommand.php
* @see http://php.net/manual/en/mongodb-driver-server.executereadwritecommand.php
* @param boolean $hasOutStage
* @return array
*/
private function createOptions($hasOutStage)
{
$options = [];
if (isset($this->options['readConcern'])) {
$options['readConcern'] = $this->options['readConcern'];
}
if ( ! $hasOutStage && isset($this->options['readPreference'])) {
$options['readPreference'] = $this->options['readPreference'];
}
if ($hasOutStage && isset($this->options['writeConcern'])) {
$options['writeConcern'] = $this->options['writeConcern'];
}
return $options;
}
} }
...@@ -142,9 +142,7 @@ class Count implements Executable ...@@ -142,9 +142,7 @@ class Count implements Executable
throw UnsupportedException::readConcernNotSupported(); throw UnsupportedException::readConcernNotSupported();
} }
$readPreference = isset($this->options['readPreference']) ? $this->options['readPreference'] : null; $cursor = $server->executeReadCommand($this->databaseName, $this->createCommand(), $this->createOptions());
$cursor = $server->executeCommand($this->databaseName, $this->createCommand(), $readPreference);
$result = current($cursor->toArray()); $result = current($cursor->toArray());
// Older server versions may return a float // Older server versions may return a float
...@@ -182,10 +180,27 @@ class Count implements Executable ...@@ -182,10 +180,27 @@ class Count implements Executable
} }
} }
return new Command($cmd);
}
/**
* Create options for executing the command.
*
* @see http://php.net/manual/en/mongodb-driver-server.executereadcommand.php
* @return array
*/
private function createOptions()
{
$options = [];
if (isset($this->options['readConcern'])) { if (isset($this->options['readConcern'])) {
$cmd['readConcern'] = \MongoDB\read_concern_as_document($this->options['readConcern']); $options['readConcern'] = $this->options['readConcern'];
} }
return new Command($cmd); if (isset($this->options['readPreference'])) {
$options['readPreference'] = $this->options['readPreference'];
}
return $options;
} }
} }
...@@ -185,7 +185,7 @@ class CreateCollection implements Executable ...@@ -185,7 +185,7 @@ class CreateCollection implements Executable
throw UnsupportedException::writeConcernNotSupported(); throw UnsupportedException::writeConcernNotSupported();
} }
$cursor = $server->executeCommand($this->databaseName, $this->createCommand()); $cursor = $server->executeWriteCommand($this->databaseName, $this->createCommand(), $this->createOptions());
if (isset($this->options['typeMap'])) { if (isset($this->options['typeMap'])) {
$cursor->setTypeMap($this->options['typeMap']); $cursor->setTypeMap($this->options['typeMap']);
...@@ -215,10 +215,23 @@ class CreateCollection implements Executable ...@@ -215,10 +215,23 @@ class CreateCollection implements Executable
} }
} }
return new Command($cmd);
}
/**
* Create options for executing the command.
*
* @see http://php.net/manual/en/mongodb-driver-server.executewritecommand.php
* @return array
*/
private function createOptions()
{
$options = [];
if (isset($this->options['writeConcern'])) { if (isset($this->options['writeConcern'])) {
$cmd['writeConcern'] = \MongoDB\write_concern_as_document($this->options['writeConcern']); $options['writeConcern'] = $this->options['writeConcern'];
} }
return new Command($cmd); return $options;
} }
} }
...@@ -143,6 +143,23 @@ class CreateIndexes implements Executable ...@@ -143,6 +143,23 @@ class CreateIndexes implements Executable
return array_map(function(IndexInput $index) { return (string) $index; }, $this->indexes); return array_map(function(IndexInput $index) { return (string) $index; }, $this->indexes);
} }
/**
* Create options for executing the command.
*
* @see http://php.net/manual/en/mongodb-driver-server.executewritecommand.php
* @return array
*/
private function createOptions()
{
$options = [];
if (isset($this->options['writeConcern'])) {
$options['writeConcern'] = $this->options['writeConcern'];
}
return $options;
}
/** /**
* Create one or more indexes for the collection using the createIndexes * Create one or more indexes for the collection using the createIndexes
* command. * command.
...@@ -161,11 +178,7 @@ class CreateIndexes implements Executable ...@@ -161,11 +178,7 @@ class CreateIndexes implements Executable
$cmd['maxTimeMS'] = $this->options['maxTimeMS']; $cmd['maxTimeMS'] = $this->options['maxTimeMS'];
} }
if (isset($this->options['writeConcern'])) { $server->executeWriteCommand($this->databaseName, new Command($cmd), $this->createOptions());
$cmd['writeConcern'] = \MongoDB\write_concern_as_document($this->options['writeConcern']);
}
$server->executeCommand($this->databaseName, new Command($cmd));
} }
/** /**
......
...@@ -124,9 +124,7 @@ class Distinct implements Executable ...@@ -124,9 +124,7 @@ class Distinct implements Executable
throw UnsupportedException::readConcernNotSupported(); throw UnsupportedException::readConcernNotSupported();
} }
$readPreference = isset($this->options['readPreference']) ? $this->options['readPreference'] : null; $cursor = $server->executeReadCommand($this->databaseName, $this->createCommand(), $this->createOptions());
$cursor = $server->executeCommand($this->databaseName, $this->createCommand(), $readPreference);
$result = current($cursor->toArray()); $result = current($cursor->toArray());
if ( ! isset($result->values) || ! is_array($result->values)) { if ( ! isset($result->values) || ! is_array($result->values)) {
...@@ -160,10 +158,27 @@ class Distinct implements Executable ...@@ -160,10 +158,27 @@ class Distinct implements Executable
$cmd['maxTimeMS'] = $this->options['maxTimeMS']; $cmd['maxTimeMS'] = $this->options['maxTimeMS'];
} }
return new Command($cmd);
}
/**
* Create options for executing the command.
*
* @see http://php.net/manual/en/mongodb-driver-server.executereadcommand.php
* @return array
*/
private function createOptions()
{
$options = [];
if (isset($this->options['readConcern'])) { if (isset($this->options['readConcern'])) {
$cmd['readConcern'] = \MongoDB\read_concern_as_document($this->options['readConcern']); $options['readConcern'] = $this->options['readConcern'];
} }
return new Command($cmd); if (isset($this->options['readPreference'])) {
$options['readPreference'] = $this->options['readPreference'];
}
return $options;
} }
} }
...@@ -93,8 +93,10 @@ class DropCollection implements Executable ...@@ -93,8 +93,10 @@ class DropCollection implements Executable
throw UnsupportedException::writeConcernNotSupported(); throw UnsupportedException::writeConcernNotSupported();
} }
$command = new Command(['drop' => $this->collectionName]);
try { try {
$cursor = $server->executeCommand($this->databaseName, $this->createCommand()); $cursor = $server->executeWriteCommand($this->databaseName, $command, $this->createOptions());
} catch (DriverRuntimeException $e) { } catch (DriverRuntimeException $e) {
/* The server may return an error if the collection does not exist. /* The server may return an error if the collection does not exist.
* Check for an error message (unfortunately, there isn't a code) * Check for an error message (unfortunately, there isn't a code)
...@@ -115,18 +117,19 @@ class DropCollection implements Executable ...@@ -115,18 +117,19 @@ class DropCollection implements Executable
} }
/** /**
* Create the drop command. * Create options for executing the command.
* *
* @return Command * @see http://php.net/manual/en/mongodb-driver-server.executewritecommand.php
* @return array
*/ */
private function createCommand() private function createOptions()
{ {
$cmd = ['drop' => $this->collectionName]; $options = [];
if (isset($this->options['writeConcern'])) { if (isset($this->options['writeConcern'])) {
$cmd['writeConcern'] = \MongoDB\write_concern_as_document($this->options['writeConcern']); $options['writeConcern'] = $this->options['writeConcern'];
} }
return new Command($cmd); return $options;
} }
} }
...@@ -89,7 +89,8 @@ class DropDatabase implements Executable ...@@ -89,7 +89,8 @@ class DropDatabase implements Executable
throw UnsupportedException::writeConcernNotSupported(); throw UnsupportedException::writeConcernNotSupported();
} }
$cursor = $server->executeCommand($this->databaseName, $this->createCommand()); $command = new Command(['dropDatabase' => 1]);
$cursor = $server->executeWriteCommand($this->databaseName, $command, $this->createOptions());
if (isset($this->options['typeMap'])) { if (isset($this->options['typeMap'])) {
$cursor->setTypeMap($this->options['typeMap']); $cursor->setTypeMap($this->options['typeMap']);
...@@ -99,18 +100,19 @@ class DropDatabase implements Executable ...@@ -99,18 +100,19 @@ class DropDatabase implements Executable
} }
/** /**
* Create the dropDatabase command. * Create options for executing the command.
* *
* @return Command * @see http://php.net/manual/en/mongodb-driver-server.executewritecommand.php
* @return array
*/ */
private function createCommand() private function createOptions()
{ {
$cmd = ['dropDatabase' => 1]; $options = [];
if (isset($this->options['writeConcern'])) { if (isset($this->options['writeConcern'])) {
$cmd['writeConcern'] = \MongoDB\write_concern_as_document($this->options['writeConcern']); $options['writeConcern'] = $this->options['writeConcern'];
} }
return new Command($cmd); return $options;
} }
} }
...@@ -107,7 +107,7 @@ class DropIndexes implements Executable ...@@ -107,7 +107,7 @@ class DropIndexes implements Executable
throw UnsupportedException::writeConcernNotSupported(); throw UnsupportedException::writeConcernNotSupported();
} }
$cursor = $server->executeCommand($this->databaseName, $this->createCommand()); $cursor = $server->executeWriteCommand($this->databaseName, $this->createCommand(), $this->createOptions());
if (isset($this->options['typeMap'])) { if (isset($this->options['typeMap'])) {
$cursor->setTypeMap($this->options['typeMap']); $cursor->setTypeMap($this->options['typeMap']);
...@@ -132,10 +132,23 @@ class DropIndexes implements Executable ...@@ -132,10 +132,23 @@ class DropIndexes implements Executable
$cmd['maxTimeMS'] = $this->options['maxTimeMS']; $cmd['maxTimeMS'] = $this->options['maxTimeMS'];
} }
return new Command($cmd);
}
/**
* Create options for executing the command.
*
* @see http://php.net/manual/en/mongodb-driver-server.executewritecommand.php
* @return array
*/
private function createOptions()
{
$options = [];
if (isset($this->options['writeConcern'])) { if (isset($this->options['writeConcern'])) {
$cmd['writeConcern'] = \MongoDB\write_concern_as_document($this->options['writeConcern']); $options['writeConcern'] = $this->options['writeConcern'];
} }
return new Command($cmd); return $options;
} }
} }
...@@ -201,7 +201,7 @@ class FindAndModify implements Executable ...@@ -201,7 +201,7 @@ class FindAndModify implements Executable
throw UnsupportedException::writeConcernNotSupported(); throw UnsupportedException::writeConcernNotSupported();
} }
$cursor = $server->executeCommand($this->databaseName, $this->createCommand($server)); $cursor = $server->executeReadWriteCommand($this->databaseName, $this->createCommand($server), $this->createOptions());
$result = current($cursor->toArray()); $result = current($cursor->toArray());
if ( ! isset($result->value)) { if ( ! isset($result->value)) {
...@@ -265,10 +265,23 @@ class FindAndModify implements Executable ...@@ -265,10 +265,23 @@ class FindAndModify implements Executable
$cmd['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; $cmd['bypassDocumentValidation'] = $this->options['bypassDocumentValidation'];
} }
return new Command($cmd);
}
/**
* Create options for executing the command.
*
* @see http://php.net/manual/en/mongodb-driver-server.executereadwritecommand.php
* @return array
*/
private function createOptions()
{
$options = [];
if (isset($this->options['writeConcern'])) { if (isset($this->options['writeConcern'])) {
$cmd['writeConcern'] = \MongoDB\write_concern_as_document($this->options['writeConcern']); $options['writeConcern'] = $this->options['writeConcern'];
} }
return new Command($cmd); return $options;
} }
} }
...@@ -107,6 +107,8 @@ class MapReduce implements Executable ...@@ -107,6 +107,8 @@ class MapReduce implements Executable
* *
* * readPreference (MongoDB\Driver\ReadPreference): Read preference. * * readPreference (MongoDB\Driver\ReadPreference): Read preference.
* *
* This option is ignored if results are output to a collection.
*
* * scope (document): Specifies global variables that are accessible in * * scope (document): Specifies global variables that are accessible in
* the map, reduce and finalize functions. * the map, reduce and finalize functions.
* *
...@@ -241,8 +243,15 @@ class MapReduce implements Executable ...@@ -241,8 +243,15 @@ class MapReduce implements Executable
throw UnsupportedException::writeConcernNotSupported(); throw UnsupportedException::writeConcernNotSupported();
} }
$readPreference = isset($this->options['readPreference']) ? $this->options['readPreference'] : null; $hasOutputCollection = ! \MongoDB\is_mapreduce_output_inline($this->out);
$cursor = $server->executeCommand($this->databaseName, $this->createCommand($server), $readPreference);
$command = $this->createCommand($server);
$options = $this->createOptions($hasOutputCollection);
$cursor = $hasOutputCollection
? $server->executeReadWriteCommand($this->databaseName, $command, $options)
: $server->executeReadCommand($this->databaseName, $command, $options);
$result = current($cursor->toArray()); $result = current($cursor->toArray());
$getIterator = $this->createGetIteratorCallable($result, $server); $getIterator = $this->createGetIteratorCallable($result, $server);
...@@ -265,7 +274,7 @@ class MapReduce implements Executable ...@@ -265,7 +274,7 @@ class MapReduce implements Executable
'out' => $this->out, 'out' => $this->out,
]; ];
foreach (['finalize', 'jsMode', 'limit', 'maxTimeMS', 'readConcern', 'verbose', 'writeConcern'] as $option) { foreach (['finalize', 'jsMode', 'limit', 'maxTimeMS', 'verbose'] as $option) {
if (isset($this->options[$option])) { if (isset($this->options[$option])) {
$cmd[$option] = $this->options[$option]; $cmd[$option] = $this->options[$option];
} }
...@@ -321,4 +330,31 @@ class MapReduce implements Executable ...@@ -321,4 +330,31 @@ class MapReduce implements Executable
throw new UnexpectedValueException('mapReduce command did not return inline results or an output collection'); throw new UnexpectedValueException('mapReduce command did not return inline results or an output collection');
} }
/**
* Create options for executing the command.
*
* @see http://php.net/manual/en/mongodb-driver-server.executereadcommand.php
* @see http://php.net/manual/en/mongodb-driver-server.executereadwritecommand.php
* @param boolean $hasOutputCollection
* @return array
*/
private function createOptions($hasOutputCollection)
{
$options = [];
if (isset($this->options['readConcern'])) {
$options['readConcern'] = $this->options['readConcern'];
}
if ( ! $hasOutputCollection && isset($this->options['readPreference'])) {
$options['readPreference'] = $this->options['readPreference'];
}
if ($hasOutputCollection && isset($this->options['writeConcern'])) {
$options['writeConcern'] = $this->options['writeConcern'];
}
return $options;
}
} }
...@@ -111,7 +111,7 @@ function is_first_key_operator($document) ...@@ -111,7 +111,7 @@ function is_first_key_operator($document)
/** /**
* Return whether the aggregation pipeline ends with an $out operator. * Return whether the aggregation pipeline ends with an $out operator.
* *
* This is used for determining whether the aggregation pipeline msut be * This is used for determining whether the aggregation pipeline must be
* executed against a primary server. * executed against a primary server.
* *
* @internal * @internal
...@@ -131,6 +131,40 @@ function is_last_pipeline_operator_out(array $pipeline) ...@@ -131,6 +131,40 @@ function is_last_pipeline_operator_out(array $pipeline)
return key($lastOp) === '$out'; return key($lastOp) === '$out';
} }
/**
* Return whether the "out" option for a mapReduce operation is "inline".
*
* This is used to determine if a mapReduce command requires a primary.
*
* @internal
* @see https://docs.mongodb.com/manual/reference/command/mapReduce/#output-inline
* @param string|array|object $out Output specification
* @return boolean
* @throws InvalidArgumentException
*/
function is_mapreduce_output_inline($out)
{
if ( ! is_array($out) && ! is_object($out)) {
return false;
}
if ($out instanceof Serializable) {
$out = $out->bsonSerialize();
}
if (is_object($out)) {
$out = get_object_vars($out);
}
if ( ! is_array($out)) {
throw InvalidArgumentException::invalidType('$out', $out, 'array or object');
}
reset($out);
return key($out) === 'inline';
}
/** /**
* Converts a ReadConcern instance to a stdClass for use in a BSON document. * Converts a ReadConcern instance to a stdClass for use in a BSON document.
* *
......
...@@ -117,6 +117,24 @@ class FunctionsTest extends TestCase ...@@ -117,6 +117,24 @@ class FunctionsTest extends TestCase
\MongoDB\is_first_key_operator($document); \MongoDB\is_first_key_operator($document);
} }
/**
* @dataProvider provideMapReduceOutValues
*/
public function testIsMapReduceOutputInline($out, $isInline)
{
$this->assertSame($isInline, \MongoDB\is_mapreduce_output_inline($out));
}
public function provideMapReduceOutValues()
{
return [
[ 'collectionName', false ],
[ ['inline' => 1], true ],
[ ['inline' => 0], true ], // only the key is significant
[ ['replace' => 'collectionName'], false ],
];
}
/** /**
* @dataProvider provideReadConcernsAndDocuments * @dataProvider provideReadConcernsAndDocuments
*/ */
......
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