lib/mongoid/clients/factory.rb
# frozen_string_literal: true
# rubocop:todo all
module Mongoid
module Clients
# Factory used to create database clients.
module Factory
extend self
extend Loggable
# Create a new client given the named configuration. If no name is
# provided, return a new client with the default configuration. If a
# name is provided for which no configuration exists, an error will be
# raised.
#
# @example Create the client.
# Factory.create(:analytics)
#
# @param [ String | Symbol ] name The named client configuration.
#
# @raise [ Errors::NoClientConfig ] If no config could be found.
#
# @return [ Mongo::Client ] The new client.
def create(name = nil)
return default unless name
config = Mongoid.clients[name]
raise Errors::NoClientConfig.new(name) unless config
create_client(config)
end
# Get the default client.
#
# @example Get the default client.
# Factory.default
#
# @raise [ Errors::NoClientConfig ] If no default configuration is
# found.
#
# @return [ Mongo::Client ] The default client.
def default
create_client(Mongoid.clients[:default])
end
private
# Create the client for the provided config.
#
# @api private
#
# @example Create the client.
# Factory.create_client(config)
#
# @param [ Hash ] configuration The client config.
#
# @return [ Mongo::Client ] The client.
def create_client(configuration)
raise Errors::NoClientsConfig.new unless configuration
config = configuration.dup
uri = config.delete(:uri)
database = config.delete(:database) || Mongo::URI.get(uri).database
hosts = config.delete(:hosts)
opts = config.delete(:options) || {}
if opts.key?(:auto_encryption_options)
opts[:auto_encryption_options] = build_auto_encryption_options(opts, database)
end
unless config.empty?
default_logger.warn("Unknown config options detected: #{config}.")
end
if uri
Mongo::Client.new(uri, options(opts))
else
Mongo::Client.new(
hosts,
options(opts).merge(database: database)
)
end
end
# Build auto encryption options for the client based on the options
# provided in the Mongoid client configuration and the encryption
# schema map for the database.
#
# @param [ Hash ] opts Options from the Mongoid client configuration.
# @param [ String ] database Database name to use for encryption schema map.
#
# @return [ Hash | nil ] Auto encryption options for the client.
#
# @api private
def build_auto_encryption_options(opts, database)
return nil unless opts[:auto_encryption_options]
opts[:auto_encryption_options].dup.tap do |auto_encryption_options|
if auto_encryption_options.key?(:schema_map)
default_logger.warn(
'The :schema_map is configured in the :auto_encryption_options for the client;' +
' encryption setting in Mongoid documents will be ignored.'
)
else
auto_encryption_options[:schema_map] = Mongoid.config.encryption_schema_map(database)
end
if auto_encryption_options.key?(:key_vault_client)
auto_encryption_options[:key_vault_client] = Mongoid.client(
auto_encryption_options[:key_vault_client]
)
end
end
end
MONGOID_WRAPPING_LIBRARY = {
name: 'Mongoid',
version: VERSION,
}.freeze
def driver_version
Mongo::VERSION.split('.')[0...2].map(&:to_i)
end
# Prepare options for Mongo::Client based on Mongoid client configuration.
#
# @param [ Hash ] opts Parameters from options section of Mongoid client configuration.
# @return [ Hash ] Options that should be passed to Mongo::Client constructor.
#
# @api private
def options(opts)
options = opts.dup
options[:platform] = PLATFORM_DETAILS
options[:app_name] = Mongoid::Config.app_name if Mongoid::Config.app_name
if (driver_version <=> [2, 13]) >= 0
wrap_lib = if options[:wrapping_libraries]
[MONGOID_WRAPPING_LIBRARY] + options[:wrapping_libraries]
else
[MONGOID_WRAPPING_LIBRARY]
end
options[:wrapping_libraries] = wrap_lib
end
options.reject{ |k, _v| k == :hosts }.to_hash.symbolize_keys!
end
end
end
end