ridgepole 0.4.8.rc1 → 0.4.8.rc2

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.
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