Commit cfcf48f1 authored by Jeremy Mikola's avatar Jeremy Mikola

Merge pull request #11

parents daed771c 39376f35
<?php
namespace MongoDB;
use BSON\ObjectId;
use MongoDB\Driver\WriteResult;
/**
* Result class for a bulk write operation.
*/
class BulkWriteResult
{
private $writeResult;
private $insertedIds;
/**
* Constructor.
*
* @param WriteResult $writeResult
* @param mixed[] $insertedIds
*/
public function __construct(WriteResult $writeResult, array $insertedIds)
{
$this->writeResult = $writeResult;
$this->insertedIds = $insertedIds;
}
/**
* Return the number of documents that were deleted.
*
* This value is undefined if the write was not acknowledged.
*
* @see BulkWriteResult::isAcknowledged()
* @return integer
*/
public function getDeletedCount()
{
return $this->writeResult->getDeletedCount();
}
/**
* Return the number of documents that were inserted.
*
* This value is undefined if the write was not acknowledged.
*
* @see BulkWriteResult::isAcknowledged()
* @return integer
*/
public function getInsertedCount()
{
return $this->writeResult->getInsertedCount();
}
/**
* Return a map of the inserted documents' IDs.
*
* The index of each ID in the map corresponds to the document's position
* in bulk operation. If the document had an ID prior to insertion (i.e. the
* driver did not generate an ID), this will contain its "_id" field value.
* Any driver-generated ID will be an MongoDB\Driver\ObjectID instance.
*
* @return mixed[]
*/
public function getInsertedIds()
{
return $this->insertedIds;
}
/**
* Return the number of documents that were matched by the filter.
*
* This value is undefined if the write was not acknowledged.
*
* @see BulkWriteResult::isAcknowledged()
* @return integer
*/
public function getMatchedCount()
{
return $this->writeResult->getMatchedCount();
}
/**
* Return the number of documents that were modified.
*
* This value is undefined if the write was not acknowledged or if the write
* executed as a legacy operation instead of write command.
*
* @see BulkWriteResult::isAcknowledged()
* @return integer|null
*/
public function getModifiedCount()
{
return $this->writeResult->getModifiedCount();
}
/**
* Return the number of documents that were upserted.
*
* This value is undefined if the write was not acknowledged.
*
* @see BulkWriteResult::isAcknowledged()
* @return integer
*/
public function getUpsertedCount()
{
return $this->writeResult->getUpsertedCount();
}
/**
* Return a map of the upserted documents' IDs.
*
* The index of each ID in the map corresponds to the document's position
* in bulk operation. If the document had an ID prior to upserting (i.e. the
* server did not need to generate an ID), this will contain its "_id". Any
* server-generated ID will be an MongoDB\Driver\ObjectID instance.
*
* @return mixed[]
*/
public function getUpsertedIds()
{
return $this->writeResult->getUpsertedIds();
}
/**
* Return whether this update was acknowledged by the server.
*
* If the update was not acknowledged, other fields from the WriteResult
* (e.g. matchedCount) will be undefined.
*
* @return boolean
*/
public function isAcknowledged()
{
return $this->writeResult->isAcknowledged();
}
}
......@@ -198,17 +198,18 @@ class Collection
*
* @see Collection::getBulkOptions() for supported $options
*
* @param array $bulk Array of operations
* @param array $ops Array of operations
* @param array $options Additional options
* @return WriteResult
*/
public function bulkWrite(array $bulk, array $options = array())
public function bulkWrite(array $ops, array $options = array())
{
$options = array_merge($this->getBulkOptions(), $options);
$bulk = new BulkWrite($options["ordered"]);
$insertedIds = array();
foreach ($bulk as $n => $op) {
foreach ($ops as $n => $op) {
foreach ($op as $opname => $args) {
if (!isset($args[0])) {
throw new InvalidArgumentException(sprintf("Missing argument#1 for '%s' (operation#%d)", $opname, $n));
......@@ -216,14 +217,25 @@ class Collection
switch ($opname) {
case "insertOne":
$bulk->insert($args[0]);
$insertedId = $bulk->insert($args[0]);
if ($insertedId !== null) {
$insertedIds[$n] = $insertedId;
} else {
$insertedIds[$n] = is_array($args[0]) ? $args[0]['_id'] : $args[0]->_id;
}
break;
case "updateMany":
if (!isset($args[1])) {
throw new InvalidArgumentException(sprintf("Missing argument#2 for '%s' (operation#%d)", $opname, $n));
}
$options = array_merge($this->getWriteOptions(), isset($args[2]) ? $args[2] : array(), array("limit" => 0));
$options = array_merge($this->getWriteOptions(), isset($args[2]) ? $args[2] : array(), array("multi" => true));
$firstKey = key($args[1]);
if (!isset($firstKey[0]) || $firstKey[0] != '$') {
throw new InvalidArgumentException("First key in \$update must be a \$operator");
}
$bulk->update($args[0], $args[1], $options);
break;
......@@ -232,7 +244,7 @@ class Collection
if (!isset($args[1])) {
throw new InvalidArgumentException(sprintf("Missing argument#2 for '%s' (operation#%d)", $opname, $n));
}
$options = array_merge($this->getWriteOptions(), isset($args[2]) ? $args[2] : array(), array("limit" => 1));
$options = array_merge($this->getWriteOptions(), isset($args[2]) ? $args[2] : array(), array("multi" => false));
$firstKey = key($args[1]);
if (!isset($firstKey[0]) || $firstKey[0] != '$') {
throw new InvalidArgumentException("First key in \$update must be a \$operator");
......@@ -245,7 +257,7 @@ class Collection
if (!isset($args[1])) {
throw new InvalidArgumentException(sprintf("Missing argument#2 for '%s' (operation#%d)", $opname, $n));
}
$options = array_merge($this->getWriteOptions(), isset($args[2]) ? $args[2] : array(), array("limit" => 1));
$options = array_merge($this->getWriteOptions(), isset($args[2]) ? $args[2] : array(), array("multi" => false));
$firstKey = key($args[1]);
if (isset($firstKey[0]) && $firstKey[0] == '$') {
throw new InvalidArgumentException("First key in \$update must NOT be a \$operator");
......@@ -269,7 +281,10 @@ class Collection
}
}
}
return $this->manager->executeBulkWrite($this->ns, $bulk, $this->wc);
$writeResult = $this->manager->executeBulkWrite($this->ns, $bulk, $this->wc);
return new BulkWriteResult($writeResult, $insertedIds);
}
/**
......
......@@ -18,7 +18,7 @@ class InsertManyResult
* @param WriteResult $writeResult
* @param mixed[] $insertedIds
*/
public function __construct(WriteResult $writeResult, array $insertedIds = array())
public function __construct(WriteResult $writeResult, array $insertedIds)
{
$this->writeResult = $writeResult;
$this->insertedIds = $insertedIds;
......@@ -38,11 +38,11 @@ class InsertManyResult
}
/**
* Return the map of inserted IDs that were generated by the driver.
* Return a map of the inserted documents' IDs.
*
* The index of each ID in the map corresponds to the document's position
* in bulk operation. If the document already an ID prior to insertion (i.e.
* the driver did not need to generate an ID), this will contain its "_id".
* in bulk operation. If the document had an ID prior to insertion (i.e. the
* driver did not generate an ID), this will contain its "_id" field value.
* Any driver-generated ID will be an MongoDB\Driver\ObjectID instance.
*
* @return mixed[]
......
......@@ -38,7 +38,7 @@ class InsertOneResult
}
/**
* Return the inserted ID that was generated by the driver.
* Return the inserted document's ID.
*
* If the document already an ID prior to insertion (i.e. the driver did not
* need to generate an ID), this will contain its "_id". Any
......
......@@ -2,7 +2,6 @@
namespace MongoDB;
use BSON\ObjectId;
use MongoDB\Driver\WriteResult;
/**
......@@ -38,7 +37,8 @@ class UpdateResult
/**
* Return the number of documents that were modified.
*
* This value is undefined if the write was not acknowledged.
* This value is undefined if the write was not acknowledged or if the write
* executed as a legacy operation instead of write command.
*
* @see UpdateResult::isAcknowledged()
* @return integer
......@@ -48,12 +48,25 @@ class UpdateResult
return $this->writeResult->getModifiedCount();
}
/**
* Return the number of documents that were upserted.
*
* This value is undefined if the write was not acknowledged.
*
* @see UpdateResult::isAcknowledged()
* @return integer
*/
public function getUpsertedCount()
{
return $this->writeResult->getUpsertedCount();
}
/**
* Return the ID of the document inserted by an upsert operation.
*
* This value is undefined if an upsert did not take place.
*
* @return ObjectId|null
* @return mixed|null
*/
public function getUpsertedId()
{
......
<?php
namespace MongoDB\Tests\Collection;
use MongoDB\Driver\BulkWrite;
class BulkWriteFunctionalTest extends FunctionalTestCase
{
private $omitModifiedCount;
public function setUp()
{
parent::setUp();
$this->omitModifiedCount = version_compare($this->getServerVersion(), '2.6.0', '<');
}
public function testInserts()
{
$ops = array(
array('insertOne' => array(array('_id' => 1, 'x' => 11))),
array('insertOne' => array(array('x' => 22))),
);
$result = $this->collection->bulkWrite($ops);
$this->assertInstanceOf('MongoDB\BulkWriteResult', $result);
$this->assertSame(2, $result->getInsertedCount());
$insertedIds = $result->getInsertedIds();
$this->assertSame(1, $insertedIds[0]);
$this->assertInstanceOf('BSON\ObjectId', $insertedIds[1]);
$expected = array(
array('_id' => $insertedIds[0], 'x' => 11),
array('_id' => $insertedIds[1], 'x' => 22),
);
$this->assertEquals($expected, $this->collection->find()->toArray());
}
public function testUpdates()
{
$this->createFixtures(4);
$ops = array(
array('updateOne' => array(array('_id' => 2), array('$inc' => array('x' => 1)))),
array('updateMany' => array(array('_id' => array('$gt' => 2)), array('$inc' => array('x' => -1)))),
array('updateOne' => array(array('_id' => 5), array('$set' => array('x' => 55)), array('upsert' => true))),
array('updateOne' => array(array('x' => 66), array('$set' => array('x' => 66)), array('upsert' => true))),
array('updateMany' => array(array('x' => array('$gt' => 50)), array('$inc' => array('x' => 1)))),
);
$result = $this->collection->bulkWrite($ops);
$this->assertInstanceOf('MongoDB\BulkWriteResult', $result);
$this->assertSame(5, $result->getMatchedCount());
$this->omitModifiedCount or $this->assertSame(5, $result->getModifiedCount());
$this->assertSame(2, $result->getUpsertedCount());
$upsertedIds = $result->getUpsertedIds();
$this->assertSame(5, $upsertedIds[2]);
$this->assertInstanceOf('BSON\ObjectId', $upsertedIds[3]);
$expected = array(
array('_id' => 1, 'x' => 11),
array('_id' => 2, 'x' => 23),
array('_id' => 3, 'x' => 32),
array('_id' => 4, 'x' => 43),
array('_id' => 5, 'x' => 56),
array('_id' => $upsertedIds[3], 'x' => 67),
);
$this->assertEquals($expected, $this->collection->find()->toArray());
}
public function testDeletes()
{
$this->createFixtures(4);
$ops = array(
array('deleteOne' => array(array('_id' => 1))),
array('deleteMany' => array(array('_id' => array('$gt' => 2)))),
);
$result = $this->collection->bulkWrite($ops);
$this->assertInstanceOf('MongoDB\BulkWriteResult', $result);
$this->assertSame(3, $result->getDeletedCount());
$expected = array(
array('_id' => 2, 'x' => 22),
);
$this->assertEquals($expected, $this->collection->find()->toArray());
}
public function testMixedOrderedOperations()
{
$this->createFixtures(3);
$ops = array(
array('updateOne' => array(array('_id' => array('$gt' => 1)), array('$inc' => array('x' => 1)))),
array('updateMany' => array(array('_id' => array('$gt' => 1)), array('$inc' => array('x' => 1)))),
array('insertOne' => array(array('_id' => 4, 'x' => 44))),
array('deleteMany' => array(array('x' => array('$nin' => array(24, 34))))),
array('replaceOne' => array(array('_id' => 4), array('_id' => 4, 'x' => 44), array('upsert' => true))),
);
$result = $this->collection->bulkWrite($ops);
$this->assertInstanceOf('MongoDB\BulkWriteResult', $result);
$this->assertSame(1, $result->getInsertedCount());
$this->assertSame(array(2 => 4), $result->getInsertedIds());
$this->assertSame(3, $result->getMatchedCount());
$this->omitModifiedCount or $this->assertSame(3, $result->getModifiedCount());
$this->assertSame(1, $result->getUpsertedCount());
$this->assertSame(array(4 => 4), $result->getUpsertedIds());
$this->assertSame(2, $result->getDeletedCount());
$expected = array(
array('_id' => 2, 'x' => 24),
array('_id' => 3, 'x' => 34),
array('_id' => 4, 'x' => 44),
);
$this->assertEquals($expected, $this->collection->find()->toArray());
}
/**
* @expectedException MongoDB\Exception\InvalidArgumentException
* @expectedExceptionMessage Unknown operation type called 'foo' (operation#0)
*/
public function testUnknownOperation()
{
$this->collection->bulkWrite(array(
array('foo' => array(array('_id' => 1))),
));
}
/**
* @expectedException MongoDB\Exception\InvalidArgumentException
* @expectedExceptionMessageRegExp /Missing argument#\d+ for '\w+' \(operation#\d+\)/
* @dataProvider provideOpsWithMissingArguments
*/
public function testMissingArguments(array $ops)
{
$this->collection->bulkWrite($ops);
}
public function provideOpsWithMissingArguments()
{
return array(
array(array(array('insertOne' => array()))),
array(array(array('updateOne' => array()))),
array(array(array('updateOne' => array(array('_id' => 1))))),
array(array(array('updateMany' => array()))),
array(array(array('updateMany' => array(array('_id' => 1))))),
array(array(array('replaceOne' => array()))),
array(array(array('replaceOne' => array(array('_id' => 1))))),
array(array(array('deleteOne' => array()))),
array(array(array('deleteMany' => array()))),
);
}
/**
* @expectedException MongoDB\Exception\InvalidArgumentException
* @expectedExceptionMessage First key in $update must be a $operator
*/
public function testUpdateOneRequiresUpdateOperators()
{
$this->collection->bulkWrite(array(
array('updateOne' => array(array('_id' => 1), array('x' => 1))),
));
}
/**
* @expectedException MongoDB\Exception\InvalidArgumentException
* @expectedExceptionMessage First key in $update must be a $operator
*/
public function testUpdateManyRequiresUpdateOperators()
{
$this->collection->bulkWrite(array(
array('updateMany' => array(array('_id' => array('$gt' => 1)), array('x' => 1))),
));
}
/**
* @expectedException MongoDB\Exception\InvalidArgumentException
* @expectedExceptionMessage First key in $update must NOT be a $operator
*/
public function testReplaceOneRequiresReplacementDocument()
{
$this->collection->bulkWrite(array(
array('replaceOne' => array(array('_id' => 1), array('$inc' => array('x' => 1)))),
));
}
/**
* Create data fixtures.
*
* @param integer $n
*/
private 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());
}
}
\ No newline at end of file
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