ridgepole 0.4.7 → 0.4.8.rc1

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: 1450957da8f5ba966dfab934b036b4a93d972e99
4
- data.tar.gz: 2d323098fd39e4e86dea90279e40dad90a4c09a8
3
+ metadata.gz: 8bf1189c330df38c7b922e8d49efbe41345bf5ca
4
+ data.tar.gz: 7577f13cff3830ee86f19617b593c68a83d225d3
5
5
  SHA512:
6
- metadata.gz: 07dacc0bce5cba26d9636bb5acbfb70a7db5bc6bcb5de2eaec9e4ad37ed84728891414d6c534560f1b59c3b3db16714141cdf03eb322274f563e3e682fd069b4
7
- data.tar.gz: 3e064705391531a4918bfdf0c88ddcaa96ceab35d85b0e53a91966afd9fb3b0833365f2019098383407f441b51cd9b25d2a78f2a822ed46cfe0aeec0696ca61f
6
+ metadata.gz: 1599cba8ef9a7720d32b8da9d5f3403c4dec8a8a92930bd80072df35c6a190934ca61f990d97da47cf7464cfe9031b68f1cc69195dabf826fb5a09e8a5f3f0ff
7
+ data.tar.gz: 1709a0da42bb15ce7548b38a3b5bcfce395a4608c68201c8d1db16fd93c38172b9023cc5dcb8c47943abb6fb970792458552fabb414ccec36047c6e74effb4f1
data/README.md CHANGED
@@ -128,6 +128,25 @@ create_table "user_comments", force: true, renamed_from: "comments" do |t|
128
128
  end
129
129
  ```
130
130
 
131
+ ## Execute
132
+ ```sh
133
+ create_table "authors", force: true do |t|
134
+ t.string "name", null: false
135
+ end
136
+
137
+ create_table "books", force: true do |t|
138
+ t.string "title", null: false
139
+ t.integer "author_id", unsigned: true, null: false
140
+ end
141
+
142
+ add_index "books", ["author_id"], name: "idx_author_id", using: :btree
143
+
144
+ execute("ALTER TABLE books ADD CONSTRAINT fk_author FOREIGN KEY (author_id) REFERENCES authors (id)") do |c|
145
+ # Execute SQL only if there is no foreign key
146
+ c.raw_connection.query("SELECT 1 FROM information_schema.key_column_usage WHERE TABLE_SCHEMA = 'bookshelf' AND CONSTRAINT_NAME = 'fk_author' LIMIT 1").each.length.zero?
147
+ end
148
+ ```
149
+
131
150
  ## Diff
132
151
  ```sh
133
152
  $ ridgepole --diff file1.schema file2.schema
data/bin/ridgepole CHANGED
@@ -34,11 +34,23 @@ set_mode = proc do |m|
34
34
  end
35
35
 
36
36
  def noop_migrate(delta)
37
- puts delta.script + "\n\n"
37
+ unless delta.script.empty?
38
+ puts delta.script + "\n\n"
39
+ end
40
+
41
+ migrated, out = delta.migrate(:noop => true)
38
42
 
39
- delta.migrate(:noop => true).each_line do |line|
40
- puts line.strip.gsub(/([^\d])([(),])([^\d])/) { "#{$1}#{$2}\n#{$3}" }.each_line.map {|i| "# #{i.gsub(/^\s+/, '')}"}.join + "\n\n"
43
+ if migrated
44
+ out.each_line do |line|
45
+ if line =~ /\A\s+/
46
+ puts "# #{line}"
47
+ else
48
+ puts line.strip.gsub(/([^\d])([(),])([^\d])/) { "#{$1}#{$2}\n#{$3}" }.each_line.map {|i| "# #{i.gsub(/^\s+/, '')}"}.join + "\n"
49
+ end
50
+ end
41
51
  end
52
+
53
+ return migrated
42
54
  end
43
55
 
44
56
  ARGV.options do |opt|
@@ -161,17 +173,18 @@ begin
161
173
 
162
174
  dsl = File.read(file)
163
175
  delta = client.diff(dsl, :path => file)
176
+ differ = delta.differ?
164
177
 
165
178
  if options[:dry_run]
166
- if delta.differ?
167
- noop_migrate(delta)
179
+ if differ
180
+ differ = noop_migrate(delta)
168
181
  end
169
182
  else
170
183
  logger.verbose_info('# Update schema')
171
- delta.migrate
184
+ differ, out = delta.migrate
172
185
  end
173
186
 
174
- unless delta.differ?
187
+ unless differ
175
188
  logger.info('No change')
176
189
  end
177
190
  when :diff
@@ -193,15 +206,18 @@ begin
193
206
 
