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,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.should have(0).item
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.should have(1).item
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.should have(4).items
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
@@ -0,0 +1,138 @@
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
+ it "should have a postition attribute" do
18
+ @migration.should respond_to(:position)
19
+ @migration.should respond_to(:position=)
20
+ @migration.position.should == 1
21
+ end
22
+
23
+ it "should have a name attribute" do
24
+ @migration.should respond_to(:name)
25
+ @migration.should respond_to(:name=)
26
+ @migration.name.should == :create_people_table
27
+ end
28
+
29
+ it "should have a :database option" do
30
+ adapter = DataMapper::Spec.adapter(:alternate)
31
+ m = DataMapper::Migration.new(2, :create_dogs_table, :database => :alternate) {}
32
+ m.instance_variable_get(:@adapter).should == adapter
33
+ end
34
+
35
+ it "should use the default database by default" do
36
+ @migration.instance_variable_get(:@database).name.should == :default
37
+ end
38
+
39
+ it "should have a verbose option" do
40
+ m = DataMapper::Migration.new(2, :create_dogs_table, :verbose => false) {}
41
+ m.instance_variable_get(:@verbose).should == false
42
+ end
43
+
44
+ it "should be verbose by default" do
45
+ m = DataMapper::Migration.new(2, :create_dogs_table) {}
46
+ m.instance_variable_get(:@verbose).should == true
47
+ end
48
+
49
+ it "should be sortable, first by position, then name" do
50
+ m1 = DataMapper::Migration.new(1, :create_people_table) {}
51
+ m2 = DataMapper::Migration.new(2, :create_dogs_table) {}
52
+ m3 = DataMapper::Migration.new(2, :create_cats_table) {}
53
+ m4 = DataMapper::Migration.new(4, :create_birds_table) {}
54
+
55
+ [m1, m2, m3, m4].sort.should == [m1, m3, m2, m4]
56
+ end
57
+
58
+ adapter = DataMapper::Spec.adapter_name
59
+
60
+ expected_module_lambda = {
61
+ :sqlite => lambda { SQL::Sqlite },
62
+ :mysql => lambda { SQL::Mysql },
63
+ :postgres => lambda { SQL::Postgres }
64
+ }[adapter.to_sym]
65
+
66
+ expected_module = expected_module_lambda ? expected_module_lambda.call : nil
67
+
68
+ if expected_module
69
+ it "should extend with #{expected_module} when adapter is #{adapter}" do
70
+ migration = DataMapper::Migration.new(1, :"#{adapter}_adapter_test") { }
71
+ (class << migration.adapter; self; end).included_modules.should include(expected_module)
72
+ end
73
+ end
74
+ end
75
+
76
+ describe DataMapper::Migration, 'defining actions' do
77
+ before do
78
+ @migration = DataMapper::Migration.new(1, :create_people_table, :verbose => false) { }
79
+ end
80
+
81
+ it "should have an #up method" do
82
+ @migration.should respond_to(:up)
83
+ end
84
+
85
+ it "should save the block passed into the #up method in @up_action" do
86
+ action = lambda {}
87
+ @migration.up(&action)
88
+
89
+ @migration.instance_variable_get(:@up_action).should == action
90
+ end
91
+
92
+ it "should have a #down method" do
93
+ @migration.should respond_to(:down)
94
+ end
95
+
96
+ it "should save the block passed into the #down method in @down_action" do
97
+ action = lambda {}
98
+ @migration.down(&action)
99
+
100
+ @migration.instance_variable_get(:@down_action).should == action
101
+ end
102
+
103
+ it "should make available an #execute method" do
104
+ @migration.should respond_to(:execute)
105
+ end
106
+
107
+ it "should run the sql passed into the #execute method"
108
+ # TODO: Find out how to stub the DataMapper::database.execute method
109
+ end
110
+
111
+ describe DataMapper::Migration, "output" do
112
+ before do
113
+ @migration = DataMapper::Migration.new(1, :create_people_table) { }
114
+ @migration.stub!(:write) # so that we don't actually write anything to the console!
115
+ end
116
+
117
+ it "should #say a string with an indent" do
118
+ @migration.should_receive(:write).with(" Foobar")
119
+ @migration.say("Foobar", 2)
120
+ end
121
+
122
+ it "should #say with a default indent of 4" do
123
+ @migration.should_receive(:write).with(" Foobar")
124
+ @migration.say("Foobar")
125
+ end
126
+
127
+ it "should #say_with_time the running time of a block" do
128
+ @migration.should_receive(:write).with(/Block/)
129
+ @migration.should_receive(:write).with(/-> [\d]+/)
130
+
131
+ @migration.say_with_time("Block"){ }
132
+ end
133
+
134
+ end
135
+
136
+ end
137
+
138
+ end
@@ -0,0 +1,190 @@
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").should have(3).items
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
+ when :postgres
74
+ it "should output a CREATE TABLE statement when sent #to_sql" do
75
+ @creator.to_sql.should == %q{CREATE TABLE "people" ("id" SERIAL PRIMARY KEY, "name" VARCHAR(50) NOT NULL, "long_string" VARCHAR(200))}
76
+ end
77
+ when :sqlite3
78
+ it "should output a CREATE TABLE statement when sent #to_sql" do
79
+ @creator.to_sql.should == %q{CREATE TABLE "people" ("id" INTEGER PRIMARY KEY AUTOINCREMENT, "name" VARCHAR(50) NOT NULL, "long_string" VARCHAR(200))}
80
+ end
81
+ end
82
+ end
83
+
84
+ describe DataMapper::Migration, "#modify_table helper" do
85
+ before do
86
+ @migration = DataMapper::Migration.new(1, :create_people_table, :verbose => false) { }
87
+ end
88
+
89
+ it "should have a #modify_table helper" do
90
+ @migration.should respond_to(:modify_table)
91
+ end
92
+
93
+ end
94
+
95
+ describe DataMapper::Migration, "other helpers" do
96
+ before do
97
+ @migration = DataMapper::Migration.new(1, :create_people_table, :verbose => false) { }
98
+ end
99
+
100
+ it "should have a #drop_table helper" do
101
+ @migration.should respond_to(:drop_table)
102
+ end
103
+
104
+ end
105
+
106
+ describe DataMapper::Migration, "version tracking" do
107
+ before(:each) do
108
+ @migration = DataMapper::Migration.new(1, :create_people_table, :verbose => false) do
109
+ up { :ran_up }
110
+ down { :ran_down }
111
+ end
112
+
113
+ @migration.send(:create_migration_info_table_if_needed)
114
+ end
115
+
116
+ after(:each) { DataMapper::Spec.adapter.execute("DROP TABLE migration_info") rescue nil }
117
+
118
+ def insert_migration_record
119
+ DataMapper::Spec.adapter.execute("INSERT INTO migration_info (migration_name) VALUES ('create_people_table')")
120
+ end
121
+
122
+ it "should know if the migration_info table exists" do
123
+ @migration.send(:migration_info_table_exists?).should be(true)
124
+ end
125
+
126
+ it "should know if the migration_info table does not exist" do
127
+ DataMapper::Spec.adapter.execute("DROP TABLE migration_info") rescue nil
128
+ @migration.send(:migration_info_table_exists?).should be(false)
129
+ end
130
+
131
+ it "should be able to find the migration_info record for itself" do
132
+ insert_migration_record
133
+ @migration.send(:migration_record).should_not be_empty
134
+ end
135
+
136
+ it "should know if a migration needs_up?" do
137
+ @migration.send(:needs_up?).should be(true)
138
+ insert_migration_record
139
+ @migration.send(:needs_up?).should be(false)
140
+ end
141
+
142
+ it "should know if a migration needs_down?" do
143
+ @migration.send(:needs_down?).should be(false)
144
+ insert_migration_record
145
+ @migration.send(:needs_down?).should be(true)
146
+ end
147
+
148
+ it "should properly quote the migration_info table via the adapter for use in queries" do
149
+ @migration.send(:migration_info_table).should == @migration.quote_table_name("migration_info")
150
+ end
151
+
152
+ it "should properly quote the migration_info.migration_name column via the adapter for use in queries" do
153
+ @migration.send(:migration_name_column).should == @migration.quote_column_name("migration_name")
154
+ end
155
+
156
+ it "should properly quote the migration's name for use in queries"
157
+ # TODO how to i call the adapter's #escape_sql method?
158
+
159
+ it "should create the migration_info table if it doesn't exist" do
160
+ DataMapper::Spec.adapter.execute("DROP TABLE migration_info")
161
+ @migration.send(:migration_info_table_exists?).should be(false)
162
+ @migration.send(:create_migration_info_table_if_needed)
163
+ @migration.send(:migration_info_table_exists?).should be(true)
164
+ end
165
+
166
+ it "should insert a record into the migration_info table on up" do
167
+ @migration.send(:migration_record).should be_empty
168
+ @migration.perform_up.should == :ran_up
169
+ @migration.send(:migration_record).should_not be_empty
170
+ end
171
+
172
+ it "should remove a record from the migration_info table on down" do
173
+ insert_migration_record
174
+ @migration.send(:migration_record).should_not be_empty
175
+ @migration.perform_down.should == :ran_down
176
+ @migration.send(:migration_record).should be_empty
177
+ end
178
+
179
+ it "should not run the up action if the record exists in the table" do
180
+ insert_migration_record
181
+ @migration.perform_up.should_not == :ran_up
182
+ end
183
+
184
+ it "should not run the down action if the record does not exist in the table" do
185
+ @migration.perform_down.should_not == :ran_down
186
+ end
187
+
188
+ end
189
+ end
190
+ 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