db2 2.6.2 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES +17 -0
- data/README +79 -141
- data/ext/Makefile.nt32 +3 -3
- data/ext/Makefile.nt32.191 +212 -0
- data/ext/extconf.rb +75 -14
- data/ext/ibm_db.c +504 -47
- data/ext/ruby_ibm_db.h +4 -1
- data/ext/ruby_ibm_db_cli.c +108 -1
- data/ext/ruby_ibm_db_cli.h +54 -1
- data/lib/active_record/connection_adapters/ibm_db_adapter.rb +423 -124
- data/lib/active_record/connection_adapters/ibm_db_pstmt.rb +1 -1
- data/test/cases/adapter_test.rb +169 -164
- data/test/cases/associations/belongs_to_associations_test.rb +268 -43
- data/test/cases/associations/cascaded_eager_loading_test.rb +31 -33
- data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +90 -156
- data/test/cases/associations/join_model_test.rb +100 -150
- data/test/cases/attribute_methods_test.rb +259 -58
- data/test/cases/base_test.rb +785 -138
- data/test/cases/calculations_test.rb +128 -8
- data/test/cases/migration_test.rb +680 -286
- data/test/cases/persistence_test.rb +642 -0
- data/test/cases/query_cache_test.rb +257 -0
- data/test/cases/relations_test.rb +1182 -0
- data/test/cases/schema_dumper_test.rb +41 -17
- data/test/cases/transaction_callbacks_test.rb +300 -0
- data/test/cases/validations/uniqueness_validation_test.rb +38 -22
- data/test/cases/xml_serialization_test.rb +408 -0
- data/test/config.yml +154 -0
- data/test/connections/native_ibm_db/connection.rb +2 -0
- data/test/models/warehouse_thing.rb +4 -4
- data/test/schema/i5/ibm_db_specific_schema.rb +3 -1
- data/test/schema/ids/ibm_db_specific_schema.rb +3 -1
- data/test/schema/luw/ibm_db_specific_schema.rb +2 -0
- data/test/schema/schema.rb +196 -92
- data/test/schema/zOS/ibm_db_specific_schema.rb +3 -1
- metadata +73 -68
- data/.gitignore +0 -1
- data/test/cases/associations/eager_test.rb +0 -862
- data/test/cases/associations/has_many_through_associations_test.rb +0 -461
- data/test/cases/finder_test.rb +0 -1088
- data/test/cases/fixtures_test.rb +0 -684
@@ -1,5 +1,6 @@
|
|
1
1
|
require "cases/helper"
|
2
2
|
require 'models/company'
|
3
|
+
require "models/contract"
|
3
4
|
require 'models/topic'
|
4
5
|
require 'models/edge'
|
5
6
|
require 'models/club'
|
@@ -23,6 +24,18 @@ class CalculationsTest < ActiveRecord::TestCase
|
|
23
24
|
assert_equal 53.0, value
|
24
25
|
end
|
25
26
|
|
27
|
+
def test_should_return_decimal_average_of_integer_field
|
28
|
+
return if current_adapter?(:IBM_DBAdapter) #average cannot be a decimal value when applied on integer field
|
29
|
+
value = Account.average(:id)
|
30
|
+
assert_equal 3.5, value
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_should_return_integer_average_if_db_returns_such
|
34
|
+
Account.connection.stubs :select_value => 3
|
35
|
+
value = Account.average(:id)
|
36
|
+
assert_equal 3, value
|
37
|
+
end
|
38
|
+
|
26
39
|
def test_should_return_nil_as_average
|
27
40
|
assert_nil NumericData.average(:bank_balance)
|
28
41
|
end
|
@@ -55,6 +68,19 @@ class CalculationsTest < ActiveRecord::TestCase
|
|
55
68
|
[1,6,2].each { |firm_id| assert c.keys.include?(firm_id) }
|
56
69
|
end
|
57
70
|
|
71
|
+
def test_should_group_by_multiple_fields
|
72
|
+
c = Account.count(:all, :group => ['firm_id', :credit_limit])
|
73
|
+
[ [nil, 50], [1, 50], [6, 50], [6, 55], [9, 53], [2, 60] ].each { |firm_and_limit| assert c.keys.include?(firm_and_limit) }
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_should_group_by_multiple_fields_having_functions
|
77
|
+
c = Topic.group(:author_name, 'COALESCE(type, title)').count(:all)
|
78
|
+
assert_equal 1, c[["Carl", "The Third Topic of the day"]]
|
79
|
+
assert_equal 1, c[["Mary", "Reply"]]
|
80
|
+
assert_equal 1, c[["David", "The First Topic"]]
|
81
|
+
assert_equal 1, c[["Carl", "Reply"]]
|
82
|
+
end
|
83
|
+
|
58
84
|
def test_should_group_by_summed_field
|
59
85
|
c = Account.sum(:credit_limit, :group => :firm_id)
|
60
86
|
assert_equal 50, c[1]
|
@@ -85,6 +111,51 @@ class CalculationsTest < ActiveRecord::TestCase
|
|
85
111
|
assert_equal [2, 6], c.keys.compact
|
86
112
|
end
|
87
113
|
|
114
|
+
def test_limit_should_apply_before_count
|
115
|
+
accounts = Account.limit(3).where('firm_id IS NOT NULL')
|
116
|
+
|
117
|
+
assert_equal 3, accounts.count(:firm_id)
|
118
|
+
assert_equal 3, accounts.select(:firm_id).count
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_count_should_shortcut_with_limit_zero
|
122
|
+
accounts = Account.limit(0)
|
123
|
+
|
124
|
+
assert_no_queries { assert_equal 0, accounts.count }
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_limit_is_kept
|
128
|
+
return if current_adapter?(:OracleAdapter, :IBM_DBAdapter)
|
129
|
+
|
130
|
+
queries = assert_sql { Account.limit(1).count }
|
131
|
+
assert_equal 1, queries.length
|
132
|
+
assert_match(/LIMIT/, queries.first)
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_offset_is_kept
|
136
|
+
return if current_adapter?(:OracleAdapter,:IBM_DBAdapter)
|
137
|
+
|
138
|
+
queries = assert_sql { Account.offset(1).count }
|
139
|
+
assert_equal 1, queries.length
|
140
|
+
assert_match(/OFFSET/, queries.first)
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_limit_with_offset_is_kept
|
144
|
+
return if current_adapter?(:OracleAdapter,:IBM_DBAdapter)
|
145
|
+
|
146
|
+
queries = assert_sql { Account.limit(1).offset(1).count }
|
147
|
+
assert_equal 1, queries.length
|
148
|
+
assert_match(/LIMIT/, queries.first)
|
149
|
+
assert_match(/OFFSET/, queries.first)
|
150
|
+
end
|
151
|
+
|
152
|
+
def test_no_limit_no_offset
|
153
|
+
queries = assert_sql { Account.count }
|
154
|
+
assert_equal 1, queries.length
|
155
|
+
assert_no_match(/LIMIT/, queries.first)
|
156
|
+
assert_no_match(/OFFSET/, queries.first)
|
157
|
+
end
|
158
|
+
|
88
159
|
def test_should_group_by_summed_field_having_condition
|
89
160
|
c = Account.sum(:credit_limit, :group => :firm_id,
|
90
161
|
:having => 'sum(credit_limit) > 50')
|
@@ -101,6 +172,13 @@ class CalculationsTest < ActiveRecord::TestCase
|
|
101
172
|
assert_equal 60, c[2]
|
102
173
|
end
|
103
174
|
|
175
|
+
def test_should_group_by_summed_field_having_condition_from_select
|
176
|
+
c = Account.select("MIN(credit_limit) AS min_credit_limit").group(:firm_id).having("MIN(credit_limit) > 50").sum(:credit_limit)
|
177
|
+
assert_nil c[1]
|
178
|
+
assert_equal 60, c[2]
|
179
|
+
assert_equal 53, c[9]
|
180
|
+
end
|
181
|
+
|
104
182
|
def test_should_group_by_summed_association
|
105
183
|
c = Account.sum(:credit_limit, :group => :firm)
|
106
184
|
assert_equal 50, c[companies(:first_firm)]
|
@@ -166,11 +244,7 @@ class CalculationsTest < ActiveRecord::TestCase
|
|
166
244
|
end
|
167
245
|
|
168
246
|
def test_should_group_by_association_with_non_numeric_foreign_key
|
169
|
-
|
170
|
-
ActiveRecord::Base.connection.expects(:prepared_select).returns([{"count_all" => 1, "firm_id" => "ABC"}])
|
171
|
-
else
|
172
|
-
ActiveRecord::Base.connection.expects(:select_all).returns([{"count_all" => 1, "firm_id" => "ABC"}])
|
173
|
-
end
|
247
|
+
ActiveRecord::Base.connection.expects(:select_all).returns([{"count_all" => 1, "firm_id" => "ABC"}])
|
174
248
|
|
175
249
|
firm = mock()
|
176
250
|
firm.expects(:id).returns("ABC")
|
@@ -254,6 +328,17 @@ class CalculationsTest < ActiveRecord::TestCase
|
|
254
328
|
assert_equal 4, Account.count(:distinct => true, :include => :firm, :select => :credit_limit)
|
255
329
|
end
|
256
330
|
|
331
|
+
def test_should_not_perform_joined_include_by_default
|
332
|
+
assert_equal Account.count, Account.includes(:firm).count
|
333
|
+
queries = assert_sql { Account.includes(:firm).count }
|
334
|
+
assert_no_match(/join/i, queries.last)
|
335
|
+
end
|
336
|
+
|
337
|
+
def test_should_perform_joined_include_when_referencing_included_tables
|
338
|
+
joined_count = Account.includes(:firm).where(:companies => {:name => '37signals'}).count
|
339
|
+
assert_equal 1, joined_count
|
340
|
+
end
|
341
|
+
|
257
342
|
def test_should_count_scoped_select
|
258
343
|
Account.update_all("credit_limit = NULL")
|
259
344
|
assert_equal 0, Account.scoped(:select => "credit_limit").count
|
@@ -261,8 +346,8 @@ class CalculationsTest < ActiveRecord::TestCase
|
|
261
346
|
|
262
347
|
def test_should_count_scoped_select_with_options
|
263
348
|
Account.update_all("credit_limit = NULL")
|
264
|
-
Account.last.
|
265
|
-
Account.first.
|
349
|
+
Account.last.update_column('credit_limit', 49)
|
350
|
+
Account.first.update_column('credit_limit', 51)
|
266
351
|
|
267
352
|
assert_equal 1, Account.scoped(:select => "credit_limit").count(:conditions => ['credit_limit >= 50'])
|
268
353
|
end
|
@@ -321,6 +406,10 @@ class CalculationsTest < ActiveRecord::TestCase
|
|
321
406
|
Account.sum(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
|
322
407
|
end
|
323
408
|
|
409
|
+
def test_sum_array_compatibility
|
410
|
+
assert_equal Account.sum(:credit_limit), Account.sum(&:credit_limit)
|
411
|
+
end
|
412
|
+
|
324
413
|
def test_average_with_from_option
|
325
414
|
assert_equal Account.average(:credit_limit), Account.average(:credit_limit, :from => 'accounts')
|
326
415
|
assert_equal Account.average(:credit_limit, :conditions => "credit_limit > 50"),
|
@@ -340,7 +429,7 @@ class CalculationsTest < ActiveRecord::TestCase
|
|
340
429
|
end
|
341
430
|
|
342
431
|
def test_from_option_with_specified_index
|
343
|
-
if Edge.connection.adapter_name == 'MySQL'
|
432
|
+
if Edge.connection.adapter_name == 'MySQL' or Edge.connection.adapter_name == 'Mysql2'
|
344
433
|
assert_equal Edge.count(:all), Edge.count(:all, :from => 'edges USE INDEX(unique_edge_index)')
|
345
434
|
assert_equal Edge.count(:all, :conditions => 'sink_id < 5'),
|
346
435
|
Edge.count(:all, :from => 'edges USE INDEX(unique_edge_index)', :conditions => 'sink_id < 5')
|
@@ -359,4 +448,35 @@ class CalculationsTest < ActiveRecord::TestCase
|
|
359
448
|
distinct_authors_for_approved_count = Topic.group(:approved).count(:author_name, :distinct => true)[true]
|
360
449
|
assert_equal distinct_authors_for_approved_count, 2
|
361
450
|
end
|
451
|
+
|
452
|
+
def test_pluck
|
453
|
+
assert_equal [1,2,3,4], Topic.order(:id).pluck(:id)
|
454
|
+
end
|
455
|
+
|
456
|
+
def test_pluck_type_cast
|
457
|
+
topic = topics(:first)
|
458
|
+
relation = Topic.where(:id => topic.id)
|
459
|
+
assert_equal [ topic.approved ], relation.pluck(:approved)
|
460
|
+
assert_equal [ topic.last_read ], relation.pluck(:last_read)
|
461
|
+
assert_equal [ topic.written_on ], relation.pluck(:written_on)
|
462
|
+
end
|
463
|
+
|
464
|
+
def test_pluck_and_uniq
|
465
|
+
assert_equal [50, 53, 55, 60], Account.order(:credit_limit).uniq.pluck(:credit_limit)
|
466
|
+
end
|
467
|
+
|
468
|
+
def test_pluck_in_relation
|
469
|
+
company = Company.first
|
470
|
+
contract = company.contracts.create!
|
471
|
+
assert_equal [contract.id], company.contracts.pluck(:id)
|
472
|
+
end
|
473
|
+
|
474
|
+
def test_pluck_with_serialization
|
475
|
+
t = Topic.create!(:content => { :foo => :bar })
|
476
|
+
assert_equal [{:foo => :bar}], Topic.where(:id => t.id).pluck(:content)
|
477
|
+
end
|
478
|
+
|
479
|
+
def test_pluck_with_qualified_column_name
|
480
|
+
assert_equal [1,2,3,4], Topic.order(:id).pluck("topics.id")
|
481
|
+
end
|
362
482
|
end
|
@@ -5,23 +5,26 @@ require 'models/person'
|
|
5
5
|
require 'models/topic'
|
6
6
|
require 'models/developer'
|
7
7
|
|
8
|
-
require MIGRATIONS_ROOT + "/valid/1_people_have_last_names"
|
9
8
|
require MIGRATIONS_ROOT + "/valid/2_we_need_reminders"
|
9
|
+
require MIGRATIONS_ROOT + "/rename/1_we_need_things"
|
10
|
+
require MIGRATIONS_ROOT + "/rename/2_rename_things"
|
10
11
|
require MIGRATIONS_ROOT + "/decimal/1_give_me_big_numbers"
|
11
|
-
require MIGRATIONS_ROOT + "/interleaved/pass_3/2_i_raise_on_down"
|
12
12
|
|
13
13
|
if ActiveRecord::Base.connection.supports_migrations?
|
14
14
|
class BigNumber < ActiveRecord::Base; end
|
15
15
|
|
16
16
|
class Reminder < ActiveRecord::Base; end
|
17
17
|
|
18
|
+
class Thing < ActiveRecord::Base; end
|
19
|
+
|
18
20
|
class ActiveRecord::Migration
|
19
|
-
class <<self
|
21
|
+
class << self
|
20
22
|
attr_accessor :message_count
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
23
|
+
end
|
24
|
+
|
25
|
+
def puts(text="")
|
26
|
+
ActiveRecord::Migration.message_count ||= 0
|
27
|
+
ActiveRecord::Migration.message_count += 1
|
25
28
|
end
|
26
29
|
end
|
27
30
|
|
@@ -46,6 +49,7 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
46
49
|
|
47
50
|
class MigrationTest < ActiveRecord::TestCase
|
48
51
|
self.use_transactional_fixtures = false
|
52
|
+
|
49
53
|
if (current_adapter?(:IBM_DBAdapter))
|
50
54
|
#Rename is supported only for server zOS 9 , DB2 COBRA and Informix
|
51
55
|
server_type = ActiveRecord::Base.connection.servertype.class.name
|
@@ -58,13 +62,18 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
58
62
|
|
59
63
|
def setup
|
60
64
|
ActiveRecord::Migration.verbose = true
|
61
|
-
|
65
|
+
ActiveRecord::Migration.message_count = 0
|
62
66
|
end
|
63
67
|
|
64
68
|
def teardown
|
65
69
|
ActiveRecord::Base.connection.initialize_schema_migrations_table
|
66
70
|
ActiveRecord::Base.connection.execute "DELETE FROM #{ActiveRecord::Migrator.schema_migrations_table_name}"
|
67
71
|
|
72
|
+
%w(things awesome_things prefix_things_suffix prefix_awesome_things_suffix).each do |table|
|
73
|
+
Thing.connection.drop_table(table) rescue nil
|
74
|
+
end
|
75
|
+
Thing.reset_column_information
|
76
|
+
|
68
77
|
%w(reminders people_reminders prefix_reminders_suffix).each do |table|
|
69
78
|
Reminder.connection.drop_table(table) rescue nil
|
70
79
|
end
|
@@ -118,7 +127,7 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
118
127
|
# Note: changed index name from "key" to "key_idx" since "key" is a Firebird reserved word
|
119
128
|
# OpenBase does not have named indexes. You must specify a single column name
|
120
129
|
unless current_adapter?(:OpenBaseAdapter)
|
121
|
-
|
130
|
+
unless current_adapter?(:IBM_DBAdapter)
|
122
131
|
Person.update_all "#{Person.connection.quote_column_name 'key'}=#{Person.connection.quote_column_name 'id'}" #some databases (including sqlite2 won't add a unique index if existing data non unique)
|
123
132
|
else
|
124
133
|
Person.update_all "#{Person.connection.quote_column_name 'key'}=#{Person.connection.quote_column_name 'first_name'}"
|
@@ -133,6 +142,18 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
133
142
|
assert_nothing_raised { Person.connection.add_index("people", %w(last_name first_name administrator), :name => "named_admin") }
|
134
143
|
assert_nothing_raised { Person.connection.remove_index("people", :name => "named_admin") }
|
135
144
|
end
|
145
|
+
|
146
|
+
# Selected adapters support index sort order
|
147
|
+
if current_adapter?(:SQLite3Adapter, :MysqlAdapter, :Mysql2Adapter, :PostgreSQLAdapter)
|
148
|
+
assert_nothing_raised { Person.connection.add_index("people", ["last_name"], :order => {:last_name => :desc}) }
|
149
|
+
assert_nothing_raised { Person.connection.remove_index("people", ["last_name"]) }
|
150
|
+
assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"], :order => {:last_name => :desc}) }
|
151
|
+
assert_nothing_raised { Person.connection.remove_index("people", ["last_name", "first_name"]) }
|
152
|
+
assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"], :order => {:last_name => :desc, :first_name => :asc}) }
|
153
|
+
assert_nothing_raised { Person.connection.remove_index("people", ["last_name", "first_name"]) }
|
154
|
+
assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"], :order => :desc) }
|
155
|
+
assert_nothing_raised { Person.connection.remove_index("people", ["last_name", "first_name"]) }
|
156
|
+
end
|
136
157
|
end
|
137
158
|
|
138
159
|
def test_index_symbol_names
|
@@ -152,6 +173,13 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
152
173
|
Person.connection.remove_index("people", :name => good_index_name)
|
153
174
|
end
|
154
175
|
|
176
|
+
def test_add_index_attribute_length_limit
|
177
|
+
Person.connection.add_index :people, [:first_name, :primary_contact_id], :length => {:first_name => 10, :primary_contact_id => nil}, :name => "attribute_length"
|
178
|
+
assert Person.connection.index_exists?(:people, [:first_name, :primary_contact_id], :name => "attribute_length")
|
179
|
+
ensure
|
180
|
+
Person.connection.remove_index(:people, :name => "attribute_length")
|
181
|
+
end
|
182
|
+
|
155
183
|
def test_remove_nonexistent_index
|
156
184
|
# we do this by name, so OpenBase is a wash as noted above
|
157
185
|
unless current_adapter?(:OpenBaseAdapter)
|
@@ -242,9 +270,9 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
242
270
|
end
|
243
271
|
|
244
272
|
unless current_adapter?(:IBM_DBAdapter)
|
245
|
-
# Cannot add a primary key to a table with some rows already in it as it violates the unique constraint
|
273
|
+
# For DB2: Cannot add a primary key to a table with some rows already in it as it violates the unique constraint
|
246
274
|
# Secondly GENERATED BY DEFAULT AS IDENTITY cannot be applied in a alter table command.
|
247
|
-
# as this will be wrong sql syntax for
|
275
|
+
# as this will be wrong sql syntax for DB
|
248
276
|
def test_add_column_with_primary_key_attribute
|
249
277
|
testing_table_with_only_foo_attribute do |connection|
|
250
278
|
assert_nothing_raised { connection.add_column :testings, :id, :primary_key }
|
@@ -280,16 +308,14 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
280
308
|
|
281
309
|
def test_create_table_with_defaults
|
282
310
|
# MySQL doesn't allow defaults on TEXT or BLOB columns.
|
283
|
-
mysql = current_adapter?(:MysqlAdapter)
|
284
|
-
|
285
|
-
ActiveRecord::Base.connection.servertype.class.name.include?('::IBM_DB2_ZOS')
|
286
|
-
|
311
|
+
mysql = current_adapter?(:MysqlAdapter) || current_adapter?(:Mysql2Adapter)
|
312
|
+
|
287
313
|
Person.connection.create_table :testings do |t|
|
288
314
|
t.column :one, :string, :default => "hello"
|
289
315
|
t.column :two, :boolean, :default => true
|
290
316
|
t.column :three, :boolean, :default => false
|
291
317
|
t.column :four, :integer, :default => 1
|
292
|
-
t.column :five, :text, :default => "hello" unless mysql
|
318
|
+
t.column :five, :text, :default => "hello" unless mysql
|
293
319
|
end
|
294
320
|
|
295
321
|
columns = Person.connection.columns(:testings)
|
@@ -297,65 +323,18 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
297
323
|
two = columns.detect { |c| c.name == "two" }
|
298
324
|
three = columns.detect { |c| c.name == "three" }
|
299
325
|
four = columns.detect { |c| c.name == "four" }
|
300
|
-
five = columns.detect { |c| c.name == "five" } unless mysql
|
326
|
+
five = columns.detect { |c| c.name == "five" } unless mysql
|
301
327
|
|
302
328
|
assert_equal "hello", one.default
|
303
329
|
assert_equal true, two.default
|
304
330
|
assert_equal false, three.default
|
305
331
|
assert_equal 1, four.default
|
306
|
-
assert_equal "hello", five.default unless mysql
|
332
|
+
assert_equal "hello", five.default unless mysql
|
307
333
|
|
308
334
|
ensure
|
309
335
|
Person.connection.drop_table :testings rescue nil
|
310
336
|
end
|
311
337
|
|
312
|
-
if current_adapter?(:IBM_DBAdapter)
|
313
|
-
def test_no_limits_datatypes_IBM_DB
|
314
|
-
ibm_ids = ActiveRecord::Base.connection.servertype.class.name.include?('::IBM_IDS')
|
315
|
-
clasz = Class.new(ActiveRecord::Base)
|
316
|
-
clasz.table_name = 'test_no_limits_datatypes_IBM_DB'
|
317
|
-
assert_nothing_raised do
|
318
|
-
clasz.connection.create_table clasz.table_name do |t|
|
319
|
-
t.column "test_varchar", :string, :limit => 10
|
320
|
-
t.column "test_integer", :integer, :limit => 5
|
321
|
-
t.column "test_boolean", :boolean, :limit => 5
|
322
|
-
t.column "test_double", :double, :limit => 10
|
323
|
-
t.column "test_date", :date, :limit => 10
|
324
|
-
t.column "test_time", :time, :limit => 10
|
325
|
-
t.column "test_tstamp", :timestamp, :limit => 10
|
326
|
-
t.column "test_xml", :xml, :limit => 10 unless ibm_ids
|
327
|
-
t.column "test_clob", :text, :limit => 10000
|
328
|
-
t.column "test_decfloat", :decfloat, :limit => 100
|
329
|
-
end
|
330
|
-
end
|
331
|
-
ensure
|
332
|
-
clasz.connection.drop_table(clasz.table_name) rescue nil
|
333
|
-
end
|
334
|
-
|
335
|
-
#Sexy migration test for column of type xml and char
|
336
|
-
def test_short_hand_migrations_for_ibm_db_datatypes
|
337
|
-
ibm_ids = ActiveRecord::Base.connection.servertype.class.name.include?('::IBM_IDS')
|
338
|
-
clasz = Class.new(ActiveRecord::Base)
|
339
|
-
clasz.table_name = 'test_short_hand_migrations'
|
340
|
-
assert_nothing_raised do
|
341
|
-
clasz.connection.create_table clasz.table_name do |t|
|
342
|
-
t.xml :xml_col unless ibm_ids
|
343
|
-
t.char :char_col, :limit=>10
|
344
|
-
t.decfloat :dec_col, :precision=>16
|
345
|
-
end
|
346
|
-
end
|
347
|
-
assert_nothing_raised do
|
348
|
-
clasz.connection.change_table clasz.table_name do |t|
|
349
|
-
t.xml :xml_col1 unless ibm_ids
|
350
|
-
t.char :char_col1, :limit=>50
|
351
|
-
t.decfloat :dec_col1, :precision=>34
|
352
|
-
end
|
353
|
-
end
|
354
|
-
ensure
|
355
|
-
clasz.connection.drop_table(clasz.table_name) rescue nil
|
356
|
-
end
|
357
|
-
end
|
358
|
-
|
359
338
|
def test_create_table_with_limits
|
360
339
|
assert_nothing_raised do
|
361
340
|
Person.connection.create_table :testings do |t|
|
@@ -455,8 +434,8 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
455
434
|
created_at_column = created_columns.detect {|c| c.name == 'created_at' }
|
456
435
|
updated_at_column = created_columns.detect {|c| c.name == 'updated_at' }
|
457
436
|
|
458
|
-
assert created_at_column.null
|
459
|
-
assert updated_at_column.null
|
437
|
+
assert !created_at_column.null
|
438
|
+
assert !updated_at_column.null
|
460
439
|
ensure
|
461
440
|
Person.connection.drop_table table_name rescue nil
|
462
441
|
end
|
@@ -487,7 +466,7 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
487
466
|
|
488
467
|
# Sybase, and SQLite3 will not allow you to add a NOT NULL
|
489
468
|
# column to a table without a default value.
|
490
|
-
unless current_adapter?(:SybaseAdapter, :
|
469
|
+
unless current_adapter?(:SybaseAdapter, :SQLite3Adapter, :IBM_DBAdapter)
|
491
470
|
def test_add_column_not_null_without_default
|
492
471
|
Person.connection.create_table :testings do |t|
|
493
472
|
t.column :foo, :string
|
@@ -537,9 +516,13 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
537
516
|
|
538
517
|
# Do a manual insertion
|
539
518
|
if current_adapter?(:OracleAdapter)
|
540
|
-
Person.connection.execute "insert into people (id, wealth) values (people_seq.nextval, 12345678901234567890.0123456789)"
|
519
|
+
Person.connection.execute "insert into people (id, wealth, created_at, updated_at) values (people_seq.nextval, 12345678901234567890.0123456789, sysdate, sysdate)"
|
541
520
|
elsif current_adapter?(:OpenBaseAdapter) || (current_adapter?(:MysqlAdapter) && Mysql.client_version < 50003) #before mysql 5.0.3 decimals stored as strings
|
542
|
-
Person.connection.execute "insert into people (wealth) values ('12345678901234567890.0123456789')"
|
521
|
+
Person.connection.execute "insert into people (wealth, created_at, updated_at) values ('12345678901234567890.0123456789', 0, 0)"
|
522
|
+
elsif current_adapter?(:PostgreSQLAdapter)
|
523
|
+
Person.connection.execute "insert into people (wealth, created_at, updated_at) values (12345678901234567890.0123456789, now(), now())"
|
524
|
+
elsif current_adapter?(:IBM_DBAdapter)
|
525
|
+
Person.connection.execute "insert into people (wealth, created_at, updated_at, lock_version, first_name) values (12345678901234567890.0123456789, CURRENT TIMESTAMP, CURRENT TIMESTAMP, 0, 'Jim')"
|
543
526
|
else
|
544
527
|
Person.connection.execute "insert into people (wealth) values (12345678901234567890.0123456789)"
|
545
528
|
end
|
@@ -557,7 +540,12 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
557
540
|
Person.delete_all
|
558
541
|
|
559
542
|
# Now use the Rails insertion
|
560
|
-
|
543
|
+
unless current_adapter?(:IBM_DBAdapter)
|
544
|
+
assert_nothing_raised { Person.create :wealth => BigDecimal.new("12345678901234567890.0123456789") }
|
545
|
+
else
|
546
|
+
# First_name is a not null column, hence ensure a value is specified
|
547
|
+
assert_nothing_raised { Person.create ({:wealth => BigDecimal.new("12345678901234567890.0123456789"), :first_name => "James"}) }
|
548
|
+
end
|
561
549
|
|
562
550
|
# SELECT
|
563
551
|
row = Person.find(:first)
|
@@ -582,6 +570,42 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
582
570
|
assert_equal 7, wealth_column.scale
|
583
571
|
end
|
584
572
|
|
573
|
+
# Test SQLite adapter specifically for decimal types with precision and scale
|
574
|
+
# attributes, since these need to be maintained in schema but aren't actually
|
575
|
+
# used in SQLite itself
|
576
|
+
if current_adapter?(:SQLite3Adapter)
|
577
|
+
def test_change_column_with_new_precision_and_scale
|
578
|
+
Person.delete_all
|
579
|
+
Person.connection.add_column 'people', 'wealth', :decimal, :precision => 9, :scale => 7
|
580
|
+
Person.reset_column_information
|
581
|
+
|
582
|
+
Person.connection.change_column 'people', 'wealth', :decimal, :precision => 12, :scale => 8
|
583
|
+
Person.reset_column_information
|
584
|
+
|
585
|
+
wealth_column = Person.columns_hash['wealth']
|
586
|
+
assert_equal 12, wealth_column.precision
|
587
|
+
assert_equal 8, wealth_column.scale
|
588
|
+
end
|
589
|
+
|
590
|
+
def test_change_column_preserve_other_column_precision_and_scale
|
591
|
+
Person.delete_all
|
592
|
+
Person.connection.add_column 'people', 'last_name', :string
|
593
|
+
Person.connection.add_column 'people', 'wealth', :decimal, :precision => 9, :scale => 7
|
594
|
+
Person.reset_column_information
|
595
|
+
|
596
|
+
wealth_column = Person.columns_hash['wealth']
|
597
|
+
assert_equal 9, wealth_column.precision
|
598
|
+
assert_equal 7, wealth_column.scale
|
599
|
+
|
600
|
+
Person.connection.change_column 'people', 'last_name', :string, :null => false
|
601
|
+
Person.reset_column_information
|
602
|
+
|
603
|
+
wealth_column = Person.columns_hash['wealth']
|
604
|
+
assert_equal 9, wealth_column.precision
|
605
|
+
assert_equal 7, wealth_column.scale
|
606
|
+
end
|
607
|
+
end
|
608
|
+
|
585
609
|
def test_native_types
|
586
610
|
Person.delete_all
|
587
611
|
Person.connection.add_column "people", "last_name", :string
|
@@ -609,7 +633,7 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
609
633
|
assert_equal "I was born ....", bob.bio
|
610
634
|
assert_equal 18, bob.age
|
611
635
|
|
612
|
-
# Test for 30
|
636
|
+
# Test for 30 significant digits (beyond the 16 of float), 10 of them
|
613
637
|
# after the decimal place.
|
614
638
|
|
615
639
|
unless current_adapter?(:SQLite3Adapter)
|
@@ -742,17 +766,17 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
742
766
|
end
|
743
767
|
end
|
744
768
|
|
745
|
-
if
|
769
|
+
if(!current_adapter?(:IBM_DBAdapter) || @ibm_db_rename_supported)
|
746
770
|
def test_add_rename
|
747
771
|
Person.delete_all
|
748
|
-
|
772
|
+
|
749
773
|
begin
|
750
774
|
Person.connection.add_column "people", "girlfriend", :string
|
751
775
|
Person.reset_column_information
|
752
776
|
Person.create :girlfriend => 'bobette'
|
753
|
-
|
777
|
+
|
754
778
|
Person.connection.rename_column "people", "girlfriend", "exgirlfriend"
|
755
|
-
|
779
|
+
|
756
780
|
Person.reset_column_information
|
757
781
|
bob = Person.find(:first)
|
758
782
|
|
@@ -763,7 +787,7 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
763
787
|
end
|
764
788
|
|
765
789
|
end
|
766
|
-
|
790
|
+
|
767
791
|
def test_rename_column_using_symbol_arguments
|
768
792
|
begin
|
769
793
|
names_before = Person.find(:all).map(&:first_name)
|
@@ -809,7 +833,7 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
809
833
|
ActiveRecord::Base.connection.create_table(:hats) do |table|
|
810
834
|
table.column :hat_name, :string, :default => nil
|
811
835
|
end
|
812
|
-
exception = if current_adapter?(:PostgreSQLAdapter)
|
836
|
+
exception = if current_adapter?(:PostgreSQLAdapter, :OracleAdapter)
|
813
837
|
ActiveRecord::StatementInvalid
|
814
838
|
else
|
815
839
|
ActiveRecord::ActiveRecordError
|
@@ -833,7 +857,7 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
833
857
|
end
|
834
858
|
end
|
835
859
|
|
836
|
-
unless
|
860
|
+
unless current_adapter?(:IBM_DBAdapter)
|
837
861
|
def test_rename_column_with_an_index
|
838
862
|
ActiveRecord::Base.connection.create_table(:hats) do |table|
|
839
863
|
table.column :hat_name, :string, :limit => 100
|
@@ -848,59 +872,62 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
848
872
|
end
|
849
873
|
end
|
850
874
|
|
851
|
-
def
|
875
|
+
def test_remove_column_with_index
|
852
876
|
ActiveRecord::Base.connection.create_table(:hats) do |table|
|
853
877
|
table.column :hat_name, :string, :limit => 100
|
854
878
|
table.column :hat_size, :integer
|
855
879
|
end
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
end
|
880
|
+
ActiveRecord::Base.connection.add_index "hats", "hat_size"
|
881
|
+
|
882
|
+
assert_nothing_raised { Person.connection.remove_column("hats", "hat_size") }
|
860
883
|
ensure
|
861
884
|
ActiveRecord::Base.connection.drop_table(:hats)
|
862
885
|
end
|
863
886
|
|
864
|
-
def
|
887
|
+
def test_remove_column_with_multi_column_index
|
865
888
|
ActiveRecord::Base.connection.create_table(:hats) do |table|
|
866
889
|
table.column :hat_name, :string, :limit => 100
|
867
890
|
table.column :hat_size, :integer
|
891
|
+
table.column :hat_style, :string, :limit => 100
|
868
892
|
end
|
869
|
-
ActiveRecord::Base.connection.add_index "hats", "hat_size"
|
893
|
+
ActiveRecord::Base.connection.add_index "hats", ["hat_style", "hat_size"], :unique => true
|
870
894
|
|
871
895
|
assert_nothing_raised { Person.connection.remove_column("hats", "hat_size") }
|
872
896
|
ensure
|
873
897
|
ActiveRecord::Base.connection.drop_table(:hats)
|
874
898
|
end
|
875
899
|
|
876
|
-
|
877
|
-
|
878
|
-
ActiveRecord::Base.connection.create_table(:hats) do |table|
|
879
|
-
table.column :hat_name, :string, :limit => 100
|
880
|
-
table.column :hat_size, :integer
|
881
|
-
table.column :hat_style, :string, :limit => 100
|
882
|
-
end
|
883
|
-
ActiveRecord::Base.connection.add_index "hats", ["hat_style", "hat_size"], :unique => true
|
884
|
-
|
885
|
-
assert_nothing_raised { Person.connection.remove_column("hats", "hat_size") }
|
886
|
-
ensure
|
887
|
-
ActiveRecord::Base.connection.drop_table(:hats)
|
888
|
-
end
|
900
|
+
def test_remove_column_no_second_parameter_raises_exception
|
901
|
+
assert_raise(ArgumentError) { Person.connection.remove_column("funny") }
|
889
902
|
end
|
890
903
|
|
891
|
-
|
892
|
-
|
893
|
-
|
904
|
+
def test_change_type_of_not_null_column
|
905
|
+
assert_nothing_raised do
|
906
|
+
unless current_adapter?(:IBM_DBAdapter)
|
894
907
|
Topic.connection.change_column "topics", "written_on", :datetime, :null => false
|
895
|
-
|
908
|
+
else
|
909
|
+
Topic.connection.change_column_null "topics", "written_on", false
|
910
|
+
end
|
911
|
+
Topic.reset_column_information
|
896
912
|
|
913
|
+
unless current_adapter?(:IBM_DBAdapter)
|
897
914
|
Topic.connection.change_column "topics", "written_on", :datetime, :null => false
|
898
|
-
|
915
|
+
else
|
916
|
+
Topic.connection.change_column_null "topics", "written_on", false
|
899
917
|
end
|
918
|
+
Topic.reset_column_information
|
919
|
+
|
920
|
+
unless current_adapter?(:IBM_DBAdapter)
|
921
|
+
Topic.connection.change_column "topics", "written_on", :datetime, :null => true
|
922
|
+
else
|
923
|
+
Topic.connection.change_column_null "topics", "written_on", true
|
924
|
+
end
|
925
|
+
|
926
|
+
Topic.reset_column_information
|
900
927
|
end
|
901
|
-
end
|
928
|
+
end
|
902
929
|
|
903
|
-
if current_adapter?(:
|
930
|
+
if current_adapter?(:SQLite3Adapter)
|
904
931
|
def test_rename_table_for_sqlite_should_work_with_reserved_words
|
905
932
|
begin
|
906
933
|
assert_nothing_raised do
|
@@ -952,14 +979,20 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
952
979
|
Person.connection.add_column "people", "funny", :boolean
|
953
980
|
Person.reset_column_information
|
954
981
|
assert Person.columns_hash["funny"].null, "Column 'funny' must initially allow nulls"
|
955
|
-
|
982
|
+
unless current_adapter?(:IBM_DBAdapter)
|
956
983
|
Person.connection.change_column "people", "funny", :boolean, :null => false, :default => true
|
984
|
+
else
|
985
|
+
Person.connection.change_column_null "people", "funny",false
|
986
|
+
end
|
957
987
|
Person.reset_column_information
|
958
988
|
assert !Person.columns_hash["funny"].null, "Column 'funny' must *not* allow nulls at this point"
|
989
|
+
unless current_adapter?(:IBM_DBAdapter)
|
959
990
|
Person.connection.change_column "people", "funny", :boolean, :null => true
|
960
|
-
|
961
|
-
|
962
|
-
end
|
991
|
+
else
|
992
|
+
Person.connection.change_column_null "people", "funny",true
|
993
|
+
end
|
994
|
+
Person.reset_column_information
|
995
|
+
assert Person.columns_hash["funny"].null, "Column 'funny' must allow nulls again at this point"
|
963
996
|
end
|
964
997
|
|
965
998
|
def test_rename_table_with_an_index
|
@@ -985,39 +1018,44 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
985
1018
|
end
|
986
1019
|
end
|
987
1020
|
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
1021
|
+
unless current_adapter?(:IBM_DBAdapter)
|
1022
|
+
# Cannot convert from type integer to varchar.
|
1023
|
+
# Safe to not run this test as add_column will be covered in other test cases
|
1024
|
+
def test_change_column
|
1025
|
+
Person.connection.add_column 'people', 'age', :integer
|
1026
|
+
label = "test_change_column Columns"
|
1027
|
+
old_columns = Person.connection.columns(Person.table_name, label)
|
1028
|
+
assert old_columns.find { |c| c.name == 'age' and c.type == :integer }
|
994
1029
|
|
995
|
-
|
1030
|
+
assert_nothing_raised { Person.connection.change_column "people", "age", :string }
|
996
1031
|
|
997
|
-
|
998
|
-
|
999
|
-
|
1032
|
+
new_columns = Person.connection.columns(Person.table_name, label)
|
1033
|
+
assert_nil new_columns.find { |c| c.name == 'age' and c.type == :integer }
|
1034
|
+
assert new_columns.find { |c| c.name == 'age' and c.type == :string }
|
1000
1035
|
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1036
|
+
old_columns = Topic.connection.columns(Topic.table_name, label)
|
1037
|
+
assert old_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == true }
|
1038
|
+
assert_nothing_raised { Topic.connection.change_column :topics, :approved, :boolean, :default => false }
|
1039
|
+
new_columns = Topic.connection.columns(Topic.table_name, label)
|
1040
|
+
assert_nil new_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == true }
|
1041
|
+
assert new_columns.find { |c| c.name == 'approved' and c.type == :boolean and c.default == false }
|
1042
|
+
assert_nothing_raised { Topic.connection.change_column :topics, :approved, :boolean, :default => true }
|
1043
|
+
end
|
1008
1044
|
end
|
1009
|
-
|
1010
|
-
|
1045
|
+
|
1011
1046
|
def test_change_column_with_nil_default
|
1012
1047
|
Person.connection.add_column "people", "contributor", :boolean, :default => true
|
1013
1048
|
Person.reset_column_information
|
1014
1049
|
assert Person.new.contributor?
|
1015
|
-
|
1050
|
+
|
1051
|
+
unless current_adapter?(:IBM_DBAdapter)
|
1016
1052
|
assert_nothing_raised { Person.connection.change_column "people", "contributor", :boolean, :default => nil }
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1053
|
+
else
|
1054
|
+
assert_nothing_raised { Person.connection.change_column_default "people", "contributor", nil }
|
1055
|
+
end
|
1056
|
+
Person.reset_column_information
|
1057
|
+
assert !Person.new.contributor?
|
1058
|
+
assert_nil Person.new.contributor
|
1021
1059
|
ensure
|
1022
1060
|
Person.connection.remove_column("people", "contributor") rescue nil
|
1023
1061
|
end
|
@@ -1026,11 +1064,14 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
1026
1064
|
Person.connection.add_column "people", "administrator", :boolean, :default => true
|
1027
1065
|
Person.reset_column_information
|
1028
1066
|
assert Person.new.administrator?
|
1029
|
-
|
1067
|
+
|
1068
|
+
unless current_adapter?(:IBM_DBAdapter)
|
1030
1069
|
assert_nothing_raised { Person.connection.change_column "people", "administrator", :boolean, :default => false }
|
1031
|
-
|
1032
|
-
|
1033
|
-
end
|
1070
|
+
else
|
1071
|
+
assert_nothing_raised { Person.connection.change_column_default "people", "administrator", false }
|
1072
|
+
end
|
1073
|
+
Person.reset_column_information
|
1074
|
+
assert !Person.new.administrator?
|
1034
1075
|
ensure
|
1035
1076
|
Person.connection.remove_column("people", "administrator") rescue nil
|
1036
1077
|
end
|
@@ -1043,10 +1084,11 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
1043
1084
|
|
1044
1085
|
def test_change_column_quotes_column_names
|
1045
1086
|
Person.connection.create_table :testings do |t|
|
1046
|
-
|
1047
|
-
t.column :select, :string, :limit => 5
|
1048
|
-
else
|
1087
|
+
unless current_adapter?(:IBM_DBAdapter)
|
1049
1088
|
t.column :select, :string
|
1089
|
+
else
|
1090
|
+
# If no limit specified by default column of length 255 is created, which later cannot be scaled down to 10
|
1091
|
+
t.column :select, :string, :limit => 5
|
1050
1092
|
end
|
1051
1093
|
end
|
1052
1094
|
|
@@ -1067,7 +1109,7 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
1067
1109
|
t.column :title, :string
|
1068
1110
|
end
|
1069
1111
|
person_klass = Class.new(Person)
|
1070
|
-
person_klass.
|
1112
|
+
person_klass.table_name = 'testings'
|
1071
1113
|
|
1072
1114
|
person_klass.connection.add_column "testings", "wealth", :integer, :null => false, :default => 99
|
1073
1115
|
person_klass.reset_column_information
|
@@ -1087,16 +1129,16 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
1087
1129
|
assert_equal false, person_klass.columns_hash["wealth"].null
|
1088
1130
|
|
1089
1131
|
# rename column to see that column doesn't lose its not null and/or default definition
|
1090
|
-
if (!current_adapter?(:IBM_DBAdapter) || @ibm_db_rename_supported)
|
1132
|
+
if (!current_adapter?(:IBM_DBAdapter) || @ibm_db_rename_supported)
|
1091
1133
|
person_klass.connection.rename_column "testings", "wealth", "money"
|
1092
1134
|
person_klass.reset_column_information
|
1093
1135
|
assert_nil person_klass.columns_hash["wealth"]
|
1094
1136
|
assert_equal 100, person_klass.columns_hash["money"].default
|
1095
1137
|
assert_equal false, person_klass.columns_hash["money"].null
|
1096
|
-
end
|
1138
|
+
end
|
1097
1139
|
|
1098
1140
|
# change column
|
1099
|
-
unless
|
1141
|
+
unless current_adapter?(:IBM_DBAdapter)
|
1100
1142
|
person_klass.connection.change_column "testings", "money", :integer, :null => false, :default => 1000
|
1101
1143
|
person_klass.reset_column_information
|
1102
1144
|
assert_equal 1000, person_klass.columns_hash["money"].default
|
@@ -1106,10 +1148,10 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
1106
1148
|
person_klass.reset_column_information
|
1107
1149
|
assert_equal 1000, person_klass.columns_hash["wealth"].default
|
1108
1150
|
assert_equal false, person_klass.columns_hash["wealth"].null
|
1109
|
-
end
|
1151
|
+
end
|
1110
1152
|
|
1111
1153
|
# change column, make it nullable and clear default
|
1112
|
-
unless
|
1154
|
+
unless current_adapter?(:IBM_DBAdapter)
|
1113
1155
|
person_klass.connection.change_column "testings", "money", :integer, :null => true, :default => nil
|
1114
1156
|
person_klass.reset_column_information
|
1115
1157
|
assert_nil person_klass.columns_hash["money"].default
|
@@ -1119,10 +1161,10 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
1119
1161
|
person_klass.reset_column_information
|
1120
1162
|
assert_nil person_klass.columns_hash["wealth"].default
|
1121
1163
|
assert_equal true, person_klass.columns_hash["wealth"].null
|
1122
|
-
end
|
1164
|
+
end
|
1123
1165
|
|
1124
1166
|
# change_column_null, make it not nullable and set null values to a default value
|
1125
|
-
unless
|
1167
|
+
unless current_adapter?(:IBM_DBAdapter)
|
1126
1168
|
person_klass.connection.execute('UPDATE testings SET money = NULL')
|
1127
1169
|
person_klass.connection.change_column_null "testings", "money", false, 2000
|
1128
1170
|
person_klass.reset_column_information
|
@@ -1131,12 +1173,15 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
1131
1173
|
assert_equal [2000], Person.connection.select_values("SELECT money FROM testings").map { |s| s.to_i }.sort
|
1132
1174
|
else
|
1133
1175
|
# Trying to set the value of the column wealth to NULL and
|
1134
|
-
# in the next statement a not null constraint is being applied which is wrong
|
1135
|
-
#person_klass.connection.execute('UPDATE testings SET
|
1176
|
+
# in the next statement a not null constraint is being applied which is wrong
|
1177
|
+
#person_klass.connection.execute('UPDATE testings SET money = NULL')
|
1136
1178
|
person_klass.connection.change_column_null "testings", "wealth", false, 2000
|
1137
1179
|
person_klass.reset_column_information
|
1180
|
+
#assert_nil person_klass.columns_hash["wealth"].default #Setting default to 2000 and expecting nil is nor correct
|
1181
|
+
assert_not_nil person_klass.columns_hash["wealth"].default
|
1138
1182
|
assert_equal false, person_klass.columns_hash["wealth"].null
|
1139
|
-
|
1183
|
+
#Changing default does not change the already inserted value. Hence expecting 2000 is wrong.
|
1184
|
+
assert_equal [99], Person.connection.select_values("SELECT wealth FROM testings").map { |s| s.to_i }.sort
|
1140
1185
|
end
|
1141
1186
|
ensure
|
1142
1187
|
Person.connection.drop_table :testings rescue nil
|
@@ -1187,6 +1232,18 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
1187
1232
|
Person.connection.drop_table :testings rescue nil
|
1188
1233
|
end
|
1189
1234
|
|
1235
|
+
def test_column_exists_on_table_with_no_options_parameter_supplied
|
1236
|
+
Person.connection.create_table :testings do |t|
|
1237
|
+
t.string :foo
|
1238
|
+
end
|
1239
|
+
Person.connection.change_table :testings do |t|
|
1240
|
+
assert t.column_exists?(:foo)
|
1241
|
+
assert !(t.column_exists?(:bar))
|
1242
|
+
end
|
1243
|
+
ensure
|
1244
|
+
Person.connection.drop_table :testings rescue nil
|
1245
|
+
end
|
1246
|
+
|
1190
1247
|
def test_add_table
|
1191
1248
|
assert !Reminder.table_exists?
|
1192
1249
|
|
@@ -1224,17 +1281,17 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
1224
1281
|
|
1225
1282
|
# TODO: set world_population >= 2**62 to cover 64-bit platforms and test
|
1226
1283
|
# is_a?(Bignum)
|
1227
|
-
unless current_adapter?(:IBM_DBAdapter)
|
1284
|
+
unless current_adapter?(:IBM_DBAdapter)
|
1228
1285
|
assert_kind_of Integer, b.world_population
|
1229
1286
|
else
|
1230
1287
|
assert_kind_of BigDecimal, b.world_population
|
1231
|
-
end
|
1288
|
+
end
|
1232
1289
|
assert_equal 6000000000, b.world_population
|
1233
|
-
unless current_adapter?(:IBM_DBAdapter)
|
1290
|
+
unless current_adapter?(:IBM_DBAdapter)
|
1234
1291
|
assert_kind_of Fixnum, b.my_house_population
|
1235
1292
|
else
|
1236
1293
|
assert_kind_of BigDecimal, b.my_house_population
|
1237
|
-
end
|
1294
|
+
end
|
1238
1295
|
assert_equal 3, b.my_house_population
|
1239
1296
|
assert_kind_of BigDecimal, b.bank_balance
|
1240
1297
|
assert_equal BigDecimal("1586.43"), b.bank_balance
|
@@ -1254,17 +1311,17 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
1254
1311
|
# so this happens there too
|
1255
1312
|
assert_kind_of BigDecimal, b.value_of_e
|
1256
1313
|
assert_equal BigDecimal("2.7182818284590452353602875"), b.value_of_e
|
1257
|
-
elsif current_adapter?(:
|
1314
|
+
elsif current_adapter?(:SQLite3Adapter)
|
1258
1315
|
# - SQLite3 stores a float, in violation of SQL
|
1259
1316
|
assert_kind_of BigDecimal, b.value_of_e
|
1260
1317
|
assert_in_delta BigDecimal("2.71828182845905"), b.value_of_e, 0.00000000000001
|
1261
1318
|
else
|
1262
1319
|
# - SQL standard is an integer
|
1263
|
-
|
1264
|
-
|
1265
|
-
|
1266
|
-
|
1267
|
-
|
1320
|
+
unless current_adapter?(:IBM_DBAdapter)
|
1321
|
+
assert_kind_of Fixnum, b.value_of_e
|
1322
|
+
else
|
1323
|
+
assert_kind_of BigDecimal, b.value_of_e
|
1324
|
+
end
|
1268
1325
|
assert_equal 2, b.value_of_e
|
1269
1326
|
end
|
1270
1327
|
|
@@ -1292,6 +1349,62 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
1292
1349
|
assert_raise(ActiveRecord::StatementInvalid) { Reminder.find(:first) }
|
1293
1350
|
end
|
1294
1351
|
|
1352
|
+
def test_filtering_migrations
|
1353
|
+
assert !Person.column_methods_hash.include?(:last_name)
|
1354
|
+
assert !Reminder.table_exists?
|
1355
|
+
|
1356
|
+
name_filter = lambda { |migration| migration.name == "ValidPeopleHaveLastNames" }
|
1357
|
+
ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/valid", &name_filter)
|
1358
|
+
|
1359
|
+
Person.reset_column_information
|
1360
|
+
assert Person.column_methods_hash.include?(:last_name)
|
1361
|
+
assert_raise(ActiveRecord::StatementInvalid) { Reminder.find(:first) }
|
1362
|
+
|
1363
|
+
ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/valid", &name_filter)
|
1364
|
+
|
1365
|
+
Person.reset_column_information
|
1366
|
+
assert !Person.column_methods_hash.include?(:last_name)
|
1367
|
+
assert_raise(ActiveRecord::StatementInvalid) { Reminder.find(:first) }
|
1368
|
+
end
|
1369
|
+
|
1370
|
+
class MockMigration < ActiveRecord::Migration
|
1371
|
+
attr_reader :went_up, :went_down
|
1372
|
+
def initialize
|
1373
|
+
@went_up = false
|
1374
|
+
@went_down = false
|
1375
|
+
end
|
1376
|
+
|
1377
|
+
def up
|
1378
|
+
@went_up = true
|
1379
|
+
super
|
1380
|
+
end
|
1381
|
+
|
1382
|
+
def down
|
1383
|
+
@went_down = true
|
1384
|
+
super
|
1385
|
+
end
|
1386
|
+
end
|
1387
|
+
|
1388
|
+
def test_instance_based_migration_up
|
1389
|
+
migration = MockMigration.new
|
1390
|
+
assert !migration.went_up, 'have not gone up'
|
1391
|
+
assert !migration.went_down, 'have not gone down'
|
1392
|
+
|
1393
|
+
migration.migrate :up
|
1394
|
+
assert migration.went_up, 'have gone up'
|
1395
|
+
assert !migration.went_down, 'have not gone down'
|
1396
|
+
end
|
1397
|
+
|
1398
|
+
def test_instance_based_migration_down
|
1399
|
+
migration = MockMigration.new
|
1400
|
+
assert !migration.went_up, 'have not gone up'
|
1401
|
+
assert !migration.went_down, 'have not gone down'
|
1402
|
+
|
1403
|
+
migration.migrate :down
|
1404
|
+
assert !migration.went_up, 'have gone up'
|
1405
|
+
assert migration.went_down, 'have not gone down'
|
1406
|
+
end
|
1407
|
+
|
1295
1408
|
def test_migrator_one_up
|
1296
1409
|
assert !Person.column_methods_hash.include?(:last_name)
|
1297
1410
|
assert !Reminder.table_exists?
|
@@ -1359,51 +1472,74 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
1359
1472
|
def test_finds_migrations
|
1360
1473
|
migrations = ActiveRecord::Migrator.new(:up, MIGRATIONS_ROOT + "/valid").migrations
|
1361
1474
|
|
1362
|
-
[[1, '
|
1475
|
+
[[1, 'ValidPeopleHaveLastNames'], [2, 'WeNeedReminders'], [3, 'InnocentJointable']].each_with_index do |pair, i|
|
1476
|
+
assert_equal migrations[i].version, pair.first
|
1477
|
+
assert_equal migrations[i].name, pair.last
|
1478
|
+
end
|
1479
|
+
end
|
1480
|
+
|
1481
|
+
def test_finds_migrations_in_subdirectories
|
1482
|
+
migrations = ActiveRecord::Migrator.new(:up, MIGRATIONS_ROOT + "/valid_with_subdirectories").migrations
|
1483
|
+
|
1484
|
+
[[1, 'ValidPeopleHaveLastNames'], [2, 'WeNeedReminders'], [3, 'InnocentJointable']].each_with_index do |pair, i|
|
1363
1485
|
assert_equal migrations[i].version, pair.first
|
1364
1486
|
assert_equal migrations[i].name, pair.last
|
1365
1487
|
end
|
1366
1488
|
end
|
1367
1489
|
|
1490
|
+
def test_finds_migrations_from_two_directories
|
1491
|
+
directories = [MIGRATIONS_ROOT + '/valid_with_timestamps', MIGRATIONS_ROOT + '/to_copy_with_timestamps']
|
1492
|
+
migrations = ActiveRecord::Migrator.new(:up, directories).migrations
|
1493
|
+
|
1494
|
+
[[20090101010101, "PeopleHaveHobbies"],
|
1495
|
+
[20090101010202, "PeopleHaveDescriptions"],
|
1496
|
+
[20100101010101, "ValidWithTimestampsPeopleHaveLastNames"],
|
1497
|
+
[20100201010101, "ValidWithTimestampsWeNeedReminders"],
|
1498
|
+
[20100301010101, "ValidWithTimestampsInnocentJointable"]].each_with_index do |pair, i|
|
1499
|
+
assert_equal pair.first, migrations[i].version
|
1500
|
+
assert_equal pair.last, migrations[i].name
|
1501
|
+
end
|
1502
|
+
end
|
1503
|
+
|
1504
|
+
def test_dump_schema_information_outputs_lexically_ordered_versions
|
1505
|
+
migration_path = MIGRATIONS_ROOT + '/valid_with_timestamps'
|
1506
|
+
ActiveRecord::Migrator.run(:up, migration_path, 20100301010101)
|
1507
|
+
ActiveRecord::Migrator.run(:up, migration_path, 20100201010101)
|
1508
|
+
|
1509
|
+
schema_info = ActiveRecord::Base.connection.dump_schema_information
|
1510
|
+
assert_match(/20100201010101.*20100301010101/m, schema_info)
|
1511
|
+
end
|
1512
|
+
|
1368
1513
|
def test_finds_pending_migrations
|
1369
1514
|
ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/interleaved/pass_2", 1)
|
1370
1515
|
migrations = ActiveRecord::Migrator.new(:up, MIGRATIONS_ROOT + "/interleaved/pass_2").pending_migrations
|
1371
1516
|
|
1372
1517
|
assert_equal 1, migrations.size
|
1373
1518
|
assert_equal migrations[0].version, 3
|
1374
|
-
assert_equal migrations[0].name, '
|
1519
|
+
assert_equal migrations[0].name, 'InterleavedInnocentJointable'
|
1375
1520
|
end
|
1376
1521
|
|
1377
1522
|
def test_relative_migrations
|
1378
|
-
|
1379
|
-
fname == (MIGRATIONS_ROOT + "/valid/1_people_have_last_names.rb")
|
1380
|
-
end
|
1381
|
-
Object.send(:remove_const, :PeopleHaveLastNames)
|
1382
|
-
|
1383
|
-
Dir.chdir(MIGRATIONS_ROOT) do
|
1523
|
+
list = Dir.chdir(MIGRATIONS_ROOT) do
|
1384
1524
|
ActiveRecord::Migrator.up("valid/", 1)
|
1385
1525
|
end
|
1386
1526
|
|
1387
|
-
|
1527
|
+
migration_proxy = list.find { |item|
|
1528
|
+
item.name == 'ValidPeopleHaveLastNames'
|
1529
|
+
}
|
1530
|
+
assert migration_proxy, 'should find pending migration'
|
1388
1531
|
end
|
1389
1532
|
|
1390
1533
|
def test_only_loads_pending_migrations
|
1391
1534
|
# migrate up to 1
|
1392
1535
|
ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/valid", 1)
|
1393
1536
|
|
1394
|
-
|
1395
|
-
Object.send(:remove_const, :PeopleHaveLastNames)
|
1396
|
-
|
1397
|
-
ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/valid", nil)
|
1537
|
+
proxies = ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/valid", nil)
|
1398
1538
|
|
1399
|
-
|
1400
|
-
|
1401
|
-
|
1402
|
-
|
1403
|
-
end
|
1404
|
-
|
1405
|
-
ensure
|
1406
|
-
load(MIGRATIONS_ROOT + "/valid/1_people_have_last_names.rb")
|
1539
|
+
names = proxies.map(&:name)
|
1540
|
+
assert !names.include?('ValidPeopleHaveLastNames')
|
1541
|
+
assert names.include?('WeNeedReminders')
|
1542
|
+
assert names.include?('InnocentJointable')
|
1407
1543
|
end
|
1408
1544
|
|
1409
1545
|
def test_target_version_zero_should_run_only_once
|
@@ -1413,16 +1549,9 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
1413
1549
|
# migrate down to 0
|
1414
1550
|
ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/valid", 0)
|
1415
1551
|
|
1416
|
-
# now unload the migrations that have been defined
|
1417
|
-
PeopleHaveLastNames.unloadable
|
1418
|
-
ActiveSupport::Dependencies.remove_unloadable_constants!
|
1419
|
-
|
1420
1552
|
# migrate down to 0 again
|
1421
|
-
ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/valid", 0)
|
1422
|
-
|
1423
|
-
assert !defined? PeopleHaveLastNames
|
1424
|
-
ensure
|
1425
|
-
load(MIGRATIONS_ROOT + "/valid/1_people_have_last_names.rb")
|
1553
|
+
proxies = ActiveRecord::Migrator.migrate(MIGRATIONS_ROOT + "/valid", 0)
|
1554
|
+
assert_equal [], proxies
|
1426
1555
|
end
|
1427
1556
|
|
1428
1557
|
def test_migrator_db_has_no_schema_migrations_table
|
@@ -1439,20 +1568,20 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
1439
1568
|
|
1440
1569
|
def test_migrator_verbosity
|
1441
1570
|
ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/valid", 1)
|
1442
|
-
|
1443
|
-
|
1571
|
+
assert_not_equal 0, ActiveRecord::Migration.message_count
|
1572
|
+
ActiveRecord::Migration.message_count = 0
|
1444
1573
|
|
1445
1574
|
ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/valid", 0)
|
1446
|
-
|
1447
|
-
|
1575
|
+
assert_not_equal 0, ActiveRecord::Migration.message_count
|
1576
|
+
ActiveRecord::Migration.message_count = 0
|
1448
1577
|
end
|
1449
1578
|
|
1450
1579
|
def test_migrator_verbosity_off
|
1451
|
-
|
1580
|
+
ActiveRecord::Migration.verbose = false
|
1452
1581
|
ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/valid", 1)
|
1453
|
-
|
1582
|
+
assert_equal 0, ActiveRecord::Migration.message_count
|
1454
1583
|
ActiveRecord::Migrator.down(MIGRATIONS_ROOT + "/valid", 0)
|
1455
|
-
|
1584
|
+
assert_equal 0, ActiveRecord::Migration.message_count
|
1456
1585
|
end
|
1457
1586
|
|
1458
1587
|
def test_migrator_going_down_due_to_version_target
|
@@ -1555,6 +1684,28 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
1555
1684
|
Reminder.reset_table_name
|
1556
1685
|
end
|
1557
1686
|
|
1687
|
+
def test_rename_table_with_prefix_and_suffix
|
1688
|
+
assert !Thing.table_exists?
|
1689
|
+
ActiveRecord::Base.table_name_prefix = 'prefix_'
|
1690
|
+
ActiveRecord::Base.table_name_suffix = '_suffix'
|
1691
|
+
Thing.reset_table_name
|
1692
|
+
Thing.reset_sequence_name
|
1693
|
+
WeNeedThings.up
|
1694
|
+
|
1695
|
+
assert Thing.create("content" => "hello world")
|
1696
|
+
assert_equal "hello world", Thing.find(:first).content
|
1697
|
+
|
1698
|
+
RenameThings.up
|
1699
|
+
Thing.table_name = "prefix_awesome_things_suffix"
|
1700
|
+
|
1701
|
+
assert_equal "hello world", Thing.find(:first).content
|
1702
|
+
ensure
|
1703
|
+
ActiveRecord::Base.table_name_prefix = ''
|
1704
|
+
ActiveRecord::Base.table_name_suffix = ''
|
1705
|
+
Thing.reset_table_name
|
1706
|
+
Thing.reset_sequence_name
|
1707
|
+
end
|
1708
|
+
|
1558
1709
|
def test_add_drop_table_with_prefix_and_suffix
|
1559
1710
|
assert !Reminder.table_exists?
|
1560
1711
|
ActiveRecord::Base.table_name_prefix = 'prefix_'
|
@@ -1660,86 +1811,7 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
1660
1811
|
|
1661
1812
|
end
|
1662
1813
|
|
1663
|
-
class SexyMigrationsTest < ActiveRecord::TestCase
|
1664
|
-
def test_references_column_type_adds_id
|
1665
|
-
with_new_table do |t|
|
1666
|
-
t.expects(:column).with('customer_id', :integer, {})
|
1667
|
-
t.references :customer
|
1668
|
-
end
|
1669
|
-
end
|
1670
|
-
|
1671
|
-
def test_references_column_type_with_polymorphic_adds_type
|
1672
|
-
with_new_table do |t|
|
1673
|
-
t.expects(:column).with('taggable_type', :string, {})
|
1674
|
-
t.expects(:column).with('taggable_id', :integer, {})
|
1675
|
-
t.references :taggable, :polymorphic => true
|
1676
|
-
end
|
1677
|
-
end
|
1678
|
-
|
1679
|
-
def test_references_column_type_with_polymorphic_and_options_null_is_false_adds_table_flag
|
1680
|
-
with_new_table do |t|
|
1681
|
-
t.expects(:column).with('taggable_type', :string, {:null => false})
|
1682
|
-
t.expects(:column).with('taggable_id', :integer, {:null => false})
|
1683
|
-
t.references :taggable, :polymorphic => true, :null => false
|
1684
|
-
end
|
1685
|
-
end
|
1686
|
-
|
1687
|
-
def test_belongs_to_works_like_references
|
1688
|
-
with_new_table do |t|
|
1689
|
-
t.expects(:column).with('customer_id', :integer, {})
|
1690
|
-
t.belongs_to :customer
|
1691
|
-
end
|
1692
|
-
end
|
1693
|
-
|
1694
|
-
def test_timestamps_creates_updated_at_and_created_at
|
1695
|
-
with_new_table do |t|
|
1696
|
-
t.expects(:column).with(:created_at, :datetime, kind_of(Hash))
|
1697
|
-
t.expects(:column).with(:updated_at, :datetime, kind_of(Hash))
|
1698
|
-
t.timestamps
|
1699
|
-
end
|
1700
|
-
end
|
1701
|
-
|
1702
|
-
def test_integer_creates_integer_column
|
1703
|
-
with_new_table do |t|
|
1704
|
-
t.expects(:column).with(:foo, 'integer', {})
|
1705
|
-
t.expects(:column).with(:bar, 'integer', {})
|
1706
|
-
t.integer :foo, :bar
|
1707
|
-
end
|
1708
|
-
end
|
1709
|
-
|
1710
|
-
def test_string_creates_string_column
|
1711
|
-
with_new_table do |t|
|
1712
|
-
t.expects(:column).with(:foo, 'string', {})
|
1713
|
-
t.expects(:column).with(:bar, 'string', {})
|
1714
|
-
t.string :foo, :bar
|
1715
|
-
end
|
1716
|
-
end
|
1717
|
-
|
1718
|
-
if current_adapter?(:PostgreSQLAdapter)
|
1719
|
-
def test_xml_creates_xml_column
|
1720
|
-
with_new_table do |t|
|
1721
|
-
t.expects(:column).with(:data, 'xml', {})
|
1722
|
-
t.xml :data
|
1723
|
-
end
|
1724
|
-
end
|
1725
|
-
end
|
1726
|
-
|
1727
|
-
protected
|
1728
|
-
def with_new_table
|
1729
|
-
Person.connection.create_table :delete_me, :force => true do |t|
|
1730
|
-
yield t
|
1731
|
-
end
|
1732
|
-
ensure
|
1733
|
-
Person.connection.drop_table :delete_me rescue nil
|
1734
|
-
end
|
1735
|
-
|
1736
|
-
end # SexyMigrationsTest
|
1737
|
-
|
1738
1814
|
class MigrationLoggerTest < ActiveRecord::TestCase
|
1739
|
-
def setup
|
1740
|
-
Object.send(:remove_const, :InnocentJointable)
|
1741
|
-
end
|
1742
|
-
|
1743
1815
|
def test_migration_should_be_run_without_logger
|
1744
1816
|
previous_logger = ActiveRecord::Base.logger
|
1745
1817
|
ActiveRecord::Base.logger = nil
|
@@ -1752,10 +1824,6 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
1752
1824
|
end
|
1753
1825
|
|
1754
1826
|
class InterleavedMigrationsTest < ActiveRecord::TestCase
|
1755
|
-
def setup
|
1756
|
-
Object.send(:remove_const, :PeopleHaveLastNames)
|
1757
|
-
end
|
1758
|
-
|
1759
1827
|
def test_migrator_interleaved_migrations
|
1760
1828
|
ActiveRecord::Migrator.up(MIGRATIONS_ROOT + "/interleaved/pass_1")
|
1761
1829
|
|
@@ -1766,10 +1834,12 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
1766
1834
|
Person.reset_column_information
|
1767
1835
|
assert Person.column_methods_hash.include?(:last_name)
|
1768
1836
|
|
1769
|
-
Object.send(:remove_const, :PeopleHaveLastNames)
|
1770
|
-
Object.send(:remove_const, :InnocentJointable)
|
1771
1837
|
assert_nothing_raised do
|
1772
|
-
ActiveRecord::Migrator.down(
|
1838
|
+
proxies = ActiveRecord::Migrator.down(
|
1839
|
+
MIGRATIONS_ROOT + "/interleaved/pass_3")
|
1840
|
+
names = proxies.map(&:name)
|
1841
|
+
assert names.include?('InterleavedPeopleHaveLastNames')
|
1842
|
+
assert names.include?('InterleavedInnocentJointable')
|
1773
1843
|
end
|
1774
1844
|
end
|
1775
1845
|
end
|
@@ -2010,5 +2080,329 @@ if ActiveRecord::Base.connection.supports_migrations?
|
|
2010
2080
|
end
|
2011
2081
|
end
|
2012
2082
|
end
|
2013
|
-
end
|
2014
2083
|
|
2084
|
+
if ActiveRecord::Base.connection.supports_bulk_alter?
|
2085
|
+
class BulkAlterTableMigrationsTest < ActiveRecord::TestCase
|
2086
|
+
def setup
|
2087
|
+
@connection = Person.connection
|
2088
|
+
@connection.create_table(:delete_me, :force => true) {|t| }
|
2089
|
+
end
|
2090
|
+
|
2091
|
+
def teardown
|
2092
|
+
Person.connection.drop_table(:delete_me) rescue nil
|
2093
|
+
end
|
2094
|
+
|
2095
|
+
def test_adding_multiple_columns
|
2096
|
+
assert_queries(1) do
|
2097
|
+
with_bulk_change_table do |t|
|
2098
|
+
t.column :name, :string
|
2099
|
+
t.string :qualification, :experience
|
2100
|
+
t.integer :age, :default => 0
|
2101
|
+
t.date :birthdate
|
2102
|
+
t.timestamps
|
2103
|
+
end
|
2104
|
+
end
|
2105
|
+
|
2106
|
+
assert_equal 8, columns.size
|
2107
|
+
[:name, :qualification, :experience].each {|s| assert_equal :string, column(s).type }
|
2108
|
+
assert_equal 0, column(:age).default
|
2109
|
+
end
|
2110
|
+
|
2111
|
+
def test_removing_columns
|
2112
|
+
with_bulk_change_table do |t|
|
2113
|
+
t.string :qualification, :experience
|
2114
|
+
end
|
2115
|
+
|
2116
|
+
[:qualification, :experience].each {|c| assert column(c) }
|
2117
|
+
|
2118
|
+
assert_queries(1) do
|
2119
|
+
with_bulk_change_table do |t|
|
2120
|
+
t.remove :qualification, :experience
|
2121
|
+
t.string :qualification_experience
|
2122
|
+
end
|
2123
|
+
end
|
2124
|
+
|
2125
|
+
[:qualification, :experience].each {|c| assert ! column(c) }
|
2126
|
+
assert column(:qualification_experience)
|
2127
|
+
end
|
2128
|
+
|
2129
|
+
def test_adding_indexes
|
2130
|
+
with_bulk_change_table do |t|
|
2131
|
+
t.string :username
|
2132
|
+
t.string :name
|
2133
|
+
t.integer :age
|
2134
|
+
end
|
2135
|
+
|
2136
|
+
# Adding an index fires a query every time to check if an index already exists or not
|
2137
|
+
assert_queries(3) do
|
2138
|
+
with_bulk_change_table do |t|
|
2139
|
+
t.index :username, :unique => true, :name => :awesome_username_index
|
2140
|
+
t.index [:name, :age]
|
2141
|
+
end
|
2142
|
+
end
|
2143
|
+
|
2144
|
+
assert_equal 2, indexes.size
|
2145
|
+
|
2146
|
+
name_age_index = index(:index_delete_me_on_name_and_age)
|
2147
|
+
assert_equal ['name', 'age'].sort, name_age_index.columns.sort
|
2148
|
+
assert ! name_age_index.unique
|
2149
|
+
|
2150
|
+
assert index(:awesome_username_index).unique
|
2151
|
+
end
|
2152
|
+
|
2153
|
+
def test_removing_index
|
2154
|
+
with_bulk_change_table do |t|
|
2155
|
+
t.string :name
|
2156
|
+
t.index :name
|
2157
|
+
end
|
2158
|
+
|
2159
|
+
assert index(:index_delete_me_on_name)
|
2160
|
+
|
2161
|
+
assert_queries(3) do
|
2162
|
+
with_bulk_change_table do |t|
|
2163
|
+
t.remove_index :name
|
2164
|
+
t.index :name, :name => :new_name_index, :unique => true
|
2165
|
+
end
|
2166
|
+
end
|
2167
|
+
|
2168
|
+
assert ! index(:index_delete_me_on_name)
|
2169
|
+
|
2170
|
+
new_name_index = index(:new_name_index)
|
2171
|
+
assert new_name_index.unique
|
2172
|
+
end
|
2173
|
+
|
2174
|
+
def test_changing_columns
|
2175
|
+
with_bulk_change_table do |t|
|
2176
|
+
t.string :name
|
2177
|
+
t.date :birthdate
|
2178
|
+
end
|
2179
|
+
|
2180
|
+
assert ! column(:name).default
|
2181
|
+
assert_equal :date, column(:birthdate).type
|
2182
|
+
|
2183
|
+
# One query for columns (delete_me table)
|
2184
|
+
# One query for primary key (delete_me table)
|
2185
|
+
# One query to do the bulk change
|
2186
|
+
assert_queries(3) do
|
2187
|
+
with_bulk_change_table do |t|
|
2188
|
+
t.change :name, :string, :default => 'NONAME'
|
2189
|
+
t.change :birthdate, :datetime
|
2190
|
+
end
|
2191
|
+
end
|
2192
|
+
|
2193
|
+
assert_equal 'NONAME', column(:name).default
|
2194
|
+
assert_equal :datetime, column(:birthdate).type
|
2195
|
+
end
|
2196
|
+
|
2197
|
+
protected
|
2198
|
+
|
2199
|
+
def with_bulk_change_table
|
2200
|
+
# Reset columns/indexes cache as we're changing the table
|
2201
|
+
@columns = @indexes = nil
|
2202
|
+
|
2203
|
+
Person.connection.change_table(:delete_me, :bulk => true) do |t|
|
2204
|
+
yield t
|
2205
|
+
end
|
2206
|
+
end
|
2207
|
+
|
2208
|
+
def column(name)
|
2209
|
+
columns.detect {|c| c.name == name.to_s }
|
2210
|
+
end
|
2211
|
+
|
2212
|
+
def columns
|
2213
|
+
@columns ||= Person.connection.columns('delete_me')
|
2214
|
+
end
|
2215
|
+
|
2216
|
+
def index(name)
|
2217
|
+
indexes.detect {|i| i.name == name.to_s }
|
2218
|
+
end
|
2219
|
+
|
2220
|
+
def indexes
|
2221
|
+
@indexes ||= Person.connection.indexes('delete_me')
|
2222
|
+
end
|
2223
|
+
end # AlterTableMigrationsTest
|
2224
|
+
|
2225
|
+
end
|
2226
|
+
|
2227
|
+
class CopyMigrationsTest < ActiveRecord::TestCase
|
2228
|
+
def setup
|
2229
|
+
end
|
2230
|
+
|
2231
|
+
def clear
|
2232
|
+
ActiveRecord::Base.timestamped_migrations = true
|
2233
|
+
to_delete = Dir[@migrations_path + "/*.rb"] - @existing_migrations
|
2234
|
+
File.delete(*to_delete)
|
2235
|
+
end
|
2236
|
+
|
2237
|
+
def test_copying_migrations_without_timestamps
|
2238
|
+
ActiveRecord::Base.timestamped_migrations = false
|
2239
|
+
@migrations_path = MIGRATIONS_ROOT + "/valid"
|
2240
|
+
@existing_migrations = Dir[@migrations_path + "/*.rb"]
|
2241
|
+
|
2242
|
+
copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy"})
|
2243
|
+
assert File.exists?(@migrations_path + "/4_people_have_hobbies.bukkits.rb")
|
2244
|
+
assert File.exists?(@migrations_path + "/5_people_have_descriptions.bukkits.rb")
|
2245
|
+
assert_equal [@migrations_path + "/4_people_have_hobbies.bukkits.rb", @migrations_path + "/5_people_have_descriptions.bukkits.rb"], copied.map(&:filename)
|
2246
|
+
|
2247
|
+
expected = "# This migration comes from bukkits (originally 1)"
|
2248
|
+
assert_equal expected, IO.readlines(@migrations_path + "/4_people_have_hobbies.bukkits.rb")[0].chomp
|
2249
|
+
|
2250
|
+
files_count = Dir[@migrations_path + "/*.rb"].length
|
2251
|
+
copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy"})
|
2252
|
+
assert_equal files_count, Dir[@migrations_path + "/*.rb"].length
|
2253
|
+
assert copied.empty?
|
2254
|
+
ensure
|
2255
|
+
clear
|
2256
|
+
end
|
2257
|
+
|
2258
|
+
def test_copying_migrations_without_timestamps_from_2_sources
|
2259
|
+
ActiveRecord::Base.timestamped_migrations = false
|
2260
|
+
@migrations_path = MIGRATIONS_ROOT + "/valid"
|
2261
|
+
@existing_migrations = Dir[@migrations_path + "/*.rb"]
|
2262
|
+
|
2263
|
+
sources = ActiveSupport::OrderedHash.new
|
2264
|
+
sources[:bukkits] = MIGRATIONS_ROOT + "/to_copy"
|
2265
|
+
sources[:omg] = MIGRATIONS_ROOT + "/to_copy2"
|
2266
|
+
ActiveRecord::Migration.copy(@migrations_path, sources)
|
2267
|
+
assert File.exists?(@migrations_path + "/4_people_have_hobbies.bukkits.rb")
|
2268
|
+
assert File.exists?(@migrations_path + "/5_people_have_descriptions.bukkits.rb")
|
2269
|
+
assert File.exists?(@migrations_path + "/6_create_articles.omg.rb")
|
2270
|
+
assert File.exists?(@migrations_path + "/7_create_comments.omg.rb")
|
2271
|
+
|
2272
|
+
files_count = Dir[@migrations_path + "/*.rb"].length
|
2273
|
+
ActiveRecord::Migration.copy(@migrations_path, sources)
|
2274
|
+
assert_equal files_count, Dir[@migrations_path + "/*.rb"].length
|
2275
|
+
ensure
|
2276
|
+
clear
|
2277
|
+
end
|
2278
|
+
|
2279
|
+
def test_copying_migrations_with_timestamps
|
2280
|
+
@migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps"
|
2281
|
+
@existing_migrations = Dir[@migrations_path + "/*.rb"]
|
2282
|
+
|
2283
|
+
Time.travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do
|
2284
|
+
copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
|
2285
|
+
assert File.exists?(@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb")
|
2286
|
+
assert File.exists?(@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb")
|
2287
|
+
expected = [@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb",
|
2288
|
+
@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb"]
|
2289
|
+
assert_equal expected, copied.map(&:filename)
|
2290
|
+
|
2291
|
+
files_count = Dir[@migrations_path + "/*.rb"].length
|
2292
|
+
copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
|
2293
|
+
assert_equal files_count, Dir[@migrations_path + "/*.rb"].length
|
2294
|
+
assert copied.empty?
|
2295
|
+
end
|
2296
|
+
ensure
|
2297
|
+
clear
|
2298
|
+
end
|
2299
|
+
|
2300
|
+
def test_copying_migrations_with_timestamps_from_2_sources
|
2301
|
+
@migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps"
|
2302
|
+
@existing_migrations = Dir[@migrations_path + "/*.rb"]
|
2303
|
+
|
2304
|
+
sources = ActiveSupport::OrderedHash.new
|
2305
|
+
sources[:bukkits] = MIGRATIONS_ROOT + "/to_copy_with_timestamps"
|
2306
|
+
sources[:omg] = MIGRATIONS_ROOT + "/to_copy_with_timestamps2"
|
2307
|
+
|
2308
|
+
Time.travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do
|
2309
|
+
copied = ActiveRecord::Migration.copy(@migrations_path, sources)
|
2310
|
+
assert File.exists?(@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb")
|
2311
|
+
assert File.exists?(@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb")
|
2312
|
+
assert File.exists?(@migrations_path + "/20100726101012_create_articles.omg.rb")
|
2313
|
+
assert File.exists?(@migrations_path + "/20100726101013_create_comments.omg.rb")
|
2314
|
+
assert_equal 4, copied.length
|
2315
|
+
|
2316
|
+
files_count = Dir[@migrations_path + "/*.rb"].length
|
2317
|
+
ActiveRecord::Migration.copy(@migrations_path, sources)
|
2318
|
+
assert_equal files_count, Dir[@migrations_path + "/*.rb"].length
|
2319
|
+
end
|
2320
|
+
ensure
|
2321
|
+
clear
|
2322
|
+
end
|
2323
|
+
|
2324
|
+
def test_copying_migrations_with_timestamps_to_destination_with_timestamps_in_future
|
2325
|
+
@migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps"
|
2326
|
+
@existing_migrations = Dir[@migrations_path + "/*.rb"]
|
2327
|
+
|
2328
|
+
Time.travel_to(Time.utc(2010, 2, 20, 10, 10, 10)) do
|
2329
|
+
ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
|
2330
|
+
assert File.exists?(@migrations_path + "/20100301010102_people_have_hobbies.bukkits.rb")
|
2331
|
+
assert File.exists?(@migrations_path + "/20100301010103_people_have_descriptions.bukkits.rb")
|
2332
|
+
|
2333
|
+
files_count = Dir[@migrations_path + "/*.rb"].length
|
2334
|
+
copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
|
2335
|
+
assert_equal files_count, Dir[@migrations_path + "/*.rb"].length
|
2336
|
+
assert copied.empty?
|
2337
|
+
end
|
2338
|
+
ensure
|
2339
|
+
clear
|
2340
|
+
end
|
2341
|
+
|
2342
|
+
def test_skipping_migrations
|
2343
|
+
@migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps"
|
2344
|
+
@existing_migrations = Dir[@migrations_path + "/*.rb"]
|
2345
|
+
|
2346
|
+
sources = ActiveSupport::OrderedHash.new
|
2347
|
+
sources[:bukkits] = MIGRATIONS_ROOT + "/to_copy_with_timestamps"
|
2348
|
+
sources[:omg] = MIGRATIONS_ROOT + "/to_copy_with_name_collision"
|
2349
|
+
|
2350
|
+
skipped = []
|
2351
|
+
on_skip = Proc.new { |name, migration| skipped << "#{name} #{migration.name}" }
|
2352
|
+
copied = ActiveRecord::Migration.copy(@migrations_path, sources, :on_skip => on_skip)
|
2353
|
+
assert_equal 2, copied.length
|
2354
|
+
|
2355
|
+
assert_equal 1, skipped.length
|
2356
|
+
assert_equal ["omg PeopleHaveHobbies"], skipped
|
2357
|
+
ensure
|
2358
|
+
clear
|
2359
|
+
end
|
2360
|
+
|
2361
|
+
def test_skip_is_not_called_if_migrations_are_from_the_same_plugin
|
2362
|
+
@migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps"
|
2363
|
+
@existing_migrations = Dir[@migrations_path + "/*.rb"]
|
2364
|
+
|
2365
|
+
sources = ActiveSupport::OrderedHash.new
|
2366
|
+
sources[:bukkits] = MIGRATIONS_ROOT + "/to_copy_with_timestamps"
|
2367
|
+
|
2368
|
+
skipped = []
|
2369
|
+
on_skip = Proc.new { |name, migration| skipped << "#{name} #{migration.name}" }
|
2370
|
+
copied = ActiveRecord::Migration.copy(@migrations_path, sources, :on_skip => on_skip)
|
2371
|
+
ActiveRecord::Migration.copy(@migrations_path, sources, :on_skip => on_skip)
|
2372
|
+
|
2373
|
+
assert_equal 2, copied.length
|
2374
|
+
assert_equal 0, skipped.length
|
2375
|
+
ensure
|
2376
|
+
clear
|
2377
|
+
end
|
2378
|
+
|
2379
|
+
def test_copying_migrations_to_non_existing_directory
|
2380
|
+
@migrations_path = MIGRATIONS_ROOT + "/non_existing"
|
2381
|
+
@existing_migrations = []
|
2382
|
+
|
2383
|
+
Time.travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do
|
2384
|
+
copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
|
2385
|
+
assert File.exists?(@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb")
|
2386
|
+
assert File.exists?(@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb")
|
2387
|
+
assert_equal 2, copied.length
|
2388
|
+
end
|
2389
|
+
ensure
|
2390
|
+
clear
|
2391
|
+
Dir.delete(@migrations_path)
|
2392
|
+
end
|
2393
|
+
|
2394
|
+
def test_copying_migrations_to_empty_directory
|
2395
|
+
@migrations_path = MIGRATIONS_ROOT + "/empty"
|
2396
|
+
@existing_migrations = []
|
2397
|
+
|
2398
|
+
Time.travel_to(Time.utc(2010, 7, 26, 10, 10, 10)) do
|
2399
|
+
copied = ActiveRecord::Migration.copy(@migrations_path, {:bukkits => MIGRATIONS_ROOT + "/to_copy_with_timestamps"})
|
2400
|
+
assert File.exists?(@migrations_path + "/20100726101010_people_have_hobbies.bukkits.rb")
|
2401
|
+
assert File.exists?(@migrations_path + "/20100726101011_people_have_descriptions.bukkits.rb")
|
2402
|
+
assert_equal 2, copied.length
|
2403
|
+
end
|
2404
|
+
ensure
|
2405
|
+
clear
|
2406
|
+
end
|
2407
|
+
end
|
2408
|
+
end
|