From cd2d37ef387f7388c10fabbb3facf00bcd490551 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Thu, 12 Jun 2014 03:07:57 -0400 Subject: [PATCH 1/5] Split API classes and interfaces --- docs/api/MongoDB/CRUD.php | 61 -------------------- docs/api/MongoDB/Command/Command.php | 14 +++++ docs/api/MongoDB/Command/CommandCursor.php | 58 +++++++++++++++++++ docs/api/MongoDB/Command/CommandResult.php | 11 ++++ docs/api/MongoDB/Cursor.php | 16 +++++ docs/api/MongoDB/Management.php | 55 ------------------ docs/api/MongoDB/Manager.php | 50 ++++++++++++++++ docs/api/MongoDB/Query/Query.php | 18 ++++++ docs/api/MongoDB/Query/QueryCursor.php | 47 +++++++++++++++ docs/api/MongoDB/Query/QueryResult.php | 7 +++ docs/api/MongoDB/Server.php | 30 ++++++++++ docs/api/MongoDB/ServerError.php | 16 +++++ docs/api/MongoDB/ServerResult.php | 11 ++++ docs/api/MongoDB/Write/BulkResult.php | 8 +++ docs/api/MongoDB/Write/DeleteBatch.php | 32 ++++++++++ docs/api/MongoDB/Write/DeleteResult.php | 11 ++++ docs/api/MongoDB/Write/InsertBatch.php | 32 ++++++++++ docs/api/MongoDB/Write/InsertResult.php | 11 ++++ docs/api/MongoDB/Write/UpdateBatch.php | 32 ++++++++++ docs/api/MongoDB/Write/UpdateResult.php | 26 +++++++++ docs/api/MongoDB/Write/Upsert.php | 16 +++++ docs/api/MongoDB/Write/WriteBatch.php | 16 +++++ docs/api/MongoDB/Write/WriteConcernError.php | 11 ++++ docs/api/MongoDB/Write/WriteError.php | 16 +++++ docs/api/MongoDB/Write/WriteResult.php | 26 +++++++++ 25 files changed, 515 insertions(+), 116 deletions(-) delete mode 100644 docs/api/MongoDB/CRUD.php create mode 100644 docs/api/MongoDB/Command/Command.php create mode 100644 docs/api/MongoDB/Command/CommandCursor.php create mode 100644 docs/api/MongoDB/Command/CommandResult.php create mode 100644 docs/api/MongoDB/Cursor.php delete mode 100644 docs/api/MongoDB/Management.php create mode 100644 docs/api/MongoDB/Manager.php create mode 100644 docs/api/MongoDB/Query/Query.php create mode 100644 docs/api/MongoDB/Query/QueryCursor.php create mode 100644 docs/api/MongoDB/Query/QueryResult.php create mode 100644 docs/api/MongoDB/Server.php create mode 100644 docs/api/MongoDB/ServerError.php create mode 100644 docs/api/MongoDB/ServerResult.php create mode 100644 docs/api/MongoDB/Write/BulkResult.php create mode 100644 docs/api/MongoDB/Write/DeleteBatch.php create mode 100644 docs/api/MongoDB/Write/DeleteResult.php create mode 100644 docs/api/MongoDB/Write/InsertBatch.php create mode 100644 docs/api/MongoDB/Write/InsertResult.php create mode 100644 docs/api/MongoDB/Write/UpdateBatch.php create mode 100644 docs/api/MongoDB/Write/UpdateResult.php create mode 100644 docs/api/MongoDB/Write/Upsert.php create mode 100644 docs/api/MongoDB/Write/WriteBatch.php create mode 100644 docs/api/MongoDB/Write/WriteConcernError.php create mode 100644 docs/api/MongoDB/Write/WriteError.php create mode 100644 docs/api/MongoDB/Write/WriteResult.php diff --git a/docs/api/MongoDB/CRUD.php b/docs/api/MongoDB/CRUD.php deleted file mode 100644 index af9453aec..000000000 --- a/docs/api/MongoDB/CRUD.php +++ /dev/null @@ -1,61 +0,0 @@ -documents[] = $document; - } -} - -class UpdateBatch implements WriteBatch { - function add($document) { - $this->documents[] = $document; - } -} - -class DeleteBatch implements WriteBatch { - function add($document) { - $this->documents[] = $document; - } -} - -class Query { - function __construct($query) {} -} -class Command { - function __construct($command) {} -} - - - - -class WriteResults { - - /* Returns nModified, n, nUserted, .. */ - function getNumbers() { - } - - /* Returns how many operations were executed */ - function getOpCount() { - } - - /* Returns the server that the operation was executed on */ - function getServer() { - } - - /* Any stats available from the server */ - function getTimer() { - } -} - -class QueryResults { - function __construct(Server $server, $cursor_id, $firstBatch) { - } -} - - diff --git a/docs/api/MongoDB/Command/Command.php b/docs/api/MongoDB/Command/Command.php new file mode 100644 index 000000000..ccdd45c47 --- /dev/null +++ b/docs/api/MongoDB/Command/Command.php @@ -0,0 +1,14 @@ +server = $server; + $this->cursorId = (integer) $cursorId; + $this->firstBatch = $firstBatch; + } + + // Iterator methods... + + /** + * @see \MongoDB\Cursor::getId() + */ + public function getId() + { + return $this->cursorId; + } + + /** + * @see \MongoDB\ServerResult::getServer() + */ + public function getServer() + { + return $this->server; + } + + /** + * @see \MongoDB\Cursor::setBatchSize() + */ + public function setBatchSize($batchSize) + { + $this->batchSize = (integer) $batchSize; + } + + // Note: this expects consistent command response documents from the server + static public function createFromCommandResult(CommandResult $result) + { + // extract $cursorId and $firstBatch from $result->getResponse() + + return new static($result->getServer(), $cursorId, $firstBatch); + } +} diff --git a/docs/api/MongoDB/Command/CommandResult.php b/docs/api/MongoDB/Command/CommandResult.php new file mode 100644 index 000000000..8ba37bf70 --- /dev/null +++ b/docs/api/MongoDB/Command/CommandResult.php @@ -0,0 +1,11 @@ +getConnectedServers() as $server) { - if ($server->matchesReadPreference($rp)) { - return $server->executeQuery($namespace, $query); - } - } - throw new NoServerMatchingReadPreference($rp); - } - - final function executeWrite($namespace, \MongoDB\WriteBatch $batch, WriteOptions $wo) { - foreach($this->getConnectedServers() as $server) { - if ($server->isPrimary()) { - return $server->executeWrite($namespace, $batch, $wo); - } - } - - throw new NoPrimaryAvailable; - } -} - diff --git a/docs/api/MongoDB/Manager.php b/docs/api/MongoDB/Manager.php new file mode 100644 index 000000000..2b7d5573c --- /dev/null +++ b/docs/api/MongoDB/Manager.php @@ -0,0 +1,50 @@ +getConnectedServers() as $server) { + if ($server->matchesReadPreference($rp)) { + return $server->executeQuery($namespace, $query); + } + } + throw new NoServerMatchingReadPreference($rp); + } + + final public function executeQuery($namespace, \MongoDB\Query $query, \MongoDB\ReadPreference $rp) + { + foreach($this->getConnectedServers() as $server) { + if ($server->matchesReadPreference($rp)) { + return $server->executeQuery($namespace, $query); + } + } + throw new NoServerMatchingReadPreference($rp); + } + + final function executeWrite($namespace, \MongoDB\WriteBatch $batch, \MongoDB\WriteOptions $wo) + { + foreach($this->getConnectedServers() as $server) { + if ($server->isPrimary()) { + return $server->executeWrite($namespace, $batch, $wo); + } + } + + throw new NoPrimaryAvailable; + } +} diff --git a/docs/api/MongoDB/Query/Query.php b/docs/api/MongoDB/Query/Query.php new file mode 100644 index 000000000..cd73b3e73 --- /dev/null +++ b/docs/api/MongoDB/Query/Query.php @@ -0,0 +1,18 @@ +server = $server; + $this->cursorId = (integer) $cursorId; + } + + // Iterator methods... + + /** + * @see \MongoDB\Cursor::getId() + */ + public function getId() + { + return $this->cursorId; + } + + /** + * @see \MongoDB\ServerResult::getServer() + */ + public function getServer() + { + return $this->server; + } + + /** + * @see \MongoDB\Cursor::setBatchSize() + */ + public function setBatchSize($batchSize) + { + $this->batchSize = (integer) $batchSize; + } +} diff --git a/docs/api/MongoDB/Query/QueryResult.php b/docs/api/MongoDB/Query/QueryResult.php new file mode 100644 index 000000000..79621f0d4 --- /dev/null +++ b/docs/api/MongoDB/Query/QueryResult.php @@ -0,0 +1,7 @@ +documents[] = $document; + } + + /** + * @see Countable::count() + */ + public function count() + { + return count($this->documents); + } + + /** + * @see WriteBatch::getDocuments() + */ + public function getDocuments() + { + return $this->documents; + } +} diff --git a/docs/api/MongoDB/Write/DeleteResult.php b/docs/api/MongoDB/Write/DeleteResult.php new file mode 100644 index 000000000..9bf41e599 --- /dev/null +++ b/docs/api/MongoDB/Write/DeleteResult.php @@ -0,0 +1,11 @@ +documents[] = $document; + } + + /** + * @see Countable::count() + */ + public function count() + { + return count($this->documents); + } + + /** + * @see WriteBatch::getDocuments() + */ + public function getDocuments() + { + return $this->documents; + } +} diff --git a/docs/api/MongoDB/Write/InsertResult.php b/docs/api/MongoDB/Write/InsertResult.php new file mode 100644 index 000000000..fe8e30822 --- /dev/null +++ b/docs/api/MongoDB/Write/InsertResult.php @@ -0,0 +1,11 @@ +documents[] = $document; + } + + /** + * @see Countable::count() + */ + public function count() + { + return count($this->documents); + } + + /** + * @see WriteBatch::getDocuments() + */ + public function getDocuments() + { + return $this->documents; + } +} diff --git a/docs/api/MongoDB/Write/UpdateResult.php b/docs/api/MongoDB/Write/UpdateResult.php new file mode 100644 index 000000000..38e7f1a97 --- /dev/null +++ b/docs/api/MongoDB/Write/UpdateResult.php @@ -0,0 +1,26 @@ + Date: Thu, 12 Jun 2014 19:00:53 -0400 Subject: [PATCH 2/5] Implement review feedback Some highlights: fix class/interface syntax; additional class/method docs; Manager convenience methods; more value objects. --- docs/api/MongoDB/Command/Command.php | 7 +- docs/api/MongoDB/Command/CommandCursor.php | 46 +++-- docs/api/MongoDB/Command/CommandResult.php | 33 +++- docs/api/MongoDB/Cursor.php | 14 +- docs/api/MongoDB/CursorId.php | 35 ++++ docs/api/MongoDB/Manager.php | 166 +++++++++++++--- docs/api/MongoDB/Query/Query.php | 20 +- docs/api/MongoDB/Query/QueryCursor.php | 37 +++- docs/api/MongoDB/Query/QueryResult.php | 7 - docs/api/MongoDB/ReadPreference.php | 28 +++ docs/api/MongoDB/Server.php | 190 +++++++++++++++++-- docs/api/MongoDB/ServerError.php | 16 -- docs/api/MongoDB/ServerResult.php | 11 -- docs/api/MongoDB/Write/BulkResult.php | 8 - docs/api/MongoDB/Write/DeleteBatch.php | 22 ++- docs/api/MongoDB/Write/DeleteResult.php | 31 ++- docs/api/MongoDB/Write/GeneratedId.php | 39 ++++ docs/api/MongoDB/Write/InsertBatch.php | 22 ++- docs/api/MongoDB/Write/InsertResult.php | 43 ++++- docs/api/MongoDB/Write/UpdateBatch.php | 22 ++- docs/api/MongoDB/Write/UpdateResult.php | 44 ++++- docs/api/MongoDB/Write/Upsert.php | 16 -- docs/api/MongoDB/Write/WriteBatch.php | 7 +- docs/api/MongoDB/Write/WriteConcernError.php | 42 +++- docs/api/MongoDB/Write/WriteError.php | 50 ++++- docs/api/MongoDB/Write/WriteResult.php | 17 +- 26 files changed, 786 insertions(+), 187 deletions(-) create mode 100644 docs/api/MongoDB/CursorId.php delete mode 100644 docs/api/MongoDB/Query/QueryResult.php create mode 100644 docs/api/MongoDB/ReadPreference.php delete mode 100644 docs/api/MongoDB/ServerError.php delete mode 100644 docs/api/MongoDB/ServerResult.php delete mode 100644 docs/api/MongoDB/Write/BulkResult.php create mode 100644 docs/api/MongoDB/Write/GeneratedId.php delete mode 100644 docs/api/MongoDB/Write/Upsert.php diff --git a/docs/api/MongoDB/Command/Command.php b/docs/api/MongoDB/Command/Command.php index ccdd45c47..8b7af5471 100644 --- a/docs/api/MongoDB/Command/Command.php +++ b/docs/api/MongoDB/Command/Command.php @@ -2,13 +2,18 @@ namespace MongoDB\Command; +/** + * Value object for a database command document. + */ final class Command { + private $document; + /** * @param array|object $document Command document */ public function __construct($document) { - // ... + $this->document = $document; } } diff --git a/docs/api/MongoDB/Command/CommandCursor.php b/docs/api/MongoDB/Command/CommandCursor.php index f853c74f0..17364580a 100644 --- a/docs/api/MongoDB/Command/CommandCursor.php +++ b/docs/api/MongoDB/Command/CommandCursor.php @@ -2,8 +2,20 @@ namespace MongoDB\Command; -// Note: consider combining implementation with \MongoDB\Query\QueryCursor -final class CommandCursor implements \MongoDB\Cursor +use MongoDB\Cursor; +use MongoDB\CursorId; + +/** + * Cursor implementation that may be constructed from values found in a + * CommandResult's response document. + * + * The iteration and internal logic is very similar to QueryCursor, so both + * classes should likely share code. The first batch is comparable to the + * documents found in the OP_REPLY message returned by a QueryCursor's original + * OP_QUERY, in that both may be available at the time the cursor is + * constructed. + */ +final class CommandCursor implements Cursor { private $server; private $batchSize; @@ -11,21 +23,21 @@ final class CommandCursor implements \MongoDB\Cursor private $firstBatch; /** - * @param Server $server - * @param integer $cursorId - * @param array $firstBatch + * @param Server $server + * @param CursorId $cursorId + * @param array $firstBatch */ - public function __construct(Server $server, $cursorId, array $firstBatch) + public function __construct(Server $server, CursorId $cursorId, array $firstBatch) { $this->server = $server; - $this->cursorId = (integer) $cursorId; + $this->cursorId = $cursorId; $this->firstBatch = $firstBatch; } // Iterator methods... /** - * @see \MongoDB\Cursor::getId() + * @return Cursor::getId() */ public function getId() { @@ -33,7 +45,7 @@ public function getId() } /** - * @see \MongoDB\ServerResult::getServer() + * @see Cursor::getServer() */ public function getServer() { @@ -41,18 +53,18 @@ public function getServer() } /** - * @see \MongoDB\Cursor::setBatchSize() + * @see Cursor::isDead() */ - public function setBatchSize($batchSize) + public function isDead() { - $this->batchSize = (integer) $batchSize; + // Return whether the cursor is exhausted and has no more results } - // Note: this expects consistent command response documents from the server - static public function createFromCommandResult(CommandResult $result) + /** + * @see \MongoDB\Cursor::setBatchSize() + */ + public function setBatchSize($batchSize) { - // extract $cursorId and $firstBatch from $result->getResponse() - - return new static($result->getServer(), $cursorId, $firstBatch); + $this->batchSize = (integer) $batchSize; } } diff --git a/docs/api/MongoDB/Command/CommandResult.php b/docs/api/MongoDB/Command/CommandResult.php index 8ba37bf70..013102bb5 100644 --- a/docs/api/MongoDB/Command/CommandResult.php +++ b/docs/api/MongoDB/Command/CommandResult.php @@ -2,10 +2,39 @@ namespace MongoDB\Command; -interface CommandResult extends \MongoDB\ServerResult +use MongoDB\Server; + +/** + * Result returned by Server and Manager executeCommand() methods. + */ +final class CommandResult { + private $server; + private $responseDocument; + + /** + * @param Server $server + * @param array|object $responseDocument + */ + public function __construct(Server $server, $responseDocument) + { + $this->server = $server; + $this->responseDocument = $responseDocument; + } + /** * @return array Original response document from the server */ - function getResponse(); + public function getResponseDocument() + { + return $this->responseDocument; + } + + /** + * @return Server Server from which the result originated + */ + public function getServer() + { + return $this->server; + } } diff --git a/docs/api/MongoDB/Cursor.php b/docs/api/MongoDB/Cursor.php index 8f481309d..c920a281c 100644 --- a/docs/api/MongoDB/Cursor.php +++ b/docs/api/MongoDB/Cursor.php @@ -2,13 +2,23 @@ namespace MongoDB; -interface Cursor extends ServerResult, \Iterator +interface Cursor extends \Iterator { /** - * @return integer Cursor identifier + * @return CursorId */ function getId(); + /** + * @return Server Server from which the cursor originated + */ + function getServer(); + + /** + * @return boolean Whether the cursor is exhausted and has no more results + */ + function isDead(); + /** * @param integer $batchSize */ diff --git a/docs/api/MongoDB/CursorId.php b/docs/api/MongoDB/CursorId.php new file mode 100644 index 000000000..ed1e79fa6 --- /dev/null +++ b/docs/api/MongoDB/CursorId.php @@ -0,0 +1,35 @@ +getConnectedServers() as $server) { - if ($server->matchesReadPreference($rp)) { - return $server->executeQuery($namespace, $query); - } - } - throw new NoServerMatchingReadPreference($rp); + /* Select server based on read preference and invoke + * Server::executeQuery(). + * + * Read preferences should be injected into the query document if + * necessary (e.g. mongos). + * + * Rely on libmongoc for server selection and read preference injection. + * + * Throw exception if no candidate server is found. + */ } - final public function executeQuery($namespace, \MongoDB\Query $query, \MongoDB\ReadPreference $rp) + /** + * @param string $namespace + * @param WriteBatch $batch + * @return WriteResult + */ + public function executeWrite($namespace, WriteBatch $batch) { - foreach($this->getConnectedServers() as $server) { - if ($server->matchesReadPreference($rp)) { - return $server->executeQuery($namespace, $query); - } - } - throw new NoServerMatchingReadPreference($rp); + /* Select writeable server and invoke Server::executeQuery(). + * + * Write options are not taken as an argument, since they are specified + * during WriteBatch construction. + * + * On error, we should consider throwing: + * + * - NoCandidateException: no writeable server was found + * - WriteException: write failed; a WriteResult should be included. + * - ConnectionException: low-level socket error + * + * If a WriteException is thrown, its WriteResult may contain multiple + * write errors and write concern errors. + */ } - final function executeWrite($namespace, \MongoDB\WriteBatch $batch, \MongoDB\WriteOptions $wo) + /** + * Convenience method for single insert operation. + * + * @param string $namespace + * @param array|object $document Document to insert + * @param array $writeOptions Write concern options + * @return InsertResult + */ + public function executeInsert($namespace, $document, array $writeOptions = null) { - foreach($this->getConnectedServers() as $server) { - if ($server->isPrimary()) { - return $server->executeWrite($namespace, $batch, $wo); - } - } + // Construct and execute an InsertBatch + } - throw new NoPrimaryAvailable; + /** + * Convenience method for single update operation. + * + * @param string $namespace + * @param array|object $query Update criteria + * @param array|object $newObj Update modifier or replacement document + * @param array $updateOptions Update options (e.g. "upsert") + * @param array $writeOptions Write concern options + * @return UpdateResult + */ + public function executeUpdate($namespace, $query, $newObj, array $updateOptions = null, array $writeOptions = null) + { + /* Construct and execute an UpdateBatch + * + * What should be the default value for $options? No multi, no upsert? + */ + } + + /** + * Convenience method for single delete operation. + * + * @param string $namespace + * @param array|object $query Deletion criteria + * @param array $deleteOptions Deletion options (e.g. "limit") + * @param array $writeOptions Write concern options + * @return DeleteResult + */ + public function executeDelete($namespace, $query, array $deleteOptions = null, array $writeOptions = null) + { + /* Construct and execute an DeleteBatch + * + * What should be the default value for $options? No limit? + */ } } diff --git a/docs/api/MongoDB/Query/Query.php b/docs/api/MongoDB/Query/Query.php index cd73b3e73..fbb9170cb 100644 --- a/docs/api/MongoDB/Query/Query.php +++ b/docs/api/MongoDB/Query/Query.php @@ -2,8 +2,22 @@ namespace MongoDB\Query; +/** + * Value object corresponding to a wire protocol OP_QUERY message. + * + * If and when queries become commands, we will need to introduce a new Query + * object, such as QueryCommand. At that point, the query will likely be + * constructed from a single document, which includes the arguments below in a + * similar fashion to findAndModify. + */ final class Query { + private $query; + private $selector; + private $flags; + private $skip; + private $limit; + /** * @param array|object $query Query document * @param array|object $selector Selector document @@ -13,6 +27,10 @@ final class Query */ public function __construct($query, $selector, $flags, $skip, $limit) { - // ... + $this->query = $query; + $this->selector = $selector; + $this->flags = (integer) $flags; + $this->skip = (integer) $skip; + $this->limit = (integer) $limit; } } diff --git a/docs/api/MongoDB/Query/QueryCursor.php b/docs/api/MongoDB/Query/QueryCursor.php index 9435dce99..a06ece593 100644 --- a/docs/api/MongoDB/Query/QueryCursor.php +++ b/docs/api/MongoDB/Query/QueryCursor.php @@ -2,27 +2,38 @@ namespace MongoDB\Query; -// Note: consider combining implementation with \MongoDB\Command\CommandCursor -final class QueryCursor implements \MongoDB\Cursor +use MongoDB\Cursor; +use MongoDB\CursorId; + +/** + * Cursor implementation that is returned after executing a Query. + * + * The iteration and internal logic is very similar to CommandCursor, so both + * classes should likely share code. The documents in the OP_REPLY message + * returned by the original OP_QUERY is comparable to the first batch of a + * command cursor, in that both may be available at the time the cursor is + * constructed. + */ +final class QueryCursor implements Cursor { private $server; private $batchSize; private $cursorId; /** - * @param Server $server - * @param integer $cursorId + * @param Server $server + * @param CursorId $cursorId */ - public function __construct(Server $server, $cursorId) + public function __construct(Server $server, CursorId $cursorId) { $this->server = $server; - $this->cursorId = (integer) $cursorId; + $this->cursorId = $cursorId; } // Iterator methods... /** - * @see \MongoDB\Cursor::getId() + * @see Cursor::getId() */ public function getId() { @@ -30,7 +41,7 @@ public function getId() } /** - * @see \MongoDB\ServerResult::getServer() + * @see Cursor::getServer() */ public function getServer() { @@ -38,7 +49,15 @@ public function getServer() } /** - * @see \MongoDB\Cursor::setBatchSize() + * @see Cursor::isDead() + */ + public function isDead() + { + // Return whether the cursor is exhausted and has no more results + } + + /** + * @see Cursor::setBatchSize() */ public function setBatchSize($batchSize) { diff --git a/docs/api/MongoDB/Query/QueryResult.php b/docs/api/MongoDB/Query/QueryResult.php deleted file mode 100644 index 79621f0d4..000000000 --- a/docs/api/MongoDB/Query/QueryResult.php +++ /dev/null @@ -1,7 +0,0 @@ -readPreference = (string) $readPreference; + $this->tagSets = $tagSets; + } +} diff --git a/docs/api/MongoDB/Server.php b/docs/api/MongoDB/Server.php index 3b6c678ad..18697db37 100644 --- a/docs/api/MongoDB/Server.php +++ b/docs/api/MongoDB/Server.php @@ -2,7 +2,27 @@ namespace MongoDB; -class Server +use MongoDB\Command\Command; +use MongoDB\Command\CommandResult; +use MongoDB\Query\Query; +use MongoDB\Query\QueryCursor; +use MongoDB\Write\WriteBatch; +use MongoDB\Write\WriteResult; + +/** + * Server abstracts a socket connection to a single MongoDB server. The server + * itself may be a mongod (stand-alone or replica set node) or mongos process. + * + * Users will typically not construct this class directly. The common use case + * will be connection to a cluster of servers via a URI with the Manager class. + * + * This class does not utilize read preferences, since there is only a single + * single socket on which to send a command, query, or write. + * + * Operation methods do not take socket-level options (e.g. socketTimeoutMS). + * Those options should be specified during construction. + */ +final class Server { const TYPE_MONGOS = 0x01; const TYPE_STANDALONE = 0x02; @@ -10,21 +30,161 @@ class Server const TYPE_SECONDARY = 0x04; const TYPE_PRIMARY = 0x05; - /* These need to be final as they will not be called by the driver to - * retrieve the information; these getters are only useful for userland. + private $host; + private $port; + private $options; + private $driverOptions; + + /** + * @param string $host Server host + * @param integer $port Server port + * @param array $options Connection options (e.g. auth, socket timeouts) + * @param array $driverOptions Driver options (e.g. stream contexts) + */ + public function __construct($host, $port, array $options = array(), array $driverOptions = array()) + { + $this->host = (string) $host; + $this->port = (integer) $port; + $this->options = $options; + $this->driverOptions = $driverOptions; + + /* Server connections may use a persistent socket connection. Sockets + * will need to be hashed by all relevant arguments, which likely means + * all of Server's constructor arguments. Argument arrays will need to + * be normalized before we compute the hash (i.e. option order shouldn't + * matter). + * + * Actual socket connections should be created lazily. + */ + } + + /** + * @param string $namespace + * @param Command $command + * @return CommandResult + */ + public function executeCommand($namespace, Command $command) + { + /* This method does not take a ReadPreference. If connected to mongos, + * it the user's responsibility to set a read preference on the command + * document (if applicable). + */ + } + + /** + * @param string $namespace + * @param Query $query + * @return QueryCursor + */ + public function executeQuery($namespace, Query $query) + { + /* This method does not take a ReadPreference. If connected to mongos, + * it the user's responsibility to set a read preference on the command + * document (if applicable). + */ + } + + /** + * @param string $namespace + * @param WriteBatch $batch + * @return WriteResult + */ + public function executeWrite($namespace, WriteBatch $batch) + { + /* Write options are not taken as an argument, since they are specified + * during WriteBatch construction. + * + * On error, we should consider throwing: + * + * - WriteException: write failed; a WriteResult should be included. + * - ConnectionException: low-level socket error + * + * If a WriteException is thrown, its WriteResult may contain multiple + * write errors and write concern errors. + * + * What exception is used for sending a write to a secondary? Would that + * be a WriteException without a WriteResult attached? + */ + } + + public function getHost() + { + /* This does not return the host name from isMaster, since the "me" + * field is only present in replica set connections. There is also less + * value in providing the driver with the host name by which the server + * identifies (vs. the host name used to connect to it). + */ + return $this->host; + } + + /** + * @return array Connection metadata (e.g. min/maxWireVersion, RS hosts) + */ + public function getInfo() + { + // Return last isMaster result document + } + + /** + * @return integer Server latency in milliseconds + */ + public function getLatency() + { + // Return last ping time in milliseconds (calculated value) + } + + /** + * @return integer + */ + public function getPort() + { + return $this->port; + } + + /** + * @see http://docs.mongodb.org/manual/reference/replica-states/ + * @return integer Replica set node state + */ + public function getState() + { + /* Return the replica set node's state via replSetGetStatus + * + * We may want to create class constants for documented states. + * + * What should this return if the node isn't in a replica set? + */ + } + + /** + * @return integer Server type code */ - final public function getHostname() {} - final public function getPort() {} - final public function getLatency() {} - final public function getMaxWireVersion() {} - final public function getMinWireVersion() {} - final public function getServerType() {} + public function getType() + { + /* Return the server's current type code. + * + * The fact that Servers are mutable and this return value is subject to + * change is not a problem, as libmongoc should have its own snapshot of + * the cluster topology for evaluating read preferences. + */ + } - // extracting config info - final public function isPassive() {} - final public function isDelayed() {} + public function isDelayed() + { + /* Return whether the secondary is delayed. + * + * What should this return for a node that isn't in a replica set? Isn't + * the actual delay time more useful than a boolean? This isn't reported + * in isMaster, so how do we calculate this short of reading the replica + * set configuration? + */ + } - final public function executeCommand($namespace, \MongoDB\Command\Command $command, \MongoDB\ReadPreference $rp) {} - final public function executeQuery($namespace, \MongoDB\Query\Query $query, \MongoDB\ReadPreference $rp) {} - final public function executeWrite($namespace, \MongoDB\Write\WriteBatch $batch, \MongoDB\WriteOptions $wo) {} + public function isPassive() + { + /* Return inferred value from isMaster data. + * + * Is this really useful in light of getInfo(), which provides the same + * information, and more? + */ + } } diff --git a/docs/api/MongoDB/ServerError.php b/docs/api/MongoDB/ServerError.php deleted file mode 100644 index 11ee9e286..000000000 --- a/docs/api/MongoDB/ServerError.php +++ /dev/null @@ -1,16 +0,0 @@ -writeOptions = $writeOptions; + } /** * @see WriteBatch::add() @@ -21,12 +33,4 @@ public function count() { return count($this->documents); } - - /** - * @see WriteBatch::getDocuments() - */ - public function getDocuments() - { - return $this->documents; - } } diff --git a/docs/api/MongoDB/Write/DeleteResult.php b/docs/api/MongoDB/Write/DeleteResult.php index 9bf41e599..9b0fb215c 100644 --- a/docs/api/MongoDB/Write/DeleteResult.php +++ b/docs/api/MongoDB/Write/DeleteResult.php @@ -2,10 +2,37 @@ namespace MongoDB\Write; -interface DeleteResult extends WriteResult +/** + * Result returned by Server and Manager executeWrite() methods processing a + * DeleteBatch. + * + * This class may be constructed internally if it will encapsulate a libmongoc + * data structure. + */ +final class DeleteResult implements WriteResult { /** * @return integer */ - function getNumRemoved(); + public function getNumRemoved() {} + + /** + * @see WriteResult::getInfo() + */ + public function getInfo() {} + + /** + * @see WriteResult::getServer() + */ + public function getServer() {} + + /** + * @see WriteResult::getWriteConcernErrors() + */ + public function getWriteConcernErrors() {} + + /** + * @see WriteResult::getWriteErrors() + */ + public function getWriteErrors() {} } diff --git a/docs/api/MongoDB/Write/GeneratedId.php b/docs/api/MongoDB/Write/GeneratedId.php new file mode 100644 index 000000000..bb7426b10 --- /dev/null +++ b/docs/api/MongoDB/Write/GeneratedId.php @@ -0,0 +1,39 @@ +id = $id; + $this->index = (integer) $index; + } + + /** + * @return mixed Document identifier + */ + public function getId() + { + return $this->id; + } + + /** + * @return integer Batch index of the corresponding operation + */ + public function getIndex() + { + return $this->index; + } +} diff --git a/docs/api/MongoDB/Write/InsertBatch.php b/docs/api/MongoDB/Write/InsertBatch.php index ba9fd2d11..00b5cca11 100644 --- a/docs/api/MongoDB/Write/InsertBatch.php +++ b/docs/api/MongoDB/Write/InsertBatch.php @@ -2,9 +2,21 @@ namespace MongoDB\Write; -final class InsertBatch extends WriteBatch +/** + * Aggregates a collection of insert operations, to be executed in batches. + */ +final class InsertBatch implements WriteBatch { private $documents; + private $writeOptions; + + /** + * @param array $writeOptions Ordering and write concern options + */ + public function __construct(array $writeOptions) + { + $this->writeOptions = $writeOptions; + } /** * @see WriteBatch::add() @@ -21,12 +33,4 @@ public function count() { return count($this->documents); } - - /** - * @see WriteBatch::getDocuments() - */ - public function getDocuments() - { - return $this->documents; - } } diff --git a/docs/api/MongoDB/Write/InsertResult.php b/docs/api/MongoDB/Write/InsertResult.php index fe8e30822..fc01261db 100644 --- a/docs/api/MongoDB/Write/InsertResult.php +++ b/docs/api/MongoDB/Write/InsertResult.php @@ -2,10 +2,49 @@ namespace MongoDB\Write; -interface InsertResult extends WriteResult +/** + * Result returned by Server and Manager executeWrite() methods processing an + * InsertBatch. + * + * This class may be constructed internally if it will encapsulate a libmongoc + * data structure. + */ +final class InsertResult implements WriteResult { /** * @return integer */ - function getNumInserted(); + public function getNumInserted() {} + + /** + * @return GeneratedId[] + */ + public function getGeneratedIds() + { + /* Return an array of identifiers generated by the driver. Each + * GeneratedId has a batch index and the ID value. + * + * This supersedes the identifier-setting hack in the 1.x driver. + */ + } + + /** + * @see WriteResult::getInfo() + */ + public function getInfo() {} + + /** + * @see WriteResult::getServer() + */ + public function getServer() {} + + /** + * @see WriteResult::getWriteConcernErrors() + */ + public function getWriteConcernErrors() {} + + /** + * @see WriteResult::getWriteErrors() + */ + public function getWriteErrors() {} } diff --git a/docs/api/MongoDB/Write/UpdateBatch.php b/docs/api/MongoDB/Write/UpdateBatch.php index b88ed19ac..47541527c 100644 --- a/docs/api/MongoDB/Write/UpdateBatch.php +++ b/docs/api/MongoDB/Write/UpdateBatch.php @@ -2,9 +2,21 @@ namespace MongoDB\Write; -final class UpdateBatch extends WriteBatch +/** + * Aggregates a collection of update operations, to be executed in batches. + */ +final class UpdateBatch implements WriteBatch { private $documents; + private $writeOptions; + + /** + * @param array $writeOptions Ordering and write concern options + */ + public function __construct(array $writeOptions) + { + $this->writeOptions = $writeOptions; + } /** * @see WriteBatch::add() @@ -21,12 +33,4 @@ public function count() { return count($this->documents); } - - /** - * @see WriteBatch::getDocuments() - */ - public function getDocuments() - { - return $this->documents; - } } diff --git a/docs/api/MongoDB/Write/UpdateResult.php b/docs/api/MongoDB/Write/UpdateResult.php index 38e7f1a97..cb5730e28 100644 --- a/docs/api/MongoDB/Write/UpdateResult.php +++ b/docs/api/MongoDB/Write/UpdateResult.php @@ -2,25 +2,57 @@ namespace MongoDB\Write; -interface UpdateResult extends WriteResult +/** + * Result returned by Server and Manager executeWrite() methods processing an + * UpdateBatch. + * + * This class may be constructed internally if it will encapsulate a libmongoc + * data structure. + */ +final class UpdateResult implements WriteResult { /** * @return integer */ - function getNumMatched(); + public function getNumMatched() {} /** * @return integer */ - function getNumModified(); + public function getNumModified() {} /** * @return integer */ - function getNumUpserted(); + public function getNumUpserted() {} /** - * @return Upsert[] + * @return GeneratedId[] */ - function getUpserts(); + public function getUpserts() + { + /* Return an array of identifiers upserted by the server. Each + * GeneratedId has a batch index and the ID value. + */ + } + + /** + * @see WriteResult::getInfo() + */ + public function getInfo() {} + + /** + * @see WriteResult::getServer() + */ + public function getServer() {} + + /** + * @see WriteResult::getWriteConcernErrors() + */ + public function getWriteConcernErrors() {} + + /** + * @see WriteResult::getWriteErrors() + */ + public function getWriteErrors() {} } diff --git a/docs/api/MongoDB/Write/Upsert.php b/docs/api/MongoDB/Write/Upsert.php deleted file mode 100644 index 571aaedc7..000000000 --- a/docs/api/MongoDB/Write/Upsert.php +++ /dev/null @@ -1,16 +0,0 @@ -message = (string) $message; + $this->code = (integer) $code; + $this->info = $info; + } + + /** + * @return integer Server error code + */ + public function getCode() + { + return $this->code; + } + /** * @return array Additional metadata for the error (e.g. {"wtimeout": true}) */ - function getInfo(); + public function getInfo() + { + return $this->info; + } + + /** + * @return string Server error message + */ + public function getMessage() + { + return $this-message; + } } diff --git a/docs/api/MongoDB/Write/WriteError.php b/docs/api/MongoDB/Write/WriteError.php index 7128d2b03..497cc52fd 100644 --- a/docs/api/MongoDB/Write/WriteError.php +++ b/docs/api/MongoDB/Write/WriteError.php @@ -2,15 +2,59 @@ namespace MongoDB\Write; -interface WriteError extends \MongoDB\ServerError +/** + * Value object for a write error (e.g. duplicate key). + */ +final class WriteError { + private $message; + private $code; + private $index; + private $operation; + + /** + * @param string $message Server error message + * @param integer $code Server error code + * @param integer $index Batch index of the error + * @param array|object $operation Operation or document responsible for the error + */ + public function __construct($message, $code, $index, $operation) + { + $this->message = (string) $message; + $this->code = (integer) $code; + $this->index = (integer) $index; + $this->operation = $operation; + } + + /** + * @return integer Server error code + */ + public function getCode() + { + return $this->code; + } + /** * @return integer Batch index of the error */ - function getIndex(); + public function getIndex() + { + return $this->index; + } + + /** + * @return string Server error message + */ + public function getMessage() + { + return $this-message; + } /** * @return array|object Operation or document responsible for the error */ - function getOperation(); + public function getOperation() + { + return $this->operation; + } } diff --git a/docs/api/MongoDB/Write/WriteResult.php b/docs/api/MongoDB/Write/WriteResult.php index 94a204abb..946b964a1 100644 --- a/docs/api/MongoDB/Write/WriteResult.php +++ b/docs/api/MongoDB/Write/WriteResult.php @@ -2,25 +2,26 @@ namespace MongoDB\Write; -interface WriteResult extends \MongoDB\ServerResult +interface WriteResult { /** - * @return array Additional metadata for the operation(s) (e.g. timings) + * @see https://github.com/mongodb/specifications/blob/master/source/server_write_commands.rst#situational-fields + * @return array Additional metadata for the operation(s) (e.g. lastOp) */ function getInfo(); /** - * @return integer Number of operations that were executed + * @return Server Server from which the result originated */ - function getOpCount(); + function getServer(); /** - * @return WriteError[] + * @return WriteConcernError[] */ - function getWriteErrors(); + function getWriteConcernErrors(); /** - * @return WriteConcernError[] + * @return WriteError[] */ - function getWriteConcernErrors(); + function getWriteErrors(); } From 1cfb4d2df022051c1b9c632aeca933e231f80976 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Fri, 13 Jun 2014 03:56:42 -0400 Subject: [PATCH 3/5] Add cursor flag constants --- docs/api/MongoDB/Query/Query.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/api/MongoDB/Query/Query.php b/docs/api/MongoDB/Query/Query.php index fbb9170cb..cfda9704a 100644 --- a/docs/api/MongoDB/Query/Query.php +++ b/docs/api/MongoDB/Query/Query.php @@ -12,6 +12,15 @@ */ final class Query { + // See: http://docs.mongodb.org/meta-driver/latest/legacy/mongodb-wire-protocol/#op-query + const FLAG_TAILABLE_CURSOR = 0x01; + const FLAG_SLAVE_OK = 0x02; + const FLAG_OPLOG_REPLAY = 0x03; + const FLAG_NO_CURSOR_TIMEOUT = 0x04; + const FLAG_AWAIT_DATA = 0x05; + const FLAG_EXHAUST = 0x06; + const FLAG_PARTIAL = 0x07; + private $query; private $selector; private $flags; From bf4ec1368af77178c963595df12c488a6df7effe Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Fri, 13 Jun 2014 04:06:25 -0400 Subject: [PATCH 4/5] Command execution takes a database name, not a namespace --- docs/api/MongoDB/Manager.php | 4 ++-- docs/api/MongoDB/Server.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/api/MongoDB/Manager.php b/docs/api/MongoDB/Manager.php index 7640a8cf1..9a3128d88 100644 --- a/docs/api/MongoDB/Manager.php +++ b/docs/api/MongoDB/Manager.php @@ -50,12 +50,12 @@ static public function createFromServers(array $servers) } /** - * @param string $namespace + * @param string $db * @param Command $command * @param ReadPreference $readPreference * @return CommandResult */ - public function executeCommand($namespace, Command $command, ReadPreference $readPreference = null) + public function executeCommand($db, Command $command, ReadPreference $readPreference = null) { /* Select server based on (1) command requirements and (2) read * preference and invoke Server::executeCommand(). diff --git a/docs/api/MongoDB/Server.php b/docs/api/MongoDB/Server.php index 18697db37..3074d260a 100644 --- a/docs/api/MongoDB/Server.php +++ b/docs/api/MongoDB/Server.php @@ -59,11 +59,11 @@ public function __construct($host, $port, array $options = array(), array $drive } /** - * @param string $namespace + * @param string $db * @param Command $command * @return CommandResult */ - public function executeCommand($namespace, Command $command) + public function executeCommand($db, Command $command) { /* This method does not take a ReadPreference. If connected to mongos, * it the user's responsibility to set a read preference on the command From 894051f35d79065e622f9d2fe1b05caf1ad9278e Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Fri, 13 Jun 2014 12:44:05 -0400 Subject: [PATCH 5/5] Specity write options in execute methods, not batch constructors --- docs/api/MongoDB/Manager.php | 25 ++++++++++++++++++------- docs/api/MongoDB/Write/DeleteBatch.php | 9 --------- docs/api/MongoDB/Write/InsertBatch.php | 9 --------- docs/api/MongoDB/Write/UpdateBatch.php | 9 --------- 4 files changed, 18 insertions(+), 34 deletions(-) diff --git a/docs/api/MongoDB/Manager.php b/docs/api/MongoDB/Manager.php index 9a3128d88..2494d31da 100644 --- a/docs/api/MongoDB/Manager.php +++ b/docs/api/MongoDB/Manager.php @@ -94,14 +94,15 @@ public function executeQuery($namespace, Query $query, ReadPreference $readPrefe /** * @param string $namespace * @param WriteBatch $batch + * @param array $writeOptions Ordering and write concern options (default: {"ordered": true, "w": 1}) * @return WriteResult */ - public function executeWrite($namespace, WriteBatch $batch) + public function executeWrite($namespace, WriteBatch $batch, array $writeOptions = null) { /* Select writeable server and invoke Server::executeQuery(). * - * Write options are not taken as an argument, since they are specified - * during WriteBatch construction. + * Write options are optional, and will be merged into the default, + * which is {"ordered": true, "w": 1}. * * On error, we should consider throwing: * @@ -119,12 +120,16 @@ public function executeWrite($namespace, WriteBatch $batch) * * @param string $namespace * @param array|object $document Document to insert - * @param array $writeOptions Write concern options + * @param array $writeOptions Write concern options (default: {"w": 1}) * @return InsertResult */ public function executeInsert($namespace, $document, array $writeOptions = null) { - // Construct and execute an InsertBatch + /* Construct and execute an InsertBatch + * + * Write options are optional, and will be merged into the default, + * which is {"w": 1}. + */ } /** @@ -134,12 +139,15 @@ public function executeInsert($namespace, $document, array $writeOptions = null) * @param array|object $query Update criteria * @param array|object $newObj Update modifier or replacement document * @param array $updateOptions Update options (e.g. "upsert") - * @param array $writeOptions Write concern options + * @param array $writeOptions Write concern options (default: {"w": 1}) * @return UpdateResult */ public function executeUpdate($namespace, $query, $newObj, array $updateOptions = null, array $writeOptions = null) { /* Construct and execute an UpdateBatch + * + * Write options are optional, and will be merged into the default, + * which is {"w": 1}. * * What should be the default value for $options? No multi, no upsert? */ @@ -151,12 +159,15 @@ public function executeUpdate($namespace, $query, $newObj, array $updateOptions * @param string $namespace * @param array|object $query Deletion criteria * @param array $deleteOptions Deletion options (e.g. "limit") - * @param array $writeOptions Write concern options + * @param array $writeOptions Write concern options (default: {"w": 1}) * @return DeleteResult */ public function executeDelete($namespace, $query, array $deleteOptions = null, array $writeOptions = null) { /* Construct and execute an DeleteBatch + * + * Write options are optional, and will be merged into the default, + * which is {"w": 1}. * * What should be the default value for $options? No limit? */ diff --git a/docs/api/MongoDB/Write/DeleteBatch.php b/docs/api/MongoDB/Write/DeleteBatch.php index b86d62c16..177145b7b 100644 --- a/docs/api/MongoDB/Write/DeleteBatch.php +++ b/docs/api/MongoDB/Write/DeleteBatch.php @@ -8,15 +8,6 @@ final class DeleteBatch implements WriteBatch { private $documents; - private $writeOptions; - - /** - * @param array $writeOptions Ordering and write concern options - */ - public function __construct(array $writeOptions) - { - $this->writeOptions = $writeOptions; - } /** * @see WriteBatch::add() diff --git a/docs/api/MongoDB/Write/InsertBatch.php b/docs/api/MongoDB/Write/InsertBatch.php index 00b5cca11..a811008e5 100644 --- a/docs/api/MongoDB/Write/InsertBatch.php +++ b/docs/api/MongoDB/Write/InsertBatch.php @@ -8,15 +8,6 @@ final class InsertBatch implements WriteBatch { private $documents; - private $writeOptions; - - /** - * @param array $writeOptions Ordering and write concern options - */ - public function __construct(array $writeOptions) - { - $this->writeOptions = $writeOptions; - } /** * @see WriteBatch::add() diff --git a/docs/api/MongoDB/Write/UpdateBatch.php b/docs/api/MongoDB/Write/UpdateBatch.php index 47541527c..8201c9f3a 100644 --- a/docs/api/MongoDB/Write/UpdateBatch.php +++ b/docs/api/MongoDB/Write/UpdateBatch.php @@ -8,15 +8,6 @@ final class UpdateBatch implements WriteBatch { private $documents; - private $writeOptions; - - /** - * @param array $writeOptions Ordering and write concern options - */ - public function __construct(array $writeOptions) - { - $this->writeOptions = $writeOptions; - } /** * @see WriteBatch::add()