├── .gitignore ├── .rspec ├── .travis.yml ├── CHANGELOG ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── database_url.gemspec ├── lib ├── database_url.rb └── database_url │ └── version.rb └── spec ├── database_url_spec.rb └── spec_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | InstalledFiles 8 | _yardoc 9 | coverage 10 | doc/ 11 | lib/bundler/man 12 | pkg 13 | rdoc 14 | spec/reports 15 | test/tmp 16 | test/version_tmp 17 | tmp 18 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --format documentation 2 | --color 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 1.9.3 4 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | 0.1.2 / 2017-06-12 2 | 3 | * Enhancements 4 | 5 | * Remove deprec warning on mysql2 - thanks @Paxa ! https://github.com/seamusabshere/database_url/pull/3 6 | 7 | 0.1.1 / 2014-10-28 8 | 9 | * Bug fixes 10 | 11 | * Don't die if no URL query - fixes #1 thanks @fmasuhr ! 12 | 13 | 0.1.0 / 2014-07-12 14 | 15 | * Breaking changes 16 | 17 | * replaced .active_record_config(url = nil) with .to_active_record_hash(url = nil) 18 | * replaced .database_url(hash) with .to_active_record_url(hash) 19 | 20 | * Enhancements 21 | 22 | * .to_sequel_hash(url = nil) 23 | * .to_sequel_url(hash) 24 | 25 | 0.0.1 / 2013-09-19 26 | 27 | Initial release! 28 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in database_url.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Seamus Abshere 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DatabaseUrl 2 | 3 | Convert back and forth between Heroku-style `ENV['DATABASE_URL']` and Rails/ActiveRecord-style `config/database.yml` config hashes. 4 | 5 | ## Usage 6 | 7 | ### Methods 8 | 9 | DatabaseUrl.to_active_record_hash(url = nil) 10 | DatabaseUrl.to_active_record_url(hash) 11 | DatabaseUrl.to_sequel_hash(url = nil) 12 | DatabaseUrl.to_sequel_url(hash) 13 | 14 | ### Get `DATABASE_URL` from config hash 15 | 16 | You pass it a hash (string or symbol keys, doesn't matter) and it gives you a URL: 17 | 18 | >> c = YAML.load_file('/path/to/config/database.yml') 19 | => {"development"=>{"adapter"=>"mysql2", "database"=>"myapp_development", "username"=>"root", "password"=>"password", "encoding"=>"utf8"}, "test"=>{"adapter"=>"mysql2", "database"=>"myapp_test", "username"=>"root", "password"=>"password", "encoding"=>"utf8"}, "production"=>{"adapter"=>"mysql2", "database"=>"myapp", "username"=>"myapp", "password"=>"XXX", "encoding"=>"utf8"}, "cucumber"=>{"adapter"=>"mysql2", "database"=>"myapp_cucumber", "username"=>"root", "password"=>"password", "encoding"=>"utf8"}} 20 | >> DatabaseUrl.to_active_record_url c['development'] 21 | => "mysql2://root:password@127.0.0.1/myapp_development?encoding=utf8" 22 | 23 | ### Get config hash from `DATABASE_URL` 24 | 25 | >> DatabaseUrl.to_active_record_hash('postgres://uuu:xxx@127.0.0.1:1234/abc') 26 | => {:adapter=>"postgres", :host=>"127.0.0.1", :port=>1234, :database=>"abc", :user=>"uuu", :password=>"xxx"} 27 | 28 | If you omit the argument, it will try `ENV['DATABASE_URL']` 29 | 30 | ## Query parameters supported 31 | 32 | * `encoding` 33 | * `pool` 34 | 35 | ## TODO 36 | 37 | * all query params 38 | * automatically pull from config/database.yml 39 | * automatically pull from ActiveRecord::Base.connection_config 40 | 41 | ## Copyright 42 | 43 | Copyright 2014 Seamus Abshere 44 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rspec/core/rake_task" 3 | 4 | RSpec::Core::RakeTask.new(:spec) 5 | 6 | task :default => :spec 7 | -------------------------------------------------------------------------------- /database_url.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'database_url/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "database_url" 8 | spec.version = DatabaseUrl::VERSION 9 | spec.authors = ["Seamus Abshere"] 10 | spec.email = ["seamus@abshere.net"] 11 | spec.description = %q{Convert back and forth between Heroku-style ENV['DATABASE_URL'] and Sequel/ActiveRecord-style config hashes.} 12 | spec.summary = %q{Convert back and forth between Heroku-style ENV['DATABASE_URL'] and Sequel/ActiveRecord-style config hashes.} 13 | spec.homepage = "https://github.com/seamusabshere/database_url" 14 | spec.license = "MIT" 15 | 16 | spec.files = `git ls-files`.split($/) 17 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 18 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 19 | spec.require_paths = ["lib"] 20 | 21 | spec.add_development_dependency "bundler", "~> 1.3" 22 | spec.add_development_dependency "rake" 23 | spec.add_development_dependency "rspec" 24 | spec.add_development_dependency "pry" 25 | end 26 | -------------------------------------------------------------------------------- /lib/database_url.rb: -------------------------------------------------------------------------------- 1 | require "database_url/version" 2 | 3 | require 'uri' 4 | require 'cgi' 5 | 6 | module DatabaseUrl 7 | class << self 8 | def to_active_record_hash(url = nil) 9 | result_hash = to_hash ACTIVE_RECORD_FIELD_MAP, url 10 | 11 | if result_hash[:adapter] == 'mysql2' 12 | result_hash[:username] = result_hash.delete(:user) 13 | end 14 | 15 | result_hash 16 | end 17 | 18 | def to_active_record_url(hash) 19 | to_url ACTIVE_RECORD_FIELD_MAP, hash 20 | end 21 | 22 | def to_sequel_hash(url = nil) 23 | to_hash SEQUEL_FIELD_MAP, url 24 | end 25 | 26 | def to_sequel_url(hash) 27 | to_url SEQUEL_FIELD_MAP, hash 28 | end 29 | 30 | private 31 | 32 | def to_hash(field_map, url = nil) 33 | if url.nil? 34 | url = ENV.fetch 'DATABASE_URL' 35 | end 36 | uri = URI.parse url 37 | memo = { 38 | adapter: uri.scheme, 39 | host: uri.host, 40 | database: File.basename(uri.path), 41 | } 42 | if uri.port 43 | memo[:port] = uri.port 44 | end 45 | if uri.user 46 | memo[:user] = uri.user 47 | end 48 | if uri.password 49 | memo[:password] = uri.password 50 | end 51 | query = CGI.parse uri.query.to_s 52 | if query.has_key?('encoding') 53 | memo[:encoding] = query['encoding'][0] 54 | end 55 | if (pool = query['pool'] || query['max_connections']) and pool.length > 0 # CGI.parse creates a Hash that defaults to [] 56 | memo[field_map.fetch('pool').to_sym] = pool[0].to_i 57 | end 58 | memo 59 | end 60 | 61 | def to_url(field_map, hash) 62 | # stringify keys 63 | c = hash.inject({}) { |memo, (k, v)| memo[k.to_s] = v; memo } 64 | userinfo = if c.has_key?('user') or c.has_key?('username') or c.has_key?('password') 65 | username = c.values_at('user', 'username').compact.first 66 | [ username, c['password'] ].join ':' 67 | end 68 | query = {} 69 | if c.has_key?('encoding') 70 | query['encoding'] = c['encoding'] 71 | end 72 | if pool = c['pool'] || c['max_connections'] 73 | query[field_map.fetch('pool')] = pool.to_i 74 | end 75 | query = if query.length > 0 76 | URI.encode_www_form query 77 | end 78 | 79 | # URI.new(scheme, userinfo, host, port, registry, path, opaque, query, fragment, parser = DEFAULT_PARSER, arg_check = false) 80 | uri = URI::Generic.new( 81 | c.fetch('adapter'), 82 | userinfo, 83 | c.fetch('host', DEFAULT_HOST), 84 | c['port'], 85 | nil, # registry 86 | "/#{c.fetch('database')}", # path 87 | nil, # opaque 88 | query, # query 89 | nil, # fragment 90 | ) 91 | uri.to_s 92 | end 93 | end 94 | 95 | DEFAULT_HOST = '127.0.0.1' 96 | 97 | SEQUEL_FIELD_MAP = { 98 | 'pool' => 'max_connections', 99 | } 100 | ACTIVE_RECORD_FIELD_MAP = { 101 | 'pool' => 'pool', 102 | } 103 | end 104 | -------------------------------------------------------------------------------- /lib/database_url/version.rb: -------------------------------------------------------------------------------- 1 | module DatabaseUrl 2 | VERSION = '0.1.2' 3 | end 4 | -------------------------------------------------------------------------------- /spec/database_url_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe DatabaseUrl do 4 | before do 5 | ENV.delete 'DATABASE_URL' 6 | end 7 | 8 | describe 'ActiveRecord' do 9 | it "builds config hashes using ENV['DATABASE_URL']" do 10 | ENV['DATABASE_URL'] = "postgres://uuu:xxx@127.0.0.1:1234/abc?encoding=latin1&pool=9" 11 | DatabaseUrl.to_active_record_hash.should == { 12 | adapter: 'postgres', 13 | host: '127.0.0.1', 14 | port: 1234, 15 | database: 'abc', 16 | user: 'uuu', 17 | password: 'xxx', 18 | encoding: 'latin1', 19 | pool: 9, 20 | } 21 | end 22 | 23 | it "builds URL from config hash" do 24 | DatabaseUrl.to_active_record_url({ 25 | adapter: 'postgreq', 26 | host: '127.0.0.2', 27 | port: 1235, 28 | database: 'abd', 29 | user: 'uu1', 30 | password: 'xx1', 31 | encoding: 'utf8', 32 | pool: 15, 33 | }).should == "postgreq://uu1:xx1@127.0.0.2:1235/abd?encoding=utf8&pool=15" 34 | end 35 | 36 | it "builds config hashes given a URL" do 37 | ENV['DATABASE_URL'] = "postgres://uuu:xxx@127.0.0.1:1234/abc" # should be ignored! 38 | DatabaseUrl.to_active_record_hash("postgres://uu2:xxx@127.0.0.3:1236/abc?encoding=latin1").should == { 39 | adapter: 'postgres', 40 | host: '127.0.0.3', 41 | port: 1236, 42 | database: 'abc', 43 | user: 'uu2', 44 | password: 'xxx', 45 | encoding: 'latin1', 46 | } 47 | end 48 | 49 | it "builds config hashes for mysql2 without warnings" do 50 | ENV['DATABASE_URL'] = "mysql2://user:xxx@127.0.0.1/dbname?encoding=utf8" # should be ignored! 51 | DatabaseUrl.to_active_record_hash(ENV['DATABASE_URL']).should == { 52 | adapter: 'mysql2', 53 | host: '127.0.0.1', 54 | database: 'dbname', 55 | username: 'user', 56 | password: 'xxx', 57 | encoding: 'utf8', 58 | } 59 | end 60 | end 61 | 62 | describe 'Sequel' do 63 | it "builds config hashes using ENV['DATABASE_URL']" do 64 | ENV['DATABASE_URL'] = "postgres://uuu:xxx@127.0.0.1:1234/abc?encoding=latin1&pool=9" 65 | DatabaseUrl.to_sequel_hash.should == { 66 | adapter: 'postgres', 67 | host: '127.0.0.1', 68 | port: 1234, 69 | database: 'abc', 70 | user: 'uuu', 71 | password: 'xxx', 72 | encoding: 'latin1', 73 | max_connections: 9, 74 | } 75 | end 76 | 77 | it "builds URL from config hash" do 78 | DatabaseUrl.to_sequel_url({ 79 | adapter: 'postgreq', 80 | host: '127.0.0.2', 81 | port: 1235, 82 | database: 'abd', 83 | user: 'uu1', 84 | password: 'xx1', 85 | encoding: 'utf8', 86 | pool: 15, 87 | }).should == "postgreq://uu1:xx1@127.0.0.2:1235/abd?encoding=utf8&max_connections=15" 88 | end 89 | 90 | it "builds config hashes given a URL" do 91 | ENV['DATABASE_URL'] = "postgres://uuu:xxx@127.0.0.1:1234/abc" # should be ignored! 92 | DatabaseUrl.to_sequel_hash("postgres://uu2:xxx@127.0.0.3:1236/abc?encoding=latin1").should == { 93 | adapter: 'postgres', 94 | host: '127.0.0.3', 95 | port: 1236, 96 | database: 'abc', 97 | user: 'uu2', 98 | password: 'xxx', 99 | encoding: 'latin1', 100 | } 101 | end 102 | end 103 | end 104 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'pry' 2 | 3 | $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) 4 | require 'database_url' 5 | --------------------------------------------------------------------------------