dm-migrations 0.9.2 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -9,9 +9,6 @@ module SQL
9
9
  SQL::Postgresql::Table.new(self, table_name)
10
10
  end
11
11
 
12
- def drop_database
13
- end
14
-
15
12
  def recreate_database
16
13
  execute "DROP SCHEMA IF EXISTS test CASCADE"
17
14
  execute "CREATE SCHEMA test"
@@ -37,19 +34,21 @@ module SQL
37
34
 
38
35
  class Table < SQL::Table
39
36
  def initialize(adapter, table_name)
37
+ @adapter, @name = adapter, table_name
40
38
  @columns = []
41
39
  adapter.query_table(table_name).each do |col_struct|
42
40
  @columns << SQL::Postgresql::Column.new(col_struct)
43
41
  end
44
42
 
45
- puts "+=+++++++++++++++++++++++++++++++++++++++"
46
- # detect column constraints
47
- adapter.query(
48
- "SELECT * FROM information_schema.table_constraints WHERE table_name='#{table_name}' AND table_schema=current_schema()"
43
+ query_column_constraints
44
+ end
45
+
46
+ def query_column_constraints
47
+ @adapter.query(
48
+ "SELECT * FROM information_schema.table_constraints WHERE table_name='#{@name}' AND table_schema=current_schema()"
49
49
  ).each do |table_constraint|
50
- puts table_constraint.inspect
51
- adapter.query(
52
- "SELECT * FROM information_schema.constraint_column_usage WHERE table_name='#{table_name}' AND table_schema=current_schema()"
50
+ @adapter.query(
51
+ "SELECT * FROM information_schema.constraint_column_usage WHERE constraint_name='#{table_constraint.constraint_name}' AND table_schema=current_schema()"
53
52
  ).each do |constrained_column|
54
53
  @columns.each do |column|
55
54
  if column.name == constrained_column.column_name
@@ -61,6 +60,7 @@ module SQL
61
60
  end
62
61
  end
63
62
  end
63
+
64
64
  end
65
65
 
66
66
  end
@@ -8,7 +8,7 @@ module SQL
8
8
  end
9
9
 
10
10
  def table(table_name)
11
- SQL::Table.new(self, table_name)
11
+ SQL::Sqlite3::Table.new(self, table_name)
12
12
  end
13
13
 
14
14
  def recreate_database
@@ -21,13 +21,6 @@ module SQL
21
21
  true
22
22
  end
23
23
 
24
- # TODO: move to dm-more/dm-migrations
25
- def property_schema_statement(schema)
26
- statement = super
27
- statement << ' PRIMARY KEY AUTOINCREMENT' if supports_serial? && schema[:serial]
28
- statement
29
- end
30
-
31
24
  class Table < SQL::Table
32
25
  def initialize(adapter, table_name)
33
26
  @columns = []
@@ -0,0 +1,55 @@
1
+ module SQL
2
+ class TableCreator
3
+ attr_accessor :table_name, :opts
4
+
5
+ def initialize(adapter, table_name, opts = {}, &block)
6
+ @adapter = adapter
7
+ @table_name = table_name.to_s
8
+ @opts = opts
9
+
10
+ @columns = []
11
+
12
+ self.instance_eval &block
13
+ end
14
+
15
+ def quoted_table_name
16
+ @adapter.send(:quote_table_name, table_name)
17
+ end
18
+
19
+ def column(name, type, opts = {})
20
+ @columns << Column.new(@adapter, name, type, opts)
21
+ end
22
+
23
+ def to_sql
24
+ "CREATE TABLE #{quoted_table_name} (#{@columns.map{ |c| c.to_sql }.join(', ')})"
25
+ end
26
+
27
+ class Column
28
+ attr_accessor :name, :type
29
+
30
+ def initialize(adapter, name, type, opts = {})
31
+ @adapter = adapter
32
+ @name = name.to_s
33
+ @opts = opts
34
+ @type = build_type(type)
35
+ end
36
+
37
+ def build_type(type_class)
38
+ schema = {:name => @name, :quote_column_name => quoted_name}.merge(@opts)
39
+ schema = @adapter.class.type_map[type_class].merge(schema)
40
+ @adapter.property_schema_statement(schema)
41
+ end
42
+
43
+ def to_sql
44
+ type
45
+ end
46
+
47
+ def quoted_name
48
+ @adapter.send(:quote_column_name, name)
49
+ end
50
+ end
51
+
52
+ end
53
+
54
+ end
55
+
@@ -0,0 +1,53 @@
1
+ module SQL
2
+ class TableModifier
3
+ attr_accessor :table_name, :opts, :statements, :adapter
4
+
5
+ def initialize(adapter, table_name, opts = {}, &block)
6
+ @adapter = adapter
7
+ @table_name = table_name.to_s
8
+ @opts = (opts)
9
+
10
+ @statements = []
11
+
12
+ self.instance_eval &block
13
+ end
14
+
15
+ def add_column(name, type, opts = {})
16
+ column = SQL::TableCreator::Column.new(@adapter, name, type, opts)
17
+ @statements << "ALTER TABLE #{quoted_table_name} ADD COLUMN #{column.to_sql}"
18
+ end
19
+
20
+ def drop_column(name)
21
+ # raise NotImplemented for SQLite3. Can't ALTER TABLE, need to copy table.
22
+ # We'd have to inspect it, and we can't, since we aren't executing any queries yet.
23
+ # TODO instead of building the SQL queries when executing the block, create AddColumn,
24
+ # AlterColumn and DropColumn objects that get #to_sql'd
25
+ if name.is_a?(Array)
26
+ name.each{ |n| drop_column(n) }
27
+ else
28
+ @statements << "ALTER TABLE #{quoted_table_name} DROP COLUMN #{quote_column_name(name)}"
29
+ end
30
+ end
31
+ alias drop_columns drop_column
32
+
33
+ def rename_column(name, new_name, opts = {})
34
+ # raise NotImplemented for SQLite3
35
+ @statements << "ALTER TABLE #{quoted_table_name} RENAME COLUMN #{quote_column_name(name)} TO #{quote_column_name(new_name)}"
36
+ end
37
+
38
+ def change_column(name, type, opts = {})
39
+ # raise NotImplemented for SQLite3
40
+ @statements << "ALTER TABLE #{quoted_table_name} ALTER COLUMN #{quote_column_name(name)} TYPE #{type}"
41
+ end
42
+
43
+ def quote_column_name(name)
44
+ @adapter.send(:quote_column_name, name.to_s)
45
+ end
46
+
47
+ def quoted_table_name
48
+ @adapter.send(:quote_table_name, table_name)
49
+ end
50
+
51
+ end
52
+
53
+ end
@@ -1,78 +1,81 @@
1
1
  require 'pathname'
2
2
  require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
3
3
 
4
- if HAS_SQLITE3 || HAS_MYSQL || HAS_POSTGRES
5
- describe 'empty migration runner' do
6
- it "should return an empty array if no migrations have been defined" do
7
- migrations.should be_kind_of(Array)
8
- migrations.should have(0).item
9
- end
10
- end
11
- describe 'migration runnner' do
12
- # set up some 'global' setup and teardown tasks
13
- before(:each) do
14
- migration( 1, :create_people_table) { }
15
- end
16
-
17
- after(:each) do
18
- @@migrations = []
4
+ [:sqlite3, :mysql, :postgres].each do |adapter|
5
+ next unless eval("HAS_#{adapter.to_s.upcase}")
6
+ describe "Using Adapter #{adapter}, " do
7
+ describe 'empty migration runner' do
8
+ it "should return an empty array if no migrations have been defined" do
9
+ migrations.should be_kind_of(Array)
10
+ migrations.should have(0).item
11
+ end
19
12
  end
20
-
21
- describe '#migration' do
22
-
23
- it 'should create a new migration object, and add it to the list of migrations' do
24
- @@migrations.should be_kind_of(Array)
25
- @@migrations.should have(1).item
26
- @@migrations.first.name.should == "create_people_table"
13
+ describe 'migration runnner' do
14
+ # set up some 'global' setup and teardown tasks
15
+ before(:each) do
16
+ migration( 1, :create_people_table) { }
27
17
  end
28
18
 
29
- it 'should allow multiple migrations to be added' do
30
- migration( 2, :add_dob_to_people) { }
31
- migration( 2, :add_favorite_pet_to_people) { }
32
- migration( 3, :add_something_else_to_people) { }
33
- @@migrations.should have(4).items
19
+ after(:each) do
20
+ @@migrations = []
34
21
  end
35
22
 
36
- it 'should raise an error on adding with a duplicated name' do
37
- lambda { migration( 1, :create_people_table) { } }.should raise_error(RuntimeError, /Migration name conflict/)
38
- end
23
+ describe '#migration' do
39
24
 
40
- end
25
+ it 'should create a new migration object, and add it to the list of migrations' do
26
+ @@migrations.should be_kind_of(Array)
27
+ @@migrations.should have(1).item
28
+ @@migrations.first.name.should == "create_people_table"
29
+ end
41
30
 
42
- describe '#migrate_up! and #migrate_down!' do
43
- before(:each) do
44
- migration( 2, :add_dob_to_people) { }
45
- migration( 2, :add_favorite_pet_to_people) { }
46
- migration( 3, :add_something_else_to_people) { }
47
- end
31
+ it 'should allow multiple migrations to be added' do
32
+ migration( 2, :add_dob_to_people) { }
33
+ migration( 2, :add_favorite_pet_to_people) { }
34
+ migration( 3, :add_something_else_to_people) { }
35
+ @@migrations.should have(4).items
36
+ end
48
37
 
49
- it 'calling migrate_up! should migrate up all the migrations' do
50
- # add our expection that migrate_up should be called
51
- @@migrations.each do |m|
52
- m.should_receive(:perform_up)
38
+ it 'should raise an error on adding with a duplicated name' do
39
+ lambda { migration( 1, :create_people_table) { } }.should raise_error(RuntimeError, /Migration name conflict/)
53
40
  end
54
- migrate_up!
41
+
55
42
  end
56
43
 
57
- it 'calling migrate_up! with an arguement should only migrate to that level' do
58
- @@migrations.each do |m|
59
- if m.position <= 2
44
+ describe '#migrate_up! and #migrate_down!' do
45
+ before(:each) do
46
+ migration( 2, :add_dob_to_people) { }
47
+ migration( 2, :add_favorite_pet_to_people) { }
48
+ migration( 3, :add_something_else_to_people) { }
49
+ end
50
+
51
+ it 'calling migrate_up! should migrate up all the migrations' do
52
+ # add our expectation that migrate_up should be called
53
+ @@migrations.each do |m|
60
54
  m.should_receive(:perform_up)
61
- else
62
- m.should_not_receive(:perform_up)
63
55
  end
56
+ migrate_up!
64
57
  end
65
- migrate_up!(2)
66
- end
67
58
 
68
- it 'calling migrate_down! should migrate down all the migrations' do
69
- # add our expection that migrate_up should be called
70
- @@migrations.each do |m|
71
- m.should_receive(:perform_down)
59
+ it 'calling migrate_up! with an arguement should only migrate to that level' do
60
+ @@migrations.each do |m|
61
+ if m.position <= 2
62
+ m.should_receive(:perform_up)
63
+ else
64
+ m.should_not_receive(:perform_up)
65
+ end
66
+ end
67
+ migrate_up!(2)
68
+ end
69
+
70
+ it 'calling migrate_down! should migrate down all the migrations' do
71
+ # add our expectation that migrate_up should be called
72
+ @@migrations.each do |m|
73
+ m.should_receive(:perform_down)
74
+ end
75
+ migrate_down!
72
76
  end
73
- migrate_down!
74
- end
75
77
 
78
+ end
76
79
  end
77
80
  end
78
81
  end
@@ -1,136 +1,136 @@
1
1
  require 'pathname'
2
2
  require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
3
3
 
4
- if HAS_SQLITE3 || HAS_MYSQL || HAS_POSTGRES
5
- describe DataMapper::Migration, 'interface' do
6
- before do
7
- @migration = DataMapper::Migration.new(1, :create_people_table, :verbose => false) { }
8
- end
4
+ [:sqlite3, :mysql, :postgres].each do |adapter|
5
+ next unless eval("HAS_#{adapter.to_s.upcase}")
6
+ describe "Using Adapter #{adapter}, " do
7
+ describe DataMapper::Migration, 'interface' do
8
+ before do
9
+ @migration = DataMapper::Migration.new(1, :create_people_table, :verbose => false) { }
10
+ end
9
11
 
10
- it "should have a postition attribute" do
11
- @migration.should respond_to(:position)
12
- @migration.should respond_to(:position=)
13
- @migration.position.should == 1
14
- end
12
+ it "should have a postition attribute" do
13
+ @migration.should respond_to(:position)
14
+ @migration.should respond_to(:position=)
15
+ @migration.position.should == 1
16
+ end
15
17
 
16
- it "should have a name attribute" do
17
- @migration.should respond_to(:name)
18
- @migration.should respond_to(:name=)
19
- @migration.name.should == :create_people_table
20
- end
18
+ it "should have a name attribute" do
19
+ @migration.should respond_to(:name)
20
+ @migration.should respond_to(:name=)
21
+ @migration.name.should == :create_people_table
22
+ end
21
23
 
22
- it "should have a :database option" do
23
- DataMapper.setup(:other, "sqlite3://#{Dir.pwd}/migration_other.db")
24
+ it "should have a :database option" do
25
+ DataMapper.setup(:other, "sqlite3://#{Dir.pwd}/migration_other.db")
24
26
 
25
- m = DataMapper::Migration.new(2, :create_dogs_table, :database => :other) {}
26
- m.instance_variable_get(:@database).name.should == :other
27
- end
27
+ m = DataMapper::Migration.new(2, :create_dogs_table, :database => :other) {}
28
+ m.instance_variable_get(:@database).name.should == :other
29
+ end
28
30
 
29
- it "should use the default database by default" do
30
- @migration.instance_variable_get(:@database).name.should == :default
31
- end
31
+ it "should use the default database by default" do
32
+ @migration.instance_variable_get(:@database).name.should == :default
33
+ end
32
34
 
33
- it "should have a verbose option" do
34
- m = DataMapper::Migration.new(2, :create_dogs_table, :verbose => false) {}
35
- m.instance_variable_get(:@verbose).should == false
36
- end
35
+ it "should have a verbose option" do
36
+ m = DataMapper::Migration.new(2, :create_dogs_table, :verbose => false) {}
37
+ m.instance_variable_get(:@verbose).should == false
38
+ end
37
39
 
38
- it "should be verbose by default" do
39
- m = DataMapper::Migration.new(2, :create_dogs_table) {}
40
- m.instance_variable_get(:@verbose).should == true
41
- end
40
+ it "should be verbose by default" do
41
+ m = DataMapper::Migration.new(2, :create_dogs_table) {}
42
+ m.instance_variable_get(:@verbose).should == true
43
+ end
42
44
 
43
- it "should be sortable, first by position, then name" do
44
- m1 = DataMapper::Migration.new(1, :create_people_table) {}
45
- m2 = DataMapper::Migration.new(2, :create_dogs_table) {}
46
- m3 = DataMapper::Migration.new(2, :create_cats_table) {}
47
- m4 = DataMapper::Migration.new(4, :create_birds_table) {}
45
+ it "should be sortable, first by position, then name" do
46
+ m1 = DataMapper::Migration.new(1, :create_people_table) {}
47
+ m2 = DataMapper::Migration.new(2, :create_dogs_table) {}
48
+ m3 = DataMapper::Migration.new(2, :create_cats_table) {}
49
+ m4 = DataMapper::Migration.new(4, :create_birds_table) {}
48
50
 
49
- [m1, m2, m3, m4].sort.should == [m1, m3, m2, m4]
50
- end
51
+ [m1, m2, m3, m4].sort.should == [m1, m3, m2, m4]
52
+ end
51
53
 
52
- if HAS_SQLITE3
53
- it "should extend with SQL::Sqlite3 when adapter is Sqlite3Adapter" do
54
- DataMapper.setup(:sqlite3, "sqlite3::memory:")
55
- migration = DataMapper::Migration.new(1, :sqlite3_adapter_test, :database => :sqlite3) { }
56
- (class << migration.adapter; self; end).included_modules.should include(SQL::Sqlite3)
54
+ if HAS_SQLITE3
55
+ it "should extend with SQL::Sqlite3 when adapter is Sqlite3Adapter" do
56
+ migration = DataMapper::Migration.new(1, :sqlite3_adapter_test, :database => :sqlite3) { }
57
+ (class << migration.adapter; self; end).included_modules.should include(SQL::Sqlite3)
58
+ end
57
59
  end
58
- end
59
60
 
60
- if HAS_MYSQL
61
- it "should extend with SQL::Mysql when adapter is MysqlAdapter" do
62
- DataMapper.setup(:mysql, "mysql://localhost/migration_test")
63
- migration = DataMapper::Migration.new(1, :mysql_adapter_test, :database => :mysql) { }
64
- (class << migration.adapter; self; end).included_modules.should include(SQL::Mysql)
61
+ if HAS_MYSQL
62
+ it "should extend with SQL::Mysql when adapter is MysqlAdapter" do
63
+ migration = DataMapper::Migration.new(1, :mysql_adapter_test, :database => :mysql) { }
64
+ (class << migration.adapter; self; end).included_modules.should include(SQL::Mysql)
65
+ end
65
66
  end
66
- end
67
67
 
68
- if HAS_POSTGRES
69
- it "should extend with SQL::Postgres when adapter is PostgresAdapter" do
70
- DataMapper.setup(:postgres, "postgres://localhost/migration_test")
71
- migration = DataMapper::Migration.new(1, :postgres_adapter_test, :database => :postgres) { }
72
- (class << migration.adapter; self; end).included_modules.should include(SQL::Postgresql)
68
+ if HAS_POSTGRES
69
+ it "should extend with SQL::Postgres when adapter is PostgresAdapter" do
70
+ migration = DataMapper::Migration.new(1, :postgres_adapter_test, :database => :postgres) { }
71
+ (class << migration.adapter; self; end).included_modules.should include(SQL::Postgresql)
72
+ end
73
73
  end
74
74
  end
75
- end
76
75
 
77
- describe DataMapper::Migration, 'defining actions' do
78
- before do
79
- @migration = DataMapper::Migration.new(1, :create_people_table, :verbose => false) { }
80
- end
76
+ describe DataMapper::Migration, 'defining actions' do
77
+ before do
78
+ @migration = DataMapper::Migration.new(1, :create_people_table, :verbose => false) { }
79
+ end
81
80
 
82
- it "should have an #up method" do
83
- @migration.should respond_to(:up)
84
- end
81
+ it "should have an #up method" do
82
+ @migration.should respond_to(:up)
83
+ end
85
84
 
86
- it "should save the block passed into the #up method in @up_action" do
87
- action = lambda {}
88
- @migration.up(&action)
85
+ it "should save the block passed into the #up method in @up_action" do
86
+ action = lambda {}
87
+ @migration.up(&action)
89
88
 
90
- @migration.instance_variable_get(:@up_action).should == action
91
- end
89
+ @migration.instance_variable_get(:@up_action).should == action
90
+ end
92
91
 
93
- it "should have a #down method" do
94
- @migration.should respond_to(:down)
95
- end
92
+ it "should have a #down method" do
93
+ @migration.should respond_to(:down)
94
+ end
96
95
 
97
- it "should save the block passed into the #down method in @down_action" do
98
- action = lambda {}
99
- @migration.down(&action)
96
+ it "should save the block passed into the #down method in @down_action" do
97
+ action = lambda {}
98
+ @migration.down(&action)
100
99
 
101
- @migration.instance_variable_get(:@down_action).should == action
102
- end
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
103
106
 
104
- it "should make available an #execute method" do
105
- @migration.should respond_to(:execute)
107
+ it "should run the sql passed into the #execute method"
108
+ # TODO: Find out how to stub the DataMapper::database.execute method
106
109
  end
107
110
 
108
- it "should run the sql passed into the #execute method"
109
- # TODO: Find out how to stub the DataMapper::database.execute method
110
- end
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
111
116
 
112
- describe DataMapper::Migration, "output" do
113
- before do
114
- @migration = DataMapper::Migration.new(1, :create_people_table) { }
115
- @migration.stub!(:write) # so that we don't actually write anything to the console!
116
- end
117
+ it "should #say a string with an indent" do
118
+ @migration.should_receive(:write).with(" Foobar")
119
+ @migration.say("Foobar", 2)
120
+ end
117
121
 
118
- it "should #say a string with an indent" do
119
- @migration.should_receive(:write).with(" Foobar")
120
- @migration.say("Foobar", 2)
121
- end
122
+ it "should #say with a default indent of 4" do
123
+ @migration.should_receive(:write).with(" Foobar")
124
+ @migration.say("Foobar")
125
+ end
122
126
 
123
- it "should #say with a default indent of 4" do
124
- @migration.should_receive(:write).with(" Foobar")
125
- @migration.say("Foobar")
126
- end
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]+/)
127
130
 
128
- it "should #say_with_time the running time of a block" do
129
- @migration.should_receive(:write).with(/Block/)
130
- @migration.should_receive(:write).with(/-> [\d]+/)
131
+ @migration.say_with_time("Block"){ }
132
+ end
131
133
 
132
- @migration.say_with_time("Block"){ }
133
134
  end
134
-
135
135
  end
136
136
  end