sequel_migration_builder 0.0.5 → 0.1.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/README.rdoc +4 -0
- data/VERSION +1 -1
- data/lib/sequel/migration_builder.rb +9 -1
- data/lib/sequel/schema/alter_table_operations.rb +51 -28
- data/lib/sequel/schema/db_column.rb +2 -2
- data/lib/sequel/schema/db_schema_parser.rb +4 -1
- data/sequel_migration_builder.gemspec +2 -2
- data/spec/alter_table_operations_spec.rb +43 -12
- data/spec/db_schema_parser_spec.rb +1 -0
- data/spec/migration_builder_spec.rb +25 -1
- metadata +3 -3
data/README.rdoc
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
0.1.0
|
@@ -114,6 +114,14 @@ module Sequel
|
|
114
114
|
table[:columns].each do |c|
|
115
115
|
add_line Schema::DbColumn.build_from_hash(c).define_statement
|
116
116
|
end
|
117
|
+
if table[:indexes]
|
118
|
+
add_blank_line
|
119
|
+
table[:indexes].each do |name, options|
|
120
|
+
opts = options.clone
|
121
|
+
columns = opts.delete(:columns)
|
122
|
+
add_line "index #{columns.inspect}, :name => #{name.to_sym.inspect}#{pretty_hash(opts)}"
|
123
|
+
end
|
124
|
+
end
|
117
125
|
if table[:primary_key]
|
118
126
|
add_blank_line
|
119
127
|
add_line "primary_key #{table[:primary_key].inspect}"
|
@@ -139,7 +147,7 @@ module Sequel
|
|
139
147
|
# Returns a string representing a hash as ':foo => :bar'
|
140
148
|
# rather than '{:foo=.:bar}'
|
141
149
|
def pretty_hash(hash)
|
142
|
-
", " + hash.inspect.gsub(/^\{|\}$/,'').gsub("=>", " => ") if hash
|
150
|
+
", " + hash.inspect.gsub(/^\{|\}$/,'').gsub("=>", " => ") if hash && ! hash.empty?
|
143
151
|
end
|
144
152
|
|
145
153
|
def table_names(tables)
|
@@ -17,7 +17,24 @@ module Sequel
|
|
17
17
|
end.flatten
|
18
18
|
|
19
19
|
new_column_names = new_table[:columns].map {|c| c.name }
|
20
|
-
operations
|
20
|
+
operations += (db_columns.keys - new_column_names).map {|name| DropColumn.new(db_columns[name]) }
|
21
|
+
|
22
|
+
db_indexes = db_table[:indexes] || {}
|
23
|
+
new_indexes = new_table[:indexes] || {}
|
24
|
+
|
25
|
+
operations += (db_indexes.keys - new_indexes.keys).map do |index_name|
|
26
|
+
DropIndex.new(index_name,
|
27
|
+
db_indexes[index_name][:columns],
|
28
|
+
db_indexes[index_name][:unique])
|
29
|
+
end
|
30
|
+
|
31
|
+
operations += (new_indexes.keys - db_indexes.keys).map do |index_name|
|
32
|
+
AddIndex.new(index_name,
|
33
|
+
new_indexes[index_name][:columns],
|
34
|
+
new_indexes[index_name][:unique])
|
35
|
+
end
|
36
|
+
|
37
|
+
operations
|
21
38
|
end
|
22
39
|
|
23
40
|
# Returns an array of operations to change the current database
|
@@ -35,49 +52,55 @@ module Sequel
|
|
35
52
|
result.map {|k| ChangeColumn.new(db_column, new_column, k) }
|
36
53
|
end
|
37
54
|
|
55
|
+
# Base alter table operation class. Each operation will return
|
56
|
+
# Sequel::Migration statement(s) to alter the table.
|
57
|
+
class Operation
|
58
|
+
# Returns the statement for the up part of the migration
|
59
|
+
attr_reader :up
|
60
|
+
|
61
|
+
# Returns the statement for the down part of the operation
|
62
|
+
attr_reader :down
|
63
|
+
end
|
64
|
+
|
38
65
|
# Changes a column.
|
39
|
-
class ChangeColumn
|
66
|
+
class ChangeColumn < Operation
|
40
67
|
def initialize(old_column, new_column, statement)
|
41
|
-
@
|
42
|
-
@
|
43
|
-
end
|
44
|
-
|
45
|
-
def up
|
46
|
-
@new_column.__send__(@statement_method)
|
47
|
-
end
|
48
|
-
|
49
|
-
def down
|
50
|
-
@old_column.__send__(@statement_method)
|
68
|
+
@up = new_column.__send__(statement)
|
69
|
+
@down = old_column.__send__(statement)
|
51
70
|
end
|
52
71
|
end
|
53
72
|
|
54
73
|
# Adds a column.
|
55
|
-
class AddColumn
|
74
|
+
class AddColumn < Operation
|
56
75
|
def initialize(column)
|
57
|
-
@
|
58
|
-
|
59
|
-
|
60
|
-
def up
|
61
|
-
@column.add_statement
|
62
|
-
end
|
63
|
-
|
64
|
-
def down
|
65
|
-
@column.drop_statement
|
76
|
+
@up = column.add_statement
|
77
|
+
@down = column.drop_statement
|
66
78
|
end
|
67
79
|
end
|
68
80
|
|
69
81
|
# Drops a column.
|
70
|
-
class DropColumn
|
82
|
+
class DropColumn < Operation
|
71
83
|
def initialize(column)
|
72
|
-
@
|
84
|
+
@up = column.drop_statement
|
85
|
+
@down = column.add_statement
|
73
86
|
end
|
87
|
+
end
|
74
88
|
|
75
|
-
|
76
|
-
|
89
|
+
# Adds an index.
|
90
|
+
class AddIndex < Operation
|
91
|
+
def initialize(name, columns, unique)
|
92
|
+
@up = "add_index #{columns.inspect}, :name => #{name.inspect}"
|
93
|
+
@up << ", :unique => true" if unique
|
94
|
+
@down = "drop_index #{columns.inspect}, :name => #{name.inspect}"
|
77
95
|
end
|
96
|
+
end
|
78
97
|
|
79
|
-
|
80
|
-
|
98
|
+
# Drops an index.
|
99
|
+
class DropIndex < Operation
|
100
|
+
def initialize(name, columns, unique)
|
101
|
+
@up = "drop_index #{columns.inspect}, :name => #{name.inspect}"
|
102
|
+
@down = "add_index #{columns.inspect}, :name => #{name.inspect}"
|
103
|
+
@down << ", :unique => true" if unique
|
81
104
|
end
|
82
105
|
end
|
83
106
|
end
|
@@ -14,7 +14,7 @@ module Sequel
|
|
14
14
|
INTEGER_TYPES = [:tinyint, :integer, :smallint, :mediumint, :bigint]
|
15
15
|
|
16
16
|
# Database column types that hold fractional values.
|
17
|
-
DECIMAL_TYPES = [:decimal, :float, :
|
17
|
+
DECIMAL_TYPES = [:decimal, :float, :double, :real]
|
18
18
|
|
19
19
|
# All numeric database column types.
|
20
20
|
NUMERIC_TYPES = INTEGER_TYPES + DECIMAL_TYPES
|
@@ -81,7 +81,7 @@ module Sequel
|
|
81
81
|
}.select {|attribute, method| __send__(method, attribute, other) }.map {|a| a.first }.to_set
|
82
82
|
end
|
83
83
|
|
84
|
-
# Returns true if this column is numeric
|
84
|
+
# Returns true if this column is numeric.
|
85
85
|
#
|
86
86
|
def numeric?
|
87
87
|
NUMERIC_TYPES.include?(column_type)
|
@@ -28,7 +28,10 @@ module Sequel
|
|
28
28
|
#
|
29
29
|
def parse_db_schema
|
30
30
|
@db.tables.inject({}) do |result, table_name|
|
31
|
-
result[table_name] = {
|
31
|
+
result[table_name] = {
|
32
|
+
:indexes => @db.indexes(table_name),
|
33
|
+
:columns => parse_table_schema(@db.schema(table_name))
|
34
|
+
}
|
32
35
|
result
|
33
36
|
end
|
34
37
|
end
|
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{sequel_migration_builder}
|
8
|
-
s.version = "0.0
|
8
|
+
s.version = "0.1.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Roland Swingler"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-07-02}
|
13
13
|
s.description = %q{Build Sequel Migrations based on the differences between two schemas}
|
14
14
|
s.email = %q{roland.swingler@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -111,13 +111,15 @@ describe Sequel::Schema::AlterTableOperations::AddColumn do
|
|
111
111
|
before(:each) { @mock_column = mock() }
|
112
112
|
|
113
113
|
it "should ask the column for its add column statement on #up" do
|
114
|
-
@mock_column.should_receive(:add_statement)
|
115
|
-
|
114
|
+
@mock_column.should_receive(:add_statement).and_return("add")
|
115
|
+
@mock_column.should_receive(:drop_statement)
|
116
|
+
Sequel::Schema::AlterTableOperations::AddColumn.new(@mock_column).up.should == "add"
|
116
117
|
end
|
117
118
|
|
118
119
|
it "should ask the column for its drop column statement on #down" do
|
119
|
-
@mock_column.should_receive(:
|
120
|
-
|
120
|
+
@mock_column.should_receive(:add_statement)
|
121
|
+
@mock_column.should_receive(:drop_statement).and_return("drop")
|
122
|
+
Sequel::Schema::AlterTableOperations::AddColumn.new(@mock_column).down.should == "drop"
|
121
123
|
end
|
122
124
|
end
|
123
125
|
|
@@ -125,13 +127,15 @@ describe Sequel::Schema::AlterTableOperations::DropColumn do
|
|
125
127
|
before(:each) { @mock_column = mock() }
|
126
128
|
|
127
129
|
it "should ask the column for its drop column statement on #up" do
|
128
|
-
@mock_column.should_receive(:
|
129
|
-
|
130
|
+
@mock_column.should_receive(:add_statement)
|
131
|
+
@mock_column.should_receive(:drop_statement).and_return("drop")
|
132
|
+
Sequel::Schema::AlterTableOperations::DropColumn.new(@mock_column).up.should == "drop"
|
130
133
|
end
|
131
134
|
|
132
135
|
it "should ask the column for its add column statement on #down" do
|
133
|
-
@mock_column.should_receive(:
|
134
|
-
|
136
|
+
@mock_column.should_receive(:drop_statement)
|
137
|
+
@mock_column.should_receive(:add_statement).and_return("add")
|
138
|
+
Sequel::Schema::AlterTableOperations::DropColumn.new(@mock_column).down.should == "add"
|
135
139
|
end
|
136
140
|
end
|
137
141
|
|
@@ -139,14 +143,41 @@ describe Sequel::Schema::AlterTableOperations::ChangeColumn do
|
|
139
143
|
it "should ask the new column for statement on #up" do
|
140
144
|
new = mock(:new)
|
141
145
|
old = mock(:old)
|
142
|
-
|
143
|
-
|
146
|
+
old.should_receive(:change_type_statement)
|
147
|
+
new.should_receive(:change_type_statement).and_return("new")
|
148
|
+
Sequel::Schema::AlterTableOperations::ChangeColumn.new(old, new, :change_type_statement).up.should == "new"
|
144
149
|
end
|
145
150
|
|
146
|
-
it "should ask the
|
151
|
+
it "should ask the old column for statement on #down" do
|
147
152
|
new = mock(:new)
|
148
153
|
old = mock(:old)
|
149
|
-
old.should_receive(:change_type_statement)
|
154
|
+
old.should_receive(:change_type_statement).and_return("old")
|
155
|
+
new.should_receive(:change_type_statement)
|
150
156
|
Sequel::Schema::AlterTableOperations::ChangeColumn.new(old, new, :change_type_statement).down
|
151
157
|
end
|
152
158
|
end
|
159
|
+
|
160
|
+
|
161
|
+
describe Sequel::Schema::AlterTableOperations::AddIndex do
|
162
|
+
it "should add the index on #up" do
|
163
|
+
Sequel::Schema::AlterTableOperations::AddIndex.new(:foo_index, :foo, true).up.
|
164
|
+
should == "add_index :foo, :name => :foo_index, :unique => true"
|
165
|
+
end
|
166
|
+
|
167
|
+
it "should drop the index on #down" do
|
168
|
+
Sequel::Schema::AlterTableOperations::AddIndex.new(:foo_index, :foo, true).down.
|
169
|
+
should == "drop_index :foo, :name => :foo_index"
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe Sequel::Schema::AlterTableOperations::DropIndex do
|
174
|
+
it "should add the index on #down" do
|
175
|
+
Sequel::Schema::AlterTableOperations::DropIndex.new(:foo_index, :foo, true).down.
|
176
|
+
should == "add_index :foo, :name => :foo_index, :unique => true"
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should drop the index on #up" do
|
180
|
+
Sequel::Schema::AlterTableOperations::DropIndex.new(:foo_index, :foo, true).up.
|
181
|
+
should == "drop_index :foo, :name => :foo_index"
|
182
|
+
end
|
183
|
+
end
|
@@ -114,6 +114,7 @@ describe "Sequel::Schema::DbSchemaParser#parse_db_schema" do
|
|
114
114
|
mock_db = mock(:db)
|
115
115
|
mock_db.should_receive(:tables).at_least(:once).and_return([:table1])
|
116
116
|
mock_db.should_receive(:schema).with(:table1).and_return([])
|
117
|
+
mock_db.should_receive(:indexes).with(:table1)
|
117
118
|
|
118
119
|
@parser = Sequel::Schema::DbSchemaParser.for_db(mock_db)
|
119
120
|
@parser.parse_db_schema.keys.should == [:table1]
|
@@ -107,13 +107,35 @@ END
|
|
107
107
|
should == expected.strip
|
108
108
|
end
|
109
109
|
|
110
|
+
it "should add indexes to the create_table statement" do
|
111
|
+
mock_db = mock(:database)
|
112
|
+
mock_db.should_receive(:tables).at_least(:once).and_return([])
|
113
|
+
table = {
|
114
|
+
:indexes => {:foo_index => {:columns => :foo, :unique => true}},
|
115
|
+
:columns => [{:name => :foo, :column_type => :integer}]
|
116
|
+
}
|
117
|
+
|
118
|
+
expected = <<-END
|
119
|
+
create_table :example_table do
|
120
|
+
integer :foo, :null => false
|
121
|
+
|
122
|
+
index :foo, :name => :foo_index, :unique => true
|
123
|
+
end
|
124
|
+
END
|
125
|
+
|
126
|
+
Sequel::MigrationBuilder.new(mock_db).create_table_statement(:example_table, table).join("\n").
|
127
|
+
should == expected.strip
|
128
|
+
end
|
129
|
+
|
110
130
|
context "when a table needs to be altered" do
|
111
131
|
before :each do
|
112
132
|
@tables = { :example_table =>
|
113
|
-
{:
|
133
|
+
{ :indexes => {:foo_index => {:columns => :foo, :unique => true}},
|
134
|
+
:columns => [{:name => :foo, :column_type => :integer}, {:name => :bar, :column_type => :varchar}]}
|
114
135
|
}
|
115
136
|
@mock_db = mock(:database)
|
116
137
|
@mock_db.should_receive(:tables).at_least(:once).and_return([:example_table])
|
138
|
+
@mock_db.should_receive(:indexes).with(:example_table).and_return({})
|
117
139
|
@mock_db.should_receive(:schema).with(:example_table).and_return([[:foo, {:type => :integer, :db_type => "smallint(5) unsigned", :allow_null => true, :ruby_default => 10}]])
|
118
140
|
|
119
141
|
end
|
@@ -125,6 +147,7 @@ up do
|
|
125
147
|
set_column_type :foo, :integer, :default => nil
|
126
148
|
set_column_allow_null :foo, false
|
127
149
|
add_column :bar, :varchar, :null => false
|
150
|
+
add_index :foo, :name => :foo_index, :unique => true
|
128
151
|
end
|
129
152
|
end
|
130
153
|
END
|
@@ -138,6 +161,7 @@ down do
|
|
138
161
|
set_column_type :foo, :smallint, :default => 10, :unsigned => true
|
139
162
|
set_column_allow_null :foo, true
|
140
163
|
drop_column :bar
|
164
|
+
drop_index :foo, :name => :foo_index
|
141
165
|
end
|
142
166
|
end
|
143
167
|
END
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
+
- 1
|
7
8
|
- 0
|
8
|
-
|
9
|
-
version: 0.0.5
|
9
|
+
version: 0.1.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Roland Swingler
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-07-02 00:00:00 +01:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|