require 'uri' require 'active_record' require 'active_support/core_ext/hash/keys' module Motel module ConnectionAdapters module ConnectionSpecification class Resolver attr_accessor :configurations def initialize(configurations = nil) @configurations = configurations || {} end def spec(config) spec = resolve(config).symbolize_keys raise(::ActiveRecord::AdapterNotSpecified, "database configuration does not specify adapter") unless spec.key?(:adapter) path_to_adapter = "active_record/connection_adapters/#{spec[:adapter]}_adapter" begin require path_to_adapter rescue Gem::LoadError => e raise Gem::LoadError, "Specified '#{spec[:adapter]}' for database adapter, but the gem is not loaded. Add `gem '#{e.name}'` to your Gemfile (and ensure its version is at the minimum required by ActiveRecord)." rescue LoadError => e raise LoadError, "Could not load '#{path_to_adapter}'. Make sure that the adapter in config/database.yml is valid. If you use an adapter other than 'mysql', 'mysql2', 'postgresql' or 'sqlite3' add the necessary adapter gem to the Gemfile.", e.backtrace end adapter_method = "#{spec[:adapter]}_connection" ::ActiveRecord::ConnectionAdapters::ConnectionSpecification.new(spec, adapter_method) end private def resolve(config) case config when nil raise ::ActiveRecord::AdapterNotSpecified when String, Symbol resolve_string_connection config.to_s when Hash resolve_hash_connection config end end def resolve_hash_connection(spec) if url = spec.delete("url") connection_hash = resolve_string_connection(url) spec.merge!(connection_hash) end spec end def resolve_string_connection(spec) hash = configurations.fetch(spec) do |k| connection_url_to_hash(k) end resolve_hash_connection hash end def connection_url_to_hash(url) config = URI.parse url adapter = config.scheme adapter = "postgresql" if adapter == "postgres" spec = { :adapter => adapter, :username => config.user, :password => config.password, :port => config.port, :database => config.path.sub(%r{^/},""), :host => config.host } spec.reject!{ |_,value| value.blank? } uri_parser = URI::Parser.new spec.map { |key,value| spec[key] = uri_parser.unescape(value) if value.is_a?(String) } if config.query options = Hash[config.query.split("&").map{ |pair| pair.split("=") }].symbolize_keys spec.merge!(options) end spec end end end end end