ridgepole 0.4.8.rc1 → 0.4.8.rc2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8bf1189c330df38c7b922e8d49efbe41345bf5ca
4
- data.tar.gz: 7577f13cff3830ee86f19617b593c68a83d225d3
3
+ metadata.gz: 022ee45d7a37fd8e93846164f89d98e055151c0d
4
+ data.tar.gz: c5f6572a791eb0c45097a3732905e8e091a6e6f4
5
5
  SHA512:
6
- metadata.gz: 1599cba8ef9a7720d32b8da9d5f3403c4dec8a8a92930bd80072df35c6a190934ca61f990d97da47cf7464cfe9031b68f1cc69195dabf826fb5a09e8a5f3f0ff
7
- data.tar.gz: 1709a0da42bb15ce7548b38a3b5bcfce395a4608c68201c8d1db16fd93c38172b9023cc5dcb8c47943abb6fb970792458552fabb414ccec36047c6e74effb4f1
6
+ metadata.gz: 458892f33c8d977dada755c86bd7f6c99410a1ed660f3673c4af92c8af6be0a77a196e0f5e64143f2f3f5ff0c6252d9ed3ab42bc0c9b6bba19c17a96f3396c3b
7
+ data.tar.gz: 354bca90dbb3a9b8720d8e7c8a814eeb5de11dd83e7ec4860cbd315de638f6b44f8076a8bbe379211d753fd834f66b6b203a2f50942fd9052e46f7caf1ef9263
data/README.md CHANGED
@@ -7,6 +7,13 @@ It defines DB schema using [Rails DSL](http://guides.rubyonrails.org/migrations.
7
7
 
8
8
  [![Gem Version](https://badge.fury.io/rb/ridgepole.png)](http://badge.fury.io/rb/ridgepole)
9
9
  [![Build Status](https://travis-ci.org/winebarrel/ridgepole.svg?branch=master)](https://travis-ci.org/winebarrel/ridgepole)
10
+ [![Coverage Status](https://coveralls.io/repos/winebarrel/ridgepole/badge.png?branch=master)](https://coveralls.io/r/winebarrel/ridgepole?branch=master)
11
+
12
+ **Notice**
13
+
14
+ * `>= 0.4.8`
15
+ * `activerecord-mysql-unsigned` is now optional. Please pass `--enable-mysql-unsigned` after you install [activerecord-mysql-unsigned](https://github.com/waka/activerecord-mysql-unsigned) if you want to use.
16
+ * Please pass `--enable-foreigner` after you install [foreigner](https://github.com/matthuhiggins/foreigner) if you want to use the foreign key.
10
17
 
11
18
  ## Installation
12
19
 
@@ -45,7 +52,8 @@ Usage: ridgepole [options]
45
52
  -o, --output FILE
46
53
  -t, --tables TABLES
47
54
  --ignore-tables TABLES
48
- --disable-mysql-unsigned
55
+ --enable-mysql-unsigned
56
+ --enable-foreigner
49
57
  --log-file LOG_FILE
50
58
  --verbose
51
59
  --debug
@@ -110,7 +118,7 @@ Apply `Schemafile`
110
118
  ```
111
119
 
112
120
  ## Rename
113
- ```sh
121
+ ```ruby
114
122
  create_table "articles", force: true do |t|
115
123
  t.string "title"
116
124
  t.text "desc", renamed_from: "text"
@@ -128,8 +136,26 @@ create_table "user_comments", force: true, renamed_from: "comments" do |t|
128
136
  end
129
137
  ```
130
138
 
139
+ ## Foreign Key
140
+ You can use the foreign key by passing `--enable-foreigner` ([foreigner](https://github.com/matthuhiggins/foreigner) is required)
141
+
142
+ ```ruby
143
+ create_table "parent", force: true do |t|
144
+ end
145
+
146
+ create_table "child", id: false, force: true do |t|
147
+ t.integer "id"
148
+ t.integer "parent_id"
149
+ end
150
+
151
+ add_index "child", ["parent_id"], name: "par_ind", using: :btree
152
+
153
+ add_foreign_key "child", "parent", name: "child_ibfk_1", dependent: :delete
154
+ ```
155
+
156
+
131
157
  ## Execute
132
- ```sh
158
+ ```ruby
133
159
  create_table "authors", force: true do |t|
134
160
  t.string "name", null: false
135
161
  end
data/bin/ridgepole CHANGED
@@ -91,7 +91,8 @@ ARGV.options do |opt|
91
91
  opt.on('-o', '--output FILE') {|v| output_file = v }
92
92
  opt.on('-t', '--tables TABLES', Array) {|v| options[:tables] = v }
93
93
  opt.on('', '--ignore-tables TABLES', Array) {|v| options[:ignore_tables] = v.map {|i| Regexp.new(i) } }
94
- opt.on('', '--disable-mysql-unsigned') { options[:disable_mysql_unsigned] = true }
94
+ opt.on('', '--enable-mysql-unsigned') { options[:enable_mysql_unsigned] = true }
95
+ opt.on('', '--enable-foreigner') { options[:enable_foreigner] = true }
95
96
  opt.on('' , '--log-file LOG_FILE') {|v| options[:log_file] = v }
96
97
  opt.on('' , '--verbose') { Ridgepole::Logger.verbose = true }
97
98
  opt.on('' , '--debug') { options[:debug] = true }
data/lib/ridgepole.rb CHANGED
@@ -4,7 +4,7 @@ require 'stringio'
4
4
 
5
5
  require 'active_record'
6
6
  require 'active_support'
7
- require 'active_support/core_ext/string/strip'
7
+ require 'active_support/core_ext'
8
8
 
9
9
  module Ridgepole; end
10
10
  require 'ridgepole/client'
@@ -13,6 +13,7 @@ require 'ridgepole/diff'
13
13
  require 'ridgepole/dsl_parser'
14
14
  require 'ridgepole/dumper'
15
15
  require 'ridgepole/execute_expander'
16
+ require 'ridgepole/ext/foreign_key'
16
17
  require 'ridgepole/logger'
17
18
  require 'ridgepole/migration_ext'
18
19
  require 'ridgepole/schema_dumper_ext'
@@ -7,9 +7,13 @@ class Ridgepole::Client
7
7
  @parser = Ridgepole::DSLParser.new(@options)
8
8
  @diff = Ridgepole::Diff.new(@options)
9
9
 
10
- unless @options[:disable_mysql_unsigned]
10
+ if @options[:enable_mysql_unsigned]
11
11
  require 'activerecord-mysql-unsigned'
12
12
  end
13
+
14
+ if @options[:enable_foreigner]
15
+ Ridgepole::ForeignKey.init
16
+ end
13
17
  end
14
18
 
15
19
  def dump(&block)
@@ -226,6 +226,14 @@ end
226
226
  end
227
227
  end
228
228
 
229
+ if @options[:enable_foreigner] and not (foreign_keys = attrs[:foreign_keys] || {}).empty?
230
+ append_change_table(table_name, buf) do
231
+ foreign_keys.each do |foreign_key_name, foreign_key_attrs|
232
+ Ridgepole::ForeignKey.append_add_foreign_key(table_name, foreign_key_name, foreign_key_attrs, buf, @options)
233
+ end
234
+ end
235
+ end
236
+
229
237
  buf.puts
230
238
  end
231
239
 
@@ -249,6 +257,10 @@ drop_table(#{table_name.inspect})
249
257
  append_change_table(table_name, buf) do
250
258
  append_change_definition(table_name, attrs[:definition] || {}, buf)
251
259
  append_change_indices(table_name, attrs[:indices] || {}, buf)
260
+
261
+ if @options[:enable_foreigner]
262
+ Ridgepole::ForeignKey.append_change_foreign_keys(table_name, attrs[:foreign_keys] || {}, buf, @options)
263
+ end
252
264
  end
253
265
 
254
266
  buf.puts
@@ -79,6 +79,10 @@ class Ridgepole::Diff
79
79
  scan_definition_change(from[:definition], to[:definition], from[:indices], table_delta)
80
80
  scan_indices_change(from[:indices], to[:indices], to[:definition], table_delta, from[:options], to[:options])
81
81
 
82
+ if @options[:enable_foreigner]
83
+ Ridgepole::ForeignKey.scan_foreign_keys_change(from[:foreign_keys], to[:foreign_keys], table_delta, @options)
84
+ end
85
+
82
86
  unless table_delta.empty?
83
87
  delta[:change] ||= {}
84
88
  delta[:change][table_name] = table_delta
@@ -251,7 +255,7 @@ class Ridgepole::Diff
251
255
  end
252
256
 
253
257
  # XXX: MySQL only?
254
- unless @options[:disable_mysql_unsigned]
258
+ if @options[:enable_mysql_unsigned]
255
259
  opts[:unsigned] = false unless opts.has_key?(:unsigned)
256
260
  end
257
261
  end
@@ -1,5 +1,11 @@
1
1
  class Ridgepole::DSLParser
2
2
  class Context
3
+ def self.include_module(mod)
4
+ unless self.included_modules.include?(mod)
5
+ include mod
6
+ end
7
+ end
8
+
3
9
  class TableDefinition
4
10
  attr_reader :__definition
5
11
 
@@ -141,6 +147,11 @@ class Ridgepole::DSLParser
141
147
  def parse(dsl, opts = {})
142
148
  definition, execute = Context.eval(dsl, opts)
143
149
  check_orphan_index(definition)
150
+
151
+ if @options[:enable_foreigner]
152
+ Ridgepole::ForeignKey.check_orphan_foreign_key(definition)
153
+ end
154
+
144
155
  [definition, execute]
145
156
  end
146
157
 
@@ -148,7 +159,7 @@ class Ridgepole::DSLParser
148
159
 
149
160
  def check_orphan_index(definition)
150
161
  definition.each do |table_name, attrs|
151
- if attrs.length == 1 and attrs[:indices]
162
+ if attrs[:indices] and not attrs[:definition]
152
163
  raise "Table `#{table_name}` to create the index is not defined: #{attrs[:indices].keys.join(',')}"
153
164
  end
154
165
  end
@@ -0,0 +1,121 @@
1
+ class Ridgepole::ForeignKey
2
+ class << self
3
+ def init
4
+ require 'foreigner'
5
+
6
+ ActiveSupport.on_load :active_record do
7
+ Foreigner.load
8
+ end
9
+
10
+ Ridgepole::DSLParser::Context.include_module(Ridgepole::ForeignKey::DSL)
11
+ end
12
+
13
+ def check_orphan_foreign_key(definition)
14
+ definition.each do |table_name, attrs|
15
+ if attrs[:foreign_keys] and not attrs[:definition]
16
+ raise "Table `#{table_name}` to create the foreign key is not defined: #{attrs[:foreign_keys].keys.join(',')}"
17
+ end
18
+ end
19
+ end
20
+
21
+ def scan_foreign_keys_change(from, to, table_delta, options)
22
+ from = (from || {}).dup
23
+ to = (to || {}).dup
24
+ foreign_keys_delta = {}
25
+
26
+ to.each do |foreign_key_name, to_attrs|
27
+ from_attrs = from.delete(foreign_key_name)
28
+
29
+ if from_attrs
30
+ if from_attrs != to_attrs
31
+ foreign_keys_delta[:add] ||= {}
32
+ foreign_keys_delta[:add][foreign_key_name] = to_attrs
33
+
34
+ unless options[:merge]
35
+ foreign_keys_delta[:delete] ||= {}
36
+ foreign_keys_delta[:delete][foreign_key_name] = from_attrs
37
+ end
38
+ end
39
+ else
40
+ foreign_keys_delta[:add] ||= {}
41
+ foreign_keys_delta[:add][foreign_key_name] = to_attrs
42
+ end
43
+ end
44
+
45
+ unless options[:merge]
46
+ from.each do |foreign_key_name, from_attrs|
47
+ foreign_keys_delta[:delete] ||= {}
48
+ foreign_keys_delta[:delete][foreign_key_name] = from_attrs
49
+ end
50
+ end
51
+
52
+ unless foreign_keys_delta.empty?
53
+ table_delta[:foreign_keys] = foreign_keys_delta
54
+ end
55
+ end
56
+
57
+ def append_change_foreign_keys(table_name, delta, buf, options)
58
+ (delta[:delete] || {}).each do |foreign_key_name, attrs|
59
+ append_remove_foreign_key(table_name, foreign_key_name, attrs, buf, options)
60
+ end
61
+
62
+ (delta[:add] || {}).each do |foreign_key_name, attrs|
63
+ append_add_foreign_key(table_name, foreign_key_name, attrs, buf, options)
64
+ end
65
+ end
66
+
67
+ def append_add_foreign_key(table_name, foreign_key_name, attrs, buf, options)
68
+ to_table = attrs.fetch(:to_table)
69
+ attrs_options = attrs[:options] || {}
70
+
71
+ if options[:bulk_change]
72
+ buf.puts(<<-EOS)
73
+ t.foreign_key(#{to_table.inspect}, #{attrs_options.inspect})
74
+ EOS
75
+ else
76
+ buf.puts(<<-EOS)
77
+ add_foreign_key(#{table_name.inspect}, #{to_table.inspect}, #{attrs_options.inspect})
78
+ EOS
79
+ end
80
+ end
81
+
82
+ def append_remove_foreign_key(table_name, foreign_key_name, attrs, buf, options)
83
+ attrs_options = attrs[:options] || {}
84
+ target = {:name => attrs_options.fetch(:name)}
85
+
86
+ if options[:bulk_change]
87
+ buf.puts(<<-EOS)
88
+ t.remove_foreign_key(#{target.inspect})
89
+ EOS
90
+ else
91
+ buf.puts(<<-EOS)
92
+ remove_foreign_key(#{table_name.inspect}, #{target.inspect})
93
+ EOS
94
+ end
95
+ end
96
+ end # of class methods
97
+
98
+ module DSL
99
+ def add_foreign_key(from_table, to_table, options = {})
100
+ unless options[:name]
101
+ raise "Foreign key name in `#{from_table}` is undefined"
102
+ end
103
+
104
+ from_table = from_table.to_s
105
+ to_table = to_table.to_s
106
+ options[:name] = options[:name].to_s
107
+ @__definition[from_table] ||= {}
108
+ @__definition[from_table][:foreign_keys] ||= {}
109
+ idx = options[:name]
110
+
111
+ if @__definition[from_table][:foreign_keys][idx]
112
+ raise "Foreign Key `#{from_table}(#{idx})` already defined"
113
+ end
114
+
115
+ @__definition[from_table][:foreign_keys][idx] = {
116
+ :to_table => to_table,
117
+ :options => options,
118
+ }
119
+ end
120
+ end
121
+ end
@@ -1,3 +1,3 @@
1
1
  module Ridgepole
2
- VERSION = '0.4.8.rc1'
2
+ VERSION = '0.4.8.rc2'
3
3
  end
data/ridgepole.gemspec CHANGED
@@ -19,9 +19,11 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ['lib']
20
20
 
21
21
  spec.add_dependency 'activerecord'
22
- spec.add_dependency 'activerecord-mysql-unsigned', '>= 0.2.0'
23
22
  spec.add_development_dependency 'bundler'
24
23
  spec.add_development_dependency 'rake'
25
24
  spec.add_development_dependency 'rspec', '>= 3.0.0'
26
25
  spec.add_development_dependency 'mysql2'
26
+ spec.add_development_dependency 'coveralls'
27
+ spec.add_development_dependency 'activerecord-mysql-unsigned', '>= 0.2.0'
28
+ spec.add_development_dependency 'foreigner'
27
29
  end
@@ -1,7 +1,7 @@
1
1
  describe 'Ridgepole::Client#dump' do
2
2
  context 'when there is a tables (disable unsigned)' do
3
3
  before { restore_tables }
4
- subject { client(disable_mysql_unsigned: true) }
4
+ subject { client(enable_mysql_unsigned: false) }
5
5
 
6
6
  it {
7
7
  expect(subject.dump).to eq <<-RUBY.strip_heredoc.strip
@@ -29,7 +29,8 @@ describe 'ridgepole' do
29
29
  -o, --output FILE
30
30
  -t, --tables TABLES
31
31
  --ignore-tables TABLES
32
- --disable-mysql-unsigned
32
+ --enable-mysql-unsigned
33
+ --enable-foreigner
33
34
  --log-file LOG_FILE
34
35
  --verbose
35
36
  --debug
@@ -141,7 +141,7 @@ describe 'Ridgepole::Client.diff' do
141
141
  subject { Ridgepole::Client }
142
142
 
143
143
  it {
144
- delta = subject.diff(actual_dsl, expected_dsl)
144
+ delta = subject.diff(actual_dsl, expected_dsl, enable_mysql_unsigned: true)
145
145
  expect(delta.differ?).to be_truthy
146
146
  expect(delta.script).to eq <<-RUBY.strip_heredoc.strip
147
147
  change_column("employee_clubs", "club_id", :integer, {:unsigned=>false, :null=>true, :default=>nil})
@@ -4,7 +4,7 @@ describe 'Ridgepole::Client.dump' do
4
4
  subject { Ridgepole::Client }
5
5
 
6
6
  it {
7
- expect(subject.dump(conn_spec)).to eq <<-RUBY.strip_heredoc.strip
7
+ expect(subject.dump(conn_spec, enable_mysql_unsigned: true)).to eq <<-RUBY.strip_heredoc.strip
8
8
  create_table "clubs", force: true do |t|
9
9
  t.string "name", default: "", null: false
10
10
  end
@@ -150,7 +150,7 @@ describe 'Ridgepole::Client#diff -> migrate' do
150
150
  }
151
151
 
152
152
  it {
153
- delta = Ridgepole::Client.diff(actual_dsl, expected_dsl, reverse: true)
153
+ delta = Ridgepole::Client.diff(actual_dsl, expected_dsl, reverse: true, enable_mysql_unsigned: true)
154
154
  expect(delta.differ?).to be_truthy
155
155
  expect(delta.script).to eq <<-RUBY.strip_heredoc.strip
156
156
  change_column("employee_clubs", "club_id", :integer, {:unsigned=>true, :null=>false})
@@ -145,7 +145,7 @@ describe 'Ridgepole::Client#diff -> migrate' do
145
145
  }
146
146
 
147
147
  it {
148
- delta = Ridgepole::Client.diff(current_schema, dsl, ignore_tables: [/^salaries$/], reverse: true)
148
+ delta = Ridgepole::Client.diff(current_schema, dsl, ignore_tables: [/^salaries$/], reverse: true, enable_mysql_unsigned: true)
149
149
  expect(delta.differ?).to be_truthy
150
150
  expect(delta.script).to eq <<-RUBY.strip_heredoc.strip
151
151
  change_column("employees", "first_name", :string, {:limit=>14, :null=>false, :unsigned=>false})
@@ -145,7 +145,7 @@ describe 'Ridgepole::Client#diff -> migrate' do
145
145
  }
146
146
 
147
147
  it {
148
- delta = Ridgepole::Client.diff(current_schema, dsl, tables: ['employees'], reverse: true)
148
+ delta = Ridgepole::Client.diff(current_schema, dsl, tables: ['employees'], reverse: true, enable_mysql_unsigned: true)
149
149
  expect(delta.differ?).to be_truthy
150
150
  expect(delta.script).to eq <<-RUBY.strip_heredoc.strip
151
151
  change_column("employees", "first_name", :string, {:limit=>14, :null=>false, :unsigned=>false})
@@ -0,0 +1,60 @@
1
+ describe 'Ridgepole::Client#diff -> migrate' do
2
+ context 'when change fk' do
3
+ let(:actual_dsl) {
4
+ <<-RUBY
5
+ create_table "parent", force: true do |t|
6
+ end
7
+
8
+ create_table "child", force: true do |t|
9
+ t.integer "parent_id", unsigned: true
10
+ end
11
+
12
+ add_index "child", ["parent_id"], name: "par_ind", using: :btree
13
+
14
+ add_foreign_key "child", "parent", name: "child_ibfk_1", dependent: :delete
15
+ RUBY
16
+ }
17
+
18
+ let(:sorted_actual_dsl) {
19
+ <<-RUBY
20
+ create_table "child", force: true do |t|
21
+ t.integer "parent_id", unsigned: true
22
+ end
23
+
24
+ add_index "child", ["parent_id"], name: "par_ind", using: :btree
25
+
26
+ create_table "parent", force: true do |t|
27
+ end
28
+
29
+ add_foreign_key "child", "parent", name: "child_ibfk_1", dependent: :delete
30
+ RUBY
31
+ }
32
+
33
+ let(:expected_dsl) {
34
+ <<-RUBY
35
+ create_table "child", force: true do |t|
36
+ t.integer "parent_id", unsigned: true
37
+ end
38
+
39
+ add_index "child", ["parent_id"], name: "par_ind", using: :btree
40
+
41
+ create_table "parent", force: true do |t|
42
+ end
43
+
44
+ add_foreign_key "child", "parent", name: "child_ibfk_1"
45
+ RUBY
46
+ }
47
+
48
+ before { subject.diff(actual_dsl).migrate }
49
+
50
+ subject { client(enable_foreigner: true) }
51
+
52
+ it {
53
+ delta = subject.diff(expected_dsl)
54
+ expect(delta.differ?).to be_truthy
55
+ expect(subject.dump.delete_empty_lines).to eq sorted_actual_dsl.strip_heredoc.strip.delete_empty_lines
56
+ delta.migrate
57
+ expect(subject.dump.delete_empty_lines).to eq expected_dsl.strip_heredoc.strip.delete_empty_lines
58
+ }
59
+ end
60
+ end
@@ -0,0 +1,172 @@
1
+ describe 'Ridgepole::Client#diff -> migrate' do
2
+ context 'when create fk' do
3
+ let(:actual_dsl) {
4
+ <<-RUBY
5
+ create_table "child", force: true do |t|
6
+ t.integer "parent_id", unsigned: true
7
+ end
8
+
9
+ add_index "child", ["parent_id"], name: "par_ind", using: :btree
10
+
11
+ create_table "parent", force: true do |t|
12
+ end
13
+ RUBY
14
+ }
15
+
16
+ let(:expected_dsl) {
17
+ actual_dsl + (<<-RUBY)
18
+
19
+ add_foreign_key "child", "parent", name: "child_ibfk_1", dependent: :delete
20
+ RUBY
21
+ }
22
+
23
+ before { subject.diff(actual_dsl).migrate }
24
+ subject { client(enable_foreigner: true) }
25
+
26
+ it {
27
+ delta = subject.diff(expected_dsl)
28
+ expect(delta.differ?).to be_truthy
29
+ expect(subject.dump.delete_empty_lines).to eq actual_dsl.strip_heredoc.strip.delete_empty_lines
30
+ delta.migrate
31
+ expect(subject.dump.delete_empty_lines).to eq expected_dsl.strip_heredoc.strip.delete_empty_lines
32
+ }
33
+
34
+ it {
35
+ delta = Ridgepole::Client.diff(actual_dsl, expected_dsl, reverse: true, enable_foreigner: true)
36
+ expect(delta.differ?).to be_truthy
37
+ expect(delta.script).to eq <<-RUBY.strip_heredoc.strip
38
+ remove_foreign_key("child", {:name=>"child_ibfk_1"})
39
+ RUBY
40
+ }
41
+
42
+ it {
43
+ delta = client(enable_foreigner: true, bulk_change: true).diff(expected_dsl)
44
+ expect(delta.differ?).to be_truthy
45
+ expect(subject.dump.delete_empty_lines).to eq actual_dsl.strip_heredoc.strip.delete_empty_lines
46
+ expect(delta.script).to eq <<-RUBY.strip_heredoc.strip
47
+ change_table("child", {:bulk => true}) do |t|
48
+ t.foreign_key("parent", {:name=>"child_ibfk_1", :dependent=>:delete})
49
+ end
50
+ RUBY
51
+ delta.migrate
52
+ expect(subject.dump.delete_empty_lines).to eq expected_dsl.strip_heredoc.strip.delete_empty_lines
53
+ }
54
+ end
55
+
56
+ context 'when create fk when create table' do
57
+ let(:dsl) {
58
+ <<-RUBY
59
+ # Define parent before child
60
+ create_table "parent", force: true do |t|
61
+ end
62
+
63
+ create_table "child", force: true do |t|
64
+ t.integer "parent_id", unsigned: true
65
+ end
66
+
67
+ add_index "child", ["parent_id"], name: "par_ind", using: :btree
68
+
69
+ add_foreign_key "child", "parent", name: "child_ibfk_1", dependent: :delete
70
+ RUBY
71
+ }
72
+
73
+ let(:sorted_dsl) {
74
+ <<-RUBY
75
+ create_table "child", force: true do |t|
76
+ t.integer "parent_id", unsigned: true
77
+ end
78
+
79
+ add_index "child", ["parent_id"], name: "par_ind", using: :btree
80
+
81
+ create_table "parent", force: true do |t|
82
+ end
83
+
84
+ add_foreign_key "child", "parent", name: "child_ibfk_1", dependent: :delete
85
+ RUBY
86
+ }
87
+
88
+ subject { client(enable_foreigner: true) }
89
+
90
+ it {
91
+ delta = subject.diff(dsl)
92
+ expect(delta.differ?).to be_truthy
93
+ expect(subject.dump.strip).to eq ''
94
+ delta.migrate
95
+ expect(subject.dump.delete_empty_lines).to eq sorted_dsl.strip_heredoc.strip.delete_empty_lines
96
+ }
97
+ end
98
+
99
+ context 'already defined' do
100
+ let(:dsl) {
101
+ <<-RUBY
102
+ # Define parent before child
103
+ create_table "parent", force: true do |t|
104
+ end
105
+
106
+ create_table "child", force: true do |t|
107
+ t.integer "parent_id", unsigned: true
108
+ end
109
+
110
+ add_index "child", ["parent_id"], name: "par_ind", using: :btree
111
+
112
+ add_foreign_key "child", "parent", name: "child_ibfk_1", dependent: :delete
113
+
114
+ add_foreign_key "child", "parent", name: "child_ibfk_1", dependent: :delete
115
+ RUBY
116
+ }
117
+
118
+ subject { client(enable_foreigner: true) }
119
+
120
+ it {
121
+ expect {
122
+ subject.diff(dsl)
123
+ }.to raise_error('Foreign Key `child(child_ibfk_1)` already defined')
124
+ }
125
+ end
126
+
127
+ context 'no name' do
128
+ let(:dsl) {
129
+ <<-RUBY
130
+ # Define parent before child
131
+ create_table "parent", force: true do |t|
132
+ end
133
+
134
+ create_table "child", force: true do |t|
135
+ t.integer "parent_id", unsigned: true
136
+ end
137
+
138
+ add_index "child", ["parent_id"], name: "par_ind", using: :btree
139
+
140
+ add_foreign_key "child", "parent", dependent: :delete
141
+ RUBY
142
+ }
143
+
144
+ subject { client(enable_foreigner: true) }
145
+
146
+ it {
147
+ expect {
148
+ subject.diff(dsl)
149
+ }.to raise_error('Foreign key name in `child` is undefined')
150
+ }
151
+ end
152
+
153
+ context 'orphan fk' do
154
+ let(:dsl) {
155
+ <<-RUBY
156
+ # Define parent before child
157
+ create_table "parent", force: true do |t|
158
+ end
159
+
160
+ add_foreign_key "child", "parent", name: "child_ibfk_1", dependent: :delete
161
+ RUBY
162
+ }
163
+
164
+ subject { client(enable_foreigner: true) }
165
+
166
+ it {
167
+ expect {
168
+ subject.diff(dsl)
169
+ }.to raise_error('Table `child` to create the foreign key is not defined: child_ibfk_1')
170
+ }
171
+ end
172
+ end
@@ -0,0 +1,113 @@
1
+ describe 'Ridgepole::Client#diff -> migrate' do
2
+ context 'when drop fk' do
3
+ let(:actual_dsl) {
4
+ <<-RUBY
5
+ create_table "parent", force: true do |t|
6
+ end
7
+
8
+ create_table "child", force: true do |t|
9
+ t.integer "parent_id", unsigned: true
10
+ end
11
+
12
+ add_index "child", ["parent_id"], name: "par_ind", using: :btree
13
+
14
+ add_foreign_key "child", "parent", name: "child_ibfk_1", dependent: :delete
15
+ RUBY
16
+ }
17
+
18
+ let(:sorted_actual_dsl) {
19
+ expected_dsl + (<<-RUBY)
20
+
21
+ add_foreign_key "child", "parent", name: "child_ibfk_1", dependent: :delete
22
+ RUBY
23
+ }
24
+
25
+ let(:expected_dsl) {
26
+ <<-RUBY
27
+ create_table "child", force: true do |t|
28
+ t.integer "parent_id", unsigned: true
29
+ end
30
+
31
+ add_index "child", ["parent_id"], name: "par_ind", using: :btree
32
+
33
+ create_table "parent", force: true do |t|
34
+ end
35
+ RUBY
36
+ }
37
+
38
+ before { subject.diff(actual_dsl).migrate }
39
+ subject { client(enable_foreigner: true) }
40
+
41
+ it {
42
+ delta = subject.diff(expected_dsl)
43
+ expect(delta.differ?).to be_truthy
44
+ expect(subject.dump).to eq sorted_actual_dsl.strip_heredoc.strip
45
+ delta.migrate
46
+ expect(subject.dump.each_line.select {|i| i !~ /\A\Z/ }.join).to eq expected_dsl.strip_heredoc.strip.each_line.select {|i| i !~ /\A\Z/ }.join
47
+ }
48
+
49
+ it {
50
+ delta = Ridgepole::Client.diff(actual_dsl, expected_dsl, reverse: true, enable_foreigner: true)
51
+ expect(delta.differ?).to be_truthy
52
+ expect(delta.script).to eq <<-RUBY.strip_heredoc.strip
53
+ add_foreign_key("child", "parent", {:name=>"child_ibfk_1", :dependent=>:delete})
54
+ RUBY
55
+ }
56
+
57
+ it {
58
+ delta = client(enable_foreigner: true, bulk_change: true).diff(expected_dsl)
59
+ expect(delta.differ?).to be_truthy
60
+ expect(subject.dump).to eq sorted_actual_dsl.strip_heredoc.strip
61
+ expect(delta.script).to eq <<-RUBY.strip_heredoc.strip
62
+ change_table("child", {:bulk => true}) do |t|
63
+ t.remove_foreign_key({:name=>"child_ibfk_1"})
64
+ end
65
+ RUBY
66
+ delta.migrate
67
+ expect(subject.dump.each_line.select {|i| i !~ /\A\Z/ }.join).to eq expected_dsl.strip_heredoc.strip.each_line.select {|i| i !~ /\A\Z/ }.join
68
+ }
69
+ end
70
+
71
+ context 'when drop fk when drop table' do
72
+ let(:dsl) {
73
+ <<-RUBY
74
+ create_table "parent", force: true do |t|
75
+ end
76
+
77
+ create_table "child", force: true do |t|
78
+ t.integer "parent_id", unsigned: true
79
+ end
80
+
81
+ add_index "child", ["parent_id"], name: "par_ind", using: :btree
82
+
83
+ add_foreign_key "child", "parent", name: "child_ibfk_1", dependent: :delete
84
+ RUBY
85
+ }
86
+
87
+ let(:sorted_dsl) {
88
+ <<-RUBY
89
+ create_table "child", force: true do |t|
90
+ t.integer "parent_id", unsigned: true
91
+ end
92
+
93
+ add_index "child", ["parent_id"], name: "par_ind", using: :btree
94
+
95
+ create_table "parent", force: true do |t|
96
+ end
97
+
98
+ add_foreign_key "child", "parent", name: "child_ibfk_1", dependent: :delete
99
+ RUBY
100
+ }
101
+
102
+ before { subject.diff(dsl).migrate }
103
+ subject { client(enable_foreigner: true) }
104
+
105
+ it {
106
+ delta = subject.diff('')
107
+ expect(delta.differ?).to be_truthy
108
+ expect(subject.dump).to eq sorted_dsl.strip_heredoc.strip
109
+ delta.migrate
110
+ expect(subject.dump.strip).to eq ''
111
+ }
112
+ end
113
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,15 @@
1
1
  $: << File.expand_path('..', __FILE__)
2
+
3
+ if ENV['TRAVIS']
4
+ require 'simplecov'
5
+ require 'coveralls'
6
+
7
+ SimpleCov.formatter = Coveralls::SimpleCov::Formatter
8
+ SimpleCov.start do
9
+ add_filter "spec/"
10
+ end
11
+ end
12
+
2
13
  require 'ridgepole'
3
14
  require 'ridgepole/cli/config'
4
15
  require 'active_support/core_ext/string/strip'
@@ -9,8 +20,15 @@ require 'json'
9
20
 
10
21
  TEST_SCHEMA = 'ridgepole_test'
11
22
 
12
- ActiveRecord::Migration.verbose = false
13
- Ridgepole::Logger.instance.level = ::Logger::ERROR
23
+ if ENV['DEBUG']
24
+ ActiveRecord::Migration.verbose = true
25
+ logger = Ridgepole::Logger.instance
26
+ logger.level = ::Logger::DEBUG
27
+ ActiveRecord::Base.logger = logger
28
+ else
29
+ ActiveRecord::Migration.verbose = false
30
+ Ridgepole::Logger.instance.level = ::Logger::ERROR
31
+ end
14
32
 
15
33
  RSpec.configure do |config|
16
34
  config.before(:each) do
@@ -32,6 +50,8 @@ def client(options = {}, config = {})
32
50
  config = conn_spec(config)
33
51
 
34
52
  options = {
53
+ :enable_mysql_unsigned => true,
54
+ :debug => !!ENV['DEBUG'],
35
55
  }.merge(options)
36
56
 
37
57
  Ridgepole::Client.new(config, options)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ridgepole
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.8.rc1
4
+ version: 0.4.8.rc2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Genki Sugawara
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-21 00:00:00.000000000 Z
11
+ date: 2014-09-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -25,21 +25,21 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: activerecord-mysql-unsigned
28
+ name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - '>='
32
32
  - !ruby/object:Gem::Version
33
- version: 0.2.0
34
- type: :runtime
33
+ version: '0'
34
+ type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - '>='
39
39
  - !ruby/object:Gem::Version
40
- version: 0.2.0
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: bundler
42
+ name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - '>='
@@ -53,7 +53,21 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: rake
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: 3.0.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: 3.0.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: mysql2
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
73
  - - '>='
@@ -67,21 +81,35 @@ dependencies:
67
81
  - !ruby/object:Gem::Version
68
82
  version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
- name: rspec
84
+ name: coveralls
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
87
  - - '>='
74
88
  - !ruby/object:Gem::Version
75
- version: 3.0.0
89
+ version: '0'
76
90
  type: :development
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
94
  - - '>='
81
95
  - !ruby/object:Gem::Version
82
- version: 3.0.0
96
+ version: '0'
83
97
  - !ruby/object:Gem::Dependency
84
- name: mysql2
98
+ name: activerecord-mysql-unsigned
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: 0.2.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: 0.2.0
111
+ - !ruby/object:Gem::Dependency
112
+ name: foreigner
85
113
  requirement: !ruby/object:Gem::Requirement
86
114
  requirements:
87
115
  - - '>='
@@ -119,6 +147,7 @@ files:
119
147
  - lib/ridgepole/dsl_parser.rb
120
148
  - lib/ridgepole/dumper.rb
121
149
  - lib/ridgepole/execute_expander.rb
150
+ - lib/ridgepole/ext/foreign_key.rb
122
151
  - lib/ridgepole/logger.rb
123
152
  - lib/ridgepole/migration_ext.rb
124
153
  - lib/ridgepole/schema_dumper_ext.rb
@@ -167,6 +196,9 @@ files:
167
196
  - spec/migrate/migrate_with_ignore_tables_spec.rb
168
197
  - spec/migrate/migrate_with_pre_post_query_spec.rb
169
198
  - spec/migrate/migrate_with_tables_spec.rb
199
+ - spec/migrate_0/migrate_change_fk_spec.rb
200
+ - spec/migrate_0/migrate_create_fk_spec.rb
201
+ - spec/migrate_0/migrate_drop_fk_spec.rb
170
202
  - spec/ridgepole_test_database.sql
171
203
  - spec/ridgepole_test_tables.sql
172
204
  - spec/spec_helper.rb
@@ -191,7 +223,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
191
223
  version: 1.3.1
192
224
  requirements: []
193
225
  rubyforge_project:
194
- rubygems_version: 2.0.14
226
+ rubygems_version: 2.4.1
195
227
  signing_key:
196
228
  specification_version: 4
197
229
  summary: Ridgepole is a tool to manage DB schema.
@@ -239,6 +271,9 @@ test_files:
239
271
  - spec/migrate/migrate_with_ignore_tables_spec.rb
240
272
  - spec/migrate/migrate_with_pre_post_query_spec.rb
241
273
  - spec/migrate/migrate_with_tables_spec.rb
274
+ - spec/migrate_0/migrate_change_fk_spec.rb
275
+ - spec/migrate_0/migrate_create_fk_spec.rb
276
+ - spec/migrate_0/migrate_drop_fk_spec.rb
242
277
  - spec/ridgepole_test_database.sql
243
278
  - spec/ridgepole_test_tables.sql
244
279
  - spec/spec_helper.rb