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.
- data/lib/dm-migrations.rb +3 -0
- data/lib/dm-migrations/adapters/dm-do-adapter.rb +284 -0
- data/lib/dm-migrations/adapters/dm-mysql-adapter.rb +283 -0
- data/lib/dm-migrations/adapters/dm-oracle-adapter.rb +321 -0
- data/lib/dm-migrations/adapters/dm-postgres-adapter.rb +159 -0
- data/lib/dm-migrations/adapters/dm-sqlite-adapter.rb +96 -0
- data/lib/dm-migrations/adapters/dm-sqlserver-adapter.rb +177 -0
- data/lib/dm-migrations/adapters/dm-yaml-adapter.rb +23 -0
- data/lib/dm-migrations/auto_migration.rb +237 -0
- data/lib/dm-migrations/migration.rb +217 -0
- data/lib/dm-migrations/migration_runner.rb +85 -0
- data/lib/dm-migrations/sql.rb +5 -0
- data/lib/dm-migrations/sql/column.rb +5 -0
- data/lib/dm-migrations/sql/mysql.rb +53 -0
- data/lib/dm-migrations/sql/postgres.rb +78 -0
- data/lib/dm-migrations/sql/sqlite.rb +45 -0
- data/lib/dm-migrations/sql/table.rb +15 -0
- data/lib/dm-migrations/sql/table_creator.rb +102 -0
- data/lib/dm-migrations/sql/table_modifier.rb +51 -0
- data/lib/spec/example/migration_example_group.rb +73 -0
- data/lib/spec/matchers/migration_matchers.rb +106 -0
- data/spec/integration/auto_migration_spec.rb +506 -0
- data/spec/integration/migration_runner_spec.rb +89 -0
- data/spec/integration/migration_spec.rb +138 -0
- data/spec/integration/sql_spec.rb +190 -0
- data/spec/isolated/require_after_setup_spec.rb +30 -0
- data/spec/isolated/require_before_setup_spec.rb +30 -0
- data/spec/isolated/require_spec.rb +25 -0
- data/spec/rcov.opts +6 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/unit/migration_spec.rb +453 -0
- data/spec/unit/sql/column_spec.rb +14 -0
- data/spec/unit/sql/postgres_spec.rb +97 -0
- data/spec/unit/sql/sqlite_extensions_spec.rb +108 -0
- data/spec/unit/sql/table_creator_spec.rb +94 -0
- data/spec/unit/sql/table_modifier_spec.rb +49 -0
- data/spec/unit/sql/table_spec.rb +28 -0
- data/spec/unit/sql_spec.rb +7 -0
- 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
|