ridgepole 3.2.1 → 3.2.3
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 +9 -0
- data/README.md +4 -3
- data/lib/ridgepole/delta.rb +60 -28
- data/lib/ridgepole/diff.rb +50 -11
- data/lib/ridgepole/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1a307f88c8f4187e3ec20de74f563caa0041e66749b0c2bf0345724a2a15103b
|
|
4
|
+
data.tar.gz: b74fc6cae628ac13466fd7dde31679d518f3bcc963bb7dd5877c193720bebf25
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9b6d880d3b5f91ab5947dd416180c097df2ea99c566df051195357898ee457dbcc35a724467e43b23620d8fc62b1dba7a44460d71535ad7977f1f851a616f08b
|
|
7
|
+
data.tar.gz: 37b2b51fbbf5aadb34fd85d1526b30ddc550bbd85467e3183148f8f8376caf78c0b25f62ed7a32585c6f03caddae73a6e8b8dcbeb762058b609fc382b971bec9
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
## 3.2
|
|
4
4
|
|
|
5
|
+
### 3.2.3 (2026/08/01)
|
|
6
|
+
|
|
7
|
+
- Emit `validate_constraint` when DB is NOT VALID and DSL implies validated. [pull#718](https://github.com/ridgepole/ridgepole/pull/718)
|
|
8
|
+
- Ignore `validate: false` diff when existing constraint lacks `:validate`. [pull#716](https://github.com/ridgepole/ridgepole/pull/716)
|
|
9
|
+
|
|
10
|
+
### 3.2.2 (2026/06/14)
|
|
11
|
+
|
|
12
|
+
- Fix constraint removal order when dropping columns. [pull#705](https://github.com/ridgepole/ridgepole/pull/705)
|
|
13
|
+
|
|
5
14
|
### 3.2.1 (2026/05/04)
|
|
6
15
|
|
|
7
16
|
- Warn when an anonymous index ambiguously matches multiple DB indexes. [pull#692](https://github.com/ridgepole/ridgepole/pull/692)
|
data/README.md
CHANGED
|
@@ -10,9 +10,10 @@ It defines DB schema using [Rails DSL](http://guides.rubyonrails.org/migrations.
|
|
|
10
10
|
[](https://codecov.io/gh/ridgepole/ridgepole)
|
|
11
11
|
|
|
12
12
|
> [!TIP]
|
|
13
|
-
>
|
|
14
|
-
>
|
|
15
|
-
>
|
|
13
|
+
> Also developing similar declarative schema tools — single Go binary, plain SQL as the schema definition:
|
|
14
|
+
>
|
|
15
|
+
> * [pistachio](https://github.com/winebarrel/pistachio): for PostgreSQL
|
|
16
|
+
> * [myschema](https://github.com/winebarrel/myschema): for MySQL
|
|
16
17
|
|
|
17
18
|
> [!warning]
|
|
18
19
|
> The order of columns when exporting has changed in Rails 8.1. https://github.com/rails/rails/pull/53281
|
data/lib/ridgepole/delta.rb
CHANGED
|
@@ -31,11 +31,11 @@ module Ridgepole
|
|
|
31
31
|
|
|
32
32
|
def script
|
|
33
33
|
buf = StringIO.new
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
pre_buf = StringIO.new
|
|
35
|
+
post_buf = StringIO.new
|
|
36
36
|
|
|
37
37
|
(@delta[:add] || {}).each do |table_name, attrs|
|
|
38
|
-
append_create_table(table_name, attrs, buf,
|
|
38
|
+
append_create_table(table_name, attrs, buf, post_buf)
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
(@delta[:rename] || {}).each do |table_name, attrs|
|
|
@@ -43,7 +43,7 @@ module Ridgepole
|
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
(@delta[:change] || {}).each do |table_name, attrs|
|
|
46
|
-
append_change(table_name, attrs, buf,
|
|
46
|
+
append_change(table_name, attrs, buf, pre_buf, post_buf)
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
(@delta[:delete] || {}).each do |table_name, attrs|
|
|
@@ -51,9 +51,9 @@ module Ridgepole
|
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
[
|
|
54
|
-
|
|
54
|
+
pre_buf,
|
|
55
55
|
buf,
|
|
56
|
-
|
|
56
|
+
post_buf
|
|
57
57
|
].map { |b| b.string.strip }.join("\n\n").strip
|
|
58
58
|
end
|
|
59
59
|
|
|
@@ -221,7 +221,7 @@ module Ridgepole
|
|
|
221
221
|
end
|
|
222
222
|
end
|
|
223
223
|
|
|
224
|
-
def append_create_table(table_name, attrs, buf,
|
|
224
|
+
def append_create_table(table_name, attrs, buf, post_buf)
|
|
225
225
|
options = attrs[:options] || {}
|
|
226
226
|
definition = attrs[:definition] || {}
|
|
227
227
|
indices = attrs[:indices] || {}
|
|
@@ -289,12 +289,12 @@ end
|
|
|
289
289
|
|
|
290
290
|
unless (foreign_keys = attrs[:foreign_keys] || {}).empty?
|
|
291
291
|
foreign_keys.each_value do |foreign_key_attrs|
|
|
292
|
-
append_add_foreign_key(table_name, foreign_key_attrs,
|
|
292
|
+
append_add_foreign_key(table_name, foreign_key_attrs, post_buf, @options)
|
|
293
293
|
end
|
|
294
294
|
end
|
|
295
295
|
|
|
296
296
|
buf.puts
|
|
297
|
-
|
|
297
|
+
post_buf.puts
|
|
298
298
|
end
|
|
299
299
|
|
|
300
300
|
def partition_indices_for_create(definition, indices)
|
|
@@ -370,7 +370,7 @@ change_table_comment(#{table_name.inspect}, #{table_comment.inspect})
|
|
|
370
370
|
end
|
|
371
371
|
end
|
|
372
372
|
|
|
373
|
-
def append_change(table_name, attrs, buf,
|
|
373
|
+
def append_change(table_name, attrs, buf, pre_buf, post_buf)
|
|
374
374
|
definition = attrs[:definition] || {}
|
|
375
375
|
primary_key_definition = attrs[:primary_key_definition] || {}
|
|
376
376
|
indices = attrs[:indices] || {}
|
|
@@ -393,10 +393,10 @@ change_table_comment(#{table_name.inspect}, #{table_comment.inspect})
|
|
|
393
393
|
end
|
|
394
394
|
end
|
|
395
395
|
|
|
396
|
-
append_change_foreign_keys(table_name, foreign_keys,
|
|
397
|
-
append_change_check_constraints(table_name, check_constraints,
|
|
398
|
-
append_change_exclusion_constraints(table_name, exclusion_constraints,
|
|
399
|
-
append_change_unique_constraints(table_name, unique_constraints,
|
|
396
|
+
append_change_foreign_keys(table_name, foreign_keys, pre_buf, post_buf, @options) unless foreign_keys.empty?
|
|
397
|
+
append_change_check_constraints(table_name, check_constraints, pre_buf, post_buf) unless check_constraints.empty?
|
|
398
|
+
append_change_exclusion_constraints(table_name, exclusion_constraints, pre_buf, post_buf) unless exclusion_constraints.empty?
|
|
399
|
+
append_change_unique_constraints(table_name, unique_constraints, pre_buf, post_buf) unless unique_constraints.empty?
|
|
400
400
|
|
|
401
401
|
if table_options || table_charset || table_collation
|
|
402
402
|
append_change_table_raw_options(table_name, table_options, table_charset, table_collation,
|
|
@@ -407,8 +407,8 @@ change_table_comment(#{table_name.inspect}, #{table_comment.inspect})
|
|
|
407
407
|
append_change_column_comments(table_name, column_comments, buf) unless column_comments.empty?
|
|
408
408
|
|
|
409
409
|
buf.puts
|
|
410
|
-
|
|
411
|
-
|
|
410
|
+
pre_buf.puts
|
|
411
|
+
post_buf.puts
|
|
412
412
|
end
|
|
413
413
|
|
|
414
414
|
def append_change_column_comments(table_name, column_comments, buf)
|
|
@@ -560,13 +560,17 @@ remove_index(#{table_name.inspect}, #{target})
|
|
|
560
560
|
end
|
|
561
561
|
end
|
|
562
562
|
|
|
563
|
-
def append_change_foreign_keys(table_name, delta,
|
|
563
|
+
def append_change_foreign_keys(table_name, delta, pre_buf, post_buf, options)
|
|
564
564
|
(delta[:delete] || {}).each_value do |attrs|
|
|
565
|
-
append_remove_foreign_key(table_name, attrs,
|
|
565
|
+
append_remove_foreign_key(table_name, attrs, pre_buf, options)
|
|
566
566
|
end
|
|
567
567
|
|
|
568
568
|
(delta[:add] || {}).each_value do |attrs|
|
|
569
|
-
append_add_foreign_key(table_name, attrs,
|
|
569
|
+
append_add_foreign_key(table_name, attrs, post_buf, options)
|
|
570
|
+
end
|
|
571
|
+
|
|
572
|
+
(delta[:validate] || {}).each_value do |attrs|
|
|
573
|
+
append_validate_foreign_key(table_name, attrs, post_buf)
|
|
570
574
|
end
|
|
571
575
|
end
|
|
572
576
|
|
|
@@ -594,13 +598,32 @@ remove_foreign_key(#{table_name.inspect}, #{target})
|
|
|
594
598
|
RUBY
|
|
595
599
|
end
|
|
596
600
|
|
|
597
|
-
def
|
|
601
|
+
def append_validate_foreign_key(table_name, attrs, buf)
|
|
602
|
+
attrs_options = attrs[:options] || {}
|
|
603
|
+
fk_name = attrs_options[:name]
|
|
604
|
+
|
|
605
|
+
target = if fk_name
|
|
606
|
+
"name: #{fk_name.inspect}"
|
|
607
|
+
else
|
|
608
|
+
attrs.fetch(:to_table).inspect
|
|
609
|
+
end
|
|
610
|
+
|
|
611
|
+
buf.puts(<<-RUBY)
|
|
612
|
+
validate_foreign_key(#{table_name.inspect}, #{target})
|
|
613
|
+
RUBY
|
|
614
|
+
end
|
|
615
|
+
|
|
616
|
+
def append_change_check_constraints(table_name, delta, pre_buf, post_buf)
|
|
598
617
|
(delta[:delete] || {}).each_value do |attrs|
|
|
599
|
-
append_remove_check_constraint(table_name, attrs,
|
|
618
|
+
append_remove_check_constraint(table_name, attrs, pre_buf)
|
|
600
619
|
end
|
|
601
620
|
|
|
602
621
|
(delta[:add] || {}).each_value do |attrs|
|
|
603
|
-
append_add_check_constraint(table_name, attrs,
|
|
622
|
+
append_add_check_constraint(table_name, attrs, post_buf)
|
|
623
|
+
end
|
|
624
|
+
|
|
625
|
+
(delta[:validate] || {}).each_value do |attrs|
|
|
626
|
+
append_validate_check_constraint(table_name, attrs, post_buf)
|
|
604
627
|
end
|
|
605
628
|
end
|
|
606
629
|
|
|
@@ -628,13 +651,22 @@ remove_check_constraint(#{table_name.inspect}, #{expression.inspect}, **#{attrs_
|
|
|
628
651
|
RUBY
|
|
629
652
|
end
|
|
630
653
|
|
|
631
|
-
def
|
|
654
|
+
def append_validate_check_constraint(table_name, attrs, buf)
|
|
655
|
+
attrs_options = attrs[:options] || {}
|
|
656
|
+
name = attrs_options[:name]
|
|
657
|
+
|
|
658
|
+
buf.puts(<<-RUBY)
|
|
659
|
+
validate_check_constraint(#{table_name.inspect}, name: #{name.inspect})
|
|
660
|
+
RUBY
|
|
661
|
+
end
|
|
662
|
+
|
|
663
|
+
def append_change_exclusion_constraints(table_name, delta, pre_buf, post_buf)
|
|
632
664
|
(delta[:delete] || {}).each_value do |attrs|
|
|
633
|
-
append_remove_exclusion_constraint(table_name, attrs,
|
|
665
|
+
append_remove_exclusion_constraint(table_name, attrs, pre_buf)
|
|
634
666
|
end
|
|
635
667
|
|
|
636
668
|
(delta[:add] || {}).each_value do |attrs|
|
|
637
|
-
append_add_exclusion_constraint(table_name, attrs,
|
|
669
|
+
append_add_exclusion_constraint(table_name, attrs, post_buf)
|
|
638
670
|
end
|
|
639
671
|
end
|
|
640
672
|
|
|
@@ -662,13 +694,13 @@ remove_exclusion_constraint(#{table_name.inspect}, #{expression.inspect}, **#{at
|
|
|
662
694
|
RUBY
|
|
663
695
|
end
|
|
664
696
|
|
|
665
|
-
def append_change_unique_constraints(table_name, delta,
|
|
697
|
+
def append_change_unique_constraints(table_name, delta, pre_buf, post_buf)
|
|
666
698
|
(delta[:delete] || {}).each_value do |attrs|
|
|
667
|
-
append_remove_unique_constraint(table_name, attrs,
|
|
699
|
+
append_remove_unique_constraint(table_name, attrs, pre_buf)
|
|
668
700
|
end
|
|
669
701
|
|
|
670
702
|
(delta[:add] || {}).each_value do |attrs|
|
|
671
|
-
append_add_unique_constraint(table_name, attrs,
|
|
703
|
+
append_add_unique_constraint(table_name, attrs, post_buf)
|
|
672
704
|
end
|
|
673
705
|
end
|
|
674
706
|
|
data/lib/ridgepole/diff.rb
CHANGED
|
@@ -524,13 +524,18 @@ module Ridgepole
|
|
|
524
524
|
next if ignore_fk
|
|
525
525
|
|
|
526
526
|
if from_attrs
|
|
527
|
-
if from_attrs != to_attrs
|
|
528
|
-
|
|
529
|
-
|
|
527
|
+
if from_attrs != to_attrs && !ignorable_validate_diff?(from_attrs, to_attrs)
|
|
528
|
+
if validate_only_diff?(from_attrs, to_attrs)
|
|
529
|
+
foreign_keys_delta[:validate] ||= {}
|
|
530
|
+
foreign_keys_delta[:validate][foreign_key_name_or_tables] = to_attrs
|
|
531
|
+
else
|
|
532
|
+
foreign_keys_delta[:add] ||= {}
|
|
533
|
+
foreign_keys_delta[:add][foreign_key_name_or_tables] = to_attrs
|
|
530
534
|
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
535
|
+
unless options[:merge]
|
|
536
|
+
foreign_keys_delta[:delete] ||= {}
|
|
537
|
+
foreign_keys_delta[:delete][foreign_key_name_or_tables] = from_attrs
|
|
538
|
+
end
|
|
534
539
|
end
|
|
535
540
|
end
|
|
536
541
|
else
|
|
@@ -558,12 +563,19 @@ module Ridgepole
|
|
|
558
563
|
from_attrs = from.delete(name)
|
|
559
564
|
|
|
560
565
|
if from_attrs
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
566
|
+
from_normalized = normalize_check_constraint(from_attrs)
|
|
567
|
+
to_normalized = normalize_check_constraint(to_attrs)
|
|
568
|
+
if from_normalized != to_normalized && !ignorable_validate_diff?(from_normalized, to_normalized)
|
|
569
|
+
if validate_only_diff?(from_normalized, to_normalized)
|
|
570
|
+
check_constraints_delta[:validate] ||= {}
|
|
571
|
+
check_constraints_delta[:validate][name] = to_attrs
|
|
572
|
+
else
|
|
573
|
+
check_constraints_delta[:add] ||= {}
|
|
574
|
+
check_constraints_delta[:add][name] = to_attrs
|
|
564
575
|
|
|
565
|
-
|
|
566
|
-
|
|
576
|
+
check_constraints_delta[:delete] ||= {}
|
|
577
|
+
check_constraints_delta[:delete][name] = from_attrs
|
|
578
|
+
end
|
|
567
579
|
end
|
|
568
580
|
else
|
|
569
581
|
check_constraints_delta[:add] ||= {}
|
|
@@ -587,6 +599,33 @@ module Ridgepole
|
|
|
587
599
|
attr
|
|
588
600
|
end
|
|
589
601
|
|
|
602
|
+
# 'validate: false' (NOT VALID) is a strategy for ALTER TABLE ADD CONSTRAINT to avoid
|
|
603
|
+
# ACCESS EXCLUSIVE lock on large tables. NOT VALID state itself is persisted by the DB,
|
|
604
|
+
# but PostgreSQL ignores NOT VALID for constraints created inline within CREATE TABLE, so
|
|
605
|
+
# whether the resulting constraint is NOT VALID depends on how it was created. Restoring
|
|
606
|
+
# NOT VALID via DROP + ADD has no benefit, so ignore the diff when the DB dump lacks
|
|
607
|
+
# :validate and the DSL specifies validate: false.
|
|
608
|
+
def ignorable_validate_diff?(from_attrs, to_attrs)
|
|
609
|
+
from_options = from_attrs[:options] || {}
|
|
610
|
+
to_options = to_attrs[:options] || {}
|
|
611
|
+
return false unless to_options[:validate] == false && !from_options.key?(:validate)
|
|
612
|
+
|
|
613
|
+
from_attrs == to_attrs.merge(options: to_options.except(:validate))
|
|
614
|
+
end
|
|
615
|
+
|
|
616
|
+
# Reverse of ignorable_validate_diff?: DB has a NOT VALID constraint (validate: false)
|
|
617
|
+
# and the DSL implies validated (:validate missing or true). Emit VALIDATE CONSTRAINT
|
|
618
|
+
# instead of DROP + re-ADD so the full-table scan runs under SHARE UPDATE EXCLUSIVE
|
|
619
|
+
# (concurrent DML allowed) rather than ACCESS EXCLUSIVE lock.
|
|
620
|
+
def validate_only_diff?(from_attrs, to_attrs)
|
|
621
|
+
from_options = from_attrs[:options] || {}
|
|
622
|
+
to_options = to_attrs[:options] || {}
|
|
623
|
+
return false unless from_options[:validate] == false && to_options[:validate] != false
|
|
624
|
+
|
|
625
|
+
from_attrs.merge(options: from_options.except(:validate)) ==
|
|
626
|
+
to_attrs.merge(options: to_options.except(:validate))
|
|
627
|
+
end
|
|
628
|
+
|
|
590
629
|
def scan_exclusion_constraints_change(from, to, table_delta)
|
|
591
630
|
from = (from || {}).dup
|
|
592
631
|
to = (to || {}).dup
|
data/lib/ridgepole/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ridgepole
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.2.
|
|
4
|
+
version: 3.2.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Genki Sugawara
|
|
@@ -245,14 +245,14 @@ dependencies:
|
|
|
245
245
|
requirements:
|
|
246
246
|
- - '='
|
|
247
247
|
- !ruby/object:Gem::Version
|
|
248
|
-
version: 1.
|
|
248
|
+
version: 1.88.2
|
|
249
249
|
type: :development
|
|
250
250
|
prerelease: false
|
|
251
251
|
version_requirements: !ruby/object:Gem::Requirement
|
|
252
252
|
requirements:
|
|
253
253
|
- - '='
|
|
254
254
|
- !ruby/object:Gem::Version
|
|
255
|
-
version: 1.
|
|
255
|
+
version: 1.88.2
|
|
256
256
|
- !ruby/object:Gem::Dependency
|
|
257
257
|
name: rubocop-rake
|
|
258
258
|
requirement: !ruby/object:Gem::Requirement
|