diff options
Diffstat (limited to 'activerecord')
16 files changed, 202 insertions, 81 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb b/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb index 43e2f628dc..e1b791fe41 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb @@ -19,7 +19,7 @@ module ActiveRecord execute(sql, name).to_a end - READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(:begin, :select, :set, :show, :release, :savepoint) # :nodoc: + READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(:begin, :commit, :explain, :select, :set, :show, :release, :savepoint, :rollback) # :nodoc: private_constant :READ_QUERY def write_query?(sql) # :nodoc: @@ -29,7 +29,7 @@ module ActiveRecord # Executes the SQL statement in the context of this connection. def execute(sql, name = nil) if preventing_writes? && write_query?(sql) - raise ActiveRecord::StatementInvalid, "Write query attempted while in readonly mode: #{sql}" + raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}" end # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been @@ -122,6 +122,10 @@ module ActiveRecord end def exec_stmt_and_free(sql, name, binds, cache_stmt: false) + if preventing_writes? && write_query?(sql) + raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}" + end + # make sure we carry over any changes to ActiveRecord::Base.default_timezone that have been # made since we established the connection @connection.query_options[:database_timezone] = ActiveRecord::Base.default_timezone diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb index 2d5b592639..c70a4fa875 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb @@ -67,7 +67,7 @@ module ActiveRecord end end - READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(:select, :show, :set) # :nodoc: + READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(:begin, :commit, :explain, :select, :set, :show, :release, :savepoint, :rollback) # :nodoc: private_constant :READ_QUERY def write_query?(sql) # :nodoc: @@ -80,7 +80,7 @@ module ActiveRecord # need it specifically, you may want consider the <tt>exec_query</tt> wrapper. def execute(sql, name = nil) if preventing_writes? && write_query?(sql) - raise ActiveRecord::StatementInvalid, "Write query attempted while in readonly mode: #{sql}" + raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}" end materialize_transactions diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 1c4e625ead..381d5ab29b 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -609,6 +609,10 @@ module ActiveRecord FEATURE_NOT_SUPPORTED = "0A000" #:nodoc: def execute_and_clear(sql, name, binds, prepare: false) + if preventing_writes? && write_query?(sql) + raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}" + end + if without_prepared_statement?(binds) result = exec_no_cache(sql, name, []) elsif !prepare diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index 615aa0d83e..44c6e99112 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -209,7 +209,7 @@ module ActiveRecord # DATABASE STATEMENTS ====================================== #++ - READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(:select) # :nodoc: + READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(:begin, :commit, :explain, :select, :pragma, :release, :savepoint, :rollback) # :nodoc: private_constant :READ_QUERY def write_query?(sql) # :nodoc: @@ -222,6 +222,10 @@ module ActiveRecord end def exec_query(sql, name = nil, binds = [], prepare: false) + if preventing_writes? && write_query?(sql) + raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}" + end + materialize_transactions type_casted_binds = type_casted_binds(binds) @@ -265,7 +269,7 @@ module ActiveRecord def execute(sql, name = nil) #:nodoc: if preventing_writes? && write_query?(sql) - raise ActiveRecord::StatementInvalid, "Write query attempted while in readonly mode: #{sql}" + raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}" end materialize_transactions diff --git a/activerecord/lib/active_record/errors.rb b/activerecord/lib/active_record/errors.rb index 7e6d4c1d46..0858af3874 100644 --- a/activerecord/lib/active_record/errors.rb +++ b/activerecord/lib/active_record/errors.rb @@ -49,6 +49,10 @@ module ActiveRecord class ConnectionNotEstablished < ActiveRecordError end + # Raised when a write to the database is attempted on a read only connection. + class ReadOnlyError < ActiveRecordError + end + # Raised when Active Record cannot find a record by given id or set of ids. class RecordNotFound < ActiveRecordError attr_reader :model, :primary_key, :id diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb index 1248ed00c5..350b044a3e 100644 --- a/activerecord/lib/active_record/fixtures.rb +++ b/activerecord/lib/active_record/fixtures.rb @@ -573,49 +573,49 @@ module ActiveRecord private - def read_and_insert(fixtures_directory, fixture_files, class_names, connection) # :nodoc: - fixtures_map = {} - fixture_sets = fixture_files.map do |fixture_set_name| - klass = class_names[fixture_set_name] - fixtures_map[fixture_set_name] = new( # ActiveRecord::FixtureSet.new - nil, - fixture_set_name, - klass, - ::File.join(fixtures_directory, fixture_set_name) - ) - end - update_all_loaded_fixtures(fixtures_map) - - insert(fixture_sets, connection) + def read_and_insert(fixtures_directory, fixture_files, class_names, connection) # :nodoc: + fixtures_map = {} + fixture_sets = fixture_files.map do |fixture_set_name| + klass = class_names[fixture_set_name] + fixtures_map[fixture_set_name] = new( # ActiveRecord::FixtureSet.new + nil, + fixture_set_name, + klass, + ::File.join(fixtures_directory, fixture_set_name) + ) + end + update_all_loaded_fixtures(fixtures_map) - fixtures_map - end + insert(fixture_sets, connection) - def insert(fixture_sets, connection) # :nodoc: - fixture_sets_by_connection = fixture_sets.group_by do |fixture_set| - fixture_set.model_class&.connection || connection + fixtures_map end - fixture_sets_by_connection.each do |conn, set| - table_rows_for_connection = Hash.new { |h, k| h[k] = [] } + def insert(fixture_sets, connection) # :nodoc: + fixture_sets_by_connection = fixture_sets.group_by do |fixture_set| + fixture_set.model_class&.connection || connection + end + + fixture_sets_by_connection.each do |conn, set| + table_rows_for_connection = Hash.new { |h, k| h[k] = [] } - set.each do |fixture_set| - fixture_set.table_rows.each do |table, rows| - table_rows_for_connection[table].unshift(*rows) + set.each do |fixture_set| + fixture_set.table_rows.each do |table, rows| + table_rows_for_connection[table].unshift(*rows) + end end - end - conn.insert_fixtures_set(table_rows_for_connection, table_rows_for_connection.keys) + conn.insert_fixtures_set(table_rows_for_connection, table_rows_for_connection.keys) - # Cap primary key sequences to max(pk). - if conn.respond_to?(:reset_pk_sequence!) - set.each { |fs| conn.reset_pk_sequence!(fs.table_name) } + # Cap primary key sequences to max(pk). + if conn.respond_to?(:reset_pk_sequence!) + set.each { |fs| conn.reset_pk_sequence!(fs.table_name) } + end end end - end - def update_all_loaded_fixtures(fixtures_map) # :nodoc: - all_loaded_fixtures.update(fixtures_map) - end + def update_all_loaded_fixtures(fixtures_map) # :nodoc: + all_loaded_fixtures.update(fixtures_map) + end end attr_reader :table_name, :name, :fixtures, :model_class, :config diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index d5b6082d13..ba221a333b 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -163,7 +163,7 @@ module ActiveRecord # Attempts to create a record with the given attributes in a table that has a unique constraint # on one or several of its columns. If a row already exists with one or several of these # unique constraints, the exception such an insertion would normally raise is caught, - # and the existing record with those attributes is found using #find_by. + # and the existing record with those attributes is found using #find_by!. # # This is similar to #find_or_create_by, but avoids the problem of stale reads between the SELECT # and the INSERT, as that method needs to first query the table, then attempt to insert a row @@ -173,7 +173,7 @@ module ActiveRecord # # * The underlying table must have the relevant columns defined with unique constraints. # * A unique constraint violation may be triggered by only one, or at least less than all, - # of the given attributes. This means that the subsequent #find_by may fail to find a + # of the given attributes. This means that the subsequent #find_by! may fail to find a # matching record, which will then raise an <tt>ActiveRecord::RecordNotFound</tt> exception, # rather than a record with the given attributes. # * While we avoid the race condition between SELECT -> INSERT from #find_or_create_by, diff --git a/activerecord/lib/active_record/type.rb b/activerecord/lib/active_record/type.rb index 405936aca6..03d00006b7 100644 --- a/activerecord/lib/active_record/type.rb +++ b/activerecord/lib/active_record/type.rb @@ -48,9 +48,9 @@ module ActiveRecord private - def current_adapter_name - ActiveRecord::Base.connection.adapter_name.downcase.to_sym - end + def current_adapter_name + ActiveRecord::Base.connection.adapter_name.downcase.to_sym + end end BigInteger = ActiveModel::Type::BigInteger diff --git a/activerecord/test/cases/adapter_test.rb b/activerecord/test/cases/adapter_test.rb index e40ae3090c..79a431c7ee 100644 --- a/activerecord/test/cases/adapter_test.rb +++ b/activerecord/test/cases/adapter_test.rb @@ -165,6 +165,43 @@ module ActiveRecord end end + def test_errors_when_an_insert_query_is_called_while_preventing_writes + assert_raises(ActiveRecord::ReadOnlyError) do + @connection.while_preventing_writes do + @connection.insert("INSERT INTO subscribers(nick) VALUES ('138853948594')") + end + end + end + + def test_errors_when_an_update_query_is_called_while_preventing_writes + @connection.insert("INSERT INTO subscribers(nick) VALUES ('138853948594')") + + assert_raises(ActiveRecord::ReadOnlyError) do + @connection.while_preventing_writes do + @connection.update("UPDATE subscribers SET nick = '9989' WHERE nick = '138853948594'") + end + end + end + + def test_errors_when_a_delete_query_is_called_while_preventing_writes + @connection.insert("INSERT INTO subscribers(nick) VALUES ('138853948594')") + + assert_raises(ActiveRecord::ReadOnlyError) do + @connection.while_preventing_writes do + @connection.delete("DELETE FROM subscribers WHERE nick = '138853948594'") + end + end + end + + def test_doesnt_error_when_a_select_query_is_called_while_preventing_writes + @connection.insert("INSERT INTO subscribers(nick) VALUES ('138853948594')") + + @connection.while_preventing_writes do + result = @connection.select_all("SELECT subscribers.* FROM subscribers WHERE nick = '138853948594'") + assert_equal 1, result.length + end + end + def test_uniqueness_violations_are_translated_to_specific_exception @connection.execute "INSERT INTO subscribers(nick) VALUES('me')" error = assert_raises(ActiveRecord::RecordNotUnique) do diff --git a/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb b/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb index bddcd309cd..7bc86476b6 100644 --- a/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb +++ b/activerecord/test/cases/adapters/mysql2/mysql2_adapter_test.rb @@ -70,7 +70,7 @@ class Mysql2AdapterTest < ActiveRecord::Mysql2TestCase end def test_errors_when_an_insert_query_is_called_while_preventing_writes - assert_raises(ActiveRecord::StatementInvalid) do + assert_raises(ActiveRecord::ReadOnlyError) do @conn.while_preventing_writes do @conn.insert("INSERT INTO `engines` (`car_id`) VALUES ('138853948594')") end @@ -80,7 +80,7 @@ class Mysql2AdapterTest < ActiveRecord::Mysql2TestCase def test_errors_when_an_update_query_is_called_while_preventing_writes @conn.insert("INSERT INTO `engines` (`car_id`) VALUES ('138853948594')") - assert_raises(ActiveRecord::StatementInvalid) do + assert_raises(ActiveRecord::ReadOnlyError) do @conn.while_preventing_writes do @conn.update("UPDATE `engines` SET `engines`.`car_id` = '9989' WHERE `engines`.`car_id` = '138853948594'") end @@ -90,7 +90,7 @@ class Mysql2AdapterTest < ActiveRecord::Mysql2TestCase def test_errors_when_a_delete_query_is_called_while_preventing_writes @conn.execute("INSERT INTO `engines` (`car_id`) VALUES ('138853948594')") - assert_raises(ActiveRecord::StatementInvalid) do + assert_raises(ActiveRecord::ReadOnlyError) do @conn.while_preventing_writes do @conn.execute("DELETE FROM `engines` where `engines`.`car_id` = '138853948594'") end @@ -100,7 +100,7 @@ class Mysql2AdapterTest < ActiveRecord::Mysql2TestCase def test_errors_when_a_replace_query_is_called_while_preventing_writes @conn.execute("INSERT INTO `engines` (`car_id`) VALUES ('138853948594')") - assert_raises(ActiveRecord::StatementInvalid) do + assert_raises(ActiveRecord::ReadOnlyError) do @conn.while_preventing_writes do @conn.execute("REPLACE INTO `engines` SET `engines`.`car_id` = '249823948'") end diff --git a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb index 59ddb8457e..34b4fc344b 100644 --- a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb +++ b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb @@ -378,7 +378,7 @@ module ActiveRecord def test_errors_when_an_insert_query_is_called_while_preventing_writes with_example_table do - assert_raises(ActiveRecord::StatementInvalid) do + assert_raises(ActiveRecord::ReadOnlyError) do @connection.while_preventing_writes do @connection.execute("INSERT INTO ex (data) VALUES ('138853948594')") end @@ -390,7 +390,7 @@ module ActiveRecord with_example_table do @connection.execute("INSERT INTO ex (data) VALUES ('138853948594')") - assert_raises(ActiveRecord::StatementInvalid) do + assert_raises(ActiveRecord::ReadOnlyError) do @connection.while_preventing_writes do @connection.execute("UPDATE ex SET data = '9989' WHERE data = '138853948594'") end @@ -402,7 +402,7 @@ module ActiveRecord with_example_table do @connection.execute("INSERT INTO ex (data) VALUES ('138853948594')") - assert_raises(ActiveRecord::StatementInvalid) do + assert_raises(ActiveRecord::ReadOnlyError) do @connection.while_preventing_writes do @connection.execute("DELETE FROM ex where data = '138853948594'") end diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb index 3b7a28b757..56ceb45040 100644 --- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb @@ -575,7 +575,7 @@ module ActiveRecord def test_errors_when_an_insert_query_is_called_while_preventing_writes with_example_table "id int, data string" do - assert_raises(ActiveRecord::StatementInvalid) do + assert_raises(ActiveRecord::ReadOnlyError) do @conn.while_preventing_writes do @conn.execute("INSERT INTO ex (data) VALUES ('138853948594')") end @@ -587,7 +587,7 @@ module ActiveRecord with_example_table "id int, data string" do @conn.execute("INSERT INTO ex (data) VALUES ('138853948594')") - assert_raises(ActiveRecord::StatementInvalid) do + assert_raises(ActiveRecord::ReadOnlyError) do @conn.while_preventing_writes do @conn.execute("UPDATE ex SET data = '9989' WHERE data = '138853948594'") end @@ -599,7 +599,7 @@ module ActiveRecord with_example_table "id int, data string" do @conn.execute("INSERT INTO ex (data) VALUES ('138853948594')") - assert_raises(ActiveRecord::StatementInvalid) do + assert_raises(ActiveRecord::ReadOnlyError) do @conn.while_preventing_writes do @conn.execute("DELETE FROM ex where data = '138853948594'") end @@ -611,7 +611,7 @@ module ActiveRecord with_example_table "id int, data string" do @conn.execute("INSERT INTO ex (data) VALUES ('138853948594')") - assert_raises(ActiveRecord::StatementInvalid) do + assert_raises(ActiveRecord::ReadOnlyError) do @conn.while_preventing_writes do @conn.execute("REPLACE INTO ex (data) VALUES ('249823948')") end diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index 171983a9f5..4938b6865f 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -1490,31 +1490,37 @@ class BasicsTest < ActiveRecord::TestCase end test "creating a record raises if preventing writes" do - assert_raises ActiveRecord::StatementInvalid do + error = assert_raises ActiveRecord::ReadOnlyError do ActiveRecord::Base.connection.while_preventing_writes do Bird.create! name: "Bluejay" end end + + assert_match %r/\AWrite query attempted while in readonly mode: INSERT /, error.message end test "updating a record raises if preventing writes" do bird = Bird.create! name: "Bluejay" - assert_raises ActiveRecord::StatementInvalid do + error = assert_raises ActiveRecord::ReadOnlyError do ActiveRecord::Base.connection.while_preventing_writes do bird.update! name: "Robin" end end + + assert_match %r/\AWrite query attempted while in readonly mode: UPDATE /, error.message end test "deleting a record raises if preventing writes" do bird = Bird.create! name: "Bluejay" - assert_raises ActiveRecord::StatementInvalid do + error = assert_raises ActiveRecord::ReadOnlyError do ActiveRecord::Base.connection.while_preventing_writes do bird.destroy! end end + + assert_match %r/\AWrite query attempted while in readonly mode: DELETE /, error.message end test "selecting a record does not raise if preventing writes" do @@ -1524,4 +1530,22 @@ class BasicsTest < ActiveRecord::TestCase assert_equal bird, Bird.where(name: "Bluejay").first end end + + test "an explain query does not raise if preventing writes" do + Bird.create!(name: "Bluejay") + + ActiveRecord::Base.connection.while_preventing_writes do + assert_queries(2) { Bird.where(name: "Bluejay").explain } + end + end + + test "an empty transaction does not raise if preventing writes" do + ActiveRecord::Base.connection.while_preventing_writes do + assert_queries(2, ignore_none: true) do + Bird.transaction do + ActiveRecord::Base.connection.materialize_transactions + end + end + end + end end diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index e471ee8039..756eeca35f 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -1315,6 +1315,13 @@ class RelationTest < ActiveRecord::TestCase assert_not_equal subscriber, Subscriber.create_or_find_by(nick: "cat") end + def test_create_or_find_by_should_not_raise_due_to_validation_errors + assert_nothing_raised do + bird = Bird.create_or_find_by(color: "green") + assert_predicate bird, :invalid? + end + end + def test_create_or_find_by_with_non_unique_attributes Subscriber.create!(nick: "bob", name: "the builder") @@ -1334,6 +1341,38 @@ class RelationTest < ActiveRecord::TestCase end end + def test_create_or_find_by_with_bang + assert_nil Subscriber.find_by(nick: "bob") + + subscriber = Subscriber.create!(nick: "bob") + + assert_equal subscriber, Subscriber.create_or_find_by!(nick: "bob") + assert_not_equal subscriber, Subscriber.create_or_find_by!(nick: "cat") + end + + def test_create_or_find_by_with_bang_should_raise_due_to_validation_errors + assert_raises(ActiveRecord::RecordInvalid) { Bird.create_or_find_by!(color: "green") } + end + + def test_create_or_find_by_with_bang_with_non_unique_attributes + Subscriber.create!(nick: "bob", name: "the builder") + + assert_raises(ActiveRecord::RecordNotFound) do + Subscriber.create_or_find_by!(nick: "bob", name: "the cat") + end + end + + def test_create_or_find_by_with_bang_within_transaction + assert_nil Subscriber.find_by(nick: "bob") + + subscriber = Subscriber.create!(nick: "bob") + + Subscriber.transaction do + assert_equal subscriber, Subscriber.create_or_find_by!(nick: "bob") + assert_not_equal subscriber, Subscriber.create_or_find_by!(nick: "cat") + end + end + def test_find_or_initialize_by assert_nil Bird.find_by(name: "bob") diff --git a/activerecord/test/models/bird.rb b/activerecord/test/models/bird.rb index be08636ac6..cfefa555b3 100644 --- a/activerecord/test/models/bird.rb +++ b/activerecord/test/models/bird.rb @@ -6,6 +6,11 @@ class Bird < ActiveRecord::Base accepts_nested_attributes_for :pirate + before_save do + # force materialize_transactions + self.class.connection.materialize_transactions + end + attr_accessor :cancel_save_from_callback before_save :cancel_save_callback_method, if: :cancel_save_from_callback def cancel_save_callback_method diff --git a/activerecord/test/support/config.rb b/activerecord/test/support/config.rb index bd6d5c339b..de0d90a18f 100644 --- a/activerecord/test/support/config.rb +++ b/activerecord/test/support/config.rb @@ -13,34 +13,34 @@ module ARTest private - def config_file - Pathname.new(ENV["ARCONFIG"] || TEST_ROOT + "/config.yml") - end - - def read_config - unless config_file.exist? - FileUtils.cp TEST_ROOT + "/config.example.yml", config_file + def config_file + Pathname.new(ENV["ARCONFIG"] || TEST_ROOT + "/config.yml") end - erb = ERB.new(config_file.read) - expand_config(YAML.parse(erb.result(binding)).transform) - end + def read_config + unless config_file.exist? + FileUtils.cp TEST_ROOT + "/config.example.yml", config_file + end - def expand_config(config) - config["connections"].each do |adapter, connection| - dbs = [["arunit", "activerecord_unittest"], ["arunit2", "activerecord_unittest2"], - ["arunit_without_prepared_statements", "activerecord_unittest"]] - dbs.each do |name, dbname| - unless connection[name].is_a?(Hash) - connection[name] = { "database" => connection[name] } - end + erb = ERB.new(config_file.read) + expand_config(YAML.parse(erb.result(binding)).transform) + end - connection[name]["database"] ||= dbname - connection[name]["adapter"] ||= adapter + def expand_config(config) + config["connections"].each do |adapter, connection| + dbs = [["arunit", "activerecord_unittest"], ["arunit2", "activerecord_unittest2"], + ["arunit_without_prepared_statements", "activerecord_unittest"]] + dbs.each do |name, dbname| + unless connection[name].is_a?(Hash) + connection[name] = { "database" => connection[name] } + end + + connection[name]["database"] ||= dbname + connection[name]["adapter"] ||= adapter + end end - end - config - end + config + end end end |