dm-hibernate-migrations 1.0.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 (40) hide show
  1. data/lib/dm-migrations.rb +3 -0
  2. data/lib/dm-migrations/adapters/dm-do-adapter.rb +284 -0
  3. data/lib/dm-migrations/adapters/dm-mysql-adapter.rb +283 -0
  4. data/lib/dm-migrations/adapters/dm-oracle-adapter.rb +321 -0
  5. data/lib/dm-migrations/adapters/dm-postgres-adapter.rb +159 -0
  6. data/lib/dm-migrations/adapters/dm-sqlite-adapter.rb +96 -0
  7. data/lib/dm-migrations/adapters/dm-sqlserver-adapter.rb +177 -0
  8. data/lib/dm-migrations/adapters/dm-yaml-adapter.rb +23 -0
  9. data/lib/dm-migrations/auto_migration.rb +237 -0
  10. data/lib/dm-migrations/migration.rb +217 -0
  11. data/lib/dm-migrations/migration_runner.rb +85 -0
  12. data/lib/dm-migrations/sql.rb +5 -0
  13. data/lib/dm-migrations/sql/column.rb +5 -0
  14. data/lib/dm-migrations/sql/mysql.rb +53 -0
  15. data/lib/dm-migrations/sql/postgres.rb +78 -0
  16. data/lib/dm-migrations/sql/sqlite.rb +45 -0
  17. data/lib/dm-migrations/sql/table.rb +15 -0
  18. data/lib/dm-migrations/sql/table_creator.rb +102 -0
  19. data/lib/dm-migrations/sql/table_modifier.rb +51 -0
  20. data/lib/spec/example/migration_example_group.rb +73 -0
  21. data/lib/spec/matchers/migration_matchers.rb +106 -0
  22. data/spec/integration/auto_migration_spec.rb +506 -0
  23. data/spec/integration/migration_runner_spec.rb +89 -0
  24. data/spec/integration/migration_spec.rb +138 -0
  25. data/spec/integration/sql_spec.rb +190 -0
  26. data/spec/isolated/require_after_setup_spec.rb +30 -0
  27. data/spec/isolated/require_before_setup_spec.rb +30 -0
  28. data/spec/isolated/require_spec.rb +25 -0
  29. data/spec/rcov.opts +6 -0
  30. data/spec/spec.opts +4 -0
  31. data/spec/spec_helper.rb +16 -0
  32. data/spec/unit/migration_spec.rb +453 -0
  33. data/spec/unit/sql/column_spec.rb +14 -0
  34. data/spec/unit/sql/postgres_spec.rb +97 -0
  35. data/spec/unit/sql/sqlite_extensions_spec.rb +108 -0
  36. data/spec/unit/sql/table_creator_spec.rb +94 -0
  37. data/spec/unit/sql/table_modifier_spec.rb +49 -0
  38. data/spec/unit/sql/table_spec.rb +28 -0
  39. data/spec/unit/sql_spec.rb +7 -0
  40. metadata +157 -0
