sequel_migration_builder 0.0.5 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -21,6 +21,10 @@ as a hash. A sample YAML version might look like:
21
21
  primary_key: id
22
22
  table_options:
23
23
  engine: myisam
24
+ indexes:
25
+ foo_index_name:
26
+ columns: foo
27
+ unique: true
24
28
  columns:
25
29
  - name: id
26
30
  column_type: integer
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.5
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 + (db_columns.keys - new_column_names).map {|column| DropColumn.new(column) }
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
- @old_column, @new_column = old_column, new_column
42
- @statement_method = statement
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
- @column = column
58
- end
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
- @column = column
84
+ @up = column.drop_statement
85
+ @down = column.add_statement
73
86
  end
87
+ end
74
88
 
75
- def up
76
- @column.drop_statement
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
- def down
80
- @column.add_statement
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, :bigdecimal]
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] = {:columns => parse_table_schema(@db.schema(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.5"
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-06-23}
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
- Sequel::Schema::AlterTableOperations::AddColumn.new(@mock_column).up
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(:drop_statement)
120
- Sequel::Schema::AlterTableOperations::AddColumn.new(@mock_column).down
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(:drop_statement)
129
- Sequel::Schema::AlterTableOperations::DropColumn.new(@mock_column).up
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(:add_statement)
134
- Sequel::Schema::AlterTableOperations::DropColumn.new(@mock_column).down
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
- new.should_receive(:change_type_statement)
143
- Sequel::Schema::AlterTableOperations::ChangeColumn.new(old, new, :change_type_statement).up
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 new column for statement on #down" do
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
- {:columns => [{:name => :foo, :column_type => :integer}, {:name => :bar, :column_type => :varchar}]}
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
- - 5
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-06-23 00:00:00 +01:00
17
+ date: 2010-07-02 00:00:00 +01:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency