Permalink
Browse files

Merge pull request #64 from doctrine/group-options

Revise query builder API for map/reduce and group
  • Loading branch information...
2 parents b47c335 + 031e192 commit 17e9c5a25c11a278af31ec6e2df1a401de367a91 @jmikola jmikola committed Jul 19, 2012
@@ -539,9 +539,24 @@ public function group($keys, array $initial, $reduce, array $options = array())
protected function doGroup($keys, array $initial, $reduce, array $options)
{
+ if (is_string($reduce)) {
+ $reduce = new \MongoCode($reduce);
+ }
+
+ if (isset($options['finalize']) && is_string($options['finalize'])) {
+ $options['finalize'] = new \MongoCode($options['finalize']);
+ }
+
$collection = $this;
$result = $this->retry(function() use ($collection, $keys, $initial, $reduce, $options) {
- return $collection->getMongoCollection()->group($keys, $initial, $reduce, $options);
+ /* Version 1.2.11+ of the driver yields an E_DEPRECATED notice if an
+ * empty array is passed to MongoCollection::group(), as it assumes
+ * an it is the "condition" option's value being passed instead of
+ * a well-formed options array (the actual deprecated behavior).
+ */
+ return empty($options)
+ ? $collection->getMongoCollection()->group($keys, $initial, $reduce)
+ : $collection->getMongoCollection()->group($keys, $initial, $reduce, $options);
});
return new ArrayIterator($result);
}
@@ -65,7 +65,12 @@ class Builder
'sort' => array(),
'limit' => null,
'skip' => null,
- 'group' => array(),
+ 'group' => array(
+ 'keys' => null,
+ 'initial' => null,
+ 'reduce' => null,
+ 'options' => array(),
+ ),
'hints' => array(),
'immortal' => false,
'snapshot' => false,
@@ -74,7 +79,7 @@ class Builder
'mapReduce' => array(
'map' => null,
'reduce' => null,
- 'options' => array()
+ 'options' => array(),
),
'near' => array(),
'new' => false,
@@ -277,17 +282,21 @@ public function remove()
/**
* Perform an operation similar to SQL's GROUP BY command
*
- * @param $keys
+ * @param mixed $keys
* @param array $initial
+ * @param string|MongoCode $reduce
+ * @param array $options
* @return Builder
*/
- public function group($keys, array $initial)
+ public function group($keys, array $initial, $reduce = null, array $options = array())
{
+ $this->query['type'] = Query::TYPE_GROUP;
$this->query['group'] = array(
'keys' => $keys,
- 'initial' => $initial
+ 'initial' => $initial,
+ 'reduce' => $reduce,
+ 'options' => $options,
);
- $this->query['type'] = Query::TYPE_GROUP;
return $this;
}
@@ -692,8 +701,8 @@ public function skip($skip)
/**
* Specify a map reduce operation for this query.
*
- * @param string $map
- * @param string $reduce
+ * @param string|MongoCode $map
+ * @param string|MongoCode $reduce
* @param array $out
* @param array $options
* @return Builder
@@ -713,55 +722,74 @@ public function mapReduce($map, $reduce, array $out = array('inline' => true), a
/**
* Specify a map operation for this query.
*
- * @param string $map
+ * @param string|MongoCode $map
* @return Builder
*/
public function map($map)
{
- $this->query['mapReduce']['map'] = $map;
$this->query['type'] = Query::TYPE_MAP_REDUCE;
+ $this->query['mapReduce']['map'] = $map;
return $this;
}
/**
* Specify a reduce operation for this query.
*
- * @param string $reduce
+ * @param string|MongoCode $reduce
* @return Builder
+ * @throws BadMethodCallException if the query type is unsupported
*/
public function reduce($reduce)
{
- $this->query['mapReduce']['reduce'] = $reduce;
- if (isset($this->query['mapReduce']['map']) && isset($this->query['mapReduce']['reduce'])) {
- $this->query['type'] = Query::TYPE_MAP_REDUCE;
+ switch ($this->query['type']) {
+ case Query::TYPE_MAP_REDUCE:
+ $this->query['mapReduce']['reduce'] = $reduce;
+ break;
+
+ case Query::TYPE_GROUP:
+ $this->query['group']['reduce'] = $reduce;
+ break;
+
+ default:
+ throw new \BadMethodCallException('mapReduce(), map() or group() must be called before reduce()');
}
+
return $this;
}
/**
* Specify a finalize operation for this query.
*
- * @param string $finalize
+ * @param string|MongoCode $finalize
* @return Builder
*/
public function finalize($finalize)
{
- $this->query['mapReduce']['options']['finalize'] = $finalize;
- $this->query['type'] = Query::TYPE_MAP_REDUCE;
+ switch ($this->query['type']) {
+ case Query::TYPE_MAP_REDUCE:
+ $this->query['mapReduce']['options']['finalize'] = $finalize;
+ break;
+
+ case Query::TYPE_GROUP:
+ $this->query['group']['options']['finalize'] = $finalize;
+ break;
+
+ default:
+ throw new \BadMethodCallException('mapReduce(), map() or group() must be called before reduce()');
+ }
+
return $this;
}
/**
- * Specify output type for mar/reduce operation.
+ * Specify output type for map/reduce operation.
*
* @param array $out
* @return Builder
*/
public function out(array $out)
{
$this->query['mapReduce']['out'] = $out;
- $this->query['type'] = Query::TYPE_MAP_REDUCE;
-
return $this;
}
@@ -144,9 +144,6 @@ public function execute()
{
switch ($this->query['type']) {
case self::TYPE_FIND:
- if (isset($this->query['mapReduce']['reduce'])) {
- $this->query['query'][$this->cmd . 'where'] = $this->query['mapReduce']['reduce'];
- }
$cursor = $this->collection->find($this->query['query'], $this->query['select']);
return $this->prepareCursor($cursor);
@@ -190,7 +187,13 @@ public function execute()
return $this->collection->remove($this->query['query'], $this->options);
case self::TYPE_GROUP:
- return $this->collection->group($this->query['group']['keys'], $this->query['group']['initial'], $this->query['mapReduce']['reduce'], $this->query['query']);
+ if (!empty($this->query['query'])) {
+ $this->query['group']['options']['condition'] = $this->query['query'];
+ }
+
+ $options = array_merge($this->options, $this->query['group']['options']);
+
+ return $this->collection->group($this->query['group']['keys'], $this->query['group']['initial'], $this->query['group']['reduce'], $options);
case self::TYPE_MAP_REDUCE:
if (!isset($this->query['mapReduce']['out'])) {
@@ -312,18 +312,38 @@ public function testGetName()
$this->assertEquals(true, $result);
}
- public function testGroup()
+ public function testGroupWithNonEmptyOptionsArray()
+ {
+ $expectedOptions = array(
+ 'condition' => array(),
+ 'finalize' => new \MongoCode(''),
+ );
+
+ $mockConnection = $this->getMockConnection();
+ $mongoCollection = $this->getMockMongoCollection();
+ $mongoCollection->expects($this->once())
+ ->method('group')
+ ->with(array(), array(), $this->isInstanceOf('MongoCode'), $this->equalTo($expectedOptions))
+ ->will($this->returnValue(array()));
+
+ $mockDatabase = $this->getMockDatabase();
+ $coll = $this->getTestCollection($mockConnection, $mongoCollection, $mockDatabase);
+ $result = $coll->group(array(), array(), '', array('condition' => array(), 'finalize' => ''));
+ $this->assertEquals(new \Doctrine\MongoDB\ArrayIterator(array()), $result);
+ }
+
+ public function testGroupWithEmptyOptionsArray()
{
$mockConnection = $this->getMockConnection();
$mongoCollection = $this->getMockMongoCollection();
$mongoCollection->expects($this->once())
->method('group')
- ->with(array(), array(), '', array())
+ ->with(array(), array(), $this->isInstanceOf('MongoCode'))
->will($this->returnValue(array()));
$mockDatabase = $this->getMockDatabase();
$coll = $this->getTestCollection($mockConnection, $mongoCollection, $mockDatabase);
- $result = $coll->group(array(), array(), '', array());
+ $result = $coll->group(array(), array(), '');
$this->assertEquals(new \Doctrine\MongoDB\ArrayIterator(array()), $result);
}
Oops, something went wrong.

0 comments on commit 17e9c5a

Please sign in to comment.