ardm-migrations 1.2.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.
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