class Mongo::URI::OptionsMapper
Performs mapping between URI
options and Ruby options.
This class contains:
-
The mapping defining how
URI
options are converted to Ruby options. -
The mapping from downcased
URI
option names to canonical-casedURI
option names. -
Methods to perform conversion of
URI
option values to Ruby option values (the convert_* methods). These generally warn and return nil when input given is invalid. -
Methods to perform conversion of Ruby option values to standardized MongoClient options (revert_* methods). These assume the input is valid and generally do not perform validation.
URI
option names are case insensitive. Ruby options are specified as symbols (though in Client
options use indifferent access).
@api private
Constants
Attributes
@return [ Hash ] The options.
Public Class Methods
Instantates the options mapper.
@option opts [ Logger
] :logger A custom logger to use.
# File lib/mongo/uri/options_mapper.rb, line 46 def initialize(**opts) @options = opts end
Private Class Methods
Simple internal dsl to register a MongoDB URI
option in the URI_OPTION_MAP
.
@param [ String ] uri_key The MongoDB URI
option to register. @param [ Symbol
] name The name of the option in the driver. @param [ Hash ] extra Extra options.
* :group [ Symbol ] Nested hash where option will go. * :type [ Symbol ] Name of function to transform value.
# File lib/mongo/uri/options_mapper.rb, line 260 def self.uri_option(uri_key, name, **extra) URI_OPTION_MAP[uri_key.downcase] = { name: name }.update(extra) URI_OPTION_CANONICAL_NAMES[uri_key.downcase] = uri_key end
Public Instance Methods
Adds an option to the uri options hash.
Acquires a target for the option based on group. Transforms the value. Merges the option into the target.
@param [ String ] key URI
option name. @param [ String ] value The value of the option. @param [ Hash ] uri_options The base option target.
# File lib/mongo/uri/options_mapper.rb, line 62 def add_uri_option(key, value, uri_options) strategy = URI_OPTION_MAP[key.downcase] if strategy.nil? log_warn("Unsupported URI option '#{key}' on URI '#{@string}'. It will be ignored.") return end group = strategy[:group] target = if group uri_options[group] || {} else uri_options end value = apply_transform(key, value, strategy[:type]) # Sometimes the value here would be nil, for example if we are processing # read preference tags or auth mechanism properties and all of the # data within is invalid. Ignore such options. unless value.nil? merge_uri_option(target, value, strategy[:name]) end if group && !target.empty? && !uri_options.key?(group) uri_options[group] = target end end
Converts Ruby options provided to “standardized MongoClient options”.
@param [ Hash ] opts Ruby options to convert.
@return [ Hash ] Standardized MongoClient options.
# File lib/mongo/uri/options_mapper.rb, line 126 def ruby_to_smc(opts) rv = {} URI_OPTION_MAP.each do |uri_key, spec| if spec[:group] v = opts[spec[:group]] v = v && v[spec[:name]] else v = opts[spec[:name]] end unless v.nil? if type = spec[:type] v = send("revert_#{type}", v) end canonical_key = URI_OPTION_CANONICAL_NAMES[uri_key] unless canonical_key raise ArgumentError, "Option #{uri_key} is not known" end rv[canonical_key] = v end end # For options that default to true, remove the value if it is true. %w(retryReads retryWrites).each do |k| if rv[k] rv.delete(k) end end # Remove auth source when it is $external for mechanisms that default # (or require) that auth source. if %w(MONGODB-AWS).include?(rv['authMechanism']) && rv['authSource'] == '$external' rv.delete('authSource') end # ssl and tls are aliases, remove ssl ones rv.delete('ssl') # TODO remove authSource if it is the same as the database, # requires this method to know the database specified in the client. rv end
Converts Ruby options provided to their representation in a URI
string.
@param [ Hash ] opts Ruby options to convert.
@return [ Hash ] URI
string hash.
# File lib/mongo/uri/options_mapper.rb, line 169 def ruby_to_string(opts) rv = {} URI_OPTION_MAP.each do |uri_key, spec| if spec[:group] v = opts[spec[:group]] v = v && v[spec[:name]] else v = opts[spec[:name]] end unless v.nil? if type = spec[:type] v = send("stringify_#{type}", v) end canonical_key = URI_OPTION_CANONICAL_NAMES[uri_key] unless canonical_key raise ArgumentError, "Option #{uri_key} is not known" end rv[canonical_key] = v end end # For options that default to true, remove the value if it is true. %w(retryReads retryWrites).each do |k| if rv[k] rv.delete(k) end end # Remove auth source when it is $external for mechanisms that default # (or require) that auth source. if %w(MONGODB-AWS).include?(rv['authMechanism']) && rv['authSource'] == '$external' rv.delete('authSource') end # ssl and tls are aliases, remove ssl ones rv.delete('ssl') # TODO remove authSource if it is the same as the database, # requires this method to know the database specified in the client. rv end
# File lib/mongo/uri/options_mapper.rb, line 88 def smc_to_ruby(opts) uri_options = {} opts.each do |key, value| strategy = URI_OPTION_MAP[key.downcase] if strategy.nil? log_warn("Unsupported URI option '#{key}' on URI '#{@string}'. It will be ignored.") return end group = strategy[:group] target = if group uri_options[group] || {} else uri_options end value = apply_transform(key, value, strategy[:type]) # Sometimes the value here would be nil, for example if we are processing # read preference tags or auth mechanism properties and all of the # data within is invalid. Ignore such options. unless value.nil? merge_uri_option(target, value, strategy[:name]) end if group && !target.empty? && !uri_options.key?(group) uri_options[group] = target end end uri_options end
Private Instance Methods
Applies URI
value transformation by either using the default cast or a transformation appropriate for the given type.
@param [ String ] key URI
option name. @param [ String ] value The value to be transformed. @param [ Symbol
] type The transform method.
# File lib/mongo/uri/options_mapper.rb, line 215 def apply_transform(key, value, type) if type send("convert_#{type}", key, value) else value end end
Extract values from the string and put them into an array.
@param [ String ] name Name of the URI
option being processed. @param [ String ] value The string to build an array from.
@return [ Array<String> ] The array built from the string.
# File lib/mongo/uri/options_mapper.rb, line 545 def convert_array(name, value) value.split(',') end
Authentication mechanism transformation.
@param [ String ] name Name of the URI
option being processed. @param [ String ] value The authentication mechanism.
@return [ Symbol
] The transformed authentication mechanism.
# File lib/mongo/uri/options_mapper.rb, line 573 def convert_auth_mech(name, value) auth_mech = AUTH_MECH_MAP[value.upcase] (auth_mech || value).tap do |mech| log_warn("#{value} is not a valid auth mechanism") unless auth_mech end end
Auth
mechanism properties extractor.
@param [ String ] name Name of the URI
option being processed. @param [ String ] value The auth mechanism properties string.
@return [ Hash | nil ] The auth mechanism properties hash.
# File lib/mongo/uri/options_mapper.rb, line 613 def convert_auth_mech_props(name, value) properties = hash_extractor('authMechanismProperties', value) if properties properties.each do |k, v| if k.to_s.downcase == 'canonicalize_host_name' && v properties[k] = (v.downcase == 'true') end end end properties end
Converts value
to a boolean.
Returns true for ‘true’, false for ‘false’, otherwise nil.
@param [ String ] name Name of the URI
option being processed. @param [ String | true | false ] value URI
option value.
@return [ true | false | nil ] Converted value.
# File lib/mongo/uri/options_mapper.rb, line 334 def convert_bool(name, value) case value when true, "true", 'TRUE' true when false, "false", 'FALSE' false else log_warn("invalid boolean option for #{name}: #{value}") nil end end
Converts value
into an integer. Only converts positive integers.
If the value is not a valid integer, warns and returns nil.
@param [ String ] name Name of the URI
option being processed. @param [ String | Integer ] value URI
option value.
@return [ nil | Integer ] Converted value.
# File lib/mongo/uri/options_mapper.rb, line 441 def convert_integer(name, value) if value.is_a?(String) && /\A\d+\z/ !~ value log_warn("#{value} is not a valid integer for #{name}") return nil end value.to_i end
Parses a boolean value and returns its inverse.
@param [ String ] name Name of the URI
option being processed. @param [ String | true | false ] value The URI
option value.
@return [ true | false | nil ] The inverse of the boolean value parsed out, otherwise nil
(and a warning will be logged).
# File lib/mongo/uri/options_mapper.rb, line 405 def convert_inverse_bool(name, value) b = convert_bool(name, value) if b.nil? nil else !b end end
Parses the max staleness value, which must be either “0” or an integer greater or equal to 90.
@param [ String ] name Name of the URI
option being processed. @param [ String | Integer ] value The max staleness string.
@return [ Integer | nil ] The max staleness integer parsed out if it is valid, otherwise nil
(and a warning will be logged).
# File lib/mongo/uri/options_mapper.rb, line 652 def convert_max_staleness(name, value) int = if value.is_a?(String) && /\A-?\d+\z/ =~ value value.to_i elsif value.is_a?(Integer) value end if int.nil? log_warn("Invalid max staleness value: #{value}") return nil end if int == -1 int = nil end if int && (int > 0 && int < 90 || int < 0) log_warn("max staleness should be either 0 or greater than 90: #{value}") int = nil end int end
Ruby’s convention is to provide timeouts in seconds, not milliseconds and to use fractions where more precision is necessary. The connection string options are always in MS so we provide an easy conversion type.
@param [ String ] name Name of the URI
option being processed. @param [ String | Integer | Float ] value The millisecond value.
@return [ Float ] The seconds value.
@since 2.0.0
# File lib/mongo/uri/options_mapper.rb, line 478 def convert_ms(name, value) case value when String if /\A-?\d+(\.\d+)?\z/ !~ value log_warn("Invalid ms value for #{name}: #{value}") return nil end if value.to_s[0] == '-' log_warn("#{name} cannot be a negative number") return nil end when Integer, Float if value < 0 log_warn("#{name} cannot be a negative number") return nil end else raise ArgumentError, "Can only convert Strings, Integers, or Floats to ms. Given: #{value.class}" end value.to_f / 1000 end
Read preference mode transformation.
@param [ String ] name Name of the URI
option being processed. @param [ String ] value The read mode string value.
@return [ Symbol
| String ] The read mode.
# File lib/mongo/uri/options_mapper.rb, line 700 def convert_read_mode(name, value) READ_MODE_MAP[value.downcase] || value end
Read preference tag set extractor.
@param [ String ] name Name of the URI
option being processed. @param [ String ] value The tag set string.
@return [ Hash ] The tag set hash.
# File lib/mongo/uri/options_mapper.rb, line 753 def convert_read_set(name, value) hash_extractor('readPreferenceTags', value) end
Converts the value into a boolean and returns it wrapped in an array.
@param [ String ] name Name of the URI
option being processed. @param [ String ] value URI
option value.
@return [ Array<true | false> | nil ] The boolean value parsed and wraped
in an array.
# File lib/mongo/uri/options_mapper.rb, line 371 def convert_repeated_bool(name, value) [convert_bool(name, value)] end
Converts value
as a write concern.
If value
is the word “majority”, returns the symbol :majority. If value
is a number, returns the number as an integer. Otherwise returns the string value
unchanged.
@param [ String ] name Name of the URI
option being processed. @param [ String | Integer ] value URI
option value.
@return [ Integer | Symbol
| String ] Converted value.
# File lib/mongo/uri/options_mapper.rb, line 767 def convert_w(name, value) case value when 'majority' :majority when /\A[0-9]+\z/ value.to_i else value end end
Parses the zlib compression level.
@param [ String ] name Name of the URI
option being processed. @param [ String | Integer ] value The zlib compression level string.
@return [ Integer | nil ] The compression level value if it is between -1 and 9 (inclusive),
otherwise nil (and a warning will be logged).
# File lib/mongo/uri/options_mapper.rb, line 808 def convert_zlib_compression_level(name, value) i = if value.is_a?(String) && /\A-?\d+\z/ =~ value value.to_i elsif value.is_a?(Integer) value end if i && (i >= -1 && i <= 9) i else log_warn("#{value} is not a valid zlibCompressionLevel") nil end end
Extract values from the string and put them into a nested hash.
@param [ String ] name Name of the URI
option being processed. @param [ String ] value The string to build a hash from.
@return [ Hash ] The hash built from the string.
# File lib/mongo/uri/options_mapper.rb, line 847 def hash_extractor(name, value) h = {} value.split(',').each do |tag| k, v = tag.split(':') if v.nil? log_warn("Invalid hash value for #{name}: key `#{k}` does not have a value: #{value}") next end h[k.to_sym] = v end if h.empty? nil else h end end
Merges a new option into the target.
If the option exists at the target destination the merge will be an addition.
Specifically required to append an additional tag set to the array of tag sets without overwriting the original.
@param [ Hash ] target The destination. @param [ Object ] value The value to be merged. @param [ Symbol
] name The name of the option.
# File lib/mongo/uri/options_mapper.rb, line 234 def merge_uri_option(target, value, name) if target.key?(name) if REPEATABLE_OPTIONS.include?(name) target[name] += value else log_warn("Repeated option key: #{name}.") end else target.merge!(name => value) end end
Reverts an array.
@param [ Array<String> ] value An array of strings.
@return [ Array<String> ] The passed value.
# File lib/mongo/uri/options_mapper.rb, line 554 def revert_array(value) value end
Reverts auth mechanism.
@param [ Symbol
] value The auth mechanism.
@return [ String ] The auth mechanism as a string.
@raise [ ArgumentError ] if its an invalid auth mechanism.
# File lib/mongo/uri/options_mapper.rb, line 587 def revert_auth_mech(value) found = AUTH_MECH_MAP.detect do |k, v| v == value end if found found.first else raise ArgumentError, "Unknown auth mechanism #{value}" end end
Reverts auth mechanism properties.
@param [ Hash | nil ] value The auth mech properties.
@return [ Hash | nil ] The passed value.
# File lib/mongo/uri/options_mapper.rb, line 630 def revert_auth_mech_props(value) value end
Reverts a boolean type.
@param [ true | false | nil ] value The boolean to revert.
@return [ true | false | nil ] The passed value.
# File lib/mongo/uri/options_mapper.rb, line 351 def revert_bool(value) value end
Reverts an integer.
@param [ Integer | nil ] value The integer.
@return [ Integer | nil ] The passed value.
# File lib/mongo/uri/options_mapper.rb, line 455 def revert_integer(value) value end
Reverts and inverts a boolean type.
@param [ true | false | nil ] value The boolean to revert and invert.
@return [ true | false | nil ] The inverted boolean.
# File lib/mongo/uri/options_mapper.rb, line 420 def revert_inverse_bool(value) value.nil? ? nil : !value end
Reverts max staleness.
@param [ Integer | nil ] value The max staleness.
@return [ Integer | nil ] The passed value.
# File lib/mongo/uri/options_mapper.rb, line 681 def revert_max_staleness(value) value end
Reverts an ms.
@param [ Float ] value The float.
@return [ Integer ] The number multiplied by 1000 as an integer.
# File lib/mongo/uri/options_mapper.rb, line 506 def revert_ms(value) (value * 1000).round end
Reverts read mode.
@param [ Symbol
| String ] value The read mode.
@return [ String ] The read mode as a string.
# File lib/mongo/uri/options_mapper.rb, line 709 def revert_read_mode(value) value.to_s.gsub(/_(\w)/) { $1.upcase } end
Reverts a repeated boolean type.
@param [ Array<true | false> | true | false | nil ] value The repeated boolean to revert.
@return [ Array<true | false> | true | false | nil ] The passed value.
# File lib/mongo/uri/options_mapper.rb, line 380 def revert_repeated_bool(value) value end
Reverts a symbol.
@param [ Symbol
] value The symbol.
@return [ String ] The passed value as a string.
# File lib/mongo/uri/options_mapper.rb, line 534 def revert_symbol(value) value.to_s end
Reverts write concern.
@param [ Integer | Symbol
| String ] value The write concern.
@return [ Integer | String ] The write concern as a string.
# File lib/mongo/uri/options_mapper.rb, line 783 def revert_w(value) case value when Symbol value.to_s else value end end
Reverts zlib compression level
@param [ Integer | nil ] value The write concern.
@return [ Integer | nil ] The passed value.
# File lib/mongo/uri/options_mapper.rb, line 828 def revert_zlib_compression_level(value) value end
Stringifies an array.
@param [ Array<String> ] value An array of strings.
@return [ String ] The array joined by commas.
# File lib/mongo/uri/options_mapper.rb, line 563 def stringify_array(value) value.join(',') end
Stringifies auth mechanism.
@param [ Symbol
] value The auth mechanism.
@return [ String | nil ] The auth mechanism as a string.
# File lib/mongo/uri/options_mapper.rb, line 603 def stringify_auth_mech(value) revert_auth_mech(value) rescue nil end
Stringifies auth mechanism properties.
@param [ Hash | nil ] value The auth mech properties.
@return [ String | nil ] The string.
# File lib/mongo/uri/options_mapper.rb, line 639 def stringify_auth_mech_props(value) return if value.nil? value.map { |k, v| "#{k}:#{v}" }.join(',') end
Stringifies a boolean type.
@param [ true | false | nil ] value The boolean.
@return [ String | nil ] The string.
# File lib/mongo/uri/options_mapper.rb, line 360 def stringify_bool(value) revert_bool(value)&.to_s end
Stringifies an integer.
@param [ Integer | nil ] value The integer.
@return [ String | nil ] The string.
# File lib/mongo/uri/options_mapper.rb, line 464 def stringify_integer(value) revert_integer(value)&.to_s end
Inverts and stringifies a boolean.
@param [ true | false | nil ] value The boolean.
@return [ String | nil ] The string.
# File lib/mongo/uri/options_mapper.rb, line 429 def stringify_inverse_bool(value) revert_inverse_bool(value)&.to_s end
Stringifies max staleness.
@param [ Integer | nil ] value The max staleness.
@return [ String | nil ] The string.
# File lib/mongo/uri/options_mapper.rb, line 690 def stringify_max_staleness(value) revert_max_staleness(value)&.to_s end
Stringifies an ms.
@param [ Float ] value The float.
@return [ String ] The string.
# File lib/mongo/uri/options_mapper.rb, line 515 def stringify_ms(value) revert_ms(value).to_s end
Stringifies a repeated boolean type.
@param [ Array<true | false> | nil ] value The repeated boolean.
@return [ Array<true | false> | nil ] The string.
# File lib/mongo/uri/options_mapper.rb, line 389 def stringify_repeated_bool(value) rep = revert_repeated_bool(value) if rep&.is_a?(Array) rep.join(",") else rep end end
Stringifies write concern.
@param [ Integer | Symbol
| String ] value The write concern.
@return [ String ] The write concern as a string.
# File lib/mongo/uri/options_mapper.rb, line 797 def stringify_w(value) revert_w(value)&.to_s end
Stringifies zlib compression level
@param [ Integer | nil ] value The write concern.
@return [ String | nil ] The string.
# File lib/mongo/uri/options_mapper.rb, line 837 def stringify_zlib_compression_level(value) revert_zlib_compression_level(value)&.to_s end