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,157 @@
1
+ require 'spec_helper'
2
+
3
+ describe "A Migration" do
4
+
5
+ supported_by :postgres, :mysql, :sqlite, :oracle, :sqlserver do
6
+
7
+ describe DataMapper::Migration, 'interface' do
8
+
9
+ before(:all) do
10
+ @adapter = DataMapper::Spec.adapter
11
+ end
12
+
13
+ before do
14
+ @migration = DataMapper::Migration.new(1, :create_people_table, :verbose => false) { }
15
+ end
16
+
17
+ before do
18
+ $stderr, @original = StringIO.new, $stderr
19
+ end
20
+
21
+ after do
22
+ $stderr = @original
23
+ end
24
+
25
+ it "should have a postition attribute" do
26
+ @migration.should respond_to(:position)
27
+
28
+ @migration.position.should == 1
29
+ end
30
+
31
+ it "should have a name attribute" do
32
+ @migration.should respond_to(:name)
33
+
34
+ @migration.name.should == :create_people_table
35
+ end
36
+
37
+ it "should have a :repository option" do
38
+ m = DataMapper::Migration.new(2, :create_dogs_table, :repository => :alternate) {}
39
+
40
+ m.instance_variable_get(:@repository).should == :alternate
41
+ end
42
+
43
+ it "should use the default repository by default" do
44
+ @migration.instance_variable_get(:@repository).should == :default
45
+ end
46
+
47
+ it "should still support a :database option" do
48
+ m = DataMapper::Migration.new(2, :create_legacy_table, :database => :legacy) {}
49
+
50
+ m.instance_variable_get(:@repository).should == :legacy
51
+ end
52
+
53
+ it "warns when :database is used" do
54
+ m = DataMapper::Migration.new(2, :create_legacy_table, :database => :legacy) {}
55
+ $stderr.string.chomp.should == 'Using the :database option with migrations is deprecated, use :repository instead'
56
+ end
57
+
58
+ it "should have a verbose option" do
59
+ m = DataMapper::Migration.new(2, :create_dogs_table, :verbose => false) {}
60
+ m.instance_variable_get(:@verbose).should == false
61
+ end
62
+
63
+ it "should be verbose by default" do
64
+ m = DataMapper::Migration.new(2, :create_dogs_table) {}
65
+ m.instance_variable_get(:@verbose).should == true
66
+ end
67
+
68
+ it "should be sortable, first by position, then name" do
69
+ m1 = DataMapper::Migration.new(1, :create_people_table) {}
70
+ m2 = DataMapper::Migration.new(2, :create_dogs_table) {}
71
+ m3 = DataMapper::Migration.new(2, :create_cats_table) {}
72
+ m4 = DataMapper::Migration.new(4, :create_birds_table) {}
73
+
74
+ [m1, m2, m3, m4].sort.should == [m1, m3, m2, m4]
75
+ end
76
+
77
+ adapter = DataMapper::Spec.adapter_name
78
+
79
+ expected_module_lambda = {
80
+ :sqlite => lambda { SQL::Sqlite },
81
+ :mysql => lambda { SQL::Mysql },
82
+ :postgres => lambda { SQL::Postgres }
83
+ }[adapter.to_sym]
84
+
85
+ expected_module = expected_module_lambda ? expected_module_lambda.call : nil
86
+
87
+ if expected_module
88
+ it "should extend with #{expected_module} when adapter is #{adapter}" do
89
+ migration = DataMapper::Migration.new(1, :"#{adapter}_adapter_test") { }
90
+ (class << migration.adapter; self; end).included_modules.should include(expected_module)
91
+ end
92
+ end
93
+ end
94
+
95
+ describe DataMapper::Migration, 'defining actions' do
96
+ before do
97
+ @migration = DataMapper::Migration.new(1, :create_people_table, :verbose => false) { }
98
+ end
99
+
100
+ it "should have an #up method" do
101
+ @migration.should respond_to(:up)
102
+ end
103
+
104
+ it "should save the block passed into the #up method in @up_action" do
105
+ action = lambda {}
106
+ @migration.up(&action)
107
+
108
+ @migration.instance_variable_get(:@up_action).should == action
109
+ end
110
+
111
+ it "should have a #down method" do
112
+ @migration.should respond_to(:down)
113
+ end
114
+
115
+ it "should save the block passed into the #down method in @down_action" do
116
+ action = lambda {}
117
+ @migration.down(&action)
118
+
119
+ @migration.instance_variable_get(:@down_action).should == action
120
+ end
121
+
122
+ it "should make available an #execute method" do
123
+ @migration.should respond_to(:execute)
124
+ end
125
+
126
+ it "should run the sql passed into the #execute method"
127
+ # TODO: Find out how to stub the DataMapper::database.execute method
128
+ end
129
+
130
+ describe DataMapper::Migration, "output" do
131
+ before do
132
+ @migration = DataMapper::Migration.new(1, :create_people_table) { }
133
+ @migration.stub!(:write) # so that we don't actually write anything to the console!
134
+ end
135
+
136
+ it "should #say a string with an indent" do
137
+ @migration.should_receive(:write).with(" Foobar")
138
+ @migration.say("Foobar", 2)
139
+ end
140
+
141
+ it "should #say with a default indent of 4" do
142
+ @migration.should_receive(:write).with(" Foobar")
143
+ @migration.say("Foobar")
144
+ end
145
+
146
+ it "should #say_with_time the running time of a block" do
147
+ @migration.should_receive(:write).with(/Block/)
148
+ @migration.should_receive(:write).with(/-> [\d]+/)
149
+
150
+ @migration.say_with_time("Block"){ }
151
+ end
152
+
153
+ end
154
+
155
+ end
156
+
157
+ end
@@ -0,0 +1,250 @@
1
+ require 'spec_helper'
2
+
3
+ describe "SQL generation" do
4
+
5
+ supported_by :postgres, :mysql, :sqlite, :oracle, :sqlserver do
6
+
7
+ describe DataMapper::Migration, "#create_table helper" do
8
+ before :all do
9
+
10
+ @adapter = DataMapper::Spec.adapter
11
+ @repository = DataMapper.repository(@adapter.name)
12
+
13
+ case DataMapper::Spec.adapter_name.to_sym
14
+ when :sqlite then @adapter.extend(SQL::Sqlite)
15
+ when :mysql then @adapter.extend(SQL::Mysql)
16
+ when :postgres then @adapter.extend(SQL::Postgres)
17
+ end
18
+
19
+ end
20
+
21
+ before do
22
+ @creator = DataMapper::Migration::TableCreator.new(@adapter, :people) do
23
+ column :id, DataMapper::Property::Serial
24
+ column :name, 'VARCHAR(50)', :allow_nil => false
25
+ column :long_string, String, :size => 200
26
+ end
27
+ end
28
+
29
+ it "should have a #create_table helper" do
30
+ @migration = DataMapper::Migration.new(1, :create_people_table, :verbose => false) { }
31
+ @migration.should respond_to(:create_table)
32
+ end
33
+
34
+ it "should have a table_name" do
35
+ @creator.table_name.should == "people"
36
+ end
37
+
38
+ it "should have an adapter" do
39
+ @creator.instance_eval("@adapter").should == @adapter
40
+ end
41
+
42
+ it "should have an options hash" do
43
+ @creator.opts.should be_kind_of(Hash)
44
+ @creator.opts.should == {}
45
+ end
46
+
47
+ it "should have an array of columns" do
48
+ @creator.instance_eval("@columns").should be_kind_of(Array)
49
+ @creator.instance_eval("@columns").size.should == 3
50
+ @creator.instance_eval("@columns").first.should be_kind_of(DataMapper::Migration::TableCreator::Column)
51
+ end
52
+
53
+ it "should quote the table name for the adapter" do
54
+ @creator.quoted_table_name.should == (DataMapper::Spec.adapter_name.to_sym == :mysql ? '`people`' : '"people"')
55
+ end
56
+
57
+ it "should allow for custom options" do
58
+ columns = @creator.instance_eval("@columns")
59
+ col = columns.detect{|c| c.name == "long_string"}
60
+ col.instance_eval("@type").should include("200")
61
+ end
62
+
63
+ it "should generate a NOT NULL column when :allow_nil is false" do
64
+ @creator.instance_eval("@columns")[1].type.should match(/NOT NULL/)
65
+ end
66
+
67
+ case DataMapper::Spec.adapter_name.to_sym
68
+ when :mysql
69
+ it "should create an InnoDB database for MySQL" do
70
+ #can't get an exact == comparison here because character set and collation may differ per connection
71
+ @creator.to_sql.should match(/^CREATE TABLE `people` \(`id` SERIAL PRIMARY KEY, `name` VARCHAR\(50\) NOT NULL, `long_string` VARCHAR\(200\)\) ENGINE = InnoDB CHARACTER SET \w+ COLLATE \w+\z/)
72
+ end
73
+
74
+ it "should allow for custom table creation options for MySQL" do
75
+ opts = {
76
+ :storage_engine => 'MyISAM',
77
+ :character_set => 'big5',
78
+ :collation => 'big5_chinese_ci',
79
+ }
80
+
81
+ creator = DataMapper::Migration::TableCreator.new(@adapter, :people, opts) do
82
+ column :id, DataMapper::Property::Serial
83
+ end
84
+
85
+ creator.to_sql.should match(/^CREATE TABLE `people` \(`id` SERIAL PRIMARY KEY\) ENGINE = MyISAM CHARACTER SET big5 COLLATE big5_chinese_ci\z/)
86
+ end
87
+
88
+ it "should respect default storage engine types specified by the MySQL adapter" do
89
+ adapter = DataMapper::Spec.adapter
90
+ adapter.extend(SQL::Mysql)
91
+
92
+ adapter.storage_engine = 'MyISAM'
93
+
94
+ creator = DataMapper::Migration::TableCreator.new(adapter, :people) do
95
+ column :id, DataMapper::Property::Serial
96
+ end
97
+
98
+ creator.to_sql.should match(/^CREATE TABLE `people` \(`id` SERIAL PRIMARY KEY\) ENGINE = MyISAM CHARACTER SET \w+ COLLATE \w+\z/)
99
+ end
100
+
101
+ when :postgres
102
+ it "should output a CREATE TABLE statement when sent #to_sql" do
103
+ @creator.to_sql.should == %q{CREATE TABLE "people" ("id" SERIAL PRIMARY KEY, "name" VARCHAR(50) NOT NULL, "long_string" VARCHAR(200))}
104
+ end
105
+ when :sqlite3
106
+ it "should output a CREATE TABLE statement when sent #to_sql" do
107
+ @creator.to_sql.should == %q{CREATE TABLE "people" ("id" INTEGER PRIMARY KEY AUTOINCREMENT, "name" VARCHAR(50) NOT NULL, "long_string" VARCHAR(200))}
108
+ end
109
+ end
110
+
111
+ context 'when the default string length is modified' do
112
+ before do
113
+ @original = DataMapper::Property::String.length
114
+ DataMapper::Property::String.length(255)
115
+
116
+ @creator = DataMapper::Migration::TableCreator.new(@adapter, :people) do
117
+ column :string, String
118
+ end
119
+ end
120
+
121
+ after do
122
+ DataMapper::Property::String.length(@original)
123
+ end
124
+
125
+ it 'uses the new length for the character column' do
126
+ @creator.to_sql.should match(/CHAR\(255\)/)
127
+ end
128
+ end
129
+ end
130
+
131
+ describe DataMapper::Migration, "#modify_table helper" do
132
+ before do
133
+ @migration = DataMapper::Migration.new(1, :create_people_table, :verbose => false) { }
134
+
135
+ end
136
+
137
+ it "should have a #modify_table helper" do
138
+ @migration.should respond_to(:modify_table)
139
+ end
140
+
141
+ case DataMapper::Spec.adapter_name.to_sym
142
+ when :postgres
143
+ before do
144
+ @modifier = DataMapper::Migration::TableModifier.new(@adapter, :people) do
145
+ change_column :name, 'VARCHAR(200)'
146
+ end
147
+ end
148
+
149
+ it "should alter the column" do
150
+ @modifier.to_sql.should == %q{ALTER TABLE "people" ALTER COLUMN "name" VARCHAR(200)}
151
+ end
152
+ end
153
+ end
154
+
155
+ describe DataMapper::Migration, "other helpers" do
156
+ before do
157
+ @migration = DataMapper::Migration.new(1, :create_people_table, :verbose => false) { }
158
+ end
159
+
160
+ it "should have a #drop_table helper" do
161
+ @migration.should respond_to(:drop_table)
162
+ end
163
+
164
+ end
165
+
166
+ describe DataMapper::Migration, "version tracking" do
167
+ before(:each) do
168
+ @migration = DataMapper::Migration.new(1, :create_people_table, :verbose => false) do
169
+ up { :ran_up }
170
+ down { :ran_down }
171
+ end
172
+
173
+ @migration.send(:create_migration_info_table_if_needed)
174
+ end
175
+
176
+ after(:each) { DataMapper::Spec.adapter.execute("DROP TABLE migration_info") rescue nil }
177
+
178
+ def insert_migration_record
179
+ DataMapper::Spec.adapter.execute("INSERT INTO migration_info (migration_name) VALUES ('create_people_table')")
180
+ end
181
+
182
+ it "should know if the migration_info table exists" do
183
+ @migration.send(:migration_info_table_exists?).should be(true)
184
+ end
185
+
186
+ it "should know if the migration_info table does not exist" do
187
+ DataMapper::Spec.adapter.execute("DROP TABLE migration_info") rescue nil
188
+ @migration.send(:migration_info_table_exists?).should be(false)
189
+ end
190
+
191
+ it "should be able to find the migration_info record for itself" do
192
+ insert_migration_record
193
+ @migration.send(:migration_record).should_not be_empty
194
+ end
195
+
196
+ it "should know if a migration needs_up?" do
197
+ @migration.send(:needs_up?).should be(true)
198
+ insert_migration_record
199
+ @migration.send(:needs_up?).should be(false)
200
+ end
201
+
202
+ it "should know if a migration needs_down?" do
203
+ @migration.send(:needs_down?).should be(false)
204
+ insert_migration_record
205
+ @migration.send(:needs_down?).should be(true)
206
+ end
207
+
208
+ it "should properly quote the migration_info table via the adapter for use in queries" do
209
+ @migration.send(:migration_info_table).should == @migration.quote_table_name("migration_info")
210
+ end
211
+
212
+ it "should properly quote the migration_info.migration_name column via the adapter for use in queries" do
213
+ @migration.send(:migration_name_column).should == @migration.quote_column_name("migration_name")
214
+ end
215
+
216
+ it "should properly quote the migration's name for use in queries"
217
+ # TODO how to i call the adapter's #escape_sql method?
218
+
219
+ it "should create the migration_info table if it doesn't exist" do
220
+ DataMapper::Spec.adapter.execute("DROP TABLE migration_info")
221
+ @migration.send(:migration_info_table_exists?).should be(false)
222
+ @migration.send(:create_migration_info_table_if_needed)
223
+ @migration.send(:migration_info_table_exists?).should be(true)
224
+ end
225
+
226
+ it "should insert a record into the migration_info table on up" do
227
+ @migration.send(:migration_record).should be_empty
228
+ @migration.perform_up.should == :ran_up
229
+ @migration.send(:migration_record).should_not be_empty
230
+ end
231
+
232
+ it "should remove a record from the migration_info table on down" do
233
+ insert_migration_record
234
+ @migration.send(:migration_record).should_not be_empty
235
+ @migration.perform_down.should == :ran_down
236
+ @migration.send(:migration_record).should be_empty
237
+ end
238
+
239
+ it "should not run the up action if the record exists in the table" do
240
+ insert_migration_record
241
+ @migration.perform_up.should_not == :ran_up
242
+ end
243
+
244
+ it "should not run the down action if the record does not exist in the table" do
245
+ @migration.perform_down.should_not == :ran_down
246
+ end
247
+
248
+ end
249
+ end
250
+ end
@@ -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' after calling DataMapper.setup" do
11
+
12
+ before(:all) do
13
+
14
+ @adapter = DataMapper::Spec.adapter
15
+ require 'dm-migrations'
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,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
data/spec/rcov.opts ADDED
@@ -0,0 +1,6 @@
1
+ --exclude "spec,^/"
2
+ --sort coverage
3
+ --callsites
4
+ --xrefs
5
+ --profile
6
+ --text-summary
data/spec/spec.opts ADDED
@@ -0,0 +1,4 @@
1
+ --colour
2
+ --loadby random
3
+ --format profile
4
+ --backtrace
@@ -0,0 +1,18 @@
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
+ require 'dm-core/spec/lib/pending_helpers'
8
+
9
+ Spec::Runner.configure do |config|
10
+
11
+ config.extend(DataMapper::Spec::Adapters::Helpers)
12
+ config.include(DataMapper::Spec::PendingHelpers)
13
+
14
+ config.after :all do
15
+ DataMapper::Spec.cleanup_models
16
+ end
17
+
18
+ end