194
207
  if diff_with_apply
195
208
  logger.verbose_info('# Update schema')
209
+ differ = delta.differ?
196
210
 
197
- if delta.differ?
198
- delta.migrate
199
- else
211
+ if differ
212
+ differ, out = delta.migrate
213
+ end
214
+
215
+ if differ
200
216
  logger.info('No change')
201
217
  end
202
218
  elsif delta.differ?
203
- noop_migrate(delta)
204
- exit_code = 1
219
+ differ = noop_migrate(delta)
220
+ exit_code = 1 if differ
205
221
  end
206
222
  end
207
223
  rescue => e
@@ -22,11 +22,11 @@ class Ridgepole::Client
22
22
  logger = Ridgepole::Logger.instance
23
23
 
24
24
  logger.verbose_info('# Parse DSL')
25
- expected_definition = @parser.parse(dsl, opts)
25
+ expected_definition, expected_execute = @parser.parse(dsl, opts)
26
26
  logger.verbose_info('# Load tables')
27
- current_definition = @parser.parse(@dumper.dump)
27
+ current_definition, current_execute = @parser.parse(@dumper.dump)
28
28
  logger.verbose_info('# Compare definitions')
29
- @diff.diff(current_definition, expected_definition)
29
+ @diff.diff(current_definition, expected_definition, :execute => expected_execute)
30
30
  end
31
31
 
32
32
  class << self
@@ -34,9 +34,9 @@ class Ridgepole::Client
34
34
  logger = Ridgepole::Logger.instance
35
35
 
36
36
  logger.verbose_info('# Parse DSL1')
37
- definition1 = load_definition(dsl_or_config1)
37
+ definition1, execute1 = load_definition(dsl_or_config1)
38
38
  logger.verbose_info('# Parse DSL2')
39
- definition2 = load_definition(dsl_or_config2)
39
+ definition2, execute2 = load_definition(dsl_or_config2)
40
40
 
41
41
  logger.verbose_info('# Compare definitions')
42
42
  diff = Ridgepole::Diff.new(options)
@@ -4,6 +4,7 @@ class Ridgepole::Delta
4
4
  def initialize(delta, options = {})
5
5
  @delta = delta
6
6
  @options = options
7
+ @logger = Ridgepole::Logger.instance
7
8
  end
8
9
 
9
10
  def migrate(options = {})
@@ -41,12 +42,15 @@ class Ridgepole::Delta
41
42
  end
42
43
 
43
44
  def differ?
44
- not script.empty?
45
+ not script.empty? or not delta_execute.empty?
45
46
  end
46
47
 
47
48
  private
48
49
 
49
50
  def migrate0(options = {})
51
+ migrated = false
52
+ out = nil
53
+
50
54
  if options[:noop]
51
55
  disable_logging_orig = ActiveRecord::Migration.disable_logging
52
56
 
@@ -59,26 +63,74 @@ class Ridgepole::Delta
59
63
  end
60
64
 
61
65
  Ridgepole::ExecuteExpander.without_operation(callback) do
62
- eval_script(script, options.merge(:out => buf))
66
+ migrated = eval_script(script, options.merge(:out => buf))
63
67
  end
64
68
 
65
- buf.string.strip
69
+ out = buf.string.strip
66
70
  ensure
67
71
  ActiveRecord::Migration.disable_logging = disable_logging_orig
68
72
  end
69
73
  else
70
- eval_script(script, options)
74
+ migrated = eval_script(script, options)
71
75
  end
76
+
77
+ [migrated, out]
72
78
  end
73
79
 
74
80
  def eval_script(script, options = {})
81
+ execute_count = 0
82
+
75
83
  begin
76
84
  with_pre_post_query(options) do
77
- ActiveRecord::Schema.new.instance_eval(script, SCRIPT_NAME, 1)
85
+ unless script.empty?
86
+ ActiveRecord::Schema.new.instance_eval(script, SCRIPT_NAME, 1)
87
+ end
88
+
89
+ execute_count = execute_sqls(options)
78
90
  end
79
91
  rescue => e
80
92
  raise_exception(script, e)
81
93
  end