@@ -0,0 +1,30 @@
1
+ require 'spec'
2
+ require 'isolated/require_spec'
3
+ require 'dm-core/spec/setup'
4
+
5
+ # To really test this behavior, this spec needs to be run in isolation and not
6
+ # as part of the typical rake spec run, which requires dm-transactions upfront
7
+
8
+ if %w[ postgres mysql sqlite oracle sqlserver ].include?(ENV['ADAPTER'])
9
+
10
+ describe "require 'dm-migrations' before calling DataMapper.setup" do
11
+
12
+ before(:all) do
13
+
14
+ require 'dm-migrations'
15
+ @adapter = DataMapper::Spec.adapter
16
+
17
+ class ::Person
18
+ include DataMapper::Resource
19
+ property :id, Serial
20
+ end
21
+
22
+ @model = Person
23
+
24
+ end
25
+
26
+ it_should_behave_like "require 'dm-migrations'"
27
+
28
+ end
29
+
30
+ end
@@ -0,0 +1,25 @@
1
+ shared_examples_for "require 'dm-migrations'" do
2
+
3
+ it "should include the migration api in the DataMapper namespace" do
4
+ DataMapper.respond_to?(:migrate! ).should be(true)
5
+ DataMapper.respond_to?(:auto_migrate! ).should be(true)
6
+ DataMapper.respond_to?(:auto_upgrade! ).should be(true)
7
+ DataMapper.respond_to?(:auto_migrate_up!, true).should be(true)
8
+ DataMapper.respond_to?(:auto_migrate_down!, true).should be(true)
9
+ end
10
+
11
+ %w[ Repository Model ].each do |name|
12
+ it "should include the migration api in DataMapper::#{name}" do
13
+ (DataMapper.const_get(name) < DataMapper::Migrations.const_get(name)).should be(true)
14
+ end
15
+ end
16
+
17
+ it "should include the migration api into the adapter" do
18
+ @adapter.respond_to?(:storage_exists? ).should be(true)
19
+ @adapter.respond_to?(:field_exists? ).should be(true)
20
+ @adapter.respond_to?(:upgrade_model_storage).should be(true)
21
+ @adapter.respond_to?(:create_model_storage ).should be(true)
22
+ @adapter.respond_to?(:destroy_model_storage).should be(true)
23
+ end
24
+
25
+ end
@@ -0,0 +1,6 @@
1
+ --exclude "spec,^/"
2
+ --sort coverage
3
+ --callsites
4
+ --xrefs
5
+ --profile
6
+ --text-summary
@@ -0,0 +1,4 @@
1
+ --colour
2
+ --loadby random
3
+ --format profile
4
+ --backtrace
@@ -0,0 +1,16 @@
1
+ require 'dm-migrations'
2
+ require 'dm-migrations/migration_runner'
3
+
4
+ require 'dm-core/spec/setup'
5
+ require 'dm-core/spec/lib/adapter_helpers'
6
+ require 'dm-core/spec/lib/spec_helper'
7
+
8
+ Spec::Runner.configure do |config|
9
+
10
+ config.extend(DataMapper::Spec::Adapters::Helpers)
11
+
12
+ config.after :all do
13
+ DataMapper::Spec.cleanup_models
14
+ end
15
+
16
+ end
@@ -0,0 +1,453 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Migration' do
4
+ supported_by :postgres, :mysql, :sqlite do
5
+ before do
6
+ @adapter = mock('adapter', :dialect => DataMapper::Spec.adapter.dialect)
7
+ @repo = mock('DataMapper.repository', :adapter => @adapter)
8
+ DataMapper.stub!(:repository).and_return(@repo)
9
+ @m = DataMapper::Migration.new(1, :do_nothing, {}) {}
10
+ @m.stub!(:write) # silence any output
11
+ end
12
+
13
+ [:position, :name, :database, :adapter].each do |meth|
14
+ it "should respond to ##{meth}" do
15
+ @m.should respond_to(meth)
16
+ end
17
+ end
18
+
19
+ describe 'initialization' do
20
+ it 'should set @position from the given position' do
21
+ @m.instance_variable_get(:@position).should == 1
22
+ end
23
+
24
+ it 'should set @name from the given name' do
25
+ @m.instance_variable_get(:@name).should == :do_nothing
26
+ end
27
+
28
+ it 'should set @options from the options hash' do
29
+ @m.instance_variable_get(:@options).should == {}
30
+ end
31
+
32
+ it 'should set @database from the default repository if no :database option is given' do
33
+ DataMapper.should_receive(:repository).with(:default).and_return(@repo)
34
+ DataMapper::Migration.new(1, :do_nothing, {}) {}
35
+ end
36
+
37
+ it 'should set @database to the repository specified with the :database option' do
38
+ DataMapper.should_receive(:repository).with(:foobar).and_return(@repo)
39
+ DataMapper::Migration.new(1, :do_nothing, :database => :foobar) {}
40
+ end
41
+
42
+ it 'should determine the class of the adapter to be extended' do
43
+ @adapter.should_receive(:dialect).and_return(DataMapper::Spec.adapter.dialect)
44
+ DataMapper::Migration.new(1, :do_nothing, {}) {}
45
+ end
46
+
47
+ it 'should extend the adapter with the right module' do
48
+ @adapter.should_receive(:extend).with(SQL.const_get(DataMapper::Spec.adapter_name.capitalize))
49
+ DataMapper::Migration.new(1, :do_nothing, {}) {}
50
+ end
51
+
52
+ it 'should raise "Unsupported adapter" on an unknown dialect' do
53
+ @adapter.should_receive(:dialect).any_number_of_times.and_return("Invalid")
54
+ @adapter.should_receive(:class).and_return("InvalidAdapter")
55
+ lambda {
56
+ DataMapper::Migration.new(1, :do_nothing, {}) {}
57
+ }.should raise_error
58
+ end
59
+
60
+ it 'should raise "Unsupported adapter" on an unknown adapter' do
61
+ @adapter.should_receive(:respond_to?).and_return(false)
62
+ @adapter.should_receive(:class).and_return("InvalidAdapter")
63
+ lambda {
64
+ DataMapper::Migration.new(1, :do_nothing, {}) {}
65
+ }.should raise_error
66
+ end
67
+
68
+ it 'should set @verbose from the options hash' do
69
+ m = DataMapper::Migration.new(1, :do_nothing, :verbose => false) {}
70
+ m.instance_variable_get(:@verbose).should be(false)
71
+ end
72
+
73
+ it 'should set @verbose to true by default' do
74
+ @m.instance_variable_get(:@verbose).should be(true)
75
+ end
76
+
77
+ it 'should set the @up_action to an empty block' do
78
+ @m.instance_variable_get(:@up_action).should be_kind_of(Proc)
79
+ end
80
+
81
+ it 'should set the @down_action to an empty block' do
82
+ @m.instance_variable_get(:@down_action).should be_kind_of(Proc)
83
+ end
84
+
85
+ it 'should evaluate the given block'
86
+
87
+ end
88
+
89
+ it 'should set the @up_action when #up is called with a block' do
90
+ action = lambda {}
91
+ @m.up(&action)
92
+ @m.instance_variable_get(:@up_action).should == action
93
+ end
94
+
95
+ it 'should set the @up_action when #up is called with a block' do
96
+ action = lambda {}
97
+ @m.down(&action)
98
+ @m.instance_variable_get(:@down_action).should == action
99
+ end
100
+
101
+ describe 'perform_up' do
102
+ before do
103
+ @up_action = mock('proc', :call => true)
104
+ @m.instance_variable_set(:@up_action, @up_action)
105
+ @m.stub!(:needs_up?).and_return(true)
106
+ @m.stub!(:update_migration_info)
107
+ end
108
+
109
+ it 'should call the action assigned to @up_action and return the result' do
110
+ @up_action.should_receive(:call).and_return(:result)
111
+ @m.perform_up.should == :result
112
+ end
113
+
114
+ it 'should output a status message with the position and name of the migration' do
115
+ @m.should_receive(:write).with(/Performing Up Migration #1: do_nothing/)
116
+ @m.perform_up
117
+ end
118
+
119
+ it 'should not run if it doesnt need to be' do
120
+ @m.should_receive(:needs_up?).and_return(false)
121
+ @up_action.should_not_receive(:call)
122
+ @m.perform_up
123
+ end
124
+
125
+ it 'should update the migration info table' do
126
+ @m.should_receive(:update_migration_info).with(:up)
127
+ @m.perform_up
128
+ end
129
+
130
+ it 'should not update the migration info table if the migration does not need run' do
131
+ @m.should_receive(:needs_up?).and_return(false)
132
+ @m.should_not_receive(:update_migration_info)
133
+ @m.perform_up
134
+ end
135
+
136
+ end
137
+
138
+ describe 'perform_down' do
139
+ before do
140
+ @down_action = mock('proc', :call => true)
141
+ @m.instance_variable_set(:@down_action, @down_action)
142
+ @m.stub!(:needs_down?).and_return(true)
143
+ @m.stub!(:update_migration_info)
144
+ end
145
+
146
+ it 'should call the action assigned to @down_action and return the result' do
147
+ @down_action.should_receive(:call).and_return(:result)
148
+ @m.perform_down.should == :result
149
+ end
150
+
151
+ it 'should output a status message with the position and name of the migration' do
152
+ @m.should_receive(:write).with(/Performing Down Migration #1: do_nothing/)
153
+ @m.perform_down
154
+ end
155
+
156
+ it 'should not run if it doesnt need to be' do
157
+ @m.should_receive(:needs_down?).and_return(false)
158
+ @down_action.should_not_receive(:call)
159
+ @m.perform_down
160
+ end
161
+
162
+ it 'should update the migration info table' do
163
+ @m.should_receive(:update_migration_info).with(:down)
164
+ @m.perform_down
165
+ end
166
+
167
+ it 'should not update the migration info table if the migration does not need run' do
168
+ @m.should_receive(:needs_down?).and_return(false)
169
+ @m.should_not_receive(:update_migration_info)
170
+ @m.perform_down
171
+ end
172
+
173
+ end
174
+
175
+ describe 'methods used in the action blocks' do
176
+
177
+ describe '#execute' do
178
+ before do
179
+ @adapter.stub!(:execute)
180
+ end
181
+
182
+ it 'should send the SQL it its executing to the adapter execute method' do
183
+ @adapter.should_receive(:execute).with('SELECT SOME SQL')
184
+ @m.execute('SELECT SOME SQL')
185
+ end
186
+
187
+ it 'should output the SQL it is executing' do
188
+ @m.should_receive(:write).with(/SELECT SOME SQL/)
189
+ @m.execute('SELECT SOME SQL')
190
+ end
191
+ end
192
+
193
+ describe 'helpers' do
194
+ before do
195
+ @m.stub!(:execute) # don't actually run anything
196
+ end
197
+
198
+ describe '#create_table' do
199
+ before do
200
+ @tc = mock('TableCreator', :to_sql => 'CREATE TABLE')
201
+ SQL::TableCreator.stub!(:new).and_return(@tc)
202
+ end
203
+
204
+ it 'should create a new TableCreator object' do
205
+ SQL::TableCreator.should_receive(:new).with(@adapter, :users, {}).and_return(@tc)
206
+ @m.create_table(:users) { }
207
+ end
208
+
209
+ it 'should convert the TableCreator object to an sql statement' do
210
+ @tc.should_receive(:to_sql).and_return('CREATE TABLE')
211
+ @m.create_table(:users) { }
212
+ end
213
+
214
+ it 'should execute the create table sql' do
215
+ @m.should_receive(:execute).with('CREATE TABLE')
216
+ @m.create_table(:users) { }
217
+ end
218
+
219
+ end
220
+
221
+ describe '#drop_table' do
222
+ it 'should quote the table name' do
223
+ @adapter.should_receive(:quote_name).with('users')
224
+ @m.drop_table :users
225
+ end
226
+
227
+ it 'should execute the DROP TABLE sql for the table' do
228
+ @adapter.stub!(:quote_name).and_return("'users'")
229
+ @m.should_receive(:execute).with(%{DROP TABLE 'users'})
230
+ @m.drop_table :users
231
+ end
232
+
233
+ end
234
+
235
+ describe '#modify_table' do
236
+ before do
237
+ @tm = mock('TableModifier', :statements => [])
238
+ SQL::TableModifier.stub!(:new).and_return(@tm)
239
+ end
240
+
241
+ it 'should create a new TableModifier object' do
242
+ SQL::TableModifier.should_receive(:new).with(@adapter, :users, {}).and_return(@tm)
243
+ @m.modify_table(:users){ }
244
+ end
245
+
246
+ it 'should get the statements from the TableModifier object' do
247
+ @tm.should_receive(:statements).and_return([])
248
+ @m.modify_table(:users){ }
249
+ end
250
+
251
+ it 'should iterate over the statements and execute each one' do
252
+ @tm.should_receive(:statements).and_return(['SELECT 1', 'SELECT 2'])
253
+ @m.should_receive(:execute).with('SELECT 1')
254
+ @m.should_receive(:execute).with('SELECT 2')
255
+ @m.modify_table(:users){ }
256
+ end
257
+
258
+ end
259
+
260
+ describe 'sorting' do
261
+ it 'should order things by position' do
262
+ m1 = DataMapper::Migration.new(1, :do_nothing){}
263
+ m2 = DataMapper::Migration.new(2, :do_nothing_else){}
264
+
265
+ (m1 <=> m2).should == -1
266
+ end
267
+
268
+ it 'should order things by name when they have the same position' do
269
+ m1 = DataMapper::Migration.new(1, :do_nothing_a){}
270
+ m2 = DataMapper::Migration.new(1, :do_nothing_b){}
271
+
272
+ (m1 <=> m2).should == -1
273
+ end
274
+
275
+ end
276
+
277
+ describe 'formatting output' do
278
+ describe '#say' do
279
+ it 'should output the message' do
280
+ @m.should_receive(:write).with(/Paul/)
281
+ @m.say("Paul")
282
+ end
283
+
284
+ it 'should indent the message with 4 spaces by default' do
285
+ @m.should_receive(:write).with(/^\s{4}/)
286
+ @m.say("Paul")
287
+ end
288
+
289
+ it 'should indext the message with a given number of spaces' do
290
+ @m.should_receive(:write).with(/^\s{3}/)
291
+ @m.say("Paul", 3)
292
+ end
293
+ end
294
+
295
+ describe '#say_with_time' do
296
+ before do
297
+ @m.stub!(:say)
298
+ end
299
+
300
+ it 'should say the message with an indent of 2' do
301
+ @m.should_receive(:say).with("Paul", 2)
302
+ @m.say_with_time("Paul"){}
303
+ end
304
+
305
+ it 'should output the time it took' do
306
+ @m.should_receive(:say).with(/\d+/, 2)
307
+ @m.say_with_time("Paul"){}
308
+ end
309
+ end
310
+
311
+ describe '#write' do
312
+ before do
313
+ # need a new migration object, because the main one had #write stubbed to silence output
314
+ @m = DataMapper::Migration.new(1, :do_nothing) {}
315
+ end
316
+
317
+ it 'should puts the message' do
318
+ @m.should_receive(:puts).with("Paul")
319
+ @m.write("Paul")
320
+ end
321
+
322
+ it 'should not puts the message if @verbose is false' do
323
+ @m.instance_variable_set(:@verbose, false)
324
+ @m.should_not_receive(:puts)
325
+ @m.write("Paul")
326
+ end
327
+
328
+ end
329
+
330
+ end
331
+
332
+ describe 'working with the migration_info table' do
333
+ before do
334
+ @adapter.stub!(:storage_exists?).and_return(true)
335
+ # --- Please remove stubs ---
336
+ @adapter.stub!(:quote_name).and_return { |name| "'#{name}'" }
337
+ end
338
+
339
+ describe '#update_migration_info' do
340
+ it 'should add a record of the migration' do
341
+ @m.should_receive(:execute).with(
342
+ %Q{INSERT INTO 'migration_info' ('migration_name') VALUES ('do_nothing')}
343
+ )
344
+ @m.update_migration_info(:up)
345
+ end
346
+
347
+ it 'should remove the record of the migration' do
348
+ @m.should_receive(:execute).with(
349
+ %Q{DELETE FROM 'migration_info' WHERE 'migration_name' = 'do_nothing'}
350
+ )
351
+ @m.update_migration_info(:down)
352
+ end
353
+
354
+ it 'should try to create the migration_info table' do
355
+ @m.should_receive(:create_migration_info_table_if_needed)
356
+ @m.update_migration_info(:up)
357
+ end
358
+ end
359
+
360
+ describe '#create_migration_info_table_if_needed' do
361
+ it 'should create the migration info table' do
362
+ @m.should_receive(:migration_info_table_exists?).and_return(false)
363
+ @m.should_receive(:execute).with(
364
+ %Q{CREATE TABLE 'migration_info' ('migration_name' VARCHAR(255) UNIQUE)}
365
+ )
366
+ @m.create_migration_info_table_if_needed
367
+ end
368
+
369
+ it 'should not try to create the migration info table if it already exists' do
370
+ @m.should_receive(:migration_info_table_exists?).and_return(true)
371
+ @m.should_not_receive(:execute)
372
+ @m.create_migration_info_table_if_needed
373
+ end
374
+ end
375
+
376
+ it 'should quote the name of the migration for use in sql' do
377
+ @m.quoted_name.should == %{'do_nothing'}
378
+ end
379
+
380
+ it 'should query the adapter to see if the migration_info table exists' do
381
+ @adapter.should_receive(:storage_exists?).with('migration_info').and_return(true)
382
+ @m.migration_info_table_exists?.should == true
383
+ end
384
+
385
+ describe '#migration_record' do
386
+ it 'should query for the migration' do
387
+ @adapter.should_receive(:select).with(
388
+ %Q{SELECT 'migration_name' FROM 'migration_info' WHERE 'migration_name' = 'do_nothing'}
389
+ )
390
+ @m.migration_record
391
+ end
392
+
393
+ it 'should not try to query if the table does not exist' do
394
+ @m.stub!(:migration_info_table_exists?).and_return(false)
395
+ @adapter.should_not_receive(:select)
396
+ @m.migration_record
397
+ end
398
+
399
+ end
400
+
401
+ describe '#needs_up?' do
402
+ it 'should be true if there is no record' do
403
+ @m.should_receive(:migration_record).and_return([])
404
+ @m.needs_up?.should == true
405
+ end
406
+
407
+ it 'should be false if the record exists' do
408
+ @m.should_receive(:migration_record).and_return([:not_empty])
409
+ @m.needs_up?.should == false
410
+ end
411
+
412
+ it 'should be true if there is no migration_info table' do
413
+ @m.should_receive(:migration_info_table_exists?).and_return(false)
414
+ @m.needs_up?.should == true
415
+ end
416
+
417
+ end
418
+
419
+ describe '#needs_down?' do
420
+ it 'should be false if there is no record' do
421
+ @m.should_receive(:migration_record).and_return([])
422
+ @m.needs_down?.should == false
423
+ end
424
+
425
+ it 'should be true if the record exists' do
426
+ @m.should_receive(:migration_record).and_return([:not_empty])
427
+ @m.needs_down?.should == true
428
+ end
429
+
430
+ it 'should be false if there is no migration_info table' do
431
+ @m.should_receive(:migration_info_table_exists?).and_return(false)
432
+ @m.needs_down?.should == false
433
+ end
434
+
435
+ end
436
+
437
+ it 'should have the adapter quote the migration_info table' do
438
+ @adapter.should_receive(:quote_name).with('migration_info').and_return("'migration_info'")
439
+ @m.migration_info_table.should == "'migration_info'"
440
+ end
441
+
442
+ it 'should have a quoted migration_name_column' do
443
+ @adapter.should_receive(:quote_name).with('migration_name').and_return("'migration_name'")
444
+ @m.migration_name_column.should == "'migration_name'"
445
+ end
446
+
447
+ end
448
+
449
+ end
450
+
451
+ end
452
+ end
453
+ end