Skip to content

Commit

Permalink
Merge pull request #9041 from sodabrew/patch-1
Browse files Browse the repository at this point in the history
Convert int, float, and bools from ENV['DATABASE_URL'] query args
  • Loading branch information
rafaelfranca committed Jan 31, 2013
2 parents ee4a2bb + 4b005fb commit 45883a3
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 11 deletions.
12 changes: 12 additions & 0 deletions activerecord/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
## Rails 4.0.0 (unreleased) ##

* The DATABASE_URL environment variable now converts ints, floats, and
the strings true and false to Ruby types. For example, SQLite requires
that the timeout value is an integer, and PostgreSQL requires that the
prepared_statements option is a boolean. These now work as expected:

Example:

DATABASE_URL=sqlite3://localhost/test_db?timeout=500
DATABASE_URL=postgresql://localhost/test_db?prepared_statements=false

*Aaron Stone*

* Relation#merge now only overwrites where values on the LHS of the
merge. Consider:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ def resolve_hash_connection(spec) # :nodoc:
ConnectionSpecification.new(spec, adapter_method)
end

# For DATABASE_URL, accept a limited concept of ints and floats
SIMPLE_INT = /^\d+$/
SIMPLE_FLOAT = /^\d+\.\d+$/

def connection_url_to_hash(url) # :nodoc:
config = URI.parse url
adapter = config.scheme
Expand All @@ -77,6 +81,21 @@ def connection_url_to_hash(url) # :nodoc:
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
# If anything looks numeric, make it numeric (e.g. pool count, timeout values, etc.)
options.map do |key,value|
options[key] = case value
when SIMPLE_INT
value.to_i
when SIMPLE_FLOAT
value.to_f
when 'true'
true
when 'false'
false
else
value
end
end
spec.merge!(options)
end
spec
Expand Down
48 changes: 37 additions & 11 deletions activerecord/test/cases/connection_specification/resolver_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,40 +8,66 @@ def resolve(spec)
Resolver.new(spec, {}).spec.config
end

def test_url_invalid_adapter
assert_raises(LoadError) do
resolve 'ridiculous://foo?encoding=utf8'
end
end

# The abstract adapter is used simply to bypass the bit of code that
# checks that the adapter file can be required in.

def test_url_host_no_db
skip "only if mysql is available" unless current_adapter?(:MysqlAdapter, :Mysql2Adapter)
spec = resolve 'mysql://foo?encoding=utf8'
spec = resolve 'abstract://foo?encoding=utf8'
assert_equal({
:adapter => "mysql",
:adapter => "abstract",
:host => "foo",
:encoding => "utf8" }, spec)
end

def test_url_host_db
skip "only if mysql is available" unless current_adapter?(:MysqlAdapter, :Mysql2Adapter)
spec = resolve 'mysql://foo/bar?encoding=utf8'
spec = resolve 'abstract://foo/bar?encoding=utf8'
assert_equal({
:adapter => "mysql",
:adapter => "abstract",
:database => "bar",
:host => "foo",
:encoding => "utf8" }, spec)
end

def test_url_port
skip "only if mysql is available" unless current_adapter?(:MysqlAdapter, :Mysql2Adapter)
spec = resolve 'mysql://foo:123?encoding=utf8'
spec = resolve 'abstract://foo:123?encoding=utf8'
assert_equal({
:adapter => "mysql",
:adapter => "abstract",
:port => 123,
:host => "foo",
:encoding => "utf8" }, spec)
end

def test_url_query_numeric
spec = resolve 'abstract://foo:123?encoding=utf8&int=500&float=10.9'
assert_equal({
:adapter => "abstract",
:port => 123,
:int => 500,
:float => 10.9,
:host => "foo",
:encoding => "utf8" }, spec)
end

def test_url_query_boolean
spec = resolve 'abstract://foo:123?true=true&false=false'
assert_equal({
:adapter => "abstract",
:port => 123,
:true => true,
:false => false,
:host => "foo" }, spec)
end

def test_encoded_password
skip "only if mysql is available" unless current_adapter?(:MysqlAdapter, :Mysql2Adapter)
password = 'am@z1ng_p@ssw0rd#!'
encoded_password = URI.encode_www_form_component(password)
spec = resolve "mysql://foo:#{encoded_password}@localhost/bar"
spec = resolve "abstract://foo:#{encoded_password}@localhost/bar"
assert_equal password, spec[:password]
end
end
Expand Down

0 comments on commit 45883a3

Please sign in to comment.