1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Only build a ConnectionSpecification if required

This commit is contained in:
José Valim 2013-12-24 10:02:07 +01:00
parent d8336cab32
commit d2ed433b0a
6 changed files with 60 additions and 60 deletions

View file

@ -36,9 +36,9 @@ group :test do
gem 'ruby-prof', '~> 0.11.2' gem 'ruby-prof', '~> 0.11.2'
end end
platforms :mri_19, :mri_20 do # platforms :mri_19, :mri_20 do
gem 'debugger' # gem 'debugger'
end # end
gem 'benchmark-ips' gem 'benchmark-ips'
end end

View file

@ -32,6 +32,24 @@ module ActiveRecord
end end
end end
def spec(config)
spec = resolve(config).symbolize_keys
raise(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"
ConnectionSpecification.new(spec, adapter_method)
end
private private
def resolve_connection(spec) #:nodoc: def resolve_connection(spec) #:nodoc:
@ -52,30 +70,15 @@ module ActiveRecord
resolve_string_connection(spec) if spec.is_a?(String) resolve_string_connection(spec) if spec.is_a?(String)
end end
raise(AdapterNotSpecified, "#{spec} database is not configured") unless config raise(AdapterNotSpecified, "#{spec} database is not configured") unless config
resolve_connection config resolve_connection(config)
end end
def resolve_hash_connection(spec) # :nodoc: def resolve_hash_connection(spec) # :nodoc:
spec = spec.symbolize_keys spec
raise(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"
ConnectionSpecification.new(spec, adapter_method)
end end
def resolve_string_connection(spec) # :nodoc: def resolve_string_connection(spec) # :nodoc:
config = URI.parse spec config = URI.parse spec
adapter = config.scheme adapter = config.scheme
adapter = "postgresql" if adapter == "postgres" adapter = "postgresql" if adapter == "postgres"
@ -89,12 +92,12 @@ module ActiveRecord
config.path.sub(%r{^/},"") config.path.sub(%r{^/},"")
end end
spec = { :adapter => adapter, spec = { "adapter" => adapter,
:username => config.user, "username" => config.user,
:password => config.password, "password" => config.password,
:port => config.port, "port" => config.port,
:database => database, "database" => database,
:host => config.host } "host" => config.host }
spec.reject!{ |_,value| value.blank? } spec.reject!{ |_,value| value.blank? }
@ -103,8 +106,7 @@ module ActiveRecord
spec.map { |key,value| spec[key] = uri_parser.unescape(value) if value.is_a?(String) } spec.map { |key,value| spec[key] = uri_parser.unescape(value) if value.is_a?(String) }
if config.query if config.query
options = Hash[config.query.split("&").map{ |pair| pair.split("=") }].symbolize_keys options = Hash[config.query.split("&").map{ |pair| pair.split("=") }]
spec.merge!(options) spec.merge!(options)
end end

View file

@ -36,7 +36,7 @@ module ActiveRecord
# may be returned on an error. # may be returned on an error.
def establish_connection(spec = ENV["DATABASE_URL"]) def establish_connection(spec = ENV["DATABASE_URL"])
resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new configurations resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new configurations
spec = resolver.resolve(spec) spec = resolver.spec(spec)
unless respond_to?(spec.adapter_method) unless respond_to?(spec.adapter_method)
raise AdapterNotFound, "database configuration specifies nonexistent #{spec.config[:adapter]} adapter" raise AdapterNotFound, "database configuration specifies nonexistent #{spec.config[:adapter]} adapter"

View file

@ -56,7 +56,7 @@ module ActiveRecord
resolver = ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.new(configuration) resolver = ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.new(configuration)
configuration.each do |key, value| configuration.each do |key, value|
configuration[key] = resolver.resolve(value).config.stringify_keys if value configuration[key] = resolver.resolve(value) if value
end end
ActiveRecord::Tasks::DatabaseTasks.database_configuration = configuration ActiveRecord::Tasks::DatabaseTasks.database_configuration = configuration

View file

@ -5,13 +5,19 @@ module ActiveRecord
class ConnectionSpecification class ConnectionSpecification
class ResolverTest < ActiveRecord::TestCase class ResolverTest < ActiveRecord::TestCase
def resolve(spec, config={}) def resolve(spec, config={})
Resolver.new(config).resolve(spec).config Resolver.new(config).resolve(spec)
end
def spec(spec, config={})
Resolver.new(config).spec(spec)
end end
def test_url_invalid_adapter def test_url_invalid_adapter
assert_raises(LoadError) do error = assert_raises(LoadError) do
resolve 'ridiculous://foo?encoding=utf8' spec 'ridiculous://foo?encoding=utf8'
end end
assert_match "Could not load 'active_record/connection_adapters/ridiculous_adapter'", error.message
end end
# The abstract adapter is used simply to bypass the bit of code that # The abstract adapter is used simply to bypass the bit of code that
@ -20,60 +26,52 @@ module ActiveRecord
def test_url_from_environment def test_url_from_environment
spec = resolve :production, 'production' => 'abstract://foo?encoding=utf8' spec = resolve :production, 'production' => 'abstract://foo?encoding=utf8'
assert_equal({ assert_equal({
adapter: "abstract", "adapter" => "abstract",
host: "foo", "host" => "foo",
encoding: "utf8" }, spec) "encoding" => "utf8" }, spec)
end end
def test_url_host_no_db def test_url_host_no_db
spec = resolve 'abstract://foo?encoding=utf8' spec = resolve 'abstract://foo?encoding=utf8'
assert_equal({ assert_equal({
adapter: "abstract", "adapter" => "abstract",
host: "foo", "host" => "foo",
encoding: "utf8" }, spec) "encoding" => "utf8" }, spec)
end end
def test_url_host_db def test_url_host_db
spec = resolve 'abstract://foo/bar?encoding=utf8' spec = resolve 'abstract://foo/bar?encoding=utf8'
assert_equal({ assert_equal({
adapter: "abstract", "adapter" => "abstract",
database: "bar", "database" => "bar",
host: "foo", "host" => "foo",
encoding: "utf8" }, spec) "encoding" => "utf8" }, spec)
end end
def test_url_port def test_url_port
spec = resolve 'abstract://foo:123?encoding=utf8' spec = resolve 'abstract://foo:123?encoding=utf8'
assert_equal({ assert_equal({
adapter: "abstract", "adapter" => "abstract",
port: 123, "port" => 123,
host: "foo", "host" => "foo",
encoding: "utf8" }, spec) "encoding" => "utf8" }, spec)
end end
def test_encoded_password def test_encoded_password
password = 'am@z1ng_p@ssw0rd#!' password = 'am@z1ng_p@ssw0rd#!'
encoded_password = URI.encode_www_form_component(password) encoded_password = URI.encode_www_form_component(password)
spec = resolve "abstract://foo:#{encoded_password}@localhost/bar" spec = resolve "abstract://foo:#{encoded_password}@localhost/bar"
assert_equal password, spec[:password] assert_equal password, spec["password"]
end
def test_descriptive_error_message_when_adapter_is_missing
error = assert_raise(LoadError) do
resolve(adapter: 'non-existing')
end
assert_match "Could not load 'active_record/connection_adapters/non-existing_adapter'", error.message
end end
def test_url_host_db_for_sqlite3 def test_url_host_db_for_sqlite3
spec = resolve 'sqlite3://foo:bar@dburl:9000/foo_test' spec = resolve 'sqlite3://foo:bar@dburl:9000/foo_test'
assert_equal('/foo_test', spec[:database]) assert_equal('/foo_test', spec["database"])
end end
def test_url_host_memory_db_for_sqlite3 def test_url_host_memory_db_for_sqlite3
spec = resolve 'sqlite3://foo:bar@dburl:9000/:memory:' spec = resolve 'sqlite3://foo:bar@dburl:9000/:memory:'
assert_equal(':memory:', spec[:database]) assert_equal(':memory:', spec["database"])
end end
end end
end end

View file

@ -84,7 +84,7 @@ module Rails
require APP_PATH require APP_PATH
ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.new( ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.new(
Rails.application.config.database_configuration || {} Rails.application.config.database_configuration || {}
).resolve(ENV["DATABASE_URL"]).config.stringify_keys ).resolve(ENV["DATABASE_URL"])
end end
end end