dm-migrations 0.9.2 → 0.9.3

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.
@@ -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