Commit 76d62e2e authored by Jeremy Mikola's avatar Jeremy Mikola

Merge pull request #4

parents f3492fb1 8e89680d
...@@ -7,12 +7,29 @@ php: ...@@ -7,12 +7,29 @@ php:
- 5.6 - 5.6
env: env:
- MONGODB_VERSION=alpha global:
- KEY_SERVER="hkp://keyserver.ubuntu.com:80"
- MONGO_REPO_URI="http://repo.mongodb.com/apt/ubuntu"
- MONGO_REPO_TYPE="precise/mongodb-enterprise/"
- SOURCES_LOC="/etc/apt/sources.list.d/mongodb.list"
matrix:
- DRIVER_VERSION=alpha SERVER_VERSION=2.4
- DRIVER_VERSION=alpha SERVER_VERSION=2.6
- DRIVER_VERSION=alpha SERVER_VERSION=3.0
services: mongodb before_install:
- sudo apt-key adv --keyserver ${KEY_SERVER} --recv 7F0CEB10
- echo "deb ${MONGO_REPO_URI} ${MONGO_REPO_TYPE}${SERVER_VERSION} multiverse" | sudo tee ${SOURCES_LOC}
- sudo apt-get update -qq
install:
- if dpkg --compare-versions ${SERVER_VERSION} le "2.4"; then export SERVER_PACKAGE=mongodb-10gen-enterprise; else export SERVER_PACKAGE=mongodb-enterprise; fi
- sudo apt-get install ${SERVER_PACKAGE}
before_script: before_script:
- mongo --eval 'tojson(db.runCommand({buildInfo:1}))' - if dpkg --compare-versions ${SERVER_VERSION} le "2.4"; then export SERVER_SERVICE=mongodb; else export SERVER_SERVICE=mongod; fi
- pecl install -f mongodb-${MONGODB_VERSION} - if ! nc -z localhost 27017; then sudo service ${SERVER_SERVICE} start; fi
- mongod --version
- pecl install -f mongodb-${DRIVER_VERSION}
- php --ri mongodb - php --ri mongodb
- composer install --dev --no-interaction --prefer-source - composer install --dev --no-interaction --prefer-source
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
<php> <php>
<ini name="error_reporting" value="-1"/> <ini name="error_reporting" value="-1"/>
<env name="MONGODB_URI" value="mongodb://127.0.0.1:27017"/> <env name="MONGODB_URI" value="mongodb://127.0.0.1:27017/?serverSelectionTimeoutMS=100"/>
<env name="MONGODB_DATABASE" value="phplib_test"/> <env name="MONGODB_DATABASE" value="phplib_test"/>
</php> </php>
......
...@@ -71,13 +71,13 @@ class Collection ...@@ -71,13 +71,13 @@ class Collection
/** /**
* Runs an aggregation framework pipeline * Runs an aggregation framework pipeline
* NOTE: The return value of this method depends on your MongoDB server version *
* and possibly options. * Note: this method's return value depends on the MongoDB server version
* MongoDB 2.6 (and later) will return a Cursor by default * and the "useCursor" option. If "useCursor" is true, a Cursor will be
* MongoDB pre 2.6 will return an ArrayIterator * returned; otherwise, an ArrayIterator is returned, which wraps the
* "result" array from the command response document.
* *
* @see http://docs.mongodb.org/manual/reference/command/aggregate/ * @see http://docs.mongodb.org/manual/reference/command/aggregate/
* @see Collection::getAggregateOptions() for supported $options
* *
* @param array $pipeline The pipeline to execute * @param array $pipeline The pipeline to execute
* @param array $options Additional options * @param array $options Additional options
...@@ -85,23 +85,61 @@ class Collection ...@@ -85,23 +85,61 @@ class Collection
*/ */
public function aggregate(array $pipeline, array $options = array()) public function aggregate(array $pipeline, array $options = array())
{ {
$options = array_merge($this->getAggregateOptions(), $options); $readPreference = new ReadPreference(ReadPreference::RP_PRIMARY);
$options = $this->_massageAggregateOptions($options); $server = $this->manager->selectServer($readPreference);
$cmd = array(
"aggregate" => $this->collname, if (FeatureDetection::isSupported($server, FeatureDetection::API_AGGREGATE_CURSOR)) {
"pipeline" => $pipeline, $options = array_merge(
) + $options; array(
/**
* Enables writing to temporary files. When set to true, aggregation stages
* can write data to the _tmp subdirectory in the dbPath directory. The
* default is false.
*
* @see http://docs.mongodb.org/manual/reference/command/aggregate/
*/
'allowDiskUse' => false,
/**
* The number of documents to return per batch.
*
* @see http://docs.mongodb.org/manual/reference/command/aggregate/
*/
'batchSize' => 0,
/**
* The maximum amount of time to allow the query to run.
*
* @see http://docs.mongodb.org/manual/reference/command/aggregate/
*/
'maxTimeMS' => 0,
/**
* Indicates if the results should be provided as a cursor.
*
* @see http://docs.mongodb.org/manual/reference/command/aggregate/
*/
'useCursor' => true,
),
$options
);
}
$cursor = $this->_runCommand($this->dbname, $cmd); $options = $this->_massageAggregateOptions($options);
$command = new Command(array(
'aggregate' => $this->collname,
'pipeline' => $pipeline,
) + $options);
$cursor = $server->executeCommand($this->dbname, $command);
if (isset($cmd["cursor"]) && $cmd["cursor"]) { if ( ! empty($options["cursor"])) {
return $cursor; return $cursor;
} }
$doc = current($cursor->toArray()); $doc = current($cursor->toArray());
if ($doc["ok"]) { if ($doc["ok"]) {
return new \ArrayIterator($doc["result"]); return new \ArrayIterator(array_map(
function (\stdClass $document) { return (array) $document; },
$doc["result"]
));
} }
throw $this->_generateCommandException($doc); throw $this->_generateCommandException($doc);
...@@ -239,12 +277,12 @@ class Collection ...@@ -239,12 +277,12 @@ class Collection
{ {
$cmd = array( $cmd = array(
"count" => $this->collname, "count" => $this->collname,
"query" => $filter, "query" => (object) $filter,
) + $options; ) + $options;
$doc = current($this->_runCommand($this->dbname, $cmd)->toArray()); $doc = current($this->_runCommand($this->dbname, $cmd)->toArray());
if ($doc["ok"]) { if ($doc["ok"]) {
return $doc["n"]; return (integer) $doc["n"];
} }
throw $this->_generateCommandException($doc); throw $this->_generateCommandException($doc);
} }
...@@ -363,7 +401,7 @@ class Collection ...@@ -363,7 +401,7 @@ class Collection
$cmd = array( $cmd = array(
"distinct" => $this->collname, "distinct" => $this->collname,
"key" => $fieldName, "key" => $fieldName,
"query" => $filter, "query" => (object) $filter,
) + $options; ) + $options;
$doc = current($this->_runCommand($this->dbname, $cmd)->toArray()); $doc = current($this->_runCommand($this->dbname, $cmd)->toArray());
...@@ -497,7 +535,7 @@ class Collection ...@@ -497,7 +535,7 @@ class Collection
$doc = current($this->_runCommand($this->dbname, $cmd)->toArray()); $doc = current($this->_runCommand($this->dbname, $cmd)->toArray());
if ($doc["ok"]) { if ($doc["ok"]) {
return $doc["value"]; return is_object($doc["value"]) ? (array) $doc["value"] : $doc["value"];
} }
throw $this->_generateCommandException($doc); throw $this->_generateCommandException($doc);
...@@ -534,7 +572,7 @@ class Collection ...@@ -534,7 +572,7 @@ class Collection
$doc = current($this->_runCommand($this->dbname, $cmd)->toArray()); $doc = current($this->_runCommand($this->dbname, $cmd)->toArray());
if ($doc["ok"]) { if ($doc["ok"]) {
return $doc["value"]; return $this->_massageFindAndModifyResult($doc, $options);
} }
throw $this->_generateCommandException($doc); throw $this->_generateCommandException($doc);
...@@ -572,61 +610,12 @@ class Collection ...@@ -572,61 +610,12 @@ class Collection
$doc = current($this->_runCommand($this->dbname, $cmd)->toArray()); $doc = current($this->_runCommand($this->dbname, $cmd)->toArray());
if ($doc["ok"]) { if ($doc["ok"]) {
return $doc["value"]; return $this->_massageFindAndModifyResult($doc, $options);
} }
throw $this->_generateCommandException($doc); throw $this->_generateCommandException($doc);
} }
/**
* Retrieves all aggregate options with their default values.
*
* @return array of Collection::aggregate() options
*/
public function getAggregateOptions()
{
$opts = array(
/**
* Enables writing to temporary files. When set to true, aggregation stages
* can write data to the _tmp subdirectory in the dbPath directory. The
* default is false.
*
* @see http://docs.mongodb.org/manual/reference/command/aggregate/
*/
"allowDiskUse" => false,
/**
* The number of documents to return per batch.
*
* @see http://docs.mongodb.org/manual/reference/command/aggregate/
*/
"batchSize" => 0,
/**
* The maximum amount of time to allow the query to run.
*
* @see http://docs.mongodb.org/manual/reference/command/aggregate/
*/
"maxTimeMS" => 0,
/**
* Indicates if the results should be provided as a cursor.
*
* The default for this value depends on the version of the server.
* - Servers >= 2.6 will use a default of true.
* - Servers < 2.6 will use a default of false.
*
* As with any other property, this value can be changed.
*
* @see http://docs.mongodb.org/manual/reference/command/aggregate/
*/
"useCursor" => true,
);
/* FIXME: Add a version check for useCursor */
return $opts;
}
/** /**
* Retrieves all Bulk Write options with their default values. * Retrieves all Bulk Write options with their default values.
* *
...@@ -961,7 +950,7 @@ class Collection ...@@ -961,7 +950,7 @@ class Collection
* *
* @see http://docs.mongodb.org/manual/reference/command/insert/ * @see http://docs.mongodb.org/manual/reference/command/insert/
* *
* @param array $documents The documents to insert * @param array[]|object[] $documents The documents to insert
* @return InsertManyResult * @return InsertManyResult
*/ */
public function insertMany(array $documents) public function insertMany(array $documents)
...@@ -976,6 +965,8 @@ class Collection ...@@ -976,6 +965,8 @@ class Collection
if ($insertedId !== null) { if ($insertedId !== null) {
$insertedIds[$i] = $insertedId; $insertedIds[$i] = $insertedId;
} else {
$insertedIds[$i] = is_array($document) ? $document['_id'] : $document->_id;
} }
} }
...@@ -989,11 +980,10 @@ class Collection ...@@ -989,11 +980,10 @@ class Collection
* *
* @see http://docs.mongodb.org/manual/reference/command/insert/ * @see http://docs.mongodb.org/manual/reference/command/insert/
* *
* @param array $document The document to insert * @param array|object $document The document to insert
* @param array $options Additional options
* @return InsertOneResult * @return InsertOneResult
*/ */
public function insertOne(array $document) public function insertOne($document)
{ {
$options = array_merge($this->getWriteOptions()); $options = array_merge($this->getWriteOptions());
...@@ -1001,6 +991,10 @@ class Collection ...@@ -1001,6 +991,10 @@ class Collection
$id = $bulk->insert($document); $id = $bulk->insert($document);
$wr = $this->manager->executeBulkWrite($this->ns, $bulk, $this->wc); $wr = $this->manager->executeBulkWrite($this->ns, $bulk, $this->wc);
if ($id === null) {
$id = is_array($document) ? $document['_id'] : $document->_id;
}
return new InsertOneResult($wr, $id); return new InsertOneResult($wr, $id);
} }
...@@ -1038,7 +1032,7 @@ class Collection ...@@ -1038,7 +1032,7 @@ class Collection
if (isset($firstKey[0]) && $firstKey[0] == '$') { if (isset($firstKey[0]) && $firstKey[0] == '$') {
throw new InvalidArgumentException("First key in \$update must NOT be a \$operator"); throw new InvalidArgumentException("First key in \$update must NOT be a \$operator");
} }
$wr = $this->_update($filter, $update, $options); $wr = $this->_update($filter, $update, $options + array("multi" => false));
return new UpdateResult($wr); return new UpdateResult($wr);
} }
...@@ -1057,7 +1051,7 @@ class Collection ...@@ -1057,7 +1051,7 @@ class Collection
*/ */
public function updateMany(array $filter, $update, array $options = array()) public function updateMany(array $filter, $update, array $options = array())
{ {
$wr = $this->_update($filter, $update, $options + array("limit" => 0)); $wr = $this->_update($filter, $update, $options + array("multi" => true));
return new UpdateResult($wr); return new UpdateResult($wr);
} }
...@@ -1080,7 +1074,7 @@ class Collection ...@@ -1080,7 +1074,7 @@ class Collection
if (!isset($firstKey[0]) || $firstKey[0] != '$') { if (!isset($firstKey[0]) || $firstKey[0] != '$') {
throw new InvalidArgumentException("First key in \$update must be a \$operator"); throw new InvalidArgumentException("First key in \$update must be a \$operator");
} }
$wr = $this->_update($filter, $update, $options); $wr = $this->_update($filter, $update, $options + array("multi" => false));
return new UpdateResult($wr); return new UpdateResult($wr);
} }
...@@ -1146,14 +1140,66 @@ class Collection ...@@ -1146,14 +1140,66 @@ class Collection
*/ */
protected function _massageAggregateOptions($options) protected function _massageAggregateOptions($options)
{ {
if ($options["useCursor"]) { if ( ! empty($options["useCursor"])) {
$options["cursor"] = array("batchSize" => $options["batchSize"]); $options["cursor"] = isset($options["batchSize"])
? array("batchSize" => (integer) $options["batchSize"])
: new stdClass;
} }
unset($options["useCursor"], $options["batchSize"]); unset($options["useCursor"], $options["batchSize"]);
return $options; return $options;
} }
/**
* Internal helper for massaging findandmodify options
* @internal
*/
final protected function _massageFindAndModifyOptions($options, $update = array())
{
$ret = array(
"sort" => $options["sort"],
"new" => isset($options["returnDocument"]) ? $options["returnDocument"] == self::FIND_ONE_AND_RETURN_AFTER : false,
"fields" => $options["projection"],
"upsert" => isset($options["upsert"]) ? $options["upsert"] : false,
);
if ($update) {
$ret["update"] = $update;
} else {
$ret["remove"] = true;
}
return $ret;
}
/**
* Internal helper for massaging the findAndModify result.
*
* @internal
* @param array $result
* @param array $options
* @return array|null
*/
final protected function _massageFindAndModifyResult(array $result, array $options)
{
if ($result['value'] === null) {
return null;
}
/* Prior to 3.0, findAndModify returns an empty document instead of null
* when an upsert is performed and the pre-modified document was
* requested.
*/
if ($options['upsert'] && ! $options['new'] &&
isset($result['lastErrorObject']->updatedExisting) &&
! $result['lastErrorObject']->updatedExisting) {
return null;
}
return is_object($result["value"])
? (array) $result['value']
: $result['value'];
}
/** /**
* Constructs the Query Wire Protocol field 'flags' based on $options * Constructs the Query Wire Protocol field 'flags' based on $options
* provided to other helpers * provided to other helpers
......
...@@ -14,6 +14,7 @@ class FeatureDetection ...@@ -14,6 +14,7 @@ class FeatureDetection
const API_LISTCOLLECTIONS_CMD = 3; const API_LISTCOLLECTIONS_CMD = 3;
const API_LISTINDEXES_CMD = 3; const API_LISTINDEXES_CMD = 3;
const API_CREATEINDEXES_CMD = 2; const API_CREATEINDEXES_CMD = 2;
const API_AGGREGATE_CURSOR = 2;
/** /**
* Return whether the server supports a particular feature. * Return whether the server supports a particular feature.
......
...@@ -16,7 +16,7 @@ class InsertManyResult ...@@ -16,7 +16,7 @@ class InsertManyResult
* Constructor. * Constructor.
* *
* @param WriteResult $writeResult * @param WriteResult $writeResult
* @param array $insertedIds * @param mixed[] $insertedIds
*/ */
public function __construct(WriteResult $writeResult, array $insertedIds = array()) public function __construct(WriteResult $writeResult, array $insertedIds = array())
{ {
...@@ -41,10 +41,11 @@ class InsertManyResult ...@@ -41,10 +41,11 @@ class InsertManyResult
* Return the map of inserted IDs that were generated by the driver. * Return the map of inserted IDs that were generated by the driver.
* *
* The index of each ID in the map corresponds to the document's position * The index of each ID in the map corresponds to the document's position
* in bulk operation. If an inserted document already had an ID (e.g. it was * in bulk operation. If the document already an ID prior to insertion (i.e.
* generated by the application), it will not be present in this map. * the driver did not need to generate an ID), this will contain its "_id".
* Any driver-generated ID will be an MongoDB\Driver\ObjectID instance.
* *
* @return array * @return mixed[]
*/ */
public function getInsertedIds() public function getInsertedIds()
{ {
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
namespace MongoDB; namespace MongoDB;
use BSON\ObjectId;
use MongoDB\Driver\WriteResult; use MongoDB\Driver\WriteResult;
/** /**
...@@ -17,9 +16,9 @@ class InsertOneResult ...@@ -17,9 +16,9 @@ class InsertOneResult
* Constructor. * Constructor.
* *
* @param WriteResult $writeResult * @param WriteResult $writeResult
* @param ObjectId $insertedId * @param mixed $insertedId
*/ */
public function __construct(WriteResult $writeResult, ObjectId $insertedId = null) public function __construct(WriteResult $writeResult, $insertedId)
{ {
$this->writeResult = $writeResult; $this->writeResult = $writeResult;
$this->insertedId = $insertedId; $this->insertedId = $insertedId;
...@@ -41,10 +40,11 @@ class InsertOneResult ...@@ -41,10 +40,11 @@ class InsertOneResult
/** /**
* Return the inserted ID that was generated by the driver. * Return the inserted ID that was generated by the driver.
* *
* If the inserted document already had an ID (e.g. it was generated by the * If the document already an ID prior to insertion (i.e. the driver did not
* application), this will be null. * need to generate an ID), this will contain its "_id". Any
* driver-generated ID will be an MongoDB\Driver\ObjectID instance.
* *
* @return ObjectId|null * @return mixed
*/ */
public function getInsertedId() public function getInsertedId()
{ {
......
<?php
namespace MongoDB\Tests\Collection;
use MongoDB\Tests\FixtureGenerator;
/**
* Functional tests for the Collection class.
*/
class CollectionFunctionalTest extends FunctionalTestCase
{
public function testDrop()
{
$writeResult = $this->collection->insertOne(array('x' => 1));
$this->assertEquals(1, $writeResult->getInsertedCount());
$commandResult = $this->collection->drop();
$this->assertCommandSucceeded($commandResult);
$this->assertCollectionCount($this->getNamespace(), 0);
}
function testInsertAndRetrieve()
{
$generator = new FixtureGenerator();
for ($i = 0; $i < 10; $i++) {
$user = $generator->createUser();
$result = $this->collection->insertOne($user);
$this->assertInstanceOf('MongoDB\InsertOneResult', $result);
$this->assertInstanceOf('BSON\ObjectId', $result->getInsertedId());
$this->assertEquals(24, strlen($result->getInsertedId()));
$user["_id"] = $result->getInsertedId();
$document = $this->collection->findOne(array("_id" => $result->getInsertedId()));
$this->assertEquals($document, $user, "The inserted and returned objects are the same");
}
$this->assertEquals(10, $i);
$query = array("firstName" => "Ransom");
$count = $this->collection->count($query);
$this->assertEquals(1, $count);
$cursor = $this->collection->find($query);
$this->assertInstanceOf('MongoDB\Driver\Cursor', $cursor);
foreach($cursor as $n => $person) {
$this->assertInternalType("array", $person);
}
$this->assertEquals(0, $n);
}
}
<?php
namespace MongoDB\Tests\Collection\CrudSpec;
use MongoDB\Collection;
use MongoDB\FeatureDetection;
use MongoDB\Driver\ReadPreference;
/**
* CRUD spec functional tests for aggregate().
*
* @see https://github.com/mongodb/specifications/tree/master/source/crud/tests
*/
class AggregateFunctionalTest extends FunctionalTestCase
{
public function setUp()
{
parent::setUp();
$this->createFixtures(3);
}
public function testAggregateWithMultipleStages()
{
$cursor = $this->collection->aggregate(
array(
array('$sort' => array('x' => 1)),
array('$match' => array('_id' => array('$gt' => 1))),
),
array('batchSize' => 2)
);
$expected = array(
array('_id' => 2, 'x' => 22),
array('_id' => 3, 'x' => 33),
);
// Use iterator_to_array() here since aggregate() may return an ArrayIterator
$this->assertSame($expected, iterator_to_array($cursor));
}
public function testAggregateWithOut()
{
$server = $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
if ( ! FeatureDetection::isSupported($server, FeatureDetection::API_AGGREGATE_CURSOR)) {
$this->markTestSkipped('$out aggregation pipeline operator is not supported');
}
$outputCollection = new Collection($this->manager, $this->getNamespace() . '_output');
$this->dropCollectionIfItExists($outputCollection);
$this->collection->aggregate(
array(
array('$sort' => array('x' => 1)),
array('$match' => array('_id' => array('$gt' => 1))),
array('$out' => $outputCollection->getCollectionName()),
)
);
$expected = array(
array('_id' => 2, 'x' => 22),
array('_id' => 3, 'x' => 33),
);
$this->assertSame($expected, $outputCollection->find()->toArray());
// Manually clean up our output collection
$this->dropCollectionIfItExists($outputCollection);
}
}
<?php
namespace MongoDB\Tests\Collection\CrudSpec;
/**
* CRUD spec functional tests for count().
*
* @see https://github.com/mongodb/specifications/tree/master/source/crud/tests
*/
class CountFunctionalTest extends FunctionalTestCase
{
public function setUp()
{
parent::setUp();
$this->createFixtures(3);
}
public function testCountWithoutFilter()
{
$this->assertSame(3, $this->collection->count());
}
public function testCountWithFilter()
{
$filter = array('_id' => array('$gt' => 1));
$this->assertSame(2, $this->collection->count($filter));
}
public function testCountWithSkipAndLimit()
{
$filter = array();
$options = array('skip' => 1, 'limit' => 3);
$this->assertSame(2, $this->collection->count($filter, $options));
}
}
<?php
namespace MongoDB\Tests\Collection\CrudSpec;
/**
* CRUD spec functional tests for deleteMany().
*
* @see https://github.com/mongodb/specifications/tree/master/source/crud/tests
*/
class DeleteManyFunctionalTest extends FunctionalTestCase
{
public function setUp()
{
parent::setUp();
$this->createFixtures(3);
}
public function testDeleteManyWhenManyDocumentsMatch()
{
$filter = array('_id' => array('$gt' => 1));
$result = $this->collection->deleteMany($filter);
$this->assertSame(2, $result->getDeletedCount());
$expected = array(
array('_id' => 1, 'x' => 11),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
public function testDeleteManyWhenNoDocumentsMatch()
{
$filter = array('_id' => 4);
$result = $this->collection->deleteMany($filter);
$this->assertSame(0, $result->getDeletedCount());
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 22),
array('_id' => 3, 'x' => 33),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
}
<?php
namespace MongoDB\Tests\Collection\CrudSpec;
/**
* CRUD spec functional tests for deleteOne().
*
* @see https://github.com/mongodb/specifications/tree/master/source/crud/tests
*/
class DeleteOneFunctionalTest extends FunctionalTestCase
{
public function setUp()
{
parent::setUp();
$this->createFixtures(3);
}
public function testDeleteOneWhenManyDocumentsMatch()
{
$filter = array('_id' => array('$gt' => 1));
$result = $this->collection->deleteOne($filter);
$this->assertSame(1, $result->getDeletedCount());
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 3, 'x' => 33),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
public function testDeleteOneWhenOneDocumentMatches()
{
$filter = array('_id' => 2);
$result = $this->collection->deleteOne($filter);
$this->assertSame(1, $result->getDeletedCount());
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 3, 'x' => 33),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
public function testDeleteOneWhenNoDocumentsMatch()
{
$filter = array('_id' => 4);
$result = $this->collection->deleteOne($filter);
$this->assertSame(0, $result->getDeletedCount());
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 22),
array('_id' => 3, 'x' => 33),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
}
<?php
namespace MongoDB\Tests\Collection\CrudSpec;
/**
* CRUD spec functional tests for distinct().
*
* @see https://github.com/mongodb/specifications/tree/master/source/crud/tests
*/
class DistinctFunctionalTest extends FunctionalTestCase
{
public function setUp()
{
parent::setUp();
$this->createFixtures(3);
}
public function testDistinctWithoutFilter()
{
$this->assertSame(array(11, 22, 33), $this->collection->distinct('x'));
}
public function testDistinctWithFilter()
{
$filter = array('_id' => array('$gt' => 1));
$this->assertSame(array(22, 33), $this->collection->distinct('x', $filter));
}
}
<?php
namespace MongoDB\Tests\Collection\CrudSpec;
/**
* CRUD spec functional tests for find().
*
* @see https://github.com/mongodb/specifications/tree/master/source/crud/tests
*/
class FindFunctionalTest extends FunctionalTestCase
{
public function setUp()
{
parent::setUp();
$this->createFixtures(5);
}
public function testFindWithFilter()
{
$filter = array('_id' => 1);
$expected = array(
array('_id' => 1, 'x' => 11),
);
$this->assertSame($expected, $this->collection->find($filter)->toArray());
}
public function testFindWithFilterSortSkipAndLimit()
{
$filter = array('_id' => array('$gt' => 2));
$options = array(
'sort' => array('_id' => 1),
'skip' => 2,
'limit' => 2,
);
$expected = array(
array('_id' => 5, 'x' => 55),
);
$this->assertSame($expected, $this->collection->find($filter, $options)->toArray());
}
public function testFindWithLimitSortAndBatchSize()
{
$filter = array();
$options = array(
'sort' => array('_id' => 1),
'limit' => 4,
'batchSize' => 2,
);
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 22),
array('_id' => 3, 'x' => 33),
array('_id' => 4, 'x' => 44),
);
$this->assertSame($expected, $this->collection->find($filter, $options)->toArray());
}
}
<?php
namespace MongoDB\Tests\Collection\CrudSpec;
/**
* CRUD spec functional tests for findOneAndDelete().
*
* @see https://github.com/mongodb/specifications/tree/master/source/crud/tests
*/
class FindOneAndDeleteFunctionalTest extends FunctionalTestCase
{
public function setUp()
{
parent::setUp();
$this->createFixtures(3);
}
public function testFindOneAndDeleteWhenManyDocumentsMatch()
{
$filter = array('_id' => array('$gt' => 1));
$options = array(
'projection' => array('x' => 1, '_id' => 0),
'sort' => array('x' => 1),
);
$document = $this->collection->findOneAndDelete($filter, $options);
$this->assertSame(array('x' => 22), $document);
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 3, 'x' => 33),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
public function testFindOneAndDeleteWhenOneDocumentMatches()
{
$filter = array('_id' => 2);
$options = array(
'projection' => array('x' => 1, '_id' => 0),
'sort' => array('x' => 1),
);
$document = $this->collection->findOneAndDelete($filter, $options);
$this->assertSame(array('x' => 22), $document);
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 3, 'x' => 33),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
public function testFindOneAndDeleteWhenNoDocumentsMatch()
{
$filter = array('_id' => 4);
$options = array(
'projection' => array('x' => 1, '_id' => 0),
'sort' => array('x' => 1),
);
$document = $this->collection->findOneAndDelete($filter, $options);
$this->assertNull($document);
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 22),
array('_id' => 3, 'x' => 33),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
}
<?php
namespace MongoDB\Tests\Collection\CrudSpec;
use MongoDB\Collection;
/**
* CRUD spec functional tests for findOneAndReplace().
*
* @see https://github.com/mongodb/specifications/tree/master/source/crud/tests
*/
class FindOneAndReplaceFunctionalTest extends FunctionalTestCase
{
public function setUp()
{
parent::setUp();
$this->createFixtures(3);
}
public function testFindOneAndReplaceWhenManyDocumentsMatchReturningDocumentBeforeModification()
{
$filter = array('_id' => array('$gt' => 1));
$replacement = array('x' => 32);
$options = array(
'projection' => array('x' => 1, '_id' => 0),
'sort' => array('x' => 1),
);
$document = $this->collection->findOneAndReplace($filter, $replacement, $options);
$this->assertSame(array('x' => 22), $document);
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 32),
array('_id' => 3, 'x' => 33),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
public function testFindOneAndReplaceWhenManyDocumentsMatchReturningDocumentAfterModification()
{
$filter = array('_id' => array('$gt' => 1));
$replacement = array('x' => 32);
$options = array(
'projection' => array('x' => 1, '_id' => 0),
'sort' => array('x' => 1),
'returnDocument' => Collection::FIND_ONE_AND_RETURN_AFTER,
);
$document = $this->collection->findOneAndReplace($filter, $replacement, $options);
$this->assertSame(array('x' => 32), $document);
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 32),
array('_id' => 3, 'x' => 33),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
public function testFindOneAndReplaceWhenOneDocumentMatchesReturningDocumentBeforeModification()
{
$filter = array('_id' => 2);
$replacement = array('x' => 32);
$options = array(
'projection' => array('x' => 1, '_id' => 0),
'sort' => array('x' => 1),
);
$document = $this->collection->findOneAndReplace($filter, $replacement, $options);
$this->assertSame(array('x' => 22), $document);
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 32),
array('_id' => 3, 'x' => 33),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
public function testFindOneAndReplaceWhenOneDocumentMatchesReturningDocumentAfterModification()
{
$filter = array('_id' => 2);
$replacement = array('x' => 32);
$options = array(
'projection' => array('x' => 1, '_id' => 0),
'sort' => array('x' => 1),
'returnDocument' => Collection::FIND_ONE_AND_RETURN_AFTER,
);
$document = $this->collection->findOneAndReplace($filter, $replacement, $options);
$this->assertSame(array('x' => 32), $document);
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 32),
array('_id' => 3, 'x' => 33),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
public function testFindOneAndReplaceWhenNoDocumentsMatchReturningDocumentBeforeModification()
{
$filter = array('_id' => 4);
$replacement = array('x' => 44);
$options = array(
'projection' => array('x' => 1, '_id' => 0),
'sort' => array('x' => 1),
);
$document = $this->collection->findOneAndReplace($filter, $replacement, $options);
$this->assertNull($document);
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 22),
array('_id' => 3, 'x' => 33),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
public function testFindOneAndReplaceWithUpsertWhenNoDocumentsMatchReturningDocumentBeforeModification()
{
$filter = array('_id' => 4);
// Server 2.4 and earlier requires any custom ID to also be in the replacement document
$replacement = array('_id' => 4, 'x' => 44);
$options = array(
'projection' => array('x' => 1, '_id' => 0),
'sort' => array('x' => 1),
'upsert' => true,
);
$document = $this->collection->findOneAndReplace($filter, $replacement, $options);
$this->assertNull($document);
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 22),
array('_id' => 3, 'x' => 33),
array('_id' => 4, 'x' => 44),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
public function testFindOneAndReplaceWhenNoDocumentsMatchReturningDocumentAfterModification()
{
$filter = array('_id' => 4);
$replacement = array('x' => 44);
$options = array(
'projection' => array('x' => 1, '_id' => 0),
'sort' => array('x' => 1),
'returnDocument' => Collection::FIND_ONE_AND_RETURN_AFTER,
);
$document = $this->collection->findOneAndReplace($filter, $replacement, $options);
$this->assertNull($document);
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 22),
array('_id' => 3, 'x' => 33),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
public function testFindOneAndReplaceWithUpsertWhenNoDocumentsMatchReturningDocumentAfterModification()
{
$filter = array('_id' => 4);
// Server 2.4 and earlier requires any custom ID to also be in the replacement document
$replacement = array('_id' => 4, 'x' => 44);
$options = array(
'projection' => array('x' => 1, '_id' => 0),
'sort' => array('x' => 1),
'returnDocument' => Collection::FIND_ONE_AND_RETURN_AFTER,
'upsert' => true,
);
$document = $this->collection->findOneAndReplace($filter, $replacement, $options);
$this->assertSame(array('x' => 44), $document);
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 22),
array('_id' => 3, 'x' => 33),
array('_id' => 4, 'x' => 44),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
}
<?php
namespace MongoDB\Tests\Collection\CrudSpec;
use MongoDB\Collection;
/**
* CRUD spec functional tests for findOneAndUpdate().
*
* @see https://github.com/mongodb/specifications/tree/master/source/crud/tests
*/
class FindOneAndUpdateFunctionalTest extends FunctionalTestCase
{
public function setUp()
{
parent::setUp();
$this->createFixtures(3);
}
public function testFindOneAndUpdateWhenManyDocumentsMatchReturningDocumentBeforeModification()
{
$filter = array('_id' => array('$gt' => 1));
$update = array('$inc' => array('x' => 1));
$options = array(
'projection' => array('x' => 1, '_id' => 0),
'sort' => array('x' => 1),
);
$document = $this->collection->findOneAndUpdate($filter, $update, $options);
$this->assertSame(array('x' => 22), $document);
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 23),
array('_id' => 3, 'x' => 33),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
public function testFindOneAndUpdateWhenManyDocumentsMatchReturningDocumentAfterModification()
{
$filter = array('_id' => array('$gt' => 1));
$update = array('$inc' => array('x' => 1));
$options = array(
'projection' => array('x' => 1, '_id' => 0),
'sort' => array('x' => 1),
'returnDocument' => Collection::FIND_ONE_AND_RETURN_AFTER,
);
$document = $this->collection->findOneAndUpdate($filter, $update, $options);
$this->assertSame(array('x' => 23), $document);
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 23),
array('_id' => 3, 'x' => 33),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
public function testFindOneAndUpdateWhenOneDocumentMatchesReturningDocumentBeforeModification()
{
$filter = array('_id' => 2);
$update = array('$inc' => array('x' => 1));
$options = array(
'projection' => array('x' => 1, '_id' => 0),
'sort' => array('x' => 1),
);
$document = $this->collection->findOneAndUpdate($filter, $update, $options);
$this->assertSame(array('x' => 22), $document);
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 23),
array('_id' => 3, 'x' => 33),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
public function testFindOneAndUpdateWhenOneDocumentMatchesReturningDocumentAfterModification()
{
$filter = array('_id' => 2);
$update = array('$inc' => array('x' => 1));
$options = array(
'projection' => array('x' => 1, '_id' => 0),
'sort' => array('x' => 1),
'returnDocument' => Collection::FIND_ONE_AND_RETURN_AFTER,
);
$document = $this->collection->findOneAndUpdate($filter, $update, $options);
$this->assertSame(array('x' => 23), $document);
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 23),
array('_id' => 3, 'x' => 33),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
public function testFindOneAndUpdateWhenNoDocumentsMatchReturningDocumentBeforeModification()
{
$filter = array('_id' => 4);
$update = array('$inc' => array('x' => 1));
$options = array(
'projection' => array('x' => 1, '_id' => 0),
'sort' => array('x' => 1),
);
$document = $this->collection->findOneAndUpdate($filter, $update, $options);
$this->assertNull($document);
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 22),
array('_id' => 3, 'x' => 33),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
public function testFindOneAndUpdateWithUpsertWhenNoDocumentsMatchReturningDocumentBeforeModification()
{
$filter = array('_id' => 4);
$update = array('$inc' => array('x' => 1));
$options = array(
'projection' => array('x' => 1, '_id' => 0),
'sort' => array('x' => 1),
'upsert' => true,
);
$document = $this->collection->findOneAndUpdate($filter, $update, $options);
$this->assertNull($document);
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 22),
array('_id' => 3, 'x' => 33),
array('_id' => 4, 'x' => 1),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
public function testFindOneAndUpdateWhenNoDocumentsMatchReturningDocumentAfterModification()
{
$filter = array('_id' => 4);
$update = array('$inc' => array('x' => 1));
$options = array(
'projection' => array('x' => 1, '_id' => 0),
'sort' => array('x' => 1),
'returnDocument' => Collection::FIND_ONE_AND_RETURN_AFTER,
);
$document = $this->collection->findOneAndUpdate($filter, $update, $options);
$this->assertNull($document);
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 22),
array('_id' => 3, 'x' => 33),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
public function testFindOneAndUpdateWithUpsertWhenNoDocumentsMatchReturningDocumentAfterModification()
{
$filter = array('_id' => 4);
$update = array('$inc' => array('x' => 1));
$options = array(
'projection' => array('x' => 1, '_id' => 0),
'sort' => array('x' => 1),
'returnDocument' => Collection::FIND_ONE_AND_RETURN_AFTER,
'upsert' => true,
);
$document = $this->collection->findOneAndUpdate($filter, $update, $options);
$this->assertSame(array('x' => 1), $document);
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 22),
array('_id' => 3, 'x' => 33),
array('_id' => 4, 'x' => 1),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
}
<?php
namespace MongoDB\Tests\Collection\CrudSpec;
use MongoDB\Driver\BulkWrite;
use MongoDB\Tests\Collection\FunctionalTestCase as BaseFunctionalTestCase;
/**
* Base class for Collection CRUD spec functional tests.
*/
abstract class FunctionalTestCase extends BaseFunctionalTestCase
{
/**
* Create data fixtures.
*
* @param integer $n
*/
protected function createFixtures($n)
{
$bulkWrite = new BulkWrite(true);
for ($i = 1; $i <= $n; $i++) {
$bulkWrite->insert(array(
'_id' => $i,
'x' => (integer) ($i . $i),
));
}
$result = $this->manager->executeBulkWrite($this->getNamespace(), $bulkWrite);
$this->assertEquals($n, $result->getInsertedCount());
}
}
<?php
namespace MongoDB\Tests\Collection\CrudSpec;
/**
* CRUD spec functional tests for insertMany().
*
* @see https://github.com/mongodb/specifications/tree/master/source/crud/tests
*/
class InsertManyFunctionalTest extends FunctionalTestCase
{
public function setUp()
{
parent::setUp();
$this->createFixtures(1);
}
public function testInsertManyWithNonexistentDocuments()
{
$documents = array(
array('_id' => 2, 'x' => 22),
array('_id' => 3, 'x' => 33),
);
$result = $this->collection->insertMany($documents);
$this->assertSame(2, $result->getInsertedCount());
$this->assertSame(array(2, 3), $result->getInsertedIds());
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 22),
array('_id' => 3, 'x' => 33),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
}
<?php
namespace MongoDB\Tests\Collection\CrudSpec;
/**
* CRUD spec functional tests for insertOne().
*
* @see https://github.com/mongodb/specifications/tree/master/source/crud/tests
*/
class InsertOneFunctionalTest extends FunctionalTestCase
{
public function setUp()
{
parent::setUp();
$this->createFixtures(1);
}
public function testInsertOneWithANonexistentDocument()
{
$document = array('_id' => 2, 'x' => 22);
$result = $this->collection->insertOne($document);
$this->assertSame(1, $result->getInsertedCount());
$this->assertSame(2, $result->getInsertedId());
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 22),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
}
<?php
namespace MongoDB\Tests\Collection\CrudSpec;
/**
* CRUD spec functional tests for replaceOne().
*
* @see https://github.com/mongodb/specifications/tree/master/source/crud/tests
*/
class ReplaceOneFunctionalTest extends FunctionalTestCase
{
private $omitModifiedCount;
public function setUp()
{
parent::setUp();
$this->createFixtures(3);
$this->omitModifiedCount = version_compare($this->getServerVersion(), '2.6.0', '<');
}
public function testReplaceOneWhenManyDocumentsMatch()
{
$filter = array('_id' => array('$gt' => 1));
$replacement = array('x' => 111);
$result = $this->collection->replaceOne($filter, $replacement);
$this->assertSame(1, $result->getMatchedCount());
$this->omitModifiedCount or $this->assertSame(1, $result->getModifiedCount());
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 111),
array('_id' => 3, 'x' => 33),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
public function testReplaceOneWhenOneDocumentMatches()
{
$filter = array('_id' => 1);
$replacement = array('x' => 111);
$result = $this->collection->replaceOne($filter, $replacement);
$this->assertSame(1, $result->getMatchedCount());
$this->omitModifiedCount or $this->assertSame(1, $result->getModifiedCount());
$expected = array(
array('_id' => 1, 'x' => 111),
array('_id' => 2, 'x' => 22),
array('_id' => 3, 'x' => 33),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
public function testReplaceOneWhenNoDocumentsMatch()
{
$filter = array('_id' => 4);
$replacement = array('x' => 111);
$result = $this->collection->replaceOne($filter, $replacement);
$this->assertSame(0, $result->getMatchedCount());
$this->omitModifiedCount or $this->assertSame(0, $result->getModifiedCount());
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 22),
array('_id' => 3, 'x' => 33),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
public function testReplaceOneWithUpsertWhenNoDocumentsMatchWithAnIdSpecified()
{
$filter = array('_id' => 4);
$replacement = array('_id' => 4, 'x' => 1);
$options = array('upsert' => true);
$result = $this->collection->replaceOne($filter, $replacement, $options);
$this->assertSame(0, $result->getMatchedCount());
$this->omitModifiedCount or $this->assertSame(0, $result->getModifiedCount());
$this->assertSame(4, $result->getUpsertedId());
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 22),
array('_id' => 3, 'x' => 33),
array('_id' => 4, 'x' => 1),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
public function testReplaceOneWithUpsertWhenNoDocumentsMatchWithoutAnIdSpecified()
{
$filter = array('_id' => 4);
// Server 2.4 and earlier requires any custom ID to also be in the replacement document
$replacement = array('_id' => 4, 'x' => 1);
$options = array('upsert' => true);
$result = $this->collection->replaceOne($filter, $replacement, $options);
$this->assertSame(0, $result->getMatchedCount());
$this->omitModifiedCount or $this->assertSame(0, $result->getModifiedCount());
$this->assertSame(4, $result->getUpsertedId());
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 22),
array('_id' => 3, 'x' => 33),
array('_id' => 4, 'x' => 1),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
}
<?php
namespace MongoDB\Tests\Collection\CrudSpec;
/**
* CRUD spec functional tests for updateMany().
*
* @see https://github.com/mongodb/specifications/tree/master/source/crud/tests
*/
class UpdateManyFunctionalTest extends FunctionalTestCase
{
private $omitModifiedCount;
public function setUp()
{
parent::setUp();
$this->createFixtures(3);
$this->omitModifiedCount = version_compare($this->getServerVersion(), '2.6.0', '<');
}
public function testUpdateManyWhenManyDocumentsMatch()
{
$filter = array('_id' => array('$gt' => 1));
$update = array('$inc' => array('x' => 1));
$result = $this->collection->updateMany($filter, $update);
$this->assertSame(2, $result->getMatchedCount());
$this->omitModifiedCount or $this->assertSame(2, $result->getModifiedCount());
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 23),
array('_id' => 3, 'x' => 34),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
public function testUpdateManyWhenOneDocumentMatches()
{
$filter = array('_id' => 1);
$update = array('$inc' => array('x' => 1));
$result = $this->collection->updateMany($filter, $update);
$this->assertSame(1, $result->getMatchedCount());
$this->omitModifiedCount or $this->assertSame(1, $result->getModifiedCount());
$expected = array(
array('_id' => 1, 'x' => 12),
array('_id' => 2, 'x' => 22),
array('_id' => 3, 'x' => 33),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
public function testUpdateManyWhenNoDocumentsMatch()
{
$filter = array('_id' => 4);
$update = array('$inc' => array('x' => 1));
$result = $this->collection->updateMany($filter, $update);
$this->assertSame(0, $result->getMatchedCount());
$this->omitModifiedCount or $this->assertSame(0, $result->getModifiedCount());
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 22),
array('_id' => 3, 'x' => 33),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
public function testUpdateManyWithUpsertWhenNoDocumentsMatch()
{
$filter = array('_id' => 4);
$update = array('$inc' => array('x' => 1));
$options = array('upsert' => true);
$result = $this->collection->updateMany($filter, $update, $options);
$this->assertSame(0, $result->getMatchedCount());
$this->omitModifiedCount or $this->assertSame(0, $result->getModifiedCount());
$this->assertSame(4, $result->getUpsertedId());
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 22),
array('_id' => 3, 'x' => 33),
array('_id' => 4, 'x' => 1),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
}
<?php
namespace MongoDB\Tests\Collection\CrudSpec;
/**
* CRUD spec functional tests for updateOne().
*
* @see https://github.com/mongodb/specifications/tree/master/source/crud/tests
*/
class UpdateOneFunctionalTest extends FunctionalTestCase
{
private $omitModifiedCount;
public function setUp()
{
parent::setUp();
$this->createFixtures(3);
$this->omitModifiedCount = version_compare($this->getServerVersion(), '2.6.0', '<');
}
public function testUpdateOneWhenManyDocumentsMatch()
{
$filter = array('_id' => array('$gt' => 1));
$update = array('$inc' => array('x' => 1));
$result = $this->collection->updateOne($filter, $update);
$this->assertSame(1, $result->getMatchedCount());
$this->omitModifiedCount or $this->assertSame(1, $result->getModifiedCount());
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 23),
array('_id' => 3, 'x' => 33),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
public function testUpdateOneWhenOneDocumentMatches()
{
$filter = array('_id' => 1);
$update = array('$inc' => array('x' => 1));
$result = $this->collection->updateOne($filter, $update);
$this->assertSame(1, $result->getMatchedCount());
$this->omitModifiedCount or $this->assertSame(1, $result->getModifiedCount());
$expected = array(
array('_id' => 1, 'x' => 12),
array('_id' => 2, 'x' => 22),
array('_id' => 3, 'x' => 33),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
public function testUpdateOneWhenNoDocumentsMatch()
{
$filter = array('_id' => 4);
$update = array('$inc' => array('x' => 1));
$result = $this->collection->updateOne($filter, $update);
$this->assertSame(0, $result->getMatchedCount());
$this->omitModifiedCount or $this->assertSame(0, $result->getModifiedCount());
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 22),
array('_id' => 3, 'x' => 33),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
public function testUpdateOneWithUpsertWhenNoDocumentsMatch()
{
$filter = array('_id' => 4);
$update = array('$inc' => array('x' => 1));
$options = array('upsert' => true);
$result = $this->collection->updateOne($filter, $update, $options);
$this->assertSame(0, $result->getMatchedCount());
$this->omitModifiedCount or $this->assertSame(0, $result->getModifiedCount());
$this->assertSame(4, $result->getUpsertedId());
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 22),
array('_id' => 3, 'x' => 33),
array('_id' => 4, 'x' => 1),
);
$this->assertSame($expected, $this->collection->find()->toArray());
}
}
<?php
namespace MongoDB\Tests\Collection;
use MongoDB\Collection;
use MongoDB\Database;
use MongoDB\Tests\FunctionalTestCase as BaseFunctionalTestCase;
/**
* Base class for Collection functional tests.
*/
abstract class FunctionalTestCase extends BaseFunctionalTestCase
{
protected $collection;
public function setUp()
{
parent::setUp();
$this->collection = new Collection($this->manager, $this->getNamespace());
$this->dropCollectionIfItExists($this->collection);
}
public function tearDown()
{
if ($this->hasFailed()) {
return;
}
$this->dropCollectionIfItExists($this->collection);
}
/**
* Drop the collection if it exists.
*
* @param Collection $collection
*/
protected function dropCollectionIfItExists(Collection $collection)
{
$database = new Database($this->manager, $collection->getDatabaseName());
$collections = $database->listCollections(array('filter' => array('name' => $collection->getCollectionName())));
if (iterator_count($collections) > 0) {
$this->assertCommandSucceeded($collection->drop());
}
}
}
<?php <?php
namespace MongoDB\Tests; namespace MongoDB\Tests\Collection;
use MongoDB\Collection;
use MongoDB\Driver\Manager;
use MongoDB\Model\IndexInfo; use MongoDB\Model\IndexInfo;
use InvalidArgumentException; use InvalidArgumentException;
class CollectionFunctionalTest extends FunctionalTestCase /**
* Functional tests for index management methods.
*
* @see https://github.com/mongodb/specifications/blob/master/source/index-management.rst
*/
class IndexManagementFunctionalTest extends FunctionalTestCase
{ {
private $collection;
public function setUp()
{
parent::setUp();
$this->collection = new Collection($this->manager, $this->getNamespace());
$this->collection->deleteMany(array());
}
public function testDrop()
{
$writeResult = $this->collection->insertOne(array('x' => 1));
$this->assertEquals(1, $writeResult->getInsertedCount());
$commandResult = $this->collection->drop();
$this->assertCommandSucceeded($commandResult);
$this->assertCollectionCount($this->getNamespace(), 0);
}
function testInsertAndRetrieve()
{
$generator = new FixtureGenerator();
for ($i = 0; $i < 10; $i++) {
$user = $generator->createUser();
$result = $this->collection->insertOne($user);
$this->assertInstanceOf('MongoDB\InsertOneResult', $result);
$this->assertInstanceOf('BSON\ObjectId', $result->getInsertedId());
$this->assertEquals(24, strlen($result->getInsertedId()));
$user["_id"] = $result->getInsertedId();
$document = $this->collection->findOne(array("_id" => $result->getInsertedId()));
$this->assertEquals($document, $user, "The inserted and returned objects are the same");
}
$this->assertEquals(10, $i);
$query = array("firstName" => "Ransom");
$count = $this->collection->count($query);
$this->assertEquals(1, $count);
$cursor = $this->collection->find($query);
$this->assertInstanceOf('MongoDB\Driver\Cursor', $cursor);
foreach($cursor as $n => $person) {
$this->assertInternalType("array", $person);
}
$this->assertEquals(0, $n);
}
public function testCreateIndex() public function testCreateIndex()
{ {
$that = $this; $that = $this;
......
<?php <?php
namespace MongoDB\Tests; namespace MongoDB\Tests\Database;
use MongoDB\Client;
use MongoDB\Database;
use MongoDB\Model\CollectionInfo; use MongoDB\Model\CollectionInfo;
use InvalidArgumentException; use InvalidArgumentException;
/** /**
* Functional tests for the Database class. * Functional tests for collection management methods.
*/ */
class DatabaseFunctionalTest extends FunctionalTestCase class CollectionManagementFunctionalTest extends FunctionalTestCase
{ {
private $database;
public function setUp()
{
parent::setUp();
$this->database = new Database($this->manager, $this->getDatabaseName());
$this->database->drop();
}
public function testCreateCollection() public function testCreateCollection()
{ {
$that = $this; $that = $this;
...@@ -49,16 +37,6 @@ class DatabaseFunctionalTest extends FunctionalTestCase ...@@ -49,16 +37,6 @@ class DatabaseFunctionalTest extends FunctionalTestCase
}); });
} }
public function testDrop()
{
$writeResult = $this->manager->executeInsert($this->getNamespace(), array('x' => 1));
$this->assertEquals(1, $writeResult->getInsertedCount());
$commandResult = $this->database->drop();
$this->assertCommandSucceeded($commandResult);
$this->assertCollectionCount($this->getNamespace(), 0);
}
public function testDropCollection() public function testDropCollection()
{ {
$writeResult = $this->manager->executeInsert($this->getNamespace(), array('x' => 1)); $writeResult = $this->manager->executeInsert($this->getNamespace(), array('x' => 1));
......
<?php
namespace MongoDB\Tests\Database;
/**
* Functional tests for the Database class.
*/
class DatabaseFunctionalTest extends FunctionalTestCase
{
public function testDrop()
{
$writeResult = $this->manager->executeInsert($this->getNamespace(), array('x' => 1));
$this->assertEquals(1, $writeResult->getInsertedCount());
$commandResult = $this->database->drop();
$this->assertCommandSucceeded($commandResult);
$this->assertCollectionCount($this->getNamespace(), 0);
}
}
<?php
namespace MongoDB\Tests\Database;
use MongoDB\Database;
use MongoDB\Tests\FunctionalTestCase as BaseFunctionalTestCase;
/**
* Base class for Database functional tests.
*/
abstract class FunctionalTestCase extends BaseFunctionalTestCase
{
protected $database;
public function setUp()
{
parent::setUp();
$this->database = new Database($this->manager, $this->getDatabaseName());
$this->database->drop();
}
}
...@@ -3,8 +3,9 @@ ...@@ -3,8 +3,9 @@
namespace MongoDB\Tests; namespace MongoDB\Tests;
use MongoDB\Driver\Command; use MongoDB\Driver\Command;
use MongoDB\Driver\Manager;
use MongoDB\Driver\Cursor; use MongoDB\Driver\Cursor;
use MongoDB\Driver\Manager;
use MongoDB\Driver\ReadPreference;
abstract class FunctionalTestCase extends TestCase abstract class FunctionalTestCase extends TestCase
{ {
...@@ -15,7 +16,7 @@ abstract class FunctionalTestCase extends TestCase ...@@ -15,7 +16,7 @@ abstract class FunctionalTestCase extends TestCase
$this->manager = new Manager($this->getUri()); $this->manager = new Manager($this->getUri());
} }
public function assertCollectionCount($namespace, $count) protected function assertCollectionCount($namespace, $count)
{ {
list($databaseName, $collectionName) = explode('.', $namespace, 2); list($databaseName, $collectionName) = explode('.', $namespace, 2);
...@@ -26,10 +27,23 @@ abstract class FunctionalTestCase extends TestCase ...@@ -26,10 +27,23 @@ abstract class FunctionalTestCase extends TestCase
$this->assertEquals($count, $document['n']); $this->assertEquals($count, $document['n']);
} }
public function assertCommandSucceeded(Cursor $cursor) protected function assertCommandSucceeded(Cursor $cursor)
{ {
$document = current($cursor->toArray()); $document = current($cursor->toArray());
$this->assertArrayHasKey('ok', $document); $this->assertArrayHasKey('ok', $document);
$this->assertEquals(1, $document['ok']); $this->assertEquals(1, $document['ok']);
} }
protected function getServerVersion(ReadPreference $readPreference = null)
{
$cursor = $this->manager->executeCommand(
$this->getDatabaseName(),
new Command(array('buildInfo' => 1)),
$readPreference ?: new ReadPreference(ReadPreference::RP_PRIMARY)
);
$document = current($cursor->toArray());
return $document['version'];
}
} }
...@@ -11,11 +11,11 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase ...@@ -11,11 +11,11 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase
* *
* @return string * @return string
*/ */
public function getCollectionName() protected function getCollectionName()
{ {
$class = new ReflectionClass($this); $class = new ReflectionClass($this);
return sprintf('%s.%s', $class->getShortName(), $this->getName(false)); return sprintf('%s.%s', $class->getShortName(), hash('crc32b', $this->getName()));
} }
/** /**
...@@ -23,7 +23,7 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase ...@@ -23,7 +23,7 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase
* *
* @return string * @return string
*/ */
public function getDatabaseName() protected function getDatabaseName()
{ {
return getenv('MONGODB_DATABASE') ?: 'phplib_test'; return getenv('MONGODB_DATABASE') ?: 'phplib_test';
} }
...@@ -33,7 +33,7 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase ...@@ -33,7 +33,7 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase
* *
* @return string * @return string
*/ */
public function getNamespace() protected function getNamespace()
{ {
return sprintf('%s.%s', $this->getDatabaseName(), $this->getCollectionName()); return sprintf('%s.%s', $this->getDatabaseName(), $this->getCollectionName());
} }
...@@ -43,7 +43,7 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase ...@@ -43,7 +43,7 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase
* *
* @return string * @return string
*/ */
public function getUri() protected function getUri()
{ {
return getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1:27017'; return getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1:27017';
} }
......
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