forked from rails/rails
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
db:create for MySQL now much cleaner.
- Loading branch information
Showing
6 changed files
with
230 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,19 @@ | ||
class ActiveRecord::Tasks::DatabaseTasks | ||
def self.create(configuration) | ||
if File.exist?(configuration['database']) | ||
$stderr.puts "#{configuration['database']} already exists" | ||
return | ||
end | ||
TASKS_PATTERNS = { | ||
/mysql/ => ActiveRecord::Tasks::MySQLDatabaseTasks, | ||
# /postgresql/ => ActiveRecord::Tasks::PostgreSQLTasker, | ||
/sqlite/ => ActiveRecord::Tasks::SQLiteDatabaseTasks | ||
} | ||
|
||
ActiveRecord::Base.establish_connection(configuration) | ||
ActiveRecord::Base.connection | ||
def self.create(configuration) | ||
class_for_adapter(configuration['adapter']).new(configuration).create | ||
rescue Exception => e | ||
$stderr.puts e, *(e.backtrace) | ||
$stderr.puts "Couldn't create database for #{configuration.inspect}" | ||
end | ||
|
||
def self.class_for_adapter(adapter) | ||
key = TASKS_PATTERNS.keys.detect { |key| adapter[key] } | ||
TASKS_PATTERNS[key] | ||
end | ||
end |
76 changes: 76 additions & 0 deletions
76
activerecord/lib/active_record/tasks/mysql_database_tasks.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
class ActiveRecord::Tasks::MySQLDatabaseTasks | ||
DEFAULT_CHARSET = ENV['CHARSET'] || 'utf8' | ||
DEFAULT_COLLATION = ENV['COLLATION'] || 'utf8_unicode_ci' | ||
ACCESS_DENIED_ERROR = 1045 | ||
|
||
delegate :connection, :establish_connection, :to => ActiveRecord::Base | ||
|
||
def initialize(configuration) | ||
@configuration = configuration | ||
end | ||
|
||
def create | ||
establish_connection configuration_without_database | ||
connection.create_database configuration['database'], creation_options | ||
establish_connection configuration | ||
rescue error_class => error | ||
raise error unless error.errno == ACCESS_DENIED_ERROR | ||
|
||
$stdout.print error.error | ||
establish_connection root_configuration_without_database | ||
connection.create_database configuration['database'], creation_options | ||
connection.execute grant_statement.gsub(/\s+/, ' ').strip | ||
establish_connection configuration | ||
rescue error_class => error | ||
$stderr.puts error.error | ||
$stderr.puts "Couldn't create database for #{configuration.inspect}, #{creation_options.inspect}" | ||
$stderr.puts "(If you set the charset manually, make sure you have a matching collation)" if configuration['charset'] | ||
end | ||
|
||
private | ||
|
||
attr_reader :configuration | ||
|
||
def configuration_without_database | ||
configuration.merge('database' => nil) | ||
end | ||
|
||
def creation_options | ||
{ | ||
:charset => (configuration['charset'] || DEFAULT_CHARSET), | ||
:collation => (configuration['collation'] || DEFAULT_COLLATION) | ||
} | ||
end | ||
|
||
def error_class | ||
case configuration['adapter'] | ||
when /jdbc/ | ||
require 'active_record/railties/jdbcmysql_error' | ||
error_class = ArJdbcMySQL::Error | ||
when /mysql2/ | ||
Mysql2::Error | ||
else | ||
Mysql::Error | ||
end | ||
end | ||
|
||
def grant_statement | ||
<<-SQL | ||
GRANT ALL PRIVILEGES ON #{configuration['database']}.* | ||
TO '#{configuration['username']}'@'localhost' | ||
IDENTIFIED BY '#{configuration['password']}' WITH GRANT OPTION; | ||
SQL | ||
end | ||
|
||
def root_configuration_without_database | ||
configuration_without_database.merge( | ||
'username' => 'root', | ||
'password' => root_password | ||
) | ||
end | ||
|
||
def root_password | ||
$stdout.print "Please provide the root password for your mysql installation\n>" | ||
$stdin.gets.strip | ||
end | ||
end |
19 changes: 19 additions & 0 deletions
19
activerecord/lib/active_record/tasks/sqlite_database_tasks.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
class ActiveRecord::Tasks::SQLiteDatabaseTasks | ||
def initialize(configuration) | ||
@configuration = configuration | ||
end | ||
|
||
def create | ||
if File.exist?(configuration['database']) | ||
$stderr.puts "#{configuration['database']} already exists" | ||
return | ||
end | ||
|
||
ActiveRecord::Base.establish_connection(configuration) | ||
ActiveRecord::Base.connection | ||
end | ||
|
||
private | ||
|
||
attr_reader :configuration | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
require 'cases/helper' | ||
|
||
module ActiveRecord | ||
class MysqlDBCreateTest < ActiveRecord::TestCase | ||
def setup | ||
@connection = stub(:create_database => true) | ||
@configuration = { | ||
'adapter' => 'mysql', | ||
'database' => 'my-app-db' | ||
} | ||
|
||
ActiveRecord::Base.stubs(:connection).returns(@connection) | ||
ActiveRecord::Base.stubs(:establish_connection).returns(true) | ||
end | ||
|
||
def test_establishes_connection_without_database | ||
ActiveRecord::Base.expects(:establish_connection). | ||
with('adapter' => 'mysql', 'database' => nil) | ||
|
||
ActiveRecord::Tasks::DatabaseTasks.create @configuration | ||
end | ||
|
||
def test_creates_database_with_default_options | ||
@connection.expects(:create_database). | ||
with('my-app-db', {:charset => 'utf8', :collation => 'utf8_unicode_ci'}) | ||
|
||
ActiveRecord::Tasks::DatabaseTasks.create @configuration | ||
end | ||
|
||
def test_creates_database_with_given_options | ||
@connection.expects(:create_database). | ||
with('my-app-db', {:charset => 'latin', :collation => 'latin_ci'}) | ||
|
||
ActiveRecord::Tasks::DatabaseTasks.create @configuration.merge( | ||
'charset' => 'latin', 'collation' => 'latin_ci' | ||
) | ||
end | ||
|
||
def test_establishes_connection_to_database | ||
ActiveRecord::Base.expects(:establish_connection).with(@configuration) | ||
|
||
ActiveRecord::Tasks::DatabaseTasks.create @configuration | ||
end | ||
end | ||
|
||
class MysqlDBCreateAsRootTest < ActiveRecord::TestCase | ||
def setup | ||
require 'mysql' | ||
|
||
@connection = stub(:create_database => true, :execute => true) | ||
@error = Mysql::Error.new "Invalid permissions" | ||
@configuration = { | ||
'adapter' => 'mysql', | ||
'database' => 'my-app-db', | ||
'username' => 'pat', | ||
'password' => 'wossname' | ||
} | ||
|
||
$stdin.stubs(:gets).returns("secret\n") | ||
$stdout.stubs(:print).returns(nil) | ||
@error.stubs(:errno).returns(1045) | ||
ActiveRecord::Base.stubs(:connection).returns(@connection) | ||
ActiveRecord::Base.stubs(:establish_connection).raises(@error).then. | ||
returns(true) | ||
end | ||
|
||
def test_root_password_is_requested | ||
$stdin.expects(:gets).returns("secret\n") | ||
|
||
ActiveRecord::Tasks::DatabaseTasks.create @configuration | ||
end | ||
|
||
def test_connection_established_as_root | ||
ActiveRecord::Base.expects(:establish_connection).with({ | ||
'adapter' => 'mysql', | ||
'database' => nil, | ||
'username' => 'root', | ||
'password' => 'secret' | ||
}) | ||
|
||
ActiveRecord::Tasks::DatabaseTasks.create @configuration | ||
end | ||
|
||
def test_database_created_by_root | ||
@connection.expects(:create_database). | ||
with('my-app-db', :charset => 'utf8', :collation => 'utf8_unicode_ci') | ||
|
||
ActiveRecord::Tasks::DatabaseTasks.create @configuration | ||
end | ||
|
||
def test_grant_privileges_for_normal_user | ||
@connection.expects(:execute).with("GRANT ALL PRIVILEGES ON my-app-db.* TO 'pat'@'localhost' IDENTIFIED BY 'wossname' WITH GRANT OPTION;") | ||
|
||
ActiveRecord::Tasks::DatabaseTasks.create @configuration | ||
end | ||
|
||
def test_connection_established_as_normal_user | ||
ActiveRecord::Base.expects(:establish_connection).returns do | ||
ActiveRecord::Base.expects(:establish_connection).with({ | ||
'adapter' => 'mysql', | ||
'database' => 'my-app-db', | ||
'username' => 'pat', | ||
'password' => 'secret' | ||
}) | ||
|
||
raise @error | ||
end | ||
|
||
ActiveRecord::Tasks::DatabaseTasks.create @configuration | ||
end | ||
|
||
def test_sends_output_to_stderr_when_other_errors | ||
@error.stubs(:errno).returns(42) | ||
|
||
$stderr.expects(:puts).at_least_once.returns(nil) | ||
|
||
ActiveRecord::Tasks::DatabaseTasks.create @configuration | ||
end | ||
end | ||
end |