class ActiveRecord::DatabaseConfigurations

registering custom handlers.
conditions of the handler. See ::register_db_config_handler for more on
If you register a custom handler, objects will be created according to the
ActiveRecord::Base.configurations.
HashConfig or UrlConfig. You can retrieve your application’s config by using
The array of DatabaseConfig objects in an application default to either a
configuration hash or URL string.
objects that are constructed from the application’s database
ActiveRecord::DatabaseConfigurations returns an array of DatabaseConfig
= Active Record Database Configurations

def self.register_db_config_handler(&block)

created instead of a +UrlConfig+.
For configs that have a +:vitess+ key, a +VitessConfig+ object will be

end
end
configuration_hash.fetch("sharded", false)
def sharded?
class VitessConfig < ActiveRecord::DatabaseConfigurations::UrlConfig

config handlers should only implement methods Active Record does not.
database config classes to avoid having to reimplement all methods. Custom
needs. It is recommended that you inherit from one of the existing
Then define your +VitessConfig+ to respond to the methods your application

handler.
created in your handler registration otherwise all objects will use the custom
Note: applications must handle the condition in which custom config should be

end
VitessConfig.new(env_name, name, config)
next unless config.key?(:vitess)
ActiveRecord::DatabaseConfigurations.register_db_config_handler do |env_name, name, url, config|

initializer:
to respond to `sharded?`. To implement this define the following in an
example if you are using Vitess, you may want your Vitess configurations
methods your application needs but Active Record doesn't implement. For
objects. This is useful for creating a custom handler that responds to
Allows an application to register a custom handler for database configuration
def self.register_db_config_handler(&block)
  db_config_handlers << block
end

def build_configs(configs)

def build_configs(configs)
  return configs.configurations if configs.is_a?(DatabaseConfigurations)
  return configs if configs.is_a?(Array)
  db_configs = configs.flat_map do |env_name, config|
    if config.is_a?(Hash) && config.values.all?(Hash)
      walk_configs(env_name.to_s, config)
    else
      build_db_config_from_raw_config(env_name.to_s, "primary", config)
    end
  end
  unless db_configs.find(&:for_current_env?)
    db_configs << environment_url_config(default_env, "primary", {})
  end
  merge_db_environment_variables(default_env, db_configs.compact)
end

def build_configuration_sentence

def build_configuration_sentence
  configs = configs_for(include_hidden: true)
  configs.group_by(&:env_name).map do |env, config|
    names = config.map(&:name)
    if names.size > 1
      "#{env}: #{names.join(", ")}"
    else
      env
    end
  end.join("\n")
end

def build_db_config_from_hash(env_name, name, config)

def build_db_config_from_hash(env_name, name, config)
  url = config[:url]
  config_without_url = config.dup
  config_without_url.delete :url
  DatabaseConfigurations.db_config_handlers.reverse_each do |handler|
    config = handler.call(env_name, name, url, config_without_url)
    return config if config
  end
  nil
end

def build_db_config_from_raw_config(env_name, name, config)

def build_db_config_from_raw_config(env_name, name, config)
  case config
  when String
    build_db_config_from_string(env_name, name, config)
  when Hash
    build_db_config_from_hash(env_name, name, config.symbolize_keys)
  else
    raise InvalidConfigurationError, "'{ #{env_name} => #{config} }' is not a valid configuration. Expected '#{config}' to be a URL string or a Hash."
  end
end

def build_db_config_from_string(env_name, name, config)

def build_db_config_from_string(env_name, name, config)
  url = config
  uri = URI.parse(url)
  if uri.scheme
    UrlConfig.new(env_name, name, url)
  else
    raise InvalidConfigurationError, "'{ #{env_name} => #{config} }' is not a valid configuration. Expected '#{config}' to be a URL string or a Hash."
  end
end

def configs_for(env_name: nil, name: nil, config_key: nil, include_hidden: false)

