ardm-migrations 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +35 -0
  3. data/.travis.yml +11 -0
  4. data/Gemfile +53 -0
  5. data/LICENSE +20 -0
  6. data/README.rdoc +39 -0
  7. data/Rakefile +4 -0
  8. data/ardm-migrations.gemspec +27 -0
  9. data/db/migrations/1_create_people_table.rb +12 -0
  10. data/db/migrations/2_add_dob_to_people.rb +13 -0
  11. data/db/migrations/config.rb +4 -0
  12. data/examples/Rakefile +144 -0
  13. data/examples/sample_migration.rb +58 -0
  14. data/examples/sample_migration_spec.rb +50 -0
  15. data/lib/ardm-migrations.rb +1 -0
  16. data/lib/dm-migrations/adapters/dm-do-adapter.rb +295 -0
  17. data/lib/dm-migrations/adapters/dm-mysql-adapter.rb +299 -0
  18. data/lib/dm-migrations/adapters/dm-oracle-adapter.rb +332 -0
  19. data/lib/dm-migrations/adapters/dm-postgres-adapter.rb +159 -0
  20. data/lib/dm-migrations/adapters/dm-sqlite-adapter.rb +96 -0
  21. data/lib/dm-migrations/adapters/dm-sqlserver-adapter.rb +177 -0
  22. data/lib/dm-migrations/adapters/dm-yaml-adapter.rb +23 -0
  23. data/lib/dm-migrations/auto_migration.rb +239 -0
  24. data/lib/dm-migrations/exceptions/duplicate_migration.rb +6 -0
  25. data/lib/dm-migrations/migration.rb +300 -0
  26. data/lib/dm-migrations/migration_runner.rb +85 -0
  27. data/lib/dm-migrations/sql/column.rb +5 -0
  28. data/lib/dm-migrations/sql/mysql.rb +61 -0
  29. data/lib/dm-migrations/sql/postgres.rb +82 -0
  30. data/lib/dm-migrations/sql/sqlite.rb +51 -0
  31. data/lib/dm-migrations/sql/table.rb +15 -0
  32. data/lib/dm-migrations/sql/table_creator.rb +109 -0
  33. data/lib/dm-migrations/sql/table_modifier.rb +57 -0
  34. data/lib/dm-migrations/sql.rb +5 -0
  35. data/lib/dm-migrations/version.rb +5 -0
  36. data/lib/dm-migrations.rb +3 -0
  37. data/lib/spec/example/migration_example_group.rb +73 -0
  38. data/lib/spec/matchers/migration_matchers.rb +106 -0
  39. data/spec/integration/auto_migration_spec.rb +553 -0
  40. data/spec/integration/auto_upgrade_spec.rb +40 -0
  41. data/spec/integration/migration_runner_spec.rb +89 -0
  42. data/spec/integration/migration_spec.rb +157 -0
  43. data/spec/integration/sql_spec.rb +250 -0
  44. data/spec/isolated/require_after_setup_spec.rb +30 -0
  45. data/spec/isolated/require_before_setup_spec.rb +30 -0
  46. data/spec/isolated/require_spec.rb +25 -0
  47. data/spec/rcov.opts +6 -0
  48. data/spec/spec.opts +4 -0
  49. data/spec/spec_helper.rb +18 -0
  50. data/spec/unit/migration_spec.rb +453 -0
  51. data/spec/unit/sql/column_spec.rb +14 -0
  52. data/spec/unit/sql/postgres_spec.rb +97 -0
  53. data/spec/unit/sql/sqlite_extensions_spec.rb +108 -0
  54. data/spec/unit/sql/table_creator_spec.rb +94 -0
  55. data/spec/unit/sql/table_modifier_spec.rb +49 -0
  56. data/spec/unit/sql/table_spec.rb +28 -0
  57. data/spec/unit/sql_spec.rb +7 -0
  58. data/tasks/spec.rake +38 -0
  59. data/tasks/yard.rake +9 -0
  60. data/tasks/yardstick.rake +19 -0
  61. metadata +150 -0
