sequel_migration_builder 0.1.4 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|