write and read connection). Defaults to +false+.
iterating over the primary connections (i.e. migrations don't need to run for the
hidden by database_tasks: false in the returned list. Most of the time we're only
* include_hidden: Determines whether to include replicas and configurations
configs with hashes that contain a particular key.
hash. Useful for selecting configs that use a custom db config handler or finding
* config_key: Selects configs that contain a particular key in the configuration
passed +name+ will be returned.
to +nil+. If no +env_name+ is specified the config for the default env and the
* name: The db config name (i.e. primary, animals, etc.). Defaults
configs for all environments.
* env_name: The environment name. Defaults to +nil+ which will collect

==== Options

returned that corresponds with the environment and type requested.
returned, otherwise an array of +DatabaseConfig+ objects will be
If a name is provided a single +DatabaseConfig+ object will be

name passed in. To include replica configurations pass include_hidden: true.
Collects the configs for the environment and optionally the specification
def configs_for(env_name: nil, name: nil, config_key: nil, include_hidden: false)
  env_name ||= default_env if name
  configs = env_with_configs(env_name)
  unless include_hidden
    configs = configs.select do |db_config|
      db_config.database_tasks?
    end
  end
  if config_key
    configs = configs.select do |db_config|
      db_config.configuration_hash.key?(config_key)
    end
  end
  if name
    configs.find do |db_config|
      db_config.name == name
    end
  else
    configs
  end
end

def default_env

def default_env
  ActiveRecord::ConnectionHandling::DEFAULT_ENV.call.to_s
end

def empty?

Checks if the application's configurations are empty.
def empty?
  configurations.empty?
end

def env_with_configs(env = nil)

def env_with_configs(env = nil)
  if env
    configurations.select { |db_config| db_config.env_name == env }
  else
    configurations
  end
end

def environment_url_config(env, name, config)

def environment_url_config(env, name, config)
  url = environment_value_for(name)
  return unless url
  UrlConfig.new(env, name, url, config)
end

def environment_value_for(name)

def environment_value_for(name)
  name_env_key = "#{name.upcase}_DATABASE_URL"
  url = ENV[name_env_key]
  url ||= ENV["DATABASE_URL"] if name == "primary"
  url
end

def find_db_config(env)

the first +DatabaseConfig+ for the environment.
If the application has multiple databases +find_db_config+ will return

Returns a single +DatabaseConfig+ object based on the requested environment.
def find_db_config(env)
  env = env.to_s
  configurations.find do |db_config|
    db_config.for_current_env? && (db_config.env_name == env || db_config.name == env)
  end || configurations.find do |db_config|
    db_config.env_name == env
  end
end

def initialize(configurations = {})

def initialize(configurations = {})
  @configurations = build_configs(configurations)
end

def merge_db_environment_variables(current_env, configs)

def merge_db_environment_variables(current_env, configs)
  configs.map do |config|
    next config if config.is_a?(UrlConfig) || config.env_name != current_env
    url_config = environment_url_config(current_env, config.name, config.configuration_hash)
    url_config || config
  end
end

def primary?(name) # :nodoc:

:nodoc:
file will be named `schema.rb` instead of `primary_schema.rb`.
example, when Rails dumps the schema, the primary configuration's schema
when the application needs to treat one configuration differently. For
as primary. This is used as the "default" configuration and is used
no primary, the first configuration for an environment will be treated
A primary configuration is one that is named primary or if there is
def primary?(name) # :nodoc:
  return true if name == "primary"
  first_config = find_db_config(default_env)
  first_config && name == first_config.name
end

def resolve(config) # :nodoc:

:nodoc:
# => DatabaseConfigurations::UrlConfig.new(config: {"adapter" => "postgresql", "host" => "localhost", "database" => "foo"})
DatabaseConfigurations.new({}).resolve("postgresql://localhost/foo")

Connection URL.

# => DatabaseConfigurations::HashConfig.new(config: {"adapter" => "sqlite3"})
DatabaseConfigurations.new({}).resolve("adapter" => "sqlite3")

One layer deep hash of connection values.

# => DatabaseConfigurations::HashConfig.new(env_name: "production", config: {})
DatabaseConfigurations.new("production" => {}).resolve(:production)

Symbol representing current environment.

== Examples

Always returns a DatabaseConfiguration::DatabaseConfig
Returns fully resolved connection, accepts hash, string or symbol.
def resolve(config) # :nodoc:
  return config if DatabaseConfigurations::DatabaseConfig === config
  case config
  when Symbol
    resolve_symbol_connection(config)
  when Hash, String
    build_db_config_from_raw_config(default_env, "primary", config)
  else
    raise TypeError, "Invalid type for configuration. Expected Symbol, String, or Hash. Got #{config.inspect}"
  end
end

def resolve_symbol_connection(name)

def resolve_symbol_connection(name)
  if db_config = find_db_config(name)
    db_config
  else
    raise AdapterNotSpecified, <<~MSG
      The `#{name}` database is not configured for the `#{default_env}` environment.
        Available database configurations are:
        #{build_configuration_sentence}
    MSG
  end
end

def walk_configs(env_name, config)

def walk_configs(env_name, config)
  config.map do |name, sub_config|
    build_db_config_from_raw_config(env_name, name.to_s, sub_config)
  end
end