Skip to content

PHPLIB-70: DatabaseInfo models and index management #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Apr 26, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
b573271
Link to canonical documentation URL
jmikola Apr 13, 2015
793bb8b
PHPLIB-72: Use model class when listing databases
jmikola Apr 13, 2015
7b6b8e0
Link to interface docs from implementations
jmikola Apr 13, 2015
6a17ac9
PHPLIB-69: Index drop methods
jmikola Apr 21, 2015
982889c
Fix word wrap in documentation
jmikola Apr 23, 2015
7191886
Use type map for database and collection enumeration
jmikola Apr 23, 2015
2f63218
PHPLIB-70: Add class-level docs to model iterators
jmikola Apr 23, 2015
48b3de1
PHPLIB-75: Refactor model classes and add class-level docs
jmikola Apr 23, 2015
79d07ff
PHPLIB-46: Index info and corresponding iterator class
jmikola Apr 23, 2015
e950dae
PHPLIB-46: Index enumeration methods
jmikola Apr 24, 2015
4de66e3
PHPLIB-63: Index creation methods
jmikola Apr 24, 2015
3108162
PHPLIB-46, PHPLIB-63, PHPLIB-69: Functional tests for index methods
jmikola Apr 24, 2015
39cf918
PHPLIB-63: Use model class to validate index creation args
jmikola Apr 24, 2015
2083eed
PHPLIB-63: Empty input to createIndexes() is a NOP
jmikola Apr 24, 2015
33f6ca4
PHPLIB-75: Use package BadMethodCallException for IndexInfo
jmikola Apr 24, 2015
5639510
PHPLIB-69: Do not allow empty index name for dropIndex()
jmikola Apr 24, 2015
a0aceaf
PHPLIB-63: Test custom name for index creation
jmikola Apr 24, 2015
bca7df7
PHPLIB-63: Refactor to avoid else condition and void methods
jmikola Apr 25, 2015
5a6ff7f
Use wire protocol version constants for feature detection
jmikola Apr 25, 2015
3df5e5e
Bump ext-mongodb dependency to 0.5.1
jmikola Apr 25, 2015
7ba1966
PHPLIB-63: Fix index creation for legacy servers
jmikola Apr 26, 2015
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
{ "name": "Derick Rethans", "email": "github@derickrethans.nl" }
],
"require": {
"ext-mongodb": "*"
"ext-mongodb": ">=0.5.1"
},
"require-dev": {
"fzaninotto/faker": "~1.0"
Expand Down
15 changes: 6 additions & 9 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
use MongoDB\Driver\Manager;
use MongoDB\Driver\ReadPreference;
use MongoDB\Driver\WriteConcern;
use ArrayIterator;
use MongoDB\Model\DatabaseInfoIterator;
use MongoDB\Model\DatabaseInfoLegacyIterator;
use stdClass;
use UnexpectedValueException;

Expand Down Expand Up @@ -54,32 +55,28 @@ public function dropDatabase($databaseName)
* List databases.
*
* @see http://docs.mongodb.org/manual/reference/command/listDatabases/
* @return Traversable
* @return DatabaseInfoIterator
* @throws UnexpectedValueException if the command result is malformed
*/
public function listDatabases()
{
$command = new Command(array('listDatabases' => 1));

$cursor = $this->manager->executeCommand('admin', $command);
$cursor->setTypeMap(array('document' => 'array'));
$result = current($cursor->toArray());

if ( ! isset($result['databases']) || ! is_array($result['databases'])) {
throw new UnexpectedValueException('listDatabases command did not return a "databases" array');
}

$databases = array_map(
function(stdClass $database) { return (array) $database; },
$result['databases']
);

/* Return a Traversable instead of an array in case listDatabases is
/* Return an Iterator instead of an array in case listDatabases is
* eventually changed to return a command cursor, like the collection
* and index enumeration commands. This makes the "totalSize" command
* field inaccessible, but users can manually invoke the command if they
* need that value.
*/
return new ArrayIterator($databases);
return new DatabaseInfoLegacyIterator($result['databases']);
}

/**
Expand Down
173 changes: 154 additions & 19 deletions src/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@

namespace MongoDB;

use MongoDB\Driver\BulkWrite;
use MongoDB\Driver\Command;
use MongoDB\Driver\Cursor;
use MongoDB\Driver\Manager;
use MongoDB\Driver\Query;
use MongoDB\Driver\ReadPreference;
use MongoDB\Driver\BulkWrite;
use MongoDB\Driver\Server;
use MongoDB\Driver\WriteConcern;
use MongoDB\Exception\InvalidArgumentException;
use MongoDB\Exception\UnexpectedTypeException;
use MongoDB\Model\IndexInfoIterator;
use MongoDB\Model\IndexInfoIteratorIterator;
use MongoDB\Model\IndexInput;

class Collection
{
Expand Down Expand Up @@ -244,34 +250,68 @@ public function count(array $filter = array(), array $options = array())
}

/**
* Create a single index in the collection.
* Create a single index for the collection.
*
* @see http://docs.mongodb.org/manual/reference/command/createIndexes/
* @see http://docs.mongodb.org/manual/reference/method/db.collection.createIndex/
* @param array|object $keys
* @param array $options
* @see Collection::createIndexes()
* @param array|object $key Document containing fields mapped to values,
* which denote order or an index type
* @param array $options Index options
* @return string The name of the created index
*/
public function createIndex($keys, array $options = array())
public function createIndex($key, array $options = array())
{
// TODO
return current($this->createIndexes(array(array('key' => $key) + $options)));
}

/**
* Create multiple indexes in the collection.
* Create one or more indexes for the collection.
*
* Each element in the $indexes array must have a "key" document, which
* contains fields mapped to an order or type. Other options may follow.
* For example:
*
* $indexes = [
* // Create a unique index on the "username" field
* [ 'key' => [ 'username' => 1 ], 'unique' => true ],
* // Create a 2dsphere index on the "loc" field with a custom name
* [ 'key' => [ 'loc' => '2dsphere' ], 'name' => 'geo' ],
* ];
*
* TODO: decide if $models should be an array of associative arrays, using
* createIndex()'s parameter names as keys, or tuples, using parameters in
* order (e.g. [keys, options]).
* If the "name" option is unspecified, a name will be generated from the
* "key" document.
*
* @see http://docs.mongodb.org/manual/reference/command/createIndexes/
* @see http://docs.mongodb.org/manual/reference/method/db.collection.createIndex/
* @param array $models
* @param array $indexes List of index specifications
* @return string[] The names of the created indexes
* @throws InvalidArgumentException if an index specification is invalid
*/
public function createIndexes(array $models)
public function createIndexes(array $indexes)
{
// TODO
if (empty($indexes)) {
return array();
}

foreach ($indexes as $i => $index) {
if ( ! is_array($index)) {
throw new UnexpectedTypeException($index, 'array');
}

if ( ! isset($index['ns'])) {
$index['ns'] = $this->ns;
}

$indexes[$i] = new IndexInput($index);
}

$readPreference = new ReadPreference(ReadPreference::RP_PRIMARY);
$server = $this->manager->selectServer($readPreference);

return (FeatureDetection::isSupported($server, FeatureDetection::API_CREATEINDEXES_CMD))
? $this->createIndexesCommand($server, $indexes)
: $this->createIndexesLegacy($server, $indexes);
}

/**
Expand Down Expand Up @@ -354,11 +394,24 @@ public function drop()
* @see http://docs.mongodb.org/manual/reference/method/db.collection.dropIndex/
* @param string $indexName
* @return Cursor
* @throws InvalidArgumentException if "*" is specified
* @throws InvalidArgumentException if $indexName is an empty string or "*"
*/
public function dropIndex($indexName)
{
// TODO
$indexName = (string) $indexName;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this string is empty, we should raise an InvalidArgumentException.


if ($indexName === '') {
throw new InvalidArgumentException('Index name cannot be empty');
}

if ($indexName === '*') {
throw new InvalidArgumentException('dropIndexes() must be used to drop multiple indexes');
}

$command = new Command(array('dropIndexes' => $this->collname, 'index' => $indexName));
$readPreference = new ReadPreference(ReadPreference::RP_PRIMARY);

return $this->manager->executeCommand($this->dbname, $command, $readPreference);
}

/**
Expand All @@ -370,7 +423,10 @@ public function dropIndex($indexName)
*/
public function dropIndexes()
{
// TODO
$command = new Command(array('dropIndexes' => $this->collname, 'index' => '*'));
$readPreference = new ReadPreference(ReadPreference::RP_PRIMARY);

return $this->manager->executeCommand($this->dbname, $command, $readPreference);
}

/**
Expand Down Expand Up @@ -949,15 +1005,20 @@ public function insertOne(array $document)
}

/**
* Returns information for all indexes in the collection.
* Returns information for all indexes for the collection.
*
* @see http://docs.mongodb.org/manual/reference/command/listIndexes/
* @see http://docs.mongodb.org/manual/reference/method/db.collection.getIndexes/
* @return Cursor
* @return IndexInfoIterator
*/
public function listIndexes()
{
// TODO
$readPreference = new ReadPreference(ReadPreference::RP_PRIMARY);
$server = $this->manager->selectServer($readPreference);

return (FeatureDetection::isSupported($server, FeatureDetection::API_LISTINDEXES_CMD))
? $this->listIndexesCommand($server)
: $this->listIndexesLegacy($server);
}

/**
Expand Down Expand Up @@ -1136,4 +1197,78 @@ protected function _update($filter, $update, $options)
$bulk->update($filter, $update, $options);
return $this->manager->executeBulkWrite($this->ns, $bulk, $this->wc);
}

/**
* Create one or more indexes for the collection using the createIndexes
* command.
*
* @param Server $server
* @param IndexInput[] $indexes
* @return string[] The names of the created indexes
*/
private function createIndexesCommand(Server $server, array $indexes)
{
$command = new Command(array(
'createIndexes' => $this->collname,
'indexes' => $indexes,
));
$server->executeCommand($this->dbname, $command);

return array_map(function(IndexInput $index) { return (string) $index; }, $indexes);
}

/**
* Create one or more indexes for the collection by inserting into the
* "system.indexes" collection (MongoDB <2.6).
*
* @param Server $server
* @param IndexInput[] $indexes
* @return string[] The names of the created indexes
*/
private function createIndexesLegacy(Server $server, array $indexes)
{
$bulk = new BulkWrite(true);

foreach ($indexes as $index) {
// TODO: Remove this once PHPC-274 is resolved (see: PHPLIB-87)
$bulk->insert($index->bsonSerialize());
}

$server->executeBulkWrite($this->dbname . '.system.indexes', $bulk);

return array_map(function(IndexInput $index) { return (string) $index; }, $indexes);
}

/**
* Returns information for all indexes for this collection using the
* listIndexes command.
*
* @see http://docs.mongodb.org/manual/reference/command/listIndexes/
* @param Server $server
* @return IndexInfoIteratorIterator
*/
private function listIndexesCommand(Server $server)
{
$command = new Command(array('listIndexes' => $this->collname));
$cursor = $server->executeCommand($this->dbname, $command);
$cursor->setTypeMap(array('document' => 'array'));

return new IndexInfoIteratorIterator($cursor);
}

/**
* Returns information for all indexes for this collection by querying the
* "system.indexes" collection (MongoDB <2.8).
*
* @param Server $server
* @return IndexInfoIteratorIterator
*/
private function listIndexesLegacy(Server $server)
{
$query = new Query(array('ns' => $this->ns));
$cursor = $server->executeQuery($this->dbname . '.system.indexes', $query);
$cursor->setTypeMap(array('document' => 'array'));

return new IndexInfoIteratorIterator($cursor);
}
}
11 changes: 5 additions & 6 deletions src/Database.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,7 @@ public function listCollections(array $options = array())
$readPreference = new ReadPreference(ReadPreference::RP_PRIMARY);
$server = $this->manager->selectServer($readPreference);

$serverInfo = $server->getInfo();
$maxWireVersion = isset($serverInfo['maxWireVersion']) ? $serverInfo['maxWireVersion'] : 0;

return ($maxWireVersion >= 3)
return (FeatureDetection::isSupported($server, FeatureDetection::API_LISTCOLLECTIONS_CMD))
? $this->listCollectionsCommand($server, $options)
: $this->listCollectionsLegacy($server, $options);
}
Expand Down Expand Up @@ -141,13 +138,14 @@ private function listCollectionsCommand(Server $server, array $options = array()
{
$command = new Command(array('listCollections' => 1) + $options);
$cursor = $server->executeCommand($this->databaseName, $command);
$cursor->setTypeMap(array('document' => 'array'));

return new CollectionInfoCommandIterator($cursor);
}

/**
* Returns information for all collections in this database by querying
* the "system.namespaces" collection (MongoDB <2.8).
* Returns information for all collections in this database by querying the
* "system.namespaces" collection (MongoDB <2.8).
*
* @param Server $server
* @param array $options
Expand Down Expand Up @@ -177,6 +175,7 @@ private function listCollectionsLegacy(Server $server, array $options = array())
$namespace = $this->databaseName . '.system.namespaces';
$query = new Query($filter);
$cursor = $server->executeQuery($namespace, $query);
$cursor->setTypeMap(array('document' => 'array'));

return new CollectionInfoLegacyIterator($cursor);
}
Expand Down
7 changes: 7 additions & 0 deletions src/Exception/BadMethodCallException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace MongoDB\Exception;

class BadMethodCallException extends \BadMethodCallException implements Exception
{
}
7 changes: 7 additions & 0 deletions src/Exception/Exception.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace MongoDB\Exception;

interface Exception
{
}
7 changes: 7 additions & 0 deletions src/Exception/InvalidArgumentException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace MongoDB\Exception;

class InvalidArgumentException extends \InvalidArgumentException implements Exception
{
}
11 changes: 11 additions & 0 deletions src/Exception/UnexpectedTypeException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

namespace MongoDB\Exception;

class UnexpectedTypeException extends InvalidArgumentException
{
public function __construct($value, $expectedType)
{
parent::__construct(sprintf('Expected argument of type "%s", "%s" given', $expectedType, is_object($value) ? get_class($value) : gettype($value)));
}
}
Loading