@@ -0,0 +1,553 @@
1
+ require 'spec_helper'
2
+
3
+ require 'dm-migrations/auto_migration'
4
+
5
+ describe DataMapper::Migrations do
6
+ def capture_log(mod)
7
+ original, mod.logger = mod.logger, DataObjects::Logger.new(@log = StringIO.new, :debug)
8
+ yield
9
+ ensure
10
+ @log.rewind
11
+ @output = @log.readlines.map do |line|
12
+ line.chomp.gsub(/\A.+?~ \(\d+\.?\d*\)\s+/, '')
13
+ end
14
+
15
+ mod.logger = original
16
+ end
17
+
18
+ before :all do
19
+ class DataMapper::Property::NumericString < DataMapper::Property::String
20
+ default 0
21
+
22
+ def dump(value)
23
+ return if value.nil?
24
+ value.to_s
25
+ end
26
+ end
27
+ end
28
+
29
+ supported_by :mysql do
30
+ before :all do
31
+ module ::Blog
32
+ class Article
33
+ include DataMapper::Resource
34
+ end
35
+ end
36
+
37
+ @model = ::Blog::Article
38
+ end
39
+
40
+ describe '#auto_migrate' do
41
+ describe 'Integer property' do
42
+ [
43
+ [ 0, 1, 'TINYINT(1) UNSIGNED' ],
44
+ [ 0, 9, 'TINYINT(1) UNSIGNED' ],
45
+ [ 0, 10, 'TINYINT(2) UNSIGNED' ],
46
+ [ 0, 99, 'TINYINT(2) UNSIGNED' ],
47
+ [ 0, 100, 'TINYINT(3) UNSIGNED' ],
48
+ [ 0, 255, 'TINYINT(3) UNSIGNED' ],
49
+ [ 0, 256, 'SMALLINT(3) UNSIGNED' ],
50
+ [ 0, 999, 'SMALLINT(3) UNSIGNED' ],
51
+ [ 0, 1000, 'SMALLINT(4) UNSIGNED' ],
52
+ [ 0, 9999, 'SMALLINT(4) UNSIGNED' ],
53
+ [ 0, 10000, 'SMALLINT(5) UNSIGNED' ],
54
+ [ 0, 65535, 'SMALLINT(5) UNSIGNED' ],
55
+ [ 0, 65536, 'MEDIUMINT(5) UNSIGNED' ],
56
+ [ 0, 99999, 'MEDIUMINT(5) UNSIGNED' ],
57
+ [ 0, 100000, 'MEDIUMINT(6) UNSIGNED' ],
58
+ [ 0, 999999, 'MEDIUMINT(6) UNSIGNED' ],
59
+ [ 0, 1000000, 'MEDIUMINT(7) UNSIGNED' ],
60
+ [ 0, 9999999, 'MEDIUMINT(7) UNSIGNED' ],
61
+ [ 0, 10000000, 'MEDIUMINT(8) UNSIGNED' ],
62
+ [ 0, 16777215, 'MEDIUMINT(8) UNSIGNED' ],
63
+ [ 0, 16777216, 'INT(8) UNSIGNED' ],
64
+ [ 0, 99999999, 'INT(8) UNSIGNED' ],
65
+ [ 0, 100000000, 'INT(9) UNSIGNED' ],
66
+ [ 0, 999999999, 'INT(9) UNSIGNED' ],
67
+ [ 0, 1000000000, 'INT(10) UNSIGNED' ],
68
+ [ 0, 4294967295, 'INT(10) UNSIGNED' ],
69
+ [ 0, 4294967296, 'BIGINT(10) UNSIGNED' ],
70
+ [ 0, 9999999999, 'BIGINT(10) UNSIGNED' ],
71
+ [ 0, 10000000000, 'BIGINT(11) UNSIGNED' ],
72
+ [ 0, 99999999999, 'BIGINT(11) UNSIGNED' ],
73
+ [ 0, 100000000000, 'BIGINT(12) UNSIGNED' ],
74
+ [ 0, 999999999999, 'BIGINT(12) UNSIGNED' ],
75
+ [ 0, 1000000000000, 'BIGINT(13) UNSIGNED' ],
76
+ [ 0, 9999999999999, 'BIGINT(13) UNSIGNED' ],
77
+ [ 0, 10000000000000, 'BIGINT(14) UNSIGNED' ],
78
+ [ 0, 99999999999999, 'BIGINT(14) UNSIGNED' ],
79
+ [ 0, 100000000000000, 'BIGINT(15) UNSIGNED' ],
80
+ [ 0, 999999999999999, 'BIGINT(15) UNSIGNED' ],
81
+ [ 0, 1000000000000000, 'BIGINT(16) UNSIGNED' ],
82
+ [ 0, 9999999999999999, 'BIGINT(16) UNSIGNED' ],
83
+ [ 0, 10000000000000000, 'BIGINT(17) UNSIGNED' ],
84
+ [ 0, 99999999999999999, 'BIGINT(17) UNSIGNED' ],
85
+ [ 0, 100000000000000000, 'BIGINT(18) UNSIGNED' ],
86
+ [ 0, 999999999999999999, 'BIGINT(18) UNSIGNED' ],
87
+ [ 0, 1000000000000000000, 'BIGINT(19) UNSIGNED' ],
88
+ [ 0, 9999999999999999999, 'BIGINT(19) UNSIGNED' ],
89
+ [ 0, 10000000000000000000, 'BIGINT(20) UNSIGNED' ],
90
+ [ 0, 18446744073709551615, 'BIGINT(20) UNSIGNED' ],
91
+
92
+ [ -1, 0, 'TINYINT(2)' ],
93
+ [ -1, 9, 'TINYINT(2)' ],
94
+ [ -1, 10, 'TINYINT(2)' ],
95
+ [ -1, 99, 'TINYINT(2)' ],
96
+ [ -1, 100, 'TINYINT(3)' ],
97
+ [ -1, 127, 'TINYINT(3)' ],
98
+ [ -1, 128, 'SMALLINT(3)' ],
99
+ [ -1, 999, 'SMALLINT(3)' ],
100
+ [ -1, 1000, 'SMALLINT(4)' ],
101
+ [ -1, 9999, 'SMALLINT(4)' ],
102
+ [ -1, 10000, 'SMALLINT(5)' ],
103
+ [ -1, 32767, 'SMALLINT(5)' ],
104
+ [ -1, 32768, 'MEDIUMINT(5)' ],
105
+ [ -1, 99999, 'MEDIUMINT(5)' ],
106
+ [ -1, 100000, 'MEDIUMINT(6)' ],
107
+ [ -1, 999999, 'MEDIUMINT(6)' ],
108
+ [ -1, 1000000, 'MEDIUMINT(7)' ],
109
+ [ -1, 8388607, 'MEDIUMINT(7)' ],
110
+ [ -1, 8388608, 'INT(7)' ],
111
+ [ -1, 9999999, 'INT(7)' ],
112
+ [ -1, 10000000, 'INT(8)' ],
113
+ [ -1, 99999999, 'INT(8)' ],
114
+ [ -1, 100000000, 'INT(9)' ],
115
+ [ -1, 999999999, 'INT(9)' ],
116
+ [ -1, 1000000000, 'INT(10)' ],
117
+ [ -1, 2147483647, 'INT(10)' ],
118
+ [ -1, 2147483648, 'BIGINT(10)' ],
119
+ [ -1, 9999999999, 'BIGINT(10)' ],
120
+ [ -1, 10000000000, 'BIGINT(11)' ],
121
+ [ -1, 99999999999, 'BIGINT(11)' ],
122
+ [ -1, 100000000000, 'BIGINT(12)' ],
123
+ [ -1, 999999999999, 'BIGINT(12)' ],
124
+ [ -1, 1000000000000, 'BIGINT(13)' ],
125
+ [ -1, 9999999999999, 'BIGINT(13)' ],
126
+ [ -1, 10000000000000, 'BIGINT(14)' ],
127
+ [ -1, 99999999999999, 'BIGINT(14)' ],
128
+ [ -1, 100000000000000, 'BIGINT(15)' ],
129
+ [ -1, 999999999999999, 'BIGINT(15)' ],
130
+ [ -1, 1000000000000000, 'BIGINT(16)' ],
131
+ [ -1, 9999999999999999, 'BIGINT(16)' ],
132
+ [ -1, 10000000000000000, 'BIGINT(17)' ],
133
+ [ -1, 99999999999999999, 'BIGINT(17)' ],
134
+ [ -1, 100000000000000000, 'BIGINT(18)' ],
135
+ [ -1, 999999999999999999, 'BIGINT(18)' ],
136
+ [ -1, 1000000000000000000, 'BIGINT(19)' ],
137
+ [ -1, 9223372036854775807, 'BIGINT(19)' ],
138
+
139
+ [ -1, 0, 'TINYINT(2)' ],
140
+ [ -9, 0, 'TINYINT(2)' ],
141
+ [ -10, 0, 'TINYINT(3)' ],
142
+ [ -99, 0, 'TINYINT(3)' ],
143
+ [ -100, 0, 'TINYINT(4)' ],
144
+ [ -128, 0, 'TINYINT(4)' ],
145
+ [ -129, 0, 'SMALLINT(4)' ],
146
+ [ -999, 0, 'SMALLINT(4)' ],
147
+ [ -1000, 0, 'SMALLINT(5)' ],
148
+ [ -9999, 0, 'SMALLINT(5)' ],
149
+ [ -10000, 0, 'SMALLINT(6)' ],
150
+ [ -32768, 0, 'SMALLINT(6)' ],
151
+ [ -32769, 0, 'MEDIUMINT(6)' ],
152
+ [ -99999, 0, 'MEDIUMINT(6)' ],
153
+ [ -100000, 0, 'MEDIUMINT(7)' ],
154
+ [ -999999, 0, 'MEDIUMINT(7)' ],
155
+ [ -1000000, 0, 'MEDIUMINT(8)' ],
156
+ [ -8388608, 0, 'MEDIUMINT(8)' ],
157
+ [ -8388609, 0, 'INT(8)' ],
158
+ [ -9999999, 0, 'INT(8)' ],
159
+ [ -10000000, 0, 'INT(9)' ],
160
+ [ -99999999, 0, 'INT(9)' ],
161
+ [ -100000000, 0, 'INT(10)' ],
162
+ [ -999999999, 0, 'INT(10)' ],
163
+ [ -1000000000, 0, 'INT(11)' ],
164
+ [ -2147483648, 0, 'INT(11)' ],
165
+ [ -2147483649, 0, 'BIGINT(11)' ],
166
+ [ -9999999999, 0, 'BIGINT(11)' ],
167
+ [ -10000000000, 0, 'BIGINT(12)' ],
168
+ [ -99999999999, 0, 'BIGINT(12)' ],
169
+ [ -100000000000, 0, 'BIGINT(13)' ],
170
+ [ -999999999999, 0, 'BIGINT(13)' ],
171
+ [ -1000000000000, 0, 'BIGINT(14)' ],
172
+ [ -9999999999999, 0, 'BIGINT(14)' ],
173
+ [ -10000000000000, 0, 'BIGINT(15)' ],
174
+ [ -99999999999999, 0, 'BIGINT(15)' ],
175
+ [ -100000000000000, 0, 'BIGINT(16)' ],
176
+ [ -999999999999999, 0, 'BIGINT(16)' ],
177
+ [ -1000000000000000, 0, 'BIGINT(17)' ],
178
+ [ -9999999999999999, 0, 'BIGINT(17)' ],
179
+ [ -10000000000000000, 0, 'BIGINT(18)' ],
180
+ [ -99999999999999999, 0, 'BIGINT(18)' ],
181
+ [ -100000000000000000, 0, 'BIGINT(19)' ],
182
+ [ -999999999999999999, 0, 'BIGINT(19)' ],
183
+ [ -1000000000000000000, 0, 'BIGINT(20)' ],
184
+ [ -9223372036854775808, 0, 'BIGINT(20)' ],
185
+
186
+ [ nil, 2147483647, 'INT(10) UNSIGNED' ],
187
+ [ 0, nil, 'INT(10) UNSIGNED' ],
188
+ [ nil, nil, 'INTEGER' ],
189
+ ].each do |min, max, statement|
190
+ options = { :key => true }
191
+ options[:min] = min if min
192
+ options[:max] = max if max
193
+
194
+ describe "with a min of #{min} and a max of #{max}" do
195
+ before :all do
196
+ @property = @model.property(:id, Integer, options)
197
+
198
+ @response = capture_log(DataObjects::Mysql) { @model.auto_migrate! }
199
+ end
200
+
201
+ it 'should return true' do
202
+ @response.should be(true)
203
+ end
204
+
205
+ it "should create a #{statement} column" do
206
+ @output.last.should =~ %r{\ACREATE TABLE `blog_articles` \(`id` #{Regexp.escape(statement)} NOT NULL, PRIMARY KEY\(`id`\)\) ENGINE = InnoDB CHARACTER SET [a-z\d]+ COLLATE (?:[a-z\d](?:_?[a-z\d]+)*)\z}
207
+ end
208
+
209
+ [ :min, :max ].each do |key|
210
+ next unless value = options[key]
211
+ it "should allow the #{key} value #{value} to be stored" do
212
+ pending_if "#{value} causes problem with JRuby 1.5.2 parser", RUBY_PLATFORM[/java/] && JRUBY_VERSION < '1.5.6' && value == -9223372036854775808 do
213
+ lambda {
214
+ resource = @model.create(@property => value)
215
+ @model.first(@property => value).should == resource
216
+ }.should_not raise_error
217
+ end
218
+ end
219
+ end
220
+ end
221
+ end
222
+ end
223
+
224
+ describe 'Text property' do
225
+ before :all do
226
+ @model.property(:id, DataMapper::Property::Serial)
227
+ end
228
+
229
+ [
230
+ [ 0, 'TINYTEXT' ],
231
+ [ 1, 'TINYTEXT' ],
232
+ [ 255, 'TINYTEXT' ],
233
+ [ 256, 'TEXT' ],
234
+ [ 65535, 'TEXT' ],
235
+ [ 65536, 'MEDIUMTEXT' ],
236
+ [ 16777215, 'MEDIUMTEXT' ],
237
+ [ 16777216, 'LONGTEXT' ],
238
+ [ 4294967295, 'LONGTEXT' ],
239
+
240
+ [ nil, 'TEXT' ],
241
+ ].each do |length, statement|
242
+ options = {}
243
+ options[:length] = length if length
244
+
245
+ describe "with a length of #{length}" do
246
+ before :all do
247
+ @property = @model.property(:body, DataMapper::Property::Text, options)
248
+
249
+ @response = capture_log(DataObjects::Mysql) { @model.auto_migrate! }
250
+ end
251
+
252
+ it 'should return true' do
253
+ @response.should be(true)
254
+ end
255
+
256
+ it "should create a #{statement} column" do
257
+ @output.last.should =~ %r{\ACREATE TABLE `blog_articles` \(`id` INT\(10\) UNSIGNED NOT NULL AUTO_INCREMENT, `body` #{Regexp.escape(statement)}, PRIMARY KEY\(`id`\)\) ENGINE = InnoDB CHARACTER SET [a-z\d]+ COLLATE (?:[a-z\d](?:_?[a-z\d]+)*)\z}
258
+ end
259
+ end
260
+ end
261
+ end
262
+
263
+ describe 'String property' do
264
+ before :all do
265
+ @model.property(:id, DataMapper::Property::Serial)
266
+ end
267
+
268
+ [
269
+ [ 1, 'VARCHAR(1)' ],
270
+ [ 50, 'VARCHAR(50)' ],
271
+ [ 255, 'VARCHAR(255)' ],
272
+ [ nil, 'VARCHAR(50)' ],
273
+ ].each do |length, statement|
274
+ options = {}
275
+ options[:length] = length if length
276
+
277
+ describe "with a length of #{length}" do
278
+ before :all do
279
+ @property = @model.property(:title, String, options)
280
+
281
+ @response = capture_log(DataObjects::Mysql) { @model.auto_migrate! }
282
+ end
283
+
284
+ it 'should return true' do
285
+ @response.should be(true)
286
+ end
287
+
288
+ it "should create a #{statement} column" do
289
+ @output.last.should =~ %r{\ACREATE TABLE `blog_articles` \(`id` INT\(10\) UNSIGNED NOT NULL AUTO_INCREMENT, `title` #{Regexp.escape(statement)}, PRIMARY KEY\(`id`\)\) ENGINE = InnoDB CHARACTER SET [a-z\d]+ COLLATE (?:[a-z\d](?:_?[a-z\d]+)*)\z}
290
+ end
291
+ end
292
+ end
293
+ end
294
+
295
+ describe 'NumericString property' do
296
+ before :all do
297
+ @model.property(:id, DataMapper::Property::Serial)
298
+ @model.property(:number, DataMapper::Property::NumericString)
299
+
300
+ @response = capture_log(DataObjects::Mysql) { @model.auto_migrate! }
301
+ end
302
+
303
+ it "should create a VARCHAR(50) column with a default of '0'" do
304
+ @output.last.should =~ %r{\ACREATE TABLE `blog_articles` \(`id` INT\(10\) UNSIGNED NOT NULL AUTO_INCREMENT, `number` VARCHAR\(50\) DEFAULT '0', PRIMARY KEY\(`id`\)\) ENGINE = InnoDB CHARACTER SET [a-z\d]+ COLLATE (?:[a-z\d](?:_?[a-z\d]+)*)\z}
305
+ end
306
+ end
307
+ end
308
+ end
309
+
310
+ supported_by :postgres do
311
+ before :all do
312
+ module ::Blog
313
+ class Article
314
+ include DataMapper::Resource
315
+ end
316
+ end
317
+
318
+ @model = ::Blog::Article
319
+ end
320
+
321
+ describe '#auto_migrate' do
322
+ describe 'Integer property' do
323
+ [
324
+ [ 0, 1, 'SMALLINT' ],
325
+ [ 0, 32767, 'SMALLINT' ],
326
+ [ 0, 32768, 'INTEGER' ],
327
+ [ 0, 2147483647, 'INTEGER' ],
328
+ [ 0, 2147483648, 'BIGINT' ],
329
+ [ 0, 9223372036854775807, 'BIGINT' ],
330
+
331
+ [ -1, 1, 'SMALLINT' ],
332
+ [ -1, 32767, 'SMALLINT' ],
333
+ [ -1, 32768, 'INTEGER' ],
334
+ [ -1, 2147483647, 'INTEGER' ],
335
+ [ -1, 2147483648, 'BIGINT' ],
336
+ [ -1, 9223372036854775807, 'BIGINT' ],
337
+
338
+ [ -1, 0, 'SMALLINT' ],
339
+ [ -32768, 0, 'SMALLINT' ],
340
+ [ -32769, 0, 'INTEGER' ],
341
+ [ -2147483648, 0, 'INTEGER' ],
342
+ [ -2147483649, 0, 'BIGINT' ],
343
+ [ -9223372036854775808, 0, 'BIGINT' ],
344
+
345
+ [ nil, 2147483647, 'INTEGER' ],
346
+ [ 0, nil, 'INTEGER' ],
347
+ [ nil, nil, 'INTEGER' ],
348
+ ].each do |min, max, statement|
349
+ options = { :key => true }
350
+ options[:min] = min if min
351
+ options[:max] = max if max
352
+
353
+ describe "with a min of #{min} and a max of #{max}" do
354
+ before :all do
355
+ @property = @model.property(:id, Integer, options)
356
+
357
+ @response = capture_log(DataObjects::Postgres) { @model.auto_migrate! }
358
+ end
359
+
360
+ it 'should return true' do
361
+ @response.should be(true)
362
+ end
363
+
364
+ it "should create a #{statement} column" do
365
+ @output[-2].should == "CREATE TABLE \"blog_articles\" (\"id\" #{statement} NOT NULL, PRIMARY KEY(\"id\"))"
366
+ end
367
+
368
+ [ :min, :max ].each do |key|
369
+ next unless value = options[key]
370
+ it "should allow the #{key} value #{value} to be stored" do
371
+ pending_if "#{value} causes problem with the JRuby < 1.6 parser", RUBY_PLATFORM =~ /java/ && JRUBY_VERSION < '1.6' && value == -9223372036854775808 do
372
+ lambda {
373
+ resource = @model.create(@property => value)
374
+ @model.first(@property => value).should eql(resource)
375
+ }.should_not raise_error
376
+ end
377
+ end
378
+ end
379
+ end
380
+ end
381
+ end
382
+
383
+ describe 'Serial property' do
384
+ [
385
+ [ 1, 'SERIAL' ],
386
+ [ 2147483647, 'SERIAL' ],
387
+ [ 2147483648, 'BIGSERIAL' ],
388
+ [ 9223372036854775807, 'BIGSERIAL' ],
389
+
390
+ [ nil, 'SERIAL' ],
391
+ ].each do |max, statement|
392
+ options = {}
393
+ options[:max] = max if max
394
+
395
+ describe "with a max of #{max}" do
396
+ before :all do
397
+ @property = @model.property(:id, DataMapper::Property::Serial, options)
398
+
399
+ @response = capture_log(DataObjects::Postgres) { @model.auto_migrate! }
400
+ end
401
+
402
+ it 'should return true' do
403
+ @response.should be(true)
404
+ end
405
+
406
+ it "should create a #{statement} column" do
407
+ @output[-2].should == "CREATE TABLE \"blog_articles\" (\"id\" #{statement} NOT NULL, PRIMARY KEY(\"id\"))"
408
+ end
409
+
410
+ [ :min, :max ].each do |key|
411
+ next unless value = options[key]
412
+ it "should allow the #{key} value #{value} to be stored" do
413
+ lambda {
414
+ resource = @model.create(@property => value)
415
+ @model.first(@property => value).should eql(resource)
416
+ }.should_not raise_error
417
+ end
418
+ end
419
+ end
420
+ end
421
+ end
422
+
423
+ describe 'String property' do
424
+ before :all do
425
+ @model.property(:id, DataMapper::Property::Serial)
426
+ end
427
+
428
+ [
429
+ [ 1, 'VARCHAR(1)' ],
430
+ [ 50, 'VARCHAR(50)' ],
431
+ [ 255, 'VARCHAR(255)' ],
432
+ [ nil, 'VARCHAR(50)' ],
433
+ ].each do |length, statement|
434
+ options = {}
435
+ options[:length] = length if length
436
+
437
+ describe "with a length of #{length}" do
438
+ before :all do
439
+ @property = @model.property(:title, String, options)
440
+
441
+ @response = capture_log(DataObjects::Postgres) { @model.auto_migrate! }
442
+ end
443
+
444
+ it 'should return true' do
445
+ @response.should be(true)
446
+ end
447
+
448
+ it "should create a #{statement} column" do
449
+ @output[-2].should == "CREATE TABLE \"blog_articles\" (\"id\" SERIAL NOT NULL, \"title\" #{statement}, PRIMARY KEY(\"id\"))"
450
+ end
451
+ end
452
+ end
453
+ end
454
+
455
+ describe 'NumericString property' do
456
+ before :all do
457
+ @model.property(:id, DataMapper::Property::Serial)
458
+ @model.property(:number, DataMapper::Property::NumericString)
459
+
460
+ @response = capture_log(DataObjects::Postgres) { @model.auto_migrate! }
461
+ end
462
+
463
+ it "should create a VARCHAR(50) column with a default of '0'" do
464
+ @output[-2].should == "CREATE TABLE \"blog_articles\" (\"id\" SERIAL NOT NULL, \"number\" VARCHAR(50) DEFAULT '0', PRIMARY KEY(\"id\"))"
465
+ end
466
+ end
467
+ end
468
+ end
469
+
470
+ supported_by :sqlserver do
471
+ before :all do
472
+ module ::Blog
473
+ class Article
474
+ include DataMapper::Resource
475
+ end
476
+ end
477
+
478
+ @model = ::Blog::Article
479
+ end
480
+
481
+ describe '#auto_migrate' do
482
+ describe 'Integer property' do
483
+ [
484
+ [ 0, 1, 'TINYINT' ],
485
+ [ 0, 255, 'TINYINT' ],
486
+ [ 0, 256, 'SMALLINT' ],
487
+ [ 0, 32767, 'SMALLINT' ],
488
+ [ 0, 32768, 'INT' ],
489
+ [ 0, 2147483647, 'INT' ],
490
+ [ 0, 2147483648, 'BIGINT' ],
491
+ [ 0, 9223372036854775807, 'BIGINT' ],
492
+
493
+ [ -1, 1, 'SMALLINT' ],
494
+ [ -1, 255, 'SMALLINT' ],
495
+ [ -1, 256, 'SMALLINT' ],
496
+ [ -1, 32767, 'SMALLINT' ],
497
+ [ -1, 32768, 'INT' ],
498
+ [ -1, 2147483647, 'INT' ],
499
+ [ -1, 2147483648, 'BIGINT' ],
500
+ [ -1, 9223372036854775807, 'BIGINT' ],
501
+
502
+ [ -1, 0, 'SMALLINT' ],
503
+ [ -32768, 0, 'SMALLINT' ],
504
+ [ -32769, 0, 'INT' ],
505
+ [ -2147483648, 0, 'INT' ],
506
+ [ -2147483649, 0, 'BIGINT' ],
507
+ [ -9223372036854775808, 0, 'BIGINT' ],
508
+
509
+ [ nil, 2147483647, 'INT' ],
510
+ [ 0, nil, 'INT' ],
511
+ [ nil, nil, 'INTEGER' ],
512
+ ].each do |min, max, statement|
513
+ options = { :key => true }
514
+ options[:min] = min if min
515
+ options[:max] = max if max
516
+
517
+ describe "with a min of #{min} and a max of #{max}" do
518
+ before :all do
519
+ @property = @model.property(:id, Integer, options)
520
+
521
+ @response = capture_log(DataObjects::Sqlserver) { @model.auto_migrate! }
522
+ end
523
+
524
+ it 'should return true' do
525
+ @response.should be(true)
526
+ end
527
+
528
+ it "should create a #{statement} column" do
529
+ @output.last.should == "CREATE TABLE \"blog_articles\" (\"id\" #{statement} NOT NULL, PRIMARY KEY(\"id\"))"
530
+ end
531
+
532
+ [ :min, :max ].each do |key|
533
+ next unless value = options[key]
534
+ it "should allow the #{key} value #{value} to be stored" do
535
+ pending_if "#{value} causes problem with JRuby 1.5.2 parser", RUBY_PLATFORM =~ /java/ && value == -9223372036854775808 do
536
+ lambda {
537
+ resource = @model.create(@property => value)
538
+ @model.first(@property => value).should eql(resource)
539
+ }.should_not raise_error
540
+ end
541
+ end
542
+ end
543
+ end
544
+ end
545
+ end
546
+
547
+ describe 'String property' do
548
+ it 'needs specs'
549
+ end
550
+ end
551
+ end
552
+
553
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ require 'dm-migrations/auto_migration'
4
+
5
+ describe DataMapper::Migrations do
6
+ def capture_log(mod)
7
+ original, mod.logger = mod.logger, DataObjects::Logger.new(@log = StringIO.new, :debug)
8
+ yield
9
+ ensure
10
+ @log.rewind
11
+ @output = @log.readlines.map do |line|
12
+ line.chomp.gsub(/\A.+?~ \(\d+\.?\d*\)\s+/, '')
13
+ end
14
+
15
+ mod.logger = original
16
+ end
17
+
18
+ supported_by :postgres do
19
+ before :all do
20
+ module ::Blog
21
+ class Article
22
+ include DataMapper::Resource
23
+
24
+ property :id, Serial
25
+ end
26
+ end
27
+
28
+ @model = ::Blog::Article
29
+ end
30
+
31
+ describe '#auto_upgrade' do
32
+ it 'should create an index' do
33
+ @model.auto_migrate!
34
+ @property = @model.property(:name, String, :index => true)
35
+ @response = capture_log(DataObjects::Postgres) { @model.auto_upgrade! }
36
+ @output[-2].should == "CREATE INDEX \"index_blog_articles_name\" ON \"blog_articles\" (\"name\")"
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,89 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'The migration runner' do
4
+
5
+ supported_by :postgres, :mysql, :sqlite, :oracle, :sqlserver do
6
+
7
+ before(:all) do
8
+ @adapter = DataMapper::Spec.adapter
9
+ @repository = DataMapper.repository(@adapter.name)
10
+ end
11
+
12
+ describe 'empty migration runner' do
13
+ it "should return an empty array if no migrations have been defined" do
14
+ migrations.should be_kind_of(Array)
15
+ migrations.size.should == 0
16
+ end
17
+ end
18
+
19
+ describe 'migration runnner' do
20
+ # set up some 'global' setup and teardown tasks
21
+ before(:each) do
22
+ # FIXME workaround because dm-migrations can only handle the :default repo
23
+ #DataMapper::Repository.adapters[:default] = DataMapper::Repository.adapters[adapter.to_sym]
24
+ migration( 1, :create_people_table) { }
25
+ end
26
+
27
+ after(:each) do
28
+ migrations.clear
29
+ end
30
+
31
+ describe '#migration' do
32
+
33
+ it 'should create a new migration object, and add it to the list of migrations' do
34
+ migrations.should be_kind_of(Array)
35
+ migrations.size.should == 1
36
+ migrations.first.name.should == "create_people_table"
37
+ end
38
+
39
+ it 'should allow multiple migrations to be added' do
40
+ migration( 2, :add_dob_to_people) { }
41
+ migration( 2, :add_favorite_pet_to_people) { }
42
+ migration( 3, :add_something_else_to_people) { }
43
+ migrations.size.should == 4
44
+ end
45
+
46
+ it 'should raise an error on adding with a duplicated name' do
47
+ lambda { migration( 1, :create_people_table) { } }.should raise_error(RuntimeError, /Migration name conflict/)
48
+ end
49
+
50
+ end
51
+
52
+ describe '#migrate_up! and #migrate_down!' do
53
+ before(:each) do
54
+ migration( 2, :add_dob_to_people) { }
55
+ migration( 2, :add_favorite_pet_to_people) { }
56
+ migration( 3, :add_something_else_to_people) { }
57
+ end
58
+
59
+ it 'calling migrate_up! should migrate up all the migrations' do
60
+ # add our expectation that migrate_up should be called
61
+ migrations.each do |m|
62
+ m.should_receive(:perform_up)
63
+ end
64
+ migrate_up!
65
+ end
66
+
67
+ it 'calling migrate_up! with an arguement should only migrate to that level' do
68
+ migrations.each do |m|
69
+ if m.position <= 2
70
+ m.should_receive(:perform_up)
71
+ else
72
+ m.should_not_receive(:perform_up)
73
+ end
74
+ end
75
+ migrate_up!(2)
76
+ end
77
+
78
+ it 'calling migrate_down! should migrate down all the migrations' do
79
+ # add our expectation that migrate_up should be called
80
+ migrations.each do |m|
81
+ m.should_receive(:perform_down)
82
+ end
83
+ migrate_down!
84
+ end
85
+
86
+ end
87
+ end
88
+ end
89
+ end