class Mongo::Error::Parser

Class for parsing the various forms that errors can come in from MongoDB command responses.

@since 2.0.0

Attributes

code[R]

@return [ Integer ] code The error code parsed from the document. @since 2.6.0

code_name[R]

@return [ String ] code_name The error code name parsed from the document. @since 2.6.0

document[R]

@return [ BSON::Document ] document The returned document.

labels[R]

@return [ Array<String> ] labels The set of labels associated with the error. @since 2.7.0

message[R]

@return [ String ] message The error message parsed from the document.

replies[R]

@return [ Array<Protocol::Message> ] replies The message replies.

wtimeout[R]

@api private

Public Class Methods

new(document, replies = nil, options = nil) click to toggle source

Create the new parser with the returned document.

In legacy mode, the code and codeName fields of the document are not examined because the status (ok: 1) is not part of the document and there is no way to distinguish successful from failed responses using the document itself, and a successful response may legitimately have {code: 123, codeName: 'foo'} as the contents of a user-inserted document. The legacy server versions do not fill out code nor codeName thus not reading them does not lose information.

@example Create the new parser.

Parser.new({ 'errmsg' => 'failed' })

@param [ BSON::Document ] document The returned document. @param [ Array<Protocol::Message> ] replies The message replies. @param [ Hash ] options The options.

@option options [ true | false ] :legacy Whether document and replies

are from a legacy (pre-3.2) response

@since 2.0.0

# File lib/mongo/error/parser.rb, line 94
def initialize(document, replies = nil, options = nil)
  @document = document || {}
  @replies = replies
  @options = if options
    options.dup
  else
    {}
  end.freeze
  parse!
end

Public Instance Methods

write_concern_error?() click to toggle source

@return [ true | false ] Whether the document includes a write

concern error. A failure may have a top level error and a write
concern error or either one of the two.

@since 2.10.0 @api experimental

# File lib/mongo/error/parser.rb, line 111
def write_concern_error?
  !!write_concern_error_document
end
write_concern_error_code() click to toggle source

@return [ Integer | nil ] The error code for the write concern error,

if a write concern error is present and has a code.

@since 2.10.0 @api experimental

# File lib/mongo/error/parser.rb, line 120
def write_concern_error_code
  write_concern_error_document && write_concern_error_document['code']
end
write_concern_error_code_name() click to toggle source

@return [ String | nil ] The code name for the write concern error,

if a write concern error is present and has a code name.

@since 2.10.0 @api experimental

# File lib/mongo/error/parser.rb, line 129
def write_concern_error_code_name
  write_concern_error_document && write_concern_error_document['codeName']
end

Private Instance Methods

append(message, error) click to toggle source
# File lib/mongo/error/parser.rb, line 175
def append(message, error)
  if message.length > 1
    message.concat(", #{error}")
  else
    message.concat(error)
  end
end
parse!() click to toggle source
# File lib/mongo/error/parser.rb, line 139
def parse!
  @message = ""
  parse_single(@message, ERR)
  parse_single(@message, ERROR)
  parse_single(@message, ERRMSG)
  parse_multiple(@message, 'writeErrors')
  if write_concern_error_document
    parse_single(@message, ERRMSG, write_concern_error_document)
  end
  parse_flag(@message)
  parse_code
  parse_labels
  parse_wtimeout
end
parse_code() click to toggle source
# File lib/mongo/error/parser.rb, line 183
def parse_code
  if document['ok'] == 1 || @options[:legacy]
    @code = @code_name = nil
  else
    @code = document['code']
    @code_name = document['codeName']
  end

  # Since there is only room for one code, do not replace
  # codes of the top level response with write concern error codes.
  # In practice this should never be an issue as a write concern
  # can only fail after the operation succeeds on the primary.
  if @code.nil? && @code_name.nil?
    if subdoc = write_concern_error_document
      @code = subdoc['code']
      @code_name = subdoc['codeName']
    end
  end

  if @code.nil? && @code_name.nil?
    # If we have writeErrors, and all of their codes are the same,
    # use that code. Otherwise don't set the code
    if write_errors = document['writeErrors']
      codes = write_errors.map { |e| e['code'] }.compact
      if codes.uniq.length == 1
        @code = codes.first
        # code name may not be returned by the server
        @code_name = write_errors.map { |e| e['codeName'] }.compact.first
      end
    end
  end
end
parse_flag(message) click to toggle source
# File lib/mongo/error/parser.rb, line 168
def parse_flag(message)
  if replies && replies.first &&
      (replies.first.respond_to?(:cursor_not_found?)) && replies.first.cursor_not_found?
    append(message, CURSOR_NOT_FOUND)
  end
end
parse_labels() click to toggle source
# File lib/mongo/error/parser.rb, line 216
def parse_labels
  @labels = document['errorLabels'] || []
end
parse_multiple(message, key) click to toggle source
# File lib/mongo/error/parser.rb, line 160
def parse_multiple(message, key)
  if errors = document[key]
    errors.each do |error|
      parse_single(message, ERRMSG, error)
    end
  end
end
parse_single(message, key, doc = document) click to toggle source
# File lib/mongo/error/parser.rb, line 154
def parse_single(message, key, doc = document)
  if error = doc[key]
    append(message ,"#{error} (#{doc[CODE]})")
  end
end
parse_wtimeout() click to toggle source
# File lib/mongo/error/parser.rb, line 220
def parse_wtimeout
  @wtimeout = write_concern_error_document &&
    write_concern_error_document['errInfo'] &&
    write_concern_error_document['errInfo']['wtimeout']
end
write_concern_error_document() click to toggle source
# File lib/mongo/error/parser.rb, line 135
def write_concern_error_document
  document['writeConcernError']
end