ridgepole 1.0.1 → 3.1.5
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 +4 -4
- data/CHANGELOG.md +234 -99
- data/README.md +131 -26
- data/bin/ridgepole +16 -7
- data/lib/ridgepole/cli/config.rb +8 -15
- data/lib/ridgepole/client.rb +3 -2
- data/lib/ridgepole/default_limit.rb +13 -9
- data/lib/ridgepole/delta.rb +211 -17
- data/lib/ridgepole/diff.rb +207 -19
- data/lib/ridgepole/dsl_parser/context.rb +56 -3
- data/lib/ridgepole/dsl_parser/table_definition.rb +49 -21
- data/lib/ridgepole/dsl_parser.rb +24 -8
- data/lib/ridgepole/dumper.rb +7 -3
- data/lib/ridgepole/execute_expander.rb +34 -8
- data/lib/ridgepole/ext/abstract_adapter/disable_table_options.rb +0 -2
- data/lib/ridgepole/ext/schema_dumper/disable_sort_columns.rb +28 -0
- data/lib/ridgepole/ext/schema_dumper/foreign_keys.rb +68 -0
- data/lib/ridgepole/external_sql_executer.rb +1 -12
- data/lib/ridgepole/logger.rb +1 -0
- data/lib/ridgepole/version.rb +1 -1
- data/lib/ridgepole.rb +1 -1
- metadata +102 -33
- data/.rspec +0 -3
- data/.rubocop.yml +0 -53
- data/.simplecov +0 -6
- data/Appraisals +0 -22
- data/Gemfile +0 -6
- data/Rakefile +0 -13
- data/docker-compose.yml +0 -26
- data/gemfiles/activerecord_5.1.gemfile +0 -7
- data/gemfiles/activerecord_5.2.gemfile +0 -8
- data/gemfiles/activerecord_6.0.gemfile +0 -7
- data/gemfiles/activerecord_6.1.gemfile +0 -7
- data/gemfiles/activerecord_7.0.gemfile +0 -7
- data/lib/ridgepole/ext/schema_dumper.rb +0 -56
- data/ridgepole.gemspec +0 -47
data/lib/ridgepole/delta.rb
CHANGED
|
@@ -4,6 +4,10 @@ module Ridgepole
|
|
|
4
4
|
class Delta
|
|
5
5
|
SCRIPT_NAME = '<Schema>'
|
|
6
6
|
|
|
7
|
+
RIDGEPOLE_OPTIONS = %i[
|
|
8
|
+
renamed_from
|
|
9
|
+
].freeze
|
|
10
|
+
|
|
7
11
|
def initialize(delta, options = {})
|
|
8
12
|
@delta = delta
|
|
9
13
|
@options = options
|
|
@@ -70,8 +74,8 @@ module Ridgepole
|
|
|
70
74
|
ActiveRecord::Migration.disable_logging = true
|
|
71
75
|
buf = StringIO.new
|
|
72
76
|
|
|
73
|
-
callback = proc do |sql
|
|
74
|
-
buf.puts sql if sql =~ /\A(CREATE|ALTER|DROP|RENAME)\b/i
|
|
77
|
+
callback = proc do |sql|
|
|
78
|
+
buf.puts sql if sql =~ /\A(CREATE|ALTER|DROP|RENAME|COMMENT)\b/i
|
|
75
79
|
end
|
|
76
80
|
|
|
77
81
|
eval_script_block = proc do
|
|
@@ -235,13 +239,39 @@ create_table(#{table_name.inspect}, #{inspect_options_include_default_proc(optio
|
|
|
235
239
|
normalize_limit(column_type, column_options)
|
|
236
240
|
|
|
237
241
|
buf.puts(<<-RUBY)
|
|
238
|
-
t.column(#{column_name.inspect}, :#{column_type.to_s.inspect}, #{inspect_options_include_default_proc(column_options)})
|
|
242
|
+
t.column(#{column_name.inspect}, :#{column_type.to_s.inspect}, #{inspect_options_include_default_proc(normalize_options(column_options))})
|
|
239
243
|
RUBY
|
|
240
244
|
end
|
|
241
245
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
246
|
+
# Partition indices: indices referencing auto_increment columns must be
|
|
247
|
+
# inside CREATE TABLE on MySQL to avoid "must be defined as a key" error.
|
|
248
|
+
# cf. https://github.com/ridgepole/ridgepole/issues/494
|
|
249
|
+
if @options[:create_table_with_index]
|
|
250
|
+
indices_in_create = indices
|
|
251
|
+
indices_after_create = {}
|
|
252
|
+
else
|
|
253
|
+
indices_in_create, indices_after_create = partition_indices_for_create(definition, indices)
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
indices_in_create.each do |index_name, index_attrs|
|
|
257
|
+
append_add_index(table_name, index_name, index_attrs, buf, true)
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
unless (check_constraints = attrs[:check_constraints] || {}).empty?
|
|
261
|
+
check_constraints.each_value do |check_constraint_attrs|
|
|
262
|
+
append_add_check_constraint(table_name, check_constraint_attrs, buf, true)
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
unless (exclusion_constraints = attrs[:exclusion_constraints] || {}).empty?
|
|
267
|
+
exclusion_constraints.each_value do |exclusion_constraint_attrs|
|
|
268
|
+
append_add_exclusion_constraint(table_name, exclusion_constraint_attrs, buf, true)
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
unless (unique_constraints = attrs[:unique_constraints] || {}).empty?
|
|
273
|
+
unique_constraints.each_value do |unique_constraint_attrs|
|
|
274
|
+
append_add_unique_constraint(table_name, unique_constraint_attrs, buf, true)
|
|
245
275
|
end
|
|
246
276
|
end
|
|
247
277
|
|
|
@@ -249,16 +279,16 @@ create_table(#{table_name.inspect}, #{inspect_options_include_default_proc(optio
|
|
|
249
279
|
end
|
|
250
280
|
RUBY
|
|
251
281
|
|
|
252
|
-
|
|
282
|
+
unless indices_after_create.empty?
|
|
253
283
|
append_change_table(table_name, buf) do
|
|
254
|
-
|
|
284
|
+
indices_after_create.each do |index_name, index_attrs|
|
|
255
285
|
append_add_index(table_name, index_name, index_attrs, buf)
|
|
256
286
|
end
|
|
257
287
|
end
|
|
258
288
|
end
|
|
259
289
|
|
|
260
290
|
unless (foreign_keys = attrs[:foreign_keys] || {}).empty?
|
|
261
|
-
foreign_keys.
|
|
291
|
+
foreign_keys.each_value do |foreign_key_attrs|
|
|
262
292
|
append_add_foreign_key(table_name, foreign_key_attrs, post_buf_for_fk, @options)
|
|
263
293
|
end
|
|
264
294
|
end
|
|
@@ -267,6 +297,30 @@ end
|
|
|
267
297
|
post_buf_for_fk.puts
|
|
268
298
|
end
|
|
269
299
|
|
|
300
|
+
def partition_indices_for_create(definition, indices)
|
|
301
|
+
return [{}, indices] unless Ridgepole::ConnectionAdapters.mysql?
|
|
302
|
+
|
|
303
|
+
auto_increment_columns = definition.select do |_col_name, col_attrs|
|
|
304
|
+
col_attrs.dig(:options, :auto_increment)
|
|
305
|
+
end.keys
|
|
306
|
+
|
|
307
|
+
return [{}, indices] if auto_increment_columns.empty?
|
|
308
|
+
|
|
309
|
+
in_create = {}
|
|
310
|
+
after_create = {}
|
|
311
|
+
|
|
312
|
+
indices.each do |idx_name, idx_attrs|
|
|
313
|
+
columns = Array(idx_attrs[:column_name])
|
|
314
|
+
if (columns & auto_increment_columns).any?
|
|
315
|
+
in_create[idx_name] = idx_attrs
|
|
316
|
+
else
|
|
317
|
+
after_create[idx_name] = idx_attrs
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
[in_create, after_create]
|
|
322
|
+
end
|
|
323
|
+
|
|
270
324
|
def append_rename_table(to_table_name, from_table_name, buf)
|
|
271
325
|
buf.puts(<<-RUBY)
|
|
272
326
|
rename_table(#{from_table_name.inspect}, #{to_table_name.inspect})
|
|
@@ -286,14 +340,14 @@ drop_table(#{table_name.inspect})
|
|
|
286
340
|
def append_change_table_options(table_name, table_options, buf)
|
|
287
341
|
# XXX: MySQL only
|
|
288
342
|
buf.puts(<<-RUBY)
|
|
289
|
-
execute "ALTER TABLE #{ActiveRecord::Base.connection.quote_table_name(table_name)} #{table_options}"
|
|
343
|
+
execute "ALTER TABLE #{ActiveRecord::Base.connection.quote_table_name(table_name)} #{table_options.dump[1..-2]}"
|
|
290
344
|
RUBY
|
|
291
345
|
|
|
292
346
|
buf.puts
|
|
293
347
|
end
|
|
294
348
|
|
|
295
349
|
def append_change_table_raw_options(table_name, raw_table_options, table_charset, table_collation, buf)
|
|
296
|
-
if raw_table_options.blank?
|
|
350
|
+
if raw_table_options.blank?
|
|
297
351
|
# Implicit engine is InnoDB in 6.1.0
|
|
298
352
|
# related: https://github.com/rails/rails/pull/39365/files#diff-868f1dccfcbed26a288bf9f3fd8a39c863a4413ab0075e12b6805d9798f556d1R441
|
|
299
353
|
raw_table_options = +'ENGINE=InnoDB'
|
|
@@ -306,8 +360,14 @@ execute "ALTER TABLE #{ActiveRecord::Base.connection.quote_table_name(table_name
|
|
|
306
360
|
end
|
|
307
361
|
|
|
308
362
|
def append_change_table_comment(table_name, table_comment, buf)
|
|
309
|
-
|
|
310
|
-
|
|
363
|
+
if Ridgepole::ConnectionAdapters.postgresql?
|
|
364
|
+
buf.puts(<<-RUBY)
|
|
365
|
+
change_table_comment(#{table_name.inspect}, #{table_comment.inspect})
|
|
366
|
+
RUBY
|
|
367
|
+
else
|
|
368
|
+
comment_literal = "COMMENT=#{ActiveRecord::Base.connection.quote(table_comment)}"
|
|
369
|
+
append_change_table_options(table_name, comment_literal, buf)
|
|
370
|
+
end
|
|
311
371
|
end
|
|
312
372
|
|
|
313
373
|
def append_change(table_name, attrs, buf, pre_buf_for_fk, post_buf_for_fk)
|
|
@@ -315,10 +375,14 @@ execute "ALTER TABLE #{ActiveRecord::Base.connection.quote_table_name(table_name
|
|
|
315
375
|
primary_key_definition = attrs[:primary_key_definition] || {}
|
|
316
376
|
indices = attrs[:indices] || {}
|
|
317
377
|
foreign_keys = attrs[:foreign_keys] || {}
|
|
378
|
+
check_constraints = attrs[:check_constraints] || {}
|
|
379
|
+
exclusion_constraints = attrs[:exclusion_constraints] || {}
|
|
380
|
+
unique_constraints = attrs[:unique_constraints] || {}
|
|
318
381
|
table_options = attrs[:table_options]
|
|
319
382
|
table_charset = attrs[:table_charset]
|
|
320
383
|
table_collation = attrs[:table_collation]
|
|
321
384
|
table_comment = attrs[:table_comment]
|
|
385
|
+
column_comments = attrs[:column_comments] || {}
|
|
322
386
|
|
|
323
387
|
if !definition.empty? || !indices.empty? || !primary_key_definition.empty?
|
|
324
388
|
append_change_table(table_name, buf) do
|
|
@@ -330,16 +394,31 @@ execute "ALTER TABLE #{ActiveRecord::Base.connection.quote_table_name(table_name
|
|
|
330
394
|
end
|
|
331
395
|
|
|
332
396
|
append_change_foreign_keys(table_name, foreign_keys, pre_buf_for_fk, post_buf_for_fk, @options) unless foreign_keys.empty?
|
|
397
|
+
append_change_check_constraints(table_name, check_constraints, buf) unless check_constraints.empty?
|
|
398
|
+
append_change_exclusion_constraints(table_name, exclusion_constraints, buf) unless exclusion_constraints.empty?
|
|
399
|
+
append_change_unique_constraints(table_name, unique_constraints, buf) unless unique_constraints.empty?
|
|
333
400
|
|
|
334
|
-
|
|
401
|
+
if table_options || table_charset || table_collation
|
|
402
|
+
append_change_table_raw_options(table_name, table_options, table_charset, table_collation,
|
|
403
|
+
buf)
|
|
404
|
+
end
|
|
335
405
|
|
|
336
406
|
append_change_table_comment(table_name, table_comment, buf) if table_comment
|
|
407
|
+
append_change_column_comments(table_name, column_comments, buf) unless column_comments.empty?
|
|
337
408
|
|
|
338
409
|
buf.puts
|
|
339
410
|
pre_buf_for_fk.puts
|
|
340
411
|
post_buf_for_fk.puts
|
|
341
412
|
end
|
|
342
413
|
|
|
414
|
+
def append_change_column_comments(table_name, column_comments, buf)
|
|
415
|
+
column_comments.each do |column_name, comment|
|
|
416
|
+
buf.puts(<<-RUBY)
|
|
417
|
+
change_column_comment(#{table_name.inspect}, #{column_name.inspect}, #{comment.inspect})
|
|
418
|
+
RUBY
|
|
419
|
+
end
|
|
420
|
+
end
|
|
421
|
+
|
|
343
422
|
def append_change_table(table_name, buf)
|
|
344
423
|
buf.puts "change_table(#{table_name.inspect}, bulk: true) do |t|" if @options[:bulk_change]
|
|
345
424
|
yield
|
|
@@ -397,8 +476,15 @@ rename_column(#{table_name.inspect}, #{from_column_name.inspect}, #{to_column_na
|
|
|
397
476
|
options = attrs[:options] || {}
|
|
398
477
|
|
|
399
478
|
# Fix for https://github.com/rails/rails/commit/7f0567b43b73b1bd1a16bfac9cd32fcbf1321b51
|
|
400
|
-
if Ridgepole::ConnectionAdapters.mysql?
|
|
479
|
+
if Ridgepole::ConnectionAdapters.mysql?
|
|
401
480
|
options[:comment] = nil unless options.key?(:comment)
|
|
481
|
+
|
|
482
|
+
# Generated/virtual columns cannot have DEFAULT values in MySQL.
|
|
483
|
+
# cf. https://github.com/ridgepole/ridgepole/issues/482
|
|
484
|
+
if type == :virtual
|
|
485
|
+
options.delete(:default)
|
|
486
|
+
options.delete(:unsigned)
|
|
487
|
+
end
|
|
402
488
|
end
|
|
403
489
|
|
|
404
490
|
if @options[:bulk_change]
|
|
@@ -475,11 +561,11 @@ remove_index(#{table_name.inspect}, #{target})
|
|
|
475
561
|
end
|
|
476
562
|
|
|
477
563
|
def append_change_foreign_keys(table_name, delta, pre_buf_for_fk, post_buf_for_fk, options)
|
|
478
|
-
(delta[:delete] || {}).
|
|
564
|
+
(delta[:delete] || {}).each_value do |attrs|
|
|
479
565
|
append_remove_foreign_key(table_name, attrs, pre_buf_for_fk, options)
|
|
480
566
|
end
|
|
481
567
|
|
|
482
|
-
(delta[:add] || {}).
|
|
568
|
+
(delta[:add] || {}).each_value do |attrs|
|
|
483
569
|
append_add_foreign_key(table_name, attrs, post_buf_for_fk, options)
|
|
484
570
|
end
|
|
485
571
|
end
|
|
@@ -508,6 +594,108 @@ remove_foreign_key(#{table_name.inspect}, #{target})
|
|
|
508
594
|
RUBY
|
|
509
595
|
end
|
|
510
596
|
|
|
597
|
+
def append_change_check_constraints(table_name, delta, buf)
|
|
598
|
+
(delta[:delete] || {}).each_value do |attrs|
|
|
599
|
+
append_remove_check_constraint(table_name, attrs, buf)
|
|
600
|
+
end
|
|
601
|
+
|
|
602
|
+
(delta[:add] || {}).each_value do |attrs|
|
|
603
|
+
append_add_check_constraint(table_name, attrs, buf)
|
|
604
|
+
end
|
|
605
|
+
end
|
|
606
|
+
|
|
607
|
+
def append_add_check_constraint(table_name, attrs, buf, force_bulk_change = false)
|
|
608
|
+
expression = attrs.fetch(:expression)
|
|
609
|
+
attrs_options = attrs[:options] || {}
|
|
610
|
+
|
|
611
|
+
if force_bulk_change
|
|
612
|
+
buf.puts(<<-RUBY)
|
|
613
|
+
t.check_constraint(#{expression.inspect}, **#{attrs_options.inspect})
|
|
614
|
+
RUBY
|
|
615
|
+
else
|
|
616
|
+
buf.puts(<<-RUBY)
|
|
617
|
+
add_check_constraint(#{table_name.inspect}, #{expression.inspect}, **#{attrs_options.inspect})
|
|
618
|
+
RUBY
|
|
619
|
+
end
|
|
620
|
+
end
|
|
621
|
+
|
|
622
|
+
def append_remove_check_constraint(table_name, attrs, buf)
|
|
623
|
+
expression = attrs.fetch(:expression)
|
|
624
|
+
attrs_options = attrs[:options] || {}
|
|
625
|
+
|
|
626
|
+
buf.puts(<<-RUBY)
|
|
627
|
+
remove_check_constraint(#{table_name.inspect}, #{expression.inspect}, **#{attrs_options.inspect})
|
|
628
|
+
RUBY
|
|
629
|
+
end
|
|
630
|
+
|
|
631
|
+
def append_change_exclusion_constraints(table_name, delta, buf)
|
|
632
|
+
(delta[:delete] || {}).each_value do |attrs|
|
|
633
|
+
append_remove_exclusion_constraint(table_name, attrs, buf)
|
|
634
|
+
end
|
|
635
|
+
|
|
636
|
+
(delta[:add] || {}).each_value do |attrs|
|
|
637
|
+
append_add_exclusion_constraint(table_name, attrs, buf)
|
|
638
|
+
end
|
|
639
|
+
end
|
|
640
|
+
|
|
641
|
+
def append_add_exclusion_constraint(table_name, attrs, buf, force_bulk_change = false)
|
|
642
|
+
expression = attrs.fetch(:expression)
|
|
643
|
+
attrs_options = attrs[:options] || {}
|
|
644
|
+
|
|
645
|
+
if force_bulk_change
|
|
646
|
+
buf.puts(<<-RUBY)
|
|
647
|
+
t.exclusion_constraint(#{expression.inspect}, **#{attrs_options.inspect})
|
|
648
|
+
RUBY
|
|
649
|
+
else
|
|
650
|
+
buf.puts(<<-RUBY)
|
|
651
|
+
add_exclusion_constraint(#{table_name.inspect}, #{expression.inspect}, **#{attrs_options.inspect})
|
|
652
|
+
RUBY
|
|
653
|
+
end
|
|
654
|
+
end
|
|
655
|
+
|
|
656
|
+
def append_remove_exclusion_constraint(table_name, attrs, buf)
|
|
657
|
+
expression = attrs.fetch(:expression)
|
|
658
|
+
attrs_options = attrs[:options] || {}
|
|
659
|
+
|
|
660
|
+
buf.puts(<<-RUBY)
|
|
661
|
+
remove_exclusion_constraint(#{table_name.inspect}, #{expression.inspect}, **#{attrs_options.inspect})
|
|
662
|
+
RUBY
|
|
663
|
+
end
|
|
664
|
+
|
|
665
|
+
def append_change_unique_constraints(table_name, delta, buf)
|
|
666
|
+
(delta[:delete] || {}).each_value do |attrs|
|
|
667
|
+
append_remove_unique_constraint(table_name, attrs, buf)
|
|
668
|
+
end
|
|
669
|
+
|
|
670
|
+
(delta[:add] || {}).each_value do |attrs|
|
|
671
|
+
append_add_unique_constraint(table_name, attrs, buf)
|
|
672
|
+
end
|
|
673
|
+
end
|
|
674
|
+
|
|
675
|
+
def append_add_unique_constraint(table_name, attrs, buf, force_bulk_change = false)
|
|
676
|
+
column_name = attrs.fetch(:column_name)
|
|
677
|
+
attrs_options = attrs[:options] || {}
|
|
678
|
+
|
|
679
|
+
if force_bulk_change
|
|
680
|
+
buf.puts(<<-RUBY)
|
|
681
|
+
t.unique_constraint(#{column_name.inspect}, **#{attrs_options.inspect})
|
|
682
|
+
RUBY
|
|
683
|
+
else
|
|
684
|
+
buf.puts(<<-RUBY)
|
|
685
|
+
add_unique_constraint(#{table_name.inspect}, #{column_name.inspect}, **#{attrs_options.inspect})
|
|
686
|
+
RUBY
|
|
687
|
+
end
|
|
688
|
+
end
|
|
689
|
+
|
|
690
|
+
def append_remove_unique_constraint(table_name, attrs, buf)
|
|
691
|
+
column_name = attrs.fetch(:column_name)
|
|
692
|
+
attrs_options = attrs[:options] || {}
|
|
693
|
+
|
|
694
|
+
buf.puts(<<-RUBY)
|
|
695
|
+
remove_unique_constraint(#{table_name.inspect}, #{column_name.inspect}, **#{attrs_options.inspect})
|
|
696
|
+
RUBY
|
|
697
|
+
end
|
|
698
|
+
|
|
511
699
|
def delta_execute
|
|
512
700
|
@delta[:execute] || []
|
|
513
701
|
end
|
|
@@ -517,6 +705,12 @@ remove_foreign_key(#{table_name.inspect}, #{target})
|
|
|
517
705
|
column_options[:limit] ||= default_limit if default_limit
|
|
518
706
|
end
|
|
519
707
|
|
|
708
|
+
def normalize_options(options)
|
|
709
|
+
opts = options.dup
|
|
710
|
+
RIDGEPOLE_OPTIONS.each { opts.delete(_1) }
|
|
711
|
+
opts
|
|
712
|
+
end
|
|
713
|
+
|
|
520
714
|
def inspect_options_include_default_proc(options)
|
|
521
715
|
options = options.dup
|
|
522
716
|
|