sequel_migration_builder 0.1.4 → 0.2.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/CHANGELOG +9 -0
- data/README.rdoc +11 -1
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/lib/sequel/migration_builder.rb +43 -43
- data/lib/sequel/schema/alter_table_operations.rb +21 -89
- data/lib/sequel/schema/db_index.rb +78 -0
- data/sequel_migration_builder.gemspec +11 -7
- data/spec/alter_table_operations_spec.rb +25 -110
- data/spec/db_index_spec.rb +76 -0
- data/spec/migration_builder_spec.rb +6 -28
- metadata +20 -7
data/CHANGELOG
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
CHANGELOG
|
2
|
+
|
3
|
+
== 0.2.0
|
4
|
+
|
5
|
+
* Switched to using the new style 'change' block in the generated
|
6
|
+
migrations, rather than 'up' or 'down'. This bumps the Sequel
|
7
|
+
requirement to at least 3.18.0.
|
8
|
+
* Changes in indexes are properly handled - not just if the names
|
9
|
+
are different.
|
data/README.rdoc
CHANGED
@@ -3,6 +3,16 @@
|
|
3
3
|
Builds sequel migrations based on the differences between an abstract
|
4
4
|
representation of the desired schema and a database instance.
|
5
5
|
|
6
|
+
This is quite a low-level library - it doesn't provide any functionality
|
7
|
+
to write out migration files, nor does it provide a ruby DSL for defining
|
8
|
+
your schema (see Schema format below).
|
9
|
+
|
10
|
+
This library is also very, very new, so there WILL be bugs.
|
11
|
+
|
12
|
+
== Install
|
13
|
+
|
14
|
+
sudo gem install sequel_migration_builder
|
15
|
+
|
6
16
|
== Example
|
7
17
|
|
8
18
|
require 'sequel/migration_builder'
|
@@ -38,7 +48,7 @@ as a hash. A sample YAML version might look like:
|
|
38
48
|
|
39
49
|
== Requirements
|
40
50
|
|
41
|
-
* Sequel 3.
|
51
|
+
* Sequel 3.18.0 or higher
|
42
52
|
|
43
53
|
== TODO
|
44
54
|
|
data/Rakefile
CHANGED
@@ -10,7 +10,7 @@ begin
|
|
10
10
|
gem.email = "roland.swingler@gmail.com"
|
11
11
|
gem.homepage = "http://github.com/knaveofdiamonds/sequel_migration_builder"
|
12
12
|
gem.authors = ["Roland Swingler"]
|
13
|
-
gem.add_dependency "sequel", ">= 3.
|
13
|
+
gem.add_dependency "sequel", ">= 3.18.0"
|
14
14
|
gem.add_development_dependency "rspec", ">= 1.2.9"
|
15
15
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
16
16
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'sequel/extensions/blank'
|
2
2
|
require 'sequel/schema/db_column'
|
3
|
+
require 'sequel/schema/db_index'
|
3
4
|
require 'sequel/schema/db_schema_parser'
|
4
5
|
require 'sequel/schema/alter_table_operations'
|
5
6
|
|
@@ -30,38 +31,23 @@ module Sequel
|
|
30
31
|
|
31
32
|
add_line "Sequel.migration do"
|
32
33
|
indent do
|
33
|
-
|
34
|
-
generate_down(tables)
|
34
|
+
generate_migration_body(tables)
|
35
35
|
end
|
36
36
|
add_line "end\n"
|
37
37
|
|
38
38
|
result.join("\n")
|
39
39
|
end
|
40
40
|
|
41
|
-
# Generates the '
|
41
|
+
# Generates the 'change' block of the migration.
|
42
42
|
#
|
43
|
-
def
|
43
|
+
def generate_migration_body(tables)
|
44
44
|
current_tables, new_tables = table_names(tables).partition do |table_name|
|
45
45
|
@db_table_names.include?(table_name)
|
46
46
|
end
|
47
47
|
|
48
|
-
add_line "
|
48
|
+
add_line "change do"
|
49
49
|
create_new_tables(new_tables, tables)
|
50
|
-
alter_tables(current_tables, tables
|
51
|
-
add_line "end"
|
52
|
-
add_blank_line
|
53
|
-
end
|
54
|
-
|
55
|
-
# Generates the down part of the migration.
|
56
|
-
#
|
57
|
-
def generate_down(tables)
|
58
|
-
current_tables, new_tables = table_names(tables).partition do |table_name|
|
59
|
-
@db_table_names.include?(table_name)
|
60
|
-
end
|
61
|
-
|
62
|
-
add_line "down do"
|
63
|
-
alter_tables(current_tables, tables, :down)
|
64
|
-
drop_new_tables(new_tables)
|
50
|
+
alter_tables(current_tables, tables)
|
65
51
|
add_line "end"
|
66
52
|
end
|
67
53
|
|
@@ -84,13 +70,13 @@ module Sequel
|
|
84
70
|
|
85
71
|
# Generates any alter table statements for current tables.
|
86
72
|
#
|
87
|
-
def alter_tables(current_table_names, tables
|
73
|
+
def alter_tables(current_table_names, tables)
|
88
74
|
each_table(current_table_names, tables) do |table_name, table, last_table|
|
89
75
|
hsh = table.dup
|
90
76
|
hsh[:columns] = hsh[:columns].map {|c| Schema::DbColumn.build_from_hash(c) }
|
91
77
|
operations = Schema::AlterTableOperations.build(@db_tables[table_name], hsh)
|
92
78
|
unless operations.empty?
|
93
|
-
alter_table_statement table_name, operations
|
79
|
+
alter_table_statement table_name, operations
|
94
80
|
add_blank_line unless last_table
|
95
81
|
end
|
96
82
|
end
|
@@ -98,10 +84,10 @@ module Sequel
|
|
98
84
|
|
99
85
|
# Generates an individual alter table statement.
|
100
86
|
#
|
101
|
-
def alter_table_statement(table_name, operations
|
87
|
+
def alter_table_statement(table_name, operations)
|
102
88
|
add_line "alter_table #{table_name.inspect} do"
|
103
89
|
indent do
|
104
|
-
operations.
|
90
|
+
operations.compact.each {|op| add_line op }
|
105
91
|
end
|
106
92
|
add_line "end"
|
107
93
|
end
|
@@ -109,30 +95,44 @@ module Sequel
|
|
109
95
|
# Generates an individual create_table statement.
|
110
96
|
#
|
111
97
|
def create_table_statement(table_name, table)
|
98
|
+
normalize_primary_key(table)
|
112
99
|
add_line "create_table #{table_name.inspect}#{pretty_hash(table[:table_options])} do"
|
113
100
|
indent do
|
114
|
-
table[:
|
115
|
-
table[:
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
101
|
+
output_columns(table[:columns], table[:primary_key])
|
102
|
+
output_indexes(table[:indexes])
|
103
|
+
output_composite_primary_key(table[:primary_key])
|
104
|
+
end
|
105
|
+
add_line "end"
|
106
|
+
end
|
107
|
+
|
108
|
+
def normalize_primary_key(table)
|
109
|
+
table[:primary_key] = [table[:primary_key]] if table[:primary_key].kind_of?(Symbol)
|
110
|
+
end
|
111
|
+
|
112
|
+
def output_columns(columns, primary_key)
|
113
|
+
columns.each do |c|
|
114
|
+
column = Schema::DbColumn.build_from_hash(c)
|
115
|
+
if primary_key && primary_key.size == 1 && primary_key.first == column.name
|
116
|
+
column.single_primary_key = true
|
129
117
|
end
|
130
|
-
|
131
|
-
|
132
|
-
|
118
|
+
add_line column.define_statement
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def output_indexes(indexes)
|
123
|
+
if indexes
|
124
|
+
add_blank_line
|
125
|
+
Schema::DbIndex.build_from_hash(indexes).each do |idx|
|
126
|
+
add_line idx.define_statement
|
133
127
|
end
|
134
128
|
end
|
135
|
-
|
129
|
+
end
|
130
|
+
|
131
|
+
def output_composite_primary_key(primary_key)
|
132
|
+
if primary_key && primary_key.size > 1
|
133
|
+
add_blank_line
|
134
|
+
add_line "primary_key #{primary_key.inspect}"
|
135
|
+
end
|
136
136
|
end
|
137
137
|
|
138
138
|
private
|
@@ -1,60 +1,48 @@
|
|
1
1
|
module Sequel
|
2
2
|
module Schema
|
3
|
-
|
4
|
-
|
3
|
+
class AlterTableOperations
|
5
4
|
# Returns an array of operations to change the current database
|
6
5
|
# table to be like the defined table.
|
7
6
|
#
|
8
7
|
def self.build(db_table, new_table)
|
8
|
+
new.build(db_table, new_table)
|
9
|
+
end
|
10
|
+
|
11
|
+
def build(db_table, new_table)
|
9
12
|
db_columns = db_table[:columns].inject({}) {|hsh, column| hsh[column.name] = column; hsh }
|
13
|
+
new_column_names = new_table[:columns].map {|c| c.name }
|
14
|
+
dropped_columns = db_columns.keys - new_column_names
|
10
15
|
|
11
16
|
operations = new_table[:columns].map do |column|
|
12
17
|
if db_columns[column.name]
|
13
18
|
build_column_operations db_columns[column.name], column
|
14
19
|
else
|
15
|
-
|
20
|
+
column.add_statement
|
16
21
|
end
|
17
22
|
end.flatten
|
18
23
|
|
19
|
-
new_column_names = new_table[:columns].map {|c| c.name }
|
20
|
-
dropped_columns = db_columns.keys - new_column_names
|
21
|
-
|
22
24
|
operations += dropped_columns.map do |name|
|
23
|
-
|
25
|
+
db_columns[name].drop_statement
|
24
26
|
end
|
25
27
|
|
26
|
-
db_indexes = db_table[:indexes] || {}
|
27
|
-
new_indexes = new_table[:indexes] || {}
|
28
|
-
|
29
|
-
operations += (db_indexes
|
30
|
-
|
31
|
-
|
32
|
-
DropIndex.new(index_name,
|
33
|
-
db_indexes[index_name][:columns],
|
34
|
-
db_indexes[index_name][:unique],
|
35
|
-
! dropped_column)
|
28
|
+
db_indexes = Schema::DbIndex.build_from_hash(db_table[:indexes] || {})
|
29
|
+
new_indexes = Schema::DbIndex.build_from_hash(new_table[:indexes] || {})
|
30
|
+
|
31
|
+
operations += (db_indexes - new_indexes).map do |index|
|
32
|
+
index.drop_statement unless index.columns.all? {|c| dropped_columns.include?(c) }
|
36
33
|
end
|
37
|
-
|
38
|
-
operations += (new_indexes
|
39
|
-
|
40
|
-
dropped_column = dropped_columns.include?(new_indexes[index_name][:columns])
|
41
|
-
else
|
42
|
-
dropped_column = new_indexes[index_name][:columns].size == 1 && dropped_columns.include?(new_indexes[index_name][:columns].first)
|
43
|
-
end
|
44
|
-
|
45
|
-
AddIndex.new(index_name,
|
46
|
-
new_indexes[index_name][:columns],
|
47
|
-
new_indexes[index_name][:unique],
|
48
|
-
! dropped_column)
|
34
|
+
|
35
|
+
operations += (new_indexes - db_indexes).map do |index|
|
36
|
+
index.add_statement
|
49
37
|
end
|
50
|
-
|
51
|
-
operations
|
38
|
+
|
39
|
+
operations
|
52
40
|
end
|
53
41
|
|
54
42
|
# Returns an array of operations to change the current database
|
55
43
|
# column to be like the defined column.
|
56
44
|
#
|
57
|
-
def
|
45
|
+
def build_column_operations(db_column, new_column)
|
58
46
|
result = []
|
59
47
|
|
60
48
|
diffs = db_column.diff(new_column)
|
@@ -63,63 +51,7 @@ module Sequel
|
|
63
51
|
result << :change_default_statement if diffs.include?(:default) && result.empty?
|
64
52
|
result << :change_null_statement if diffs.include?(:null)
|
65
53
|
|
66
|
-
result.map {|
|
67
|
-
end
|
68
|
-
|
69
|
-
# Base alter table operation class. Each operation will return
|
70
|
-
# Sequel::Migration statement(s) to alter the table.
|
71
|
-
class Operation
|
72
|
-
# Returns the statement for the up part of the migration
|
73
|
-
attr_reader :up
|
74
|
-
|
75
|
-
# Returns the statement for the down part of the operation
|
76
|
-
attr_reader :down
|
77
|
-
end
|
78
|
-
|
79
|
-
# Changes a column.
|
80
|
-
class ChangeColumn < Operation
|
81
|
-
def initialize(old_column, new_column, statement)
|
82
|
-
@up = new_column.__send__(statement)
|
83
|
-
@down = old_column.__send__(statement)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
# Adds a column.
|
88
|
-
class AddColumn < Operation
|
89
|
-
def initialize(column)
|
90
|
-
@up = column.add_statement
|
91
|
-
@down = column.drop_statement
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
# Drops a column.
|
96
|
-
class DropColumn < Operation
|
97
|
-
def initialize(column)
|
98
|
-
@up = column.drop_statement
|
99
|
-
@down = column.add_statement
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
# Adds an index.
|
104
|
-
class AddIndex < Operation
|
105
|
-
def initialize(name, columns, unique, include_drop_index=true)
|
106
|
-
@up = "add_index #{columns.inspect}, :name => #{name.inspect}"
|
107
|
-
@up << ", :unique => true" if unique
|
108
|
-
if include_drop_index
|
109
|
-
@down = "drop_index #{columns.inspect}, :name => #{name.inspect}"
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
# Drops an index.
|
115
|
-
class DropIndex < Operation
|
116
|
-
def initialize(name, columns, unique, include_drop_index=true)
|
117
|
-
if include_drop_index
|
118
|
-
@up = "drop_index #{columns.inspect}, :name => #{name.inspect}"
|
119
|
-
end
|
120
|
-
@down = "add_index #{columns.inspect}, :name => #{name.inspect}"
|
121
|
-
@down << ", :unique => true" if unique
|
122
|
-
end
|
54
|
+
result.map {|statement| new_column.__send__(statement) }
|
123
55
|
end
|
124
56
|
end
|
125
57
|
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Sequel
|
2
|
+
module Schema
|
3
|
+
class DbIndex
|
4
|
+
attr_accessor :name
|
5
|
+
attr_reader :columns
|
6
|
+
|
7
|
+
# Builds an Array of DbIndexes from the index hash returned by
|
8
|
+
# Sequel::Database#indexes
|
9
|
+
def self.build_from_hash(definitions)
|
10
|
+
definitions.map {|name,attrs| new(name, attrs[:columns], attrs[:unique]) }
|
11
|
+
end
|
12
|
+
|
13
|
+
# Creates a new DbIndex definition.
|
14
|
+
#
|
15
|
+
# columns may be a single column name as a symbol, or an array
|
16
|
+
# of column symbol names.
|
17
|
+
#
|
18
|
+
# Indexes are not unique by default.
|
19
|
+
def initialize(name, columns, unique=false)
|
20
|
+
@name = name.to_sym
|
21
|
+
@columns = columns.kind_of?(Array) ? columns.clone : [columns]
|
22
|
+
@unique = unique
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns true if this index is unique
|
26
|
+
def unique?
|
27
|
+
!! @unique
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns true if this index has more than one column.
|
31
|
+
def multi_column?
|
32
|
+
@columns.size > 1
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns the sequel migration statement to define an index in a
|
36
|
+
# create_table block.
|
37
|
+
def define_statement
|
38
|
+
base_add_statement('index')
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns the sequel migration statement to add an index in an
|
42
|
+
# alter_table block.
|
43
|
+
def add_statement
|
44
|
+
base_add_statement('add_index')
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns the sequel migration statement to remove an index in an
|
48
|
+
# alter_table block.
|
49
|
+
def drop_statement
|
50
|
+
"drop_index #{columns_for_statement.inspect}, :name => #{name.inspect}"
|
51
|
+
end
|
52
|
+
|
53
|
+
# Indexes are equal if all their attributes are equal.
|
54
|
+
def ==(other)
|
55
|
+
other.kind_of?(self.class) &&
|
56
|
+
@name == other.name && @columns == other.columns && @unique == other.unique?
|
57
|
+
end
|
58
|
+
alias :eql? :==
|
59
|
+
|
60
|
+
def hash # :nodoc:
|
61
|
+
@name.hash
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def columns_for_statement
|
67
|
+
return columns.first unless multi_column?
|
68
|
+
columns
|
69
|
+
end
|
70
|
+
|
71
|
+
def base_add_statement(keyword)
|
72
|
+
parts = ["#{keyword} #{columns_for_statement.inspect}, :name => #{name.inspect}"]
|
73
|
+
parts << ":unique => #{@unique.inspect}" if unique?
|
74
|
+
parts.join(", ")
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
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.
|
8
|
+
s.version = "0.2.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{
|
12
|
+
s.date = %q{2011-01-13}
|
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 = [
|
@@ -19,6 +19,7 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.files = [
|
20
20
|
".document",
|
21
21
|
".gitignore",
|
22
|
+
"CHANGELOG",
|
22
23
|
"LICENSE",
|
23
24
|
"README.rdoc",
|
24
25
|
"Rakefile",
|
@@ -26,10 +27,12 @@ Gem::Specification.new do |s|
|
|
26
27
|
"lib/sequel/migration_builder.rb",
|
27
28
|
"lib/sequel/schema/alter_table_operations.rb",
|
28
29
|
"lib/sequel/schema/db_column.rb",
|
30
|
+
"lib/sequel/schema/db_index.rb",
|
29
31
|
"lib/sequel/schema/db_schema_parser.rb",
|
30
32
|
"sequel_migration_builder.gemspec",
|
31
33
|
"spec/alter_table_operations_spec.rb",
|
32
34
|
"spec/db_column_spec.rb",
|
35
|
+
"spec/db_index_spec.rb",
|
33
36
|
"spec/db_schema_parser_spec.rb",
|
34
37
|
"spec/migration_builder_spec.rb",
|
35
38
|
"spec/spec.opts",
|
@@ -38,11 +41,12 @@ Gem::Specification.new do |s|
|
|
38
41
|
s.homepage = %q{http://github.com/knaveofdiamonds/sequel_migration_builder}
|
39
42
|
s.rdoc_options = ["--charset=UTF-8"]
|
40
43
|
s.require_paths = ["lib"]
|
41
|
-
s.rubygems_version = %q{1.3.
|
44
|
+
s.rubygems_version = %q{1.3.7}
|
42
45
|
s.summary = %q{Build Sequel Migrations based on the differences between two schemas}
|
43
46
|
s.test_files = [
|
44
47
|
"spec/alter_table_operations_spec.rb",
|
45
48
|
"spec/db_column_spec.rb",
|
49
|
+
"spec/db_index_spec.rb",
|
46
50
|
"spec/db_schema_parser_spec.rb",
|
47
51
|
"spec/migration_builder_spec.rb",
|
48
52
|
"spec/spec_helper.rb"
|
@@ -52,15 +56,15 @@ Gem::Specification.new do |s|
|
|
52
56
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
53
57
|
s.specification_version = 3
|
54
58
|
|
55
|
-
if Gem::Version.new(Gem::
|
56
|
-
s.add_runtime_dependency(%q<sequel>, [">= 3.
|
59
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
60
|
+
s.add_runtime_dependency(%q<sequel>, [">= 3.18.0"])
|
57
61
|
s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
|
58
62
|
else
|
59
|
-
s.add_dependency(%q<sequel>, [">= 3.
|
63
|
+
s.add_dependency(%q<sequel>, [">= 3.18.0"])
|
60
64
|
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
61
65
|
end
|
62
66
|
else
|
63
|
-
s.add_dependency(%q<sequel>, [">= 3.
|
67
|
+
s.add_dependency(%q<sequel>, [">= 3.18.0"])
|
64
68
|
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
65
69
|
end
|
66
70
|
end
|
@@ -4,69 +4,73 @@ def build_column(hash)
|
|
4
4
|
Sequel::Schema::DbColumn.build_from_hash(hash)
|
5
5
|
end
|
6
6
|
|
7
|
-
describe "Sequel::Schema::AlterTableOperations
|
7
|
+
describe "Sequel::Schema::AlterTableOperations#build_column_operations" do
|
8
|
+
before :each do
|
9
|
+
@subject = Sequel::Schema::AlterTableOperations.new
|
10
|
+
end
|
11
|
+
|
8
12
|
it "should return an empty Array if there are no differences between column definitions" do
|
9
13
|
a = build_column(:name => :foo, :column_type => :integer)
|
10
14
|
b = build_column(:name => :foo, :column_type => :integer)
|
11
15
|
|
12
|
-
|
16
|
+
@subject.build_column_operations(a,b).should == []
|
13
17
|
end
|
14
18
|
|
15
19
|
it "should return a ChangeColumn operation if the types are different" do
|
16
20
|
a = build_column(:name => :foo, :column_type => :integer)
|
17
21
|
b = build_column(:name => :foo, :column_type => :smallint)
|
18
|
-
ops =
|
22
|
+
ops = @subject.build_column_operations(a,b)
|
19
23
|
|
20
|
-
ops.first.
|
24
|
+
ops.first.should == "set_column_type :foo, :smallint, :default => nil"
|
21
25
|
end
|
22
26
|
|
23
27
|
it "should return a ChangeColumn operation if the sizes are different" do
|
24
28
|
a = build_column(:name => :foo, :column_type => :char, :size => 20)
|
25
29
|
b = build_column(:name => :foo, :column_type => :char, :size => 10)
|
26
|
-
ops =
|
30
|
+
ops = @subject.build_column_operations(a,b)
|
27
31
|
|
28
|
-
ops.first.
|
32
|
+
ops.first.should == "set_column_type :foo, :char, :default => nil, :size => 10"
|
29
33
|
end
|
30
34
|
|
31
35
|
it "should return a ChangeColumn operation if the unsigned value is different" do
|
32
36
|
a = build_column(:name => :foo, :column_type => :integer, :unsigned => true)
|
33
37
|
b = build_column(:name => :foo, :column_type => :integer, :unsigned => false)
|
34
|
-
ops =
|
38
|
+
ops = @subject.build_column_operations(a,b)
|
35
39
|
|
36
|
-
ops.first.
|
40
|
+
ops.first.should == "set_column_type :foo, :integer, :default => nil, :unsigned => false"
|
37
41
|
end
|
38
42
|
|
39
43
|
it "should return a ChangeColumn operation to set the null value if the null value is different" do
|
40
44
|
a = build_column(:name => :foo, :column_type => :integer, :null => true)
|
41
45
|
b = build_column(:name => :foo, :column_type => :integer, :null => false)
|
42
|
-
ops =
|
46
|
+
ops = @subject.build_column_operations(a,b)
|
43
47
|
|
44
|
-
ops.first.
|
48
|
+
ops.first.should == "set_column_allow_null :foo, false"
|
45
49
|
end
|
46
50
|
|
47
51
|
it "should return a ChangeColumn operation to set the default if the default value is different" do
|
48
52
|
a = build_column(:name => :foo, :column_type => :integer, :default => 1)
|
49
53
|
b = build_column(:name => :foo, :column_type => :integer, :default => 2)
|
50
|
-
ops =
|
54
|
+
ops = @subject.build_column_operations(a,b)
|
51
55
|
|
52
|
-
ops.first.
|
56
|
+
ops.first.should == "set_column_default :foo, 2"
|
53
57
|
end
|
54
58
|
|
55
59
|
it "should only return 1 operation if the default and other values are different" do
|
56
60
|
a = build_column(:name => :foo, :column_type => :integer, :default => 1)
|
57
61
|
b = build_column(:name => :foo, :column_type => :smallint, :default => 2)
|
58
|
-
ops =
|
62
|
+
ops = @subject.build_column_operations(a,b)
|
59
63
|
|
60
64
|
ops.size.should == 1
|
61
|
-
ops.first.
|
65
|
+
ops.first.should == "set_column_type :foo, :smallint, :default => 2"
|
62
66
|
end
|
63
67
|
|
64
68
|
it "should return a ChangeColumn operation if the elements are different" do
|
65
69
|
a = build_column(:name => :foo, :column_type => :enum, :elements => ["A"])
|
66
70
|
b = build_column(:name => :foo, :column_type => :enum, :elements => ["A", "B"])
|
67
|
-
ops =
|
71
|
+
ops = @subject.build_column_operations(a,b)
|
68
72
|
|
69
|
-
ops.first.
|
73
|
+
ops.first.should == "set_column_type :foo, :enum, :default => nil, :elements => [\"A\", \"B\"]"
|
70
74
|
end
|
71
75
|
end
|
72
76
|
|
@@ -89,7 +93,7 @@ describe "Sequel::Schema::AlterTableOperations.build" do
|
|
89
93
|
ops = Sequel::Schema::AlterTableOperations.build(table_a,table_b)
|
90
94
|
|
91
95
|
ops.size.should == 1
|
92
|
-
ops.first.should
|
96
|
+
ops.first.should =~ /add_column/
|
93
97
|
end
|
94
98
|
|
95
99
|
it "should return a drop column operation if the column has been removed" do
|
@@ -100,7 +104,7 @@ describe "Sequel::Schema::AlterTableOperations.build" do
|
|
100
104
|
ops = Sequel::Schema::AlterTableOperations.build(table_a,table_b)
|
101
105
|
|
102
106
|
ops.size.should == 1
|
103
|
-
ops.first.should
|
107
|
+
ops.first.should =~ /drop_column/
|
104
108
|
end
|
105
109
|
|
106
110
|
it "should return a change column operation if columns are different" do
|
@@ -111,105 +115,16 @@ describe "Sequel::Schema::AlterTableOperations.build" do
|
|
111
115
|
ops = Sequel::Schema::AlterTableOperations.build(table_a,table_b)
|
112
116
|
|
113
117
|
ops.size.should == 1
|
114
|
-
ops.first.should
|
118
|
+
ops.first.should =~ /set_column/
|
115
119
|
end
|
116
120
|
|
117
|
-
it "should not output a drop index statement in #
|
121
|
+
it "should not output a drop index statement in #change if the index's column is also removed" do
|
118
122
|
table_a = {:name => :example_table,
|
119
123
|
:indexes => {:foo_idx => {:columns => [:foo]}},
|
120
124
|
:columns => [build_column(:name => :foo, :column_type => :integer)]}
|
121
125
|
table_b = {:name => :example_table, :indexes => {}, :columns => []}
|
122
126
|
ops = Sequel::Schema::AlterTableOperations.build(table_a,table_b)
|
123
127
|
|
124
|
-
ops.last.should
|
125
|
-
ops.last.up.should be_nil
|
126
|
-
ops.last.down.should == "add_index [:foo], :name => :foo_idx"
|
127
|
-
end
|
128
|
-
|
129
|
-
it "should not output a drop index statement in #down if the index's column is also added" do
|
130
|
-
table_a = {:name => :example_table,
|
131
|
-
:indexes => {},
|
132
|
-
:columns => [build_column(:name => :foo, :column_type => :integer)]}
|
133
|
-
table_b = {:name => :example_table, :indexes => {:foo_idx => {:columns => [:foo]}}, :columns => []}
|
134
|
-
ops = Sequel::Schema::AlterTableOperations.build(table_a,table_b)
|
135
|
-
|
136
|
-
ops.last.should be_kind_of(Sequel::Schema::AlterTableOperations::AddIndex)
|
137
|
-
ops.last.up.should == "add_index [:foo], :name => :foo_idx"
|
138
|
-
ops.last.down.should be_nil
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
describe Sequel::Schema::AlterTableOperations::AddColumn do
|
143
|
-
before(:each) { @mock_column = mock() }
|
144
|
-
|
145
|
-
it "should ask the column for its add column statement on #up" do
|
146
|
-
@mock_column.should_receive(:add_statement).and_return("add")
|
147
|
-
@mock_column.should_receive(:drop_statement)
|
148
|
-
Sequel::Schema::AlterTableOperations::AddColumn.new(@mock_column).up.should == "add"
|
149
|
-
end
|
150
|
-
|
151
|
-
it "should ask the column for its drop column statement on #down" do
|
152
|
-
@mock_column.should_receive(:add_statement)
|
153
|
-
@mock_column.should_receive(:drop_statement).and_return("drop")
|
154
|
-
Sequel::Schema::AlterTableOperations::AddColumn.new(@mock_column).down.should == "drop"
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
describe Sequel::Schema::AlterTableOperations::DropColumn do
|
159
|
-
before(:each) { @mock_column = mock() }
|
160
|
-
|
161
|
-
it "should ask the column for its drop column statement on #up" do
|
162
|
-
@mock_column.should_receive(:add_statement)
|
163
|
-
@mock_column.should_receive(:drop_statement).and_return("drop")
|
164
|
-
Sequel::Schema::AlterTableOperations::DropColumn.new(@mock_column).up.should == "drop"
|
165
|
-
end
|
166
|
-
|
167
|
-
it "should ask the column for its add column statement on #down" do
|
168
|
-
@mock_column.should_receive(:drop_statement)
|
169
|
-
@mock_column.should_receive(:add_statement).and_return("add")
|
170
|
-
Sequel::Schema::AlterTableOperations::DropColumn.new(@mock_column).down.should == "add"
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
describe Sequel::Schema::AlterTableOperations::ChangeColumn do
|
175
|
-
it "should ask the new column for statement on #up" do
|
176
|
-
new = mock(:new)
|
177
|
-
old = mock(:old)
|
178
|
-
old.should_receive(:change_type_statement)
|
179
|
-
new.should_receive(:change_type_statement).and_return("new")
|
180
|
-
Sequel::Schema::AlterTableOperations::ChangeColumn.new(old, new, :change_type_statement).up.should == "new"
|
181
|
-
end
|
182
|
-
|
183
|
-
it "should ask the old column for statement on #down" do
|
184
|
-
new = mock(:new)
|
185
|
-
old = mock(:old)
|
186
|
-
old.should_receive(:change_type_statement).and_return("old")
|
187
|
-
new.should_receive(:change_type_statement)
|
188
|
-
Sequel::Schema::AlterTableOperations::ChangeColumn.new(old, new, :change_type_statement).down
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
|
-
|
193
|
-
describe Sequel::Schema::AlterTableOperations::AddIndex do
|
194
|
-
it "should add the index on #up" do
|
195
|
-
Sequel::Schema::AlterTableOperations::AddIndex.new(:foo_index, :foo, true).up.
|
196
|
-
should == "add_index :foo, :name => :foo_index, :unique => true"
|
197
|
-
end
|
198
|
-
|
199
|
-
it "should drop the index on #down" do
|
200
|
-
Sequel::Schema::AlterTableOperations::AddIndex.new(:foo_index, :foo, true).down.
|
201
|
-
should == "drop_index :foo, :name => :foo_index"
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
describe Sequel::Schema::AlterTableOperations::DropIndex do
|
206
|
-
it "should add the index on #down" do
|
207
|
-
Sequel::Schema::AlterTableOperations::DropIndex.new(:foo_index, :foo, true).down.
|
208
|
-
should == "add_index :foo, :name => :foo_index, :unique => true"
|
209
|
-
end
|
210
|
-
|
211
|
-
it "should drop the index on #up" do
|
212
|
-
Sequel::Schema::AlterTableOperations::DropIndex.new(:foo_index, :foo, true).up.
|
213
|
-
should == "drop_index :foo, :name => :foo_index"
|
128
|
+
ops.last.should be_nil
|
214
129
|
end
|
215
130
|
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/spec_helper"
|
2
|
+
|
3
|
+
describe Sequel::Schema::DbIndex do
|
4
|
+
it "should have a name" do
|
5
|
+
Sequel::Schema::DbIndex.new('foo_index', :foo).name.should == :foo_index
|
6
|
+
end
|
7
|
+
|
8
|
+
it "can have columns" do
|
9
|
+
Sequel::Schema::DbIndex.new('foo_index', [:foo, :bar]).columns.should == [:foo, :bar]
|
10
|
+
end
|
11
|
+
|
12
|
+
it "converts a single column symbol to a 1 element array of columns" do
|
13
|
+
Sequel::Schema::DbIndex.new('foo_index', :foo).columns.should == [:foo]
|
14
|
+
end
|
15
|
+
|
16
|
+
it "is not unique by default" do
|
17
|
+
Sequel::Schema::DbIndex.new('foo_index', :foo).should_not be_unique
|
18
|
+
end
|
19
|
+
|
20
|
+
it "can be unique" do
|
21
|
+
Sequel::Schema::DbIndex.new('foo_index', :foo, true).should be_unique
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should respond to multi_column?" do
|
25
|
+
Sequel::Schema::DbIndex.new('foo_index', :foo, true).should_not be_multi_column
|
26
|
+
Sequel::Schema::DbIndex.new('foo_index', [:foo, :bar], true).should be_multi_column
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should be equal when compared with ==" do
|
30
|
+
i1 = Sequel::Schema::DbIndex.new('foo_idx', :foo, true)
|
31
|
+
|
32
|
+
i1.should == Sequel::Schema::DbIndex.new('foo_idx', :foo, true)
|
33
|
+
i1.should == Sequel::Schema::DbIndex.new('foo_idx', [:foo], true)
|
34
|
+
i1.should_not == Sequel::Schema::DbIndex.new('foo_idx', :foo, false)
|
35
|
+
i1.should_not == Sequel::Schema::DbIndex.new('foo', :foo, true)
|
36
|
+
i1.should_not == Sequel::Schema::DbIndex.new('foo_idx', :bar, true)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should be equal when compared with eql?" do
|
40
|
+
i1 = Sequel::Schema::DbIndex.new('foo_idx', :foo, true)
|
41
|
+
|
42
|
+
i1.hash.should == Sequel::Schema::DbIndex.new('foo_idx', :foo, true).hash
|
43
|
+
i1.should be_eql(Sequel::Schema::DbIndex.new('foo_idx', :foo, true))
|
44
|
+
end
|
45
|
+
|
46
|
+
it "can be built from a hash returned by Sequel::Database#indexes" do
|
47
|
+
hsh = {:foo_idx => {:columns => [:foo], :unique => true}}
|
48
|
+
Sequel::Schema::DbIndex.build_from_hash(hsh).should ==
|
49
|
+
[Sequel::Schema::DbIndex.new(:foo_idx, :foo, true)]
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should have a define statement" do
|
53
|
+
Sequel::Schema::DbIndex.new(:foo_idx, :foo, true).define_statement.should ==
|
54
|
+
"index :foo, :name => :foo_idx, :unique => true"
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should have a define statement for multiple columns" do
|
58
|
+
Sequel::Schema::DbIndex.new(:foo_idx, [:foo, :bar], true).define_statement.should ==
|
59
|
+
"index [:foo, :bar], :name => :foo_idx, :unique => true"
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should not output the unique value if it is false" do
|
63
|
+
Sequel::Schema::DbIndex.new(:foo_idx, :foo).define_statement.should ==
|
64
|
+
"index :foo, :name => :foo_idx"
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should have an add_index statement" do
|
68
|
+
Sequel::Schema::DbIndex.new(:foo_idx, :foo, true).add_statement.should ==
|
69
|
+
"add_index :foo, :name => :foo_idx, :unique => true"
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should have an drop_index statement" do
|
73
|
+
Sequel::Schema::DbIndex.new(:foo_idx, :foo, true).drop_statement.should ==
|
74
|
+
"drop_index :foo, :name => :foo_idx"
|
75
|
+
end
|
76
|
+
end
|
@@ -16,15 +16,11 @@ describe Sequel::MigrationBuilder do
|
|
16
16
|
|
17
17
|
expected = <<-END
|
18
18
|
Sequel.migration do
|
19
|
-
|
19
|
+
change do
|
20
20
|
create_table :example_table do
|
21
21
|
integer :foo, :null => false
|
22
22
|
end
|
23
23
|
end
|
24
|
-
|
25
|
-
down do
|
26
|
-
drop_table :example_table
|
27
|
-
end
|
28
24
|
end
|
29
25
|
END
|
30
26
|
|
@@ -45,7 +41,7 @@ END
|
|
45
41
|
|
46
42
|
expected = <<-END
|
47
43
|
Sequel.migration do
|
48
|
-
|
44
|
+
change do
|
49
45
|
create_table :example_table do
|
50
46
|
integer :foo, :null => false
|
51
47
|
varchar :bar, :null => false
|
@@ -55,11 +51,6 @@ Sequel.migration do
|
|
55
51
|
integer :foo
|
56
52
|
end
|
57
53
|
end
|
58
|
-
|
59
|
-
down do
|
60
|
-
drop_table :example_table_2
|
61
|
-
drop_table :example_table
|
62
|
-
end
|
63
54
|
end
|
64
55
|
END
|
65
56
|
|
@@ -140,7 +131,7 @@ END
|
|
140
131
|
|
141
132
|
it "should return an alter table statement with column changes for #generate_up" do
|
142
133
|
expected = <<-END
|
143
|
-
|
134
|
+
change do
|
144
135
|
alter_table :example_table do
|
145
136
|
set_column_type :foo, :integer, :default => nil
|
146
137
|
set_column_allow_null :foo, false
|
@@ -149,21 +140,8 @@ up do
|
|
149
140
|
end
|
150
141
|
end
|
151
142
|
END
|
152
|
-
Sequel::MigrationBuilder.new(@mock_db).
|
153
|
-
|
154
|
-
|
155
|
-
it "should return an alter table statement with column changes for #generate_down" do
|
156
|
-
expected = <<-END
|
157
|
-
down do
|
158
|
-
alter_table :example_table do
|
159
|
-
set_column_type :foo, :smallint, :default => 10, :unsigned => true
|
160
|
-
set_column_allow_null :foo, true
|
161
|
-
drop_column :bar
|
162
|
-
drop_index :foo, :name => :foo_index
|
163
|
-
end
|
164
|
-
end
|
165
|
-
END
|
166
|
-
Sequel::MigrationBuilder.new(@mock_db).generate_down(@tables).join("\n").should == expected.strip
|
143
|
+
Sequel::MigrationBuilder.new(@mock_db).
|
144
|
+
generate_migration_body(@tables).join("\n").should == expected.strip
|
167
145
|
end
|
168
146
|
end
|
169
147
|
|
@@ -173,7 +151,7 @@ END
|
|
173
151
|
mock_db.should_receive(:tables).at_least(:once).and_return([:example_table])
|
174
152
|
|
175
153
|
expected = <<-END
|
176
|
-
|
154
|
+
change do
|
177
155
|
drop_table :example_table
|
178
156
|
end
|
179
157
|
END
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequel_migration_builder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
4
5
|
prerelease: false
|
5
6
|
segments:
|
6
7
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
8
|
+
- 2
|
9
|
+
- 0
|
10
|
+
version: 0.2.0
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Roland Swingler
|
@@ -14,30 +15,34 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date:
|
18
|
+
date: 2011-01-13 00:00:00 +00:00
|
18
19
|
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
22
|
name: sequel
|
22
23
|
prerelease: false
|
23
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
24
26
|
requirements:
|
25
27
|
- - ">="
|
26
28
|
- !ruby/object:Gem::Version
|
29
|
+
hash: 79
|
27
30
|
segments:
|
28
31
|
- 3
|
29
|
-
-
|
32
|
+
- 18
|
30
33
|
- 0
|
31
|
-
version: 3.
|
34
|
+
version: 3.18.0
|
32
35
|
type: :runtime
|
33
36
|
version_requirements: *id001
|
34
37
|
- !ruby/object:Gem::Dependency
|
35
38
|
name: rspec
|
36
39
|
prerelease: false
|
37
40
|
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
38
42
|
requirements:
|
39
43
|
- - ">="
|
40
44
|
- !ruby/object:Gem::Version
|
45
|
+
hash: 13
|
41
46
|
segments:
|
42
47
|
- 1
|
43
48
|
- 2
|
@@ -57,6 +62,7 @@ extra_rdoc_files:
|
|
57
62
|
files:
|
58
63
|
- .document
|
59
64
|
- .gitignore
|
65
|
+
- CHANGELOG
|
60
66
|
- LICENSE
|
61
67
|
- README.rdoc
|
62
68
|
- Rakefile
|
@@ -64,10 +70,12 @@ files:
|
|
64
70
|
- lib/sequel/migration_builder.rb
|
65
71
|
- lib/sequel/schema/alter_table_operations.rb
|
66
72
|
- lib/sequel/schema/db_column.rb
|
73
|
+
- lib/sequel/schema/db_index.rb
|
67
74
|
- lib/sequel/schema/db_schema_parser.rb
|
68
75
|
- sequel_migration_builder.gemspec
|
69
76
|
- spec/alter_table_operations_spec.rb
|
70
77
|
- spec/db_column_spec.rb
|
78
|
+
- spec/db_index_spec.rb
|
71
79
|
- spec/db_schema_parser_spec.rb
|
72
80
|
- spec/migration_builder_spec.rb
|
73
81
|
- spec/spec.opts
|
@@ -82,29 +90,34 @@ rdoc_options:
|
|
82
90
|
require_paths:
|
83
91
|
- lib
|
84
92
|
required_ruby_version: !ruby/object:Gem::Requirement
|
93
|
+
none: false
|
85
94
|
requirements:
|
86
95
|
- - ">="
|
87
96
|
- !ruby/object:Gem::Version
|
97
|
+
hash: 3
|
88
98
|
segments:
|
89
99
|
- 0
|
90
100
|
version: "0"
|
91
101
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
|
+
none: false
|
92
103
|
requirements:
|
93
104
|
- - ">="
|
94
105
|
- !ruby/object:Gem::Version
|
106
|
+
hash: 3
|
95
107
|
segments:
|
96
108
|
- 0
|
97
109
|
version: "0"
|
98
110
|
requirements: []
|
99
111
|
|
100
112
|
rubyforge_project:
|
101
|
-
rubygems_version: 1.3.
|
113
|
+
rubygems_version: 1.3.7
|
102
114
|
signing_key:
|
103
115
|
specification_version: 3
|
104
116
|
summary: Build Sequel Migrations based on the differences between two schemas
|
105
117
|
test_files:
|
106
118
|
- spec/alter_table_operations_spec.rb
|
107
119
|
- spec/db_column_spec.rb
|
120
|
+
- spec/db_index_spec.rb
|
108
121
|
- spec/db_schema_parser_spec.rb
|
109
122
|
- spec/migration_builder_spec.rb
|
110
123
|
- spec/spec_helper.rb
|