class Mongo::Operation::Result
Result
wrapper for wire protocol replies.
An operation has zero or one replies. The only operations producing zero replies are unacknowledged writes; all other operations produce one reply. This class provides an object that can be operated on (for example, to check whether an operation succeeded) even when the operation did not produce a reply (in which case it is assumed to have succeeded).
@since 2.0.0 @api semiprivate
Constants
- CURSOR
The field name for the cursor document in an aggregation.
@since 2.2.0 @api private
- CURSOR_ID
The cursor id field in the cursor document.
@since 2.2.0 @api private
- FIRST_BATCH
The field name for the first batch of a cursor.
@since 2.2.0 @api private
- N
The number of documents updated in the write.
@since 2.0.0 @api private
- NAMESPACE
The namespace field in the cursor document.
@since 2.2.0 @api private
- NEXT_BATCH
The field name for the next batch of a cursor.
@since 2.2.0 @api private
- OK
The ok status field in the result.
@since 2.0.0 @api private
- RESULT
The result field constant.
@since 2.2.0 @api private
Attributes
@return [ Server::Description
] Server
description of the server that
the operation was performed on that this result is for.
@api private
@return [ Array<Protocol::Message> ] replies The wrapped wire protocol replies.
@api private
Public Class Methods
Initialize a new result.
For an unkacknowledged write, pass nil in replies.
For all other operations, replies must be a Protocol::Message
instance or an array containing a single Protocol::Message
instance.
@param [ Protocol::Message
| Array<Protocol::Message> | nil ] replies
The wire protocol replies.
@param [ Server::Description
| nil ] connection_description
Server description of the server that performed the operation that this result is for. This parameter is allowed to be nil for compatibility with existing mongo_kerberos library, but should always be not nil in the driver proper.
@api private
# File lib/mongo/operation/result.rb, line 99 def initialize(replies, connection_description = nil) if replies if replies.is_a?(Array) if replies.length != 1 raise ArgumentError, "Only one (or zero) reply is supported, given #{replies.length}" end reply = replies.first else reply = replies end unless reply.is_a?(Protocol::Message) raise ArgumentError, "Argument must be a Message instance, but is a #{reply.class}: #{reply.inspect}" end @replies = [ reply ] @connection_description = connection_description end end
Public Instance Methods
Is the result acknowledged?
@note On MongoDB 2.6 and higher all writes are acknowledged since the
driver uses write commands for all write operations. On 2.4 and lower, the result is acknowledged if the GLE has been executed after the command. If not, no replies will be specified. Reads will always return true here since a replies is always provided.
@return [ true, false ] If the result is acknowledged.
@since 2.0.0 @api public
# File lib/mongo/operation/result.rb, line 144 def acknowledged? !!@replies end
Get the cluster time reported in the server response.
@example Get the cluster time.
result.cluster_time
@return [ ClusterTime
| nil ] The cluster time document.
Changed in version 2.9.0: This attribute became an instance of ClusterTime
, which is a subclass of BSON::Document. Previously it was an instance of BSON::Document.
@since 2.5.0 @api public
# File lib/mongo/operation/result.rb, line 403 def cluster_time first_document && ClusterTime[first_document['$clusterTime']] end
Get the cursor id if the response is acknowledged.
@note Cursor
ids of 0 indicate there is no cursor on the server.
@example Get the cursor id.
result.cursor_id
@return [ Integer ] The cursor id.
@since 2.0.0 @api private
# File lib/mongo/operation/result.rb, line 159 def cursor_id acknowledged? ? replies.last.cursor_id : 0 end
Get the documents in the result.
@example Get the documents.
result.documents
@return [ Array<BSON::Document> ] The documents.
@since 2.0.0 @api public
# File lib/mongo/operation/result.rb, line 183 def documents if acknowledged? replies.flat_map(&:documents) else [] end end
Iterate over the documents in the replies.
@example Iterate over the documents.
result.each do |doc| p doc end
@return [ Enumerator ] The enumerator.
@yieldparam [ BSON::Document ] Each document in the result.
@since 2.0.0 @api public
# File lib/mongo/operation/result.rb, line 204 def each(&block) documents.each(&block) end
The exception instance (of the Error::OperationFailure
class) that would be raised during processing of this result.
This method should only be called when result is not successful.
@return [ Error::OperationFailure
] The exception.
@api private
# File lib/mongo/operation/result.rb, line 322 def error @error ||= Error::OperationFailure.new( parser.message, self, code: parser.code, code_name: parser.code_name, write_concern_error_document: parser.write_concern_error_document, write_concern_error_code: parser.write_concern_error_code, write_concern_error_code_name: parser.write_concern_error_code_name, write_concern_error_labels: parser.write_concern_error_labels, labels: parser.labels, wtimeout: parser.wtimeout, connection_description: connection_description, ) end
Get the pretty formatted inspection of the result.
@example Inspect the result.
result.inspect
@return [ String ] The inspection.
@since 2.0.0 @api public
# File lib/mongo/operation/result.rb, line 217 def inspect "#<#{self.class.name}:0x#{object_id} documents=#{documents}>" end
Gets the set of error labels associated with the result.
@example Get the labels.
result.labels
@return [ Array ] labels The set of labels.
@since 2.7.0 @api private
# File lib/mongo/operation/result.rb, line 416 def labels @labels ||= parser.labels end
Get the namespace of the cursor. The method should be defined in result classes where ‘ns’ is in the server response.
@return [ Nil ]
@since 2.0.0 @api private
# File lib/mongo/operation/result.rb, line 170 def namespace nil end
Check the first document’s ok field.
@example Check the ok field.
result.ok?
@return [ true, false ] If the command returned ok.
@since 2.1.0 @api public
# File lib/mongo/operation/result.rb, line 286 def ok? # first_document[OK] is a float, and the server can return # ok as a BSON int32, BSON int64 or a BSON double. # The number 1 is exactly representable in a float, hence # 1.0 == 1 is going to perform correctly all of the time # (until the server returns something other than 1 for success, that is) first_document[OK] == 1 end
Get the operation time reported in the server response.
@example Get the operation time.
result.operation_time
@return [ Object | nil ] The operation time value.
@since 2.5.0 @api public
# File lib/mongo/operation/result.rb, line 386 def operation_time first_document && first_document[OPERATION_TIME] end
Get the reply from the result.
Returns nil if there is no reply (i.e. the operation was an unacknowledged write).
@return [ Protocol::Message
] The first reply.
@since 2.0.0 @api private
# File lib/mongo/operation/result.rb, line 230 def reply if acknowledged? replies.first else nil end end
Get the count of documents returned by the server.
@example Get the number returned.
result.returned_count
@return [ Integer ] The number of documents returned.
@since 2.0.0 @api public
# File lib/mongo/operation/result.rb, line 247 def returned_count if acknowledged? reply.number_returned else 0 end end
If the result was a command then determine if it was considered a success.
@note If the write was unacknowledged, then this will always return
true.
@example Was the command successful?
result.successful?
@return [ true, false ] If the command was successful.
@since 2.0.0 @api public
# File lib/mongo/operation/result.rb, line 268 def successful? return true if !acknowledged? if first_document.has_key?(OK) ok? && parser.message.empty? else !query_failure? && parser.message.empty? end end
@return [ TopologyVersion
| nil ] The topology version.
@api private
# File lib/mongo/operation/result.rb, line 349 def topology_version unless defined?(@topology_version) @topology_version = first_document['topologyVersion'] && TopologyVersion.new(first_document['topologyVersion']) end @topology_version end
Validate the result by checking for any errors.
@note This only checks for errors with writes since authentication is
handled at the connection level and any authentication errors would be raised there, before a Result is ever created.
@example Validate the result.
result.validate!
@raise [ Error::OperationFailure
] If an error is in the result.
@return [ Result
] The result if verification passed.
@since 2.0.0 @api private
# File lib/mongo/operation/result.rb, line 310 def validate! !successful? ? raise_operation_failure : self end
Whether the operation failed with a write concern error.
@api private
# File lib/mongo/operation/result.rb, line 423 def write_concern_error? !!(first_document && first_document['writeConcernError']) end
Get the number of documents written by the server.
@example Get the number of documents written.
result.written_count
@return [ Integer ] The number of documents written.
@since 2.0.0 @api public
# File lib/mongo/operation/result.rb, line 366 def written_count if acknowledged? first_document[N] || 0 else 0 end end
Private Instance Methods
# File lib/mongo/operation/result.rb, line 429 def aggregate_returned_count replies.reduce(0) do |n, reply| n += reply.number_returned n end end
# File lib/mongo/operation/result.rb, line 436 def aggregate_written_count documents.reduce(0) do |n, document| n += (document[N] || 0) n end end
# File lib/mongo/operation/result.rb, line 447 def first_document @first_document ||= first || BSON::Document.new end
# File lib/mongo/operation/result.rb, line 443 def parser @parser ||= Error::Parser.new(first_document, replies) end
# File lib/mongo/operation/result.rb, line 451 def query_failure? replies.first && (replies.first.query_failure? || replies.first.cursor_not_found?) end
Raises a Mongo::OperationFailure exception corresponding to the error information in this result.
@raise Error::OperationFailure
# File lib/mongo/operation/result.rb, line 342 def raise_operation_failure raise error end