94
+
95
+ not script.empty? or execute_count.nonzero?
96
+ end
97
+
98
+ def execute_sqls(options = {})
99
+ es = @delta[:execute] || []
100
+ out = options[:out] || $stdout
101
+ execute_count = 0
102
+
103
+ es.each do |exec|
104
+ sql, cond = exec.values_at(:sql, :condition)
105
+ executable = false
106
+
107
+ begin
108
+ executable = cond.nil? || cond.call(ActiveRecord::Base.connection)
109
+ rescue => e
110
+ errmsg = "[WARN] `#{sql}` is not executed: #{e.message}"
111
+
112
+ if @options[:debug]
113
+ errmsg = ([errmsg] + e.backtrace).join("\n\tfrom ")
114
+ end
115
+
116
+ Ridgepole::Logger.instance.warn(errmsg)
117
+
118
+ executable = false
119
+ end
120
+
121
+ next unless executable
122
+
123
+ if options[:noop]
124
+ out.puts(sql.strip_heredoc)
125
+ else
126
+ @logger.info(sql.strip_heredoc)
127
+ ActiveRecord::Base.connection.execute(sql)
128
+ end
129
+
130
+ execute_count += 1
131
+ end
132
+
133
+ return execute_count
82
134
  end
83
135
 
84
136
  def with_pre_post_query(options = {})
@@ -324,4 +376,8 @@ remove_index(#{table_name.inspect}, #{target.inspect})
324
376
  EOS
325
377
  end
326
378
  end
379
+
380
+ def delta_execute
381
+ @delta[:execute] || []
382
+ end
327
383
  end
@@ -3,9 +3,9 @@ class Ridgepole::Diff
3
3
  @options = options
4
4
  end
5
5
 
6
- def diff(from, to)
7
- from = (from || {}).dup
8
- to = (to || {}).dup
6
+ def diff(from, to, options = {})
7
+ from = (from || {}).deep_dup
8
+ to = (to || {}).deep_dup
9
9
 
10
10
  if @options[:reverse]
11
11
  from, to = to, from
@@ -36,6 +36,8 @@ class Ridgepole::Diff
36
36
  end
37
37
  end
38
38
 
39
+ delta[:execute] = options[:execute]
40
+
39
41
  Ridgepole::Delta.new(delta, @options)
40
42
  end
41
43
 
@@ -40,26 +40,28 @@ class Ridgepole::DSLParser
40
40
 
41
41
  def timestamps(*args)
42
42
  options = {:null => false}.merge(args.extract_options!)
43
- column(:created_at, :datetime, options.dup)
44
- column(:updated_at, :datetime, options.dup)
43
+ column(:created_at, :datetime, options)
44
+ column(:updated_at, :datetime, options)
45
45
  end
46
46
 
47
47
  def references(*args)
48
48
  options = args.extract_options!
49
49
  polymorphic = options.delete(:polymorphic)
50
50
  args.each do |col|
51
- column("#{col}_id", :integer, options.dup)
52
- column("#{col}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options.dup) unless polymorphic.nil?
51
+ column("#{col}_id", :integer, options)
52
+ column("#{col}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) unless polymorphic.nil?
53
53
  end
54
54
  end
55
55
  alias :belongs_to :references
56
56
  end
57
57
 
58
58
  attr_reader :__definition
59
+ attr_reader :__execute
59
60
 
60
61
  def initialize(opts = {})
61
62
  @__working_dir = File.expand_path(opts[:path] ? File.dirname(opts[:path]) : Dir.pwd)
62
63
  @__definition = {}
64
+ @__execute = []
63
65
  end
64
66
 
65
67
  def self.eval(dsl, opts = {})
@@ -71,7 +73,7 @@ class Ridgepole::DSLParser
71
73
  ctx.instance_eval(dsl)
72
74
  end
73
75
 
74
- ctx.__definition
76
+ [ctx.__definition, ctx.__execute]
75
77
  end
76
78
 
77
79
  def create_table(table_name, options = {})
@@ -123,6 +125,13 @@ class Ridgepole::DSLParser
123
125
  Kernel.require(file)
124
126
  end
125
127
  end
128
+
129
+ def execute(sql, name = nil, &cond)
130
+ @__execute << {
131
+ :sql => sql,
132
+ :condition => cond,
133
+ }
134
+ end
126
135
  end
127
136
 
128
137
  def initialize(options = {})
@@ -130,15 +139,15 @@ class Ridgepole::DSLParser
130
139
  end
131
140
 
132
141
  def parse(dsl, opts = {})
133
- parsed = Context.eval(dsl, opts)
134
- check_orphan_index(parsed)
135
- parsed
142
+ definition, execute = Context.eval(dsl, opts)
143
+ check_orphan_index(definition)
144
+ [definition, execute]
136
145
  end
137
146
 
138
147
  private
139
148
 
140
- def check_orphan_index(parsed)
141
- parsed.each do |table_name, attrs|
149
+ def check_orphan_index(definition)
150
+ definition.each do |table_name, attrs|
142
151
  if attrs.length == 1 and attrs[:indices]
143
152
  raise "Table `#{table_name}` to create the index is not defined: #{attrs[:indices].keys.join(',')}"
144
153
  end
@@ -1,3 +1,3 @@
1
1
  module Ridgepole
2
- VERSION = '0.4.7'
2
+ VERSION = '0.4.8.rc1'
3
3
  end
@@ -110,8 +110,8 @@ describe 'ridgepole' do
110
110
  Ridgepole::Client#initialize([{"adapter"=>"mysql2", "database"=>"ridgepole_test"}, {:dry_run=>false, :debug=>false}])
111
111
  Apply `Schemafile`
112
112
  Ridgepole::Client#diff
113
- Ridgepole::Delta#migrate
114
113
  Ridgepole::Delta#differ?
114
+ Ridgepole::Delta#migrate
115
115
  No change
116
116
  EOS
117
117
  end
@@ -131,8 +131,8 @@ describe 'ridgepole' do
131
131
  Ridgepole::Client#initialize([{"adapter"=>"mysql2", "database"=>"ridgepole_test_for_conf_file"}, {:dry_run=>false, :debug=>true}])
132
132
  Apply `Schemafile`
133
133
  Ridgepole::Client#diff
134
- Ridgepole::Delta#migrate
135
134
  Ridgepole::Delta#differ?
135
+ Ridgepole::Delta#migrate
136
136
  No change
137
137
  EOS
138
138
  end
@@ -157,8 +157,8 @@ describe 'ridgepole' do
157
157
  Ridgepole::Client#initialize([{"adapter"=>"mysql2", "database"=>"ridgepole_development"}, {:dry_run=>false, :debug=>true}])
158
158
  Apply `Schemafile`
159
159
  Ridgepole::Client#diff
160
- Ridgepole::Delta#migrate
161
160
  Ridgepole::Delta#differ?
161
+ Ridgepole::Delta#migrate
162
162
  No change
163
163
  EOS
164
164
  end
@@ -173,7 +173,6 @@ describe 'ridgepole' do
173
173
  Apply `Schemafile` (dry-run)
174
174
  Ridgepole::Client#diff
175
175
  Ridgepole::Delta#differ?
176
- Ridgepole::Delta#differ?
177
176
  No change
178
177
  EOS
179
178
  end
@@ -189,8 +188,8 @@ describe 'ridgepole' do
189
188
  Ridgepole::Client#initialize([{"adapter"=>"mysql2", "database"=>"ridgepole_test"}, {:dry_run=>false, :debug=>false}])
190
189
  Apply `Schemafile`
191
190
  Ridgepole::Client#diff
192
- Ridgepole::Delta#migrate
193
191
  Ridgepole::Delta#differ?
192
+ Ridgepole::Delta#migrate
194
193
  EOS
195
194
  end
196
195
 
@@ -204,15 +203,13 @@ describe 'ridgepole' do
204
203
  Ridgepole::Client#diff
205
204
  Ridgepole::Delta#differ?
206
205
  Ridgepole::Delta#script
206
+ Ridgepole::Delta#script
207
207
  create_table :table do
208
208
  end
209
209
 
210
210
  Ridgepole::Delta#migrate
211
211
  # create_table :table do
212
-
213
212
  # end
214
-
215
- Ridgepole::Delta#differ?
216
213
  EOS
217
214
  end
218
215
  end
@@ -244,12 +241,12 @@ describe 'ridgepole' do
244
241
  Ridgepole::Client.diff([{"adapter"=>"mysql2", "database"=>"ridgepole_test"}, {"adapter"=>"mysql2", "database"=>"ridgepole_test"}, {:dry_run=>false, :debug=>false}])
245
242
  Ridgepole::Delta#differ?
246
243
  Ridgepole::Delta#script
244
+ Ridgepole::Delta#script
247
245
  create_table :table do
248
246
  end
249
247
 
250
248
  Ridgepole::Delta#migrate
251
249
  # create_table :table do
252
-
253
250
  # end
254
251
  EOS
255
252
  end
@@ -30,7 +30,8 @@ describe 'Ridgepole::Client#diff -> migrate' do
30
30
  delta = subject.diff(expected_dsl)
31
31
  expect(delta.differ?).to be_truthy
32
32
  expect(subject.dump).to eq actual_dsl.strip_heredoc.strip
33
- sql = delta.migrate(:noop => true)
33
+ migrated, sql = delta.migrate(:noop => true)
34
+ expect(migrated).to be_truthy
34
35
  expect(subject.dump).to eq actual_dsl.strip_heredoc.strip
35
36
 
36
37
  sql = sql.each_line.map {|i| i.strip }.join("\n")
@@ -69,7 +70,8 @@ describe 'Ridgepole::Client#diff -> migrate' do
69
70
  delta = subject.diff(expected_dsl)
70
71
  expect(delta.differ?).to be_truthy
71
72
  expect(subject.dump).to eq actual_dsl.strip_heredoc.strip
72
- sql = delta.migrate(:noop => true)
73
+ migrated, sql = delta.migrate(:noop => true)
74
+ expect(migrated).to be_truthy
73
75
  expect(subject.dump).to eq actual_dsl.strip_heredoc.strip
74
76
 
75
77
  sql = sql.each_line.map {|i| i.strip }.join("\n")
@@ -108,7 +110,8 @@ describe 'Ridgepole::Client#diff -> migrate' do
108
110
  delta = subject.diff(expected_dsl)
109
111
  expect(delta.differ?).to be_truthy
110
112
  expect(subject.dump).to eq actual_dsl.strip_heredoc.strip
111
- sql = delta.migrate(:noop => true)
113
+ migrated, sql = delta.migrate(:noop => true)
114
+ expect(migrated).to be_truthy
112
115
  expect(subject.dump).to eq actual_dsl.strip_heredoc.strip
113
116
 
114
117
  sql = sql.each_line.map {|i| i.strip }.join("\n")
@@ -0,0 +1,285 @@
1
+ describe 'Ridgepole::Client#diff -> migrate' do
2
+ context 'when execute' do
3
+ let(:dsl) {
4
+ <<-RUBY
5
+ create_table "authors", force: true do |t|
6
+ t.string "name", null: false
7
+ end
8
+
9
+ create_table "books", force: true do |t|
10
+ t.string "title", null: false
11
+ t.integer "author_id", unsigned: true, null: false
12
+ end
13
+
14
+ add_index "books", ["author_id"], name: "idx_author_id", using: :btree
15
+ RUBY
16
+ }
17
+
18
+ let(:dsl_with_execute) {
19
+ <<-RUBY
20
+ create_table "authors", force: true do |t|
21
+ t.string "name", null: false
22
+ end
23
+
24
+ create_table "books", force: true do |t|
25
+ t.string "title", null: false
26
+ t.integer "author_id", unsigned: true, null: false
27
+ end
28
+
29
+ add_index "books", ["author_id"], name: "idx_author_id", using: :btree
30
+
31
+ execute("ALTER TABLE books ADD CONSTRAINT fk_author FOREIGN KEY (author_id) REFERENCES authors (id)") do |c|
32
+ c.raw_connection.query("SELECT 1 FROM information_schema.key_column_usage WHERE TABLE_SCHEMA = '#{TEST_SCHEMA}' AND CONSTRAINT_NAME = 'fk_author' LIMIT 1").each.length.zero?
33
+ end
34
+ RUBY
35
+ }
36
+
37
+ before { subject.diff(dsl).migrate }
38
+ subject { client }
39
+
40
+ it {
41
+ delta = subject.diff(dsl_with_execute)
42
+ expect(delta.differ?).to be_truthy
43
+ expect(subject.dump.delete_empty_lines).to eq dsl.strip_heredoc.strip.delete_empty_lines
44
+
45
+ expect(show_create_table(:books).strip).to eq <<-SQL.strip_heredoc.strip
46
+ CREATE TABLE `books` (
47
+ `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
48
+ `title` varchar(255) NOT NULL,
49
+ `author_id` int(10) unsigned NOT NULL,
50
+ PRIMARY KEY (`id`),
51
+ KEY `idx_author_id` (`author_id`) USING BTREE
52
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8
53
+ SQL
54
+
55
+ delta.migrate
56
+ expect(subject.dump.delete_empty_lines).to eq dsl.strip_heredoc.strip.delete_empty_lines
57
+
58
+ expect(show_create_table(:books).strip).to eq <<-SQL.strip_heredoc.strip
59
+ CREATE TABLE `books` (
60
+ `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
61
+ `title` varchar(255) NOT NULL,
62
+ `author_id` int(10) unsigned NOT NULL,
63
+ PRIMARY KEY (`id`),
64
+ KEY `idx_author_id` (`author_id`) USING BTREE,
65
+ CONSTRAINT `fk_author` FOREIGN KEY (`author_id`) REFERENCES `authors` (`id`)
66
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8
67
+ SQL
68
+ }
69
+ end
70
+
71
+ context 'when not execute' do
72
+ let(:dsl) {
73
+ <<-RUBY
74
+ create_table "authors", force: true do |t|
75
+ t.string "name", null: false
76
+ end
77
+
78
+ create_table "books", force: true do |t|
79
+ t.string "title", null: false
80
+ t.integer "author_id", unsigned: true, null: false
81
+ end
82
+
83
+ add_index "books", ["author_id"], name: "idx_author_id", using: :btree
84
+ RUBY
85
+ }
86
+
87
+ let(:dsl_with_execute) {
88
+ <<-RUBY
89
+ create_table "authors", force: true do |t|
90
+ t.string "name", null: false
91
+ end
92
+
93
+ create_table "books", force: true do |t|
94
+ t.string "title", null: false
95
+ t.integer "author_id", unsigned: true, null: false
96
+ end
97
+
98
+ add_index "books", ["author_id"], name: "idx_author_id", using: :btree
99
+
100
+ execute("ALTER TABLE books ADD CONSTRAINT fk_author FOREIGN KEY (author_id) REFERENCES authors (id)") do |c|
101
+ c.raw_connection.query("SELECT 1 FROM information_schema.key_column_usage WHERE TABLE_SCHEMA = '#{TEST_SCHEMA}' AND CONSTRAINT_NAME = 'fk_author' LIMIT 1").each.length.zero?
102
+ end
103
+ RUBY
104
+ }
105
+
106
+ before { subject.diff(dsl_with_execute).migrate }
107
+ subject { client }
108
+
109
+ it {
110
+ delta = subject.diff(dsl_with_execute)
111
+ expect(delta.differ?).to be_truthy
112
+ expect(subject.dump.delete_empty_lines).to eq dsl.strip_heredoc.strip.delete_empty_lines
113
+
114
+ expect(show_create_table(:books).strip).to eq <<-SQL.strip_heredoc.strip
115
+ CREATE TABLE `books` (
116
+ `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
117
+ `title` varchar(255) NOT NULL,
118
+ `author_id` int(10) unsigned NOT NULL,
119
+ PRIMARY KEY (`id`),
120
+ KEY `idx_author_id` (`author_id`) USING BTREE,
121
+ CONSTRAINT `fk_author` FOREIGN KEY (`author_id`) REFERENCES `authors` (`id`)
122
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8
123
+ SQL
124
+
125
+ migrated, out = delta.migrate
126
+ expect(migrated).to be_falsey
127
+ expect(subject.dump.delete_empty_lines).to eq dsl.strip_heredoc.strip.delete_empty_lines
128
+
129
+ expect(show_create_table(:books).strip).to eq <<-SQL.strip_heredoc.strip
130
+ CREATE TABLE `books` (
131
+ `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
132
+ `title` varchar(255) NOT NULL,
133
+ `author_id` int(10) unsigned NOT NULL,
134
+ PRIMARY KEY (`id`),
135
+ KEY `idx_author_id` (`author_id`) USING BTREE,
136
+ CONSTRAINT `fk_author` FOREIGN KEY (`author_id`) REFERENCES `authors` (`id`)
137
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8
138
+ SQL
139
+ }
140
+ end
141
+
142
+ context 'when execute (noop)' do
143
+ let(:dsl) {
144
+ <<-RUBY
145
+ create_table "authors", force: true do |t|
146
+ t.string "name", null: false
147
+ end
148
+
149
+ create_table "books", force: true do |t|
150
+ t.string "title", null: false
151
+ t.integer "author_id", unsigned: true, null: false
152
+ end
153
+
154
+ add_index "books", ["author_id"], name: "idx_author_id", using: :btree
155
+ RUBY
156
+ }
157
+
158
+ let(:dsl_with_execute) {
159
+ <<-RUBY
160
+ create_table "authors", force: true do |t|
161
+ t.string "name", null: false
162
+ end
163
+
164
+ create_table "books", force: true do |t|
165
+ t.string "title", null: false
166
+ t.integer "author_id", unsigned: true, null: false
167
+ end
168
+
169
+ add_index "books", ["author_id"], name: "idx_author_id", using: :btree
170
+
171
+ execute("ALTER TABLE books ADD CONSTRAINT fk_author FOREIGN KEY (author_id) REFERENCES authors (id)") do |c|
172
+ c.raw_connection.query("SELECT 1 FROM information_schema.key_column_usage WHERE TABLE_SCHEMA = '#{TEST_SCHEMA}' AND CONSTRAINT_NAME = 'fk_author' LIMIT 1").each.length.zero?
173
+ end
174
+ RUBY
175
+ }
176
+
177
+ before { subject.diff(dsl).migrate }
178
+ subject { client }
179
+
180
+ it {
181
+ delta = subject.diff(dsl_with_execute)
182
+ expect(delta.differ?).to be_truthy
183
+ expect(subject.dump.delete_empty_lines).to eq dsl.strip_heredoc.strip.delete_empty_lines
184
+
185
+ expect(show_create_table(:books).strip).to eq <<-SQL.strip_heredoc.strip
186
+ CREATE TABLE `books` (
187
+ `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
188
+ `title` varchar(255) NOT NULL,
189
+ `author_id` int(10) unsigned NOT NULL,
190
+ PRIMARY KEY (`id`),
191
+ KEY `idx_author_id` (`author_id`) USING BTREE
192
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8
193
+ SQL
194
+
195
+ migrated, sql = delta.migrate(:noop => true)
196
+ expect(migrated).to be_truthy
197
+ expect(subject.dump.delete_empty_lines).to eq dsl.strip_heredoc.strip.delete_empty_lines
198
+
199
+ expect(sql.strip).to eq "ALTER TABLE books ADD CONSTRAINT fk_author FOREIGN KEY (author_id) REFERENCES authors (id)"
200
+
201
+ expect(show_create_table(:books).strip).to eq <<-SQL.strip_heredoc.strip
202
+ CREATE TABLE `books` (
203
+ `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
204
+ `title` varchar(255) NOT NULL,
205
+ `author_id` int(10) unsigned NOT NULL,
206
+ PRIMARY KEY (`id`),
207
+ KEY `idx_author_id` (`author_id`) USING BTREE
208
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8
209
+ SQL
210
+ }
211
+ end
212
+
213
+ context 'when not execute (noop)' do
214
+ let(:dsl) {
215
+ <<-RUBY
216
+ create_table "authors", force: true do |t|
217
+ t.string "name", null: false
218
+ end
219
+
220
+ create_table "books", force: true do |t|
221
+ t.string "title", null: false
222
+ t.integer "author_id", unsigned: true, null: false
223
+ end
224
+
225
+ add_index "books", ["author_id"], name: "idx_author_id", using: :btree
226
+ RUBY
227
+ }
228
+
229
+ let(:dsl_with_execute) {
230
+ <<-RUBY
231
+ create_table "authors", force: true do |t|
232
+ t.string "name", null: false
233
+ end
234
+
235
+ create_table "books", force: true do |t|
236
+ t.string "title", null: false
237
+ t.integer "author_id", unsigned: true, null: false
238
+ end
239
+
240
+ add_index "books", ["author_id"], name: "idx_author_id", using: :btree
241
+
242
+ execute("ALTER TABLE books ADD CONSTRAINT fk_author FOREIGN KEY (author_id) REFERENCES authors (id)") do |c|
243
+ c.raw_connection.query("SELECT 1 FROM information_schema.key_column_usage WHERE TABLE_SCHEMA = '#{TEST_SCHEMA}' AND CONSTRAINT_NAME = 'fk_author' LIMIT 1").each.length.zero?
244
+ end
245
+ RUBY
246
+ }
247
+
248
+ before { subject.diff(dsl_with_execute).migrate }
249
+ subject { client }
250
+
251
+ it {
252
+ delta = subject.diff(dsl_with_execute)
253
+ expect(delta.differ?).to be_truthy
254
+ expect(subject.dump.delete_empty_lines).to eq dsl.strip_heredoc.strip.delete_empty_lines
255
+
256
+ expect(show_create_table(:books).strip).to eq <<-SQL.strip_heredoc.strip
257
+ CREATE TABLE `books` (
258
+ `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
259
+ `title` varchar(255) NOT NULL,
260
+ `author_id` int(10) unsigned NOT NULL,
261
+ PRIMARY KEY (`id`),
262
+ KEY `idx_author_id` (`author_id`) USING BTREE,
263
+ CONSTRAINT `fk_author` FOREIGN KEY (`author_id`) REFERENCES `authors` (`id`)
264
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8
265
+ SQL
266
+
267
+ migrated, sql = delta.migrate(:noop => true)
268
+ expect(migrated).to be_falsey
269
+ expect(subject.dump.delete_empty_lines).to eq dsl.strip_heredoc.strip.delete_empty_lines
270
+
271
+ expect(sql.strip).to eq ""
272
+
273
+ expect(show_create_table(:books).strip).to eq <<-SQL.strip_heredoc.strip
274
+ CREATE TABLE `books` (
275
+ `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
276
+ `title` varchar(255) NOT NULL,
277
+ `author_id` int(10) unsigned NOT NULL,
278
+ PRIMARY KEY (`id`),
279
+ KEY `idx_author_id` (`author_id`) USING BTREE,
280
+ CONSTRAINT `fk_author` FOREIGN KEY (`author_id`) REFERENCES `authors` (`id`)
281
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8
282
+ SQL
283
+ }
284
+ end
285
+ end
@@ -75,7 +75,8 @@ describe 'Ridgepole::Client#diff -> migrate' do
75
75
  it {
76
76
  delta = subject.diff(expected_dsl)
77
77
  expect(delta.differ?).to be_truthy
78
- sql = delta.migrate(:noop => true)
78
+ migrated, sql = delta.migrate(:noop => true)
79
+ expect(migrated).to be_truthy
79
80
  expect(subject.dump).to eq actual_dsl
80
81
 
81
82
  sql = sql.each_line.map {|i| i.strip }.join("\n")
@@ -104,7 +105,8 @@ describe 'Ridgepole::Client#diff -> migrate' do
104
105
  it {
105
106
  delta = client(:bulk_change => true).diff(expected_dsl)
106
107
  expect(delta.differ?).to be_truthy
107
- sql = delta.migrate(:noop => true)
108
+ migrated, sql = delta.migrate(:noop => true)
109
+ expect(migrated).to be_truthy
108
110
  expect(subject.dump).to eq actual_dsl
109
111
 
110
112
  sql = sql.each_line.map {|i| i.strip }.join("\n")
@@ -205,7 +207,8 @@ describe 'Ridgepole::Client#diff -> migrate' do
205
207
  it {
206
208
  delta = subject.diff(expected_dsl)
207
209
  expect(delta.differ?).to be_truthy
208
- sql = delta.migrate(:noop => true)
210
+ migrated, sql = delta.migrate(:noop => true)
211
+ expect(migrated).to be_truthy
209
212
  expect(subject.dump).to eq actual_dsl
210
213
 
211
214
  sql = sql.each_line.map {|i| i.strip }.join("\n")
data/spec/spec_helper.rb CHANGED
@@ -7,6 +7,8 @@ require 'open3'
7
7
  require 'tempfile'
8
8
  require 'json'
9
9
 
10
+ TEST_SCHEMA = 'ridgepole_test'
11
+
10
12
  ActiveRecord::Migration.verbose = false
11
13
  Ridgepole::Logger.instance.level = ::Logger::ERROR
12
14
 
@@ -38,10 +40,15 @@ end
38
40
  def conn_spec(config = {})
39
41
  {
40
42
  adapter: 'mysql2',
41
- database: 'ridgepole_test',
43
+ database: TEST_SCHEMA,
42
44
  }.merge(config)
43
45
  end
44
46
 
47
+ def show_create_table(table_name)
48
+ raw_conn = ActiveRecord::Base.connection.raw_connection
49
+ raw_conn.query("SHOW CREATE TABLE `#{table_name}`").first[1]
50
+ end
51
+
45
52
  def default_cli_hook
46
53
  <<-RUBY.strip_heredoc
47
54
  require 'ridgepole'
@@ -51,7 +58,7 @@ def default_cli_hook
51
58
  end
52
59
  def migrate(*args)
53
60
  puts "Ridgepole::Delta#migrate"
54
- "create_table :table do\\nend"
61
+ [#{differ}, "create_table :table do\\nend"]
55
62
  end
56
63
  def script
57
64
  puts "Ridgepole::Delta#script"
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.7
4
+ version: 0.4.8.rc1
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-14 00:00:00.000000000 Z
11
+ date: 2014-09-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -153,6 +153,7 @@ files:
153
153
  - spec/migrate/migrate_duplicate_index_spec.rb
154
154
  - spec/migrate/migrate_duplicate_table_spec.rb
155
155
  - spec/migrate/migrate_empty_spec.rb
156
+ - spec/migrate/migrate_execute_spec.rb
156
157
  - spec/migrate/migrate_merge_mode_spec.rb
157
158
  - spec/migrate/migrate_noop_spec.rb
158
159
  - spec/migrate/migrate_rename_column_spec.rb
@@ -185,12 +186,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
185
186
  version: '0'
186
187
  required_rubygems_version: !ruby/object:Gem::Requirement
187
188
  requirements:
188
- - - '>='
189
+ - - '>'
189
190
  - !ruby/object:Gem::Version
190
- version: '0'
191
+ version: 1.3.1
191
192
  requirements: []
192
193
  rubyforge_project:
193
- rubygems_version: 2.4.1
194
+ rubygems_version: 2.0.14
194
195
  signing_key:
195
196
  specification_version: 4
196
197
  summary: Ridgepole is a tool to manage DB schema.
@@ -224,6 +225,7 @@ test_files:
224
225
  - spec/migrate/migrate_duplicate_index_spec.rb
225
226
  - spec/migrate/migrate_duplicate_table_spec.rb
226
227
  - spec/migrate/migrate_empty_spec.rb
228
+ - spec/migrate/migrate_execute_spec.rb
227
229
  - spec/migrate/migrate_merge_mode_spec.rb
228
230
  - spec/migrate/migrate_noop_spec.rb
229
231
  - spec/migrate/migrate_rename_column_spec.rb