database_consistency 3.0.16 → 3.1.1
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/lib/database_consistency/checkers/association_checkers/association_checker.rb +1 -1
- data/lib/database_consistency/checkers/association_checkers/foreign_key_cascade_checker.rb +2 -2
- data/lib/database_consistency/checkers/association_checkers/foreign_key_checker.rb +1 -1
- data/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb +3 -2
- data/lib/database_consistency/checkers/association_checkers/missing_index_checker.rb +18 -5
- data/lib/database_consistency/checkers/column_checkers/enum_value_checker.rb +3 -3
- data/lib/database_consistency/checkers/column_checkers/missing_index_find_by_checker.rb +2 -2
- data/lib/database_consistency/checkers/column_checkers/primary_key_type_checker.rb +1 -1
- data/lib/database_consistency/checkers/column_checkers/three_state_boolean_checker.rb +1 -1
- data/lib/database_consistency/checkers/index_checkers/redundant_index_checker.rb +1 -1
- data/lib/database_consistency/checkers/index_checkers/redundant_unique_index_checker.rb +1 -1
- data/lib/database_consistency/checkers/model_checkers/view_primary_key_checker.rb +1 -1
- data/lib/database_consistency/checkers/validator_checkers/missing_unique_index_checker.rb +3 -2
- data/lib/database_consistency/checkers/validators_fraction_checkers/column_presence_checker.rb +3 -1
- data/lib/database_consistency/checkers/validators_fraction_checkers/numericality_constraint_checker.rb +3 -3
- data/lib/database_consistency/helper.rb +6 -2
- data/lib/database_consistency/processors/indexes_processor.rb +1 -1
- data/lib/database_consistency/version.rb +1 -1
- data/lib/database_consistency/writers/autofix/helpers/migration.rb +2 -2
- data/lib/database_consistency/writers/simple/missing_foreign_key_cascade.rb +9 -2
- data/lib/database_consistency/writers/simple_writer.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: dd7ba14920b79a253aa4c1b603f4dde0478780f0a0a0b4342eb6a928b153545e
|
|
4
|
+
data.tar.gz: f655cf5cff2f43b0bef8986fa9617c7891b484f375e34289aaa585b3541f21cb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3f52bb80a9d738cd62d4385027069b46ea1fd6c8f99fc8aeb161d0d5e75dff8e6004fe61abc0f76497d7dee9e7247ba0cd066018d1920ee23063b928363c25a4
|
|
7
|
+
data.tar.gz: 796243796d3e50f1aaa5dd750523be44c1db2c8736cf97720921435026b60283be024253e9972a7f2cedc2ed63ba0bdde3e991dcefb1bb88fe91c9a85a20c282
|
|
@@ -25,7 +25,7 @@ module DatabaseConsistency
|
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
def foreign_key # rubocop:disable Metrics/AbcSize
|
|
28
|
-
model.
|
|
28
|
+
model.connection_pool.with_connection { |conn| conn.foreign_keys(model.table_name) }.find do |foreign_key|
|
|
29
29
|
(Helper.extract_columns(association.foreign_key) - Array.wrap(foreign_key.column)).empty? &&
|
|
30
30
|
foreign_key.to_table == association.klass.table_name
|
|
31
31
|
end
|
|
@@ -67,8 +67,8 @@ module DatabaseConsistency
|
|
|
67
67
|
def foreign_key
|
|
68
68
|
@foreign_key ||=
|
|
69
69
|
association.klass
|
|
70
|
-
.
|
|
71
|
-
.foreign_keys(association.klass.table_name)
|
|
70
|
+
.connection_pool
|
|
71
|
+
.with_connection { |conn| conn.foreign_keys(association.klass.table_name) }
|
|
72
72
|
.find { |fk| (Helper.extract_columns(association.foreign_key) - Array.wrap(fk.column)).empty? }
|
|
73
73
|
end
|
|
74
74
|
|
|
@@ -22,7 +22,7 @@ module DatabaseConsistency
|
|
|
22
22
|
supported? &&
|
|
23
23
|
association.belongs_to? && !association.polymorphic? &&
|
|
24
24
|
same_database? &&
|
|
25
|
-
model.
|
|
25
|
+
model.connection_pool.with_connection { |conn| conn.table_exists?(model.table_name) }
|
|
26
26
|
rescue NameError
|
|
27
27
|
false
|
|
28
28
|
end
|
|
@@ -115,7 +115,7 @@ module DatabaseConsistency
|
|
|
115
115
|
|
|
116
116
|
# @return [DatabaseConsistency::Databases::Factory]
|
|
117
117
|
def database_factory
|
|
118
|
-
@database_factory ||= Databases::Factory.new(association.active_record.
|
|
118
|
+
@database_factory ||= Databases::Factory.new(association.active_record.connection_pool.with_connection(&:adapter_name))
|
|
119
119
|
end
|
|
120
120
|
|
|
121
121
|
# @param [ActiveRecord::Base] model
|
|
@@ -123,7 +123,8 @@ module DatabaseConsistency
|
|
|
123
123
|
#
|
|
124
124
|
# @return [ActiveRecord::ConnectionAdapters::Column]
|
|
125
125
|
def column(model, column_name)
|
|
126
|
-
model.
|
|
126
|
+
model.connection_pool.with_connection { |conn| conn.columns(model.table_name) }
|
|
127
|
+
.find { |column| column.name == column_name } ||
|
|
127
128
|
(raise Errors::MissingField, missing_field_error(model.table_name, column_name))
|
|
128
129
|
end
|
|
129
130
|
|
|
@@ -16,11 +16,13 @@ module DatabaseConsistency
|
|
|
16
16
|
# - association isn't a `HasOne` or `HasMany`
|
|
17
17
|
# - association has `through` option
|
|
18
18
|
# - associated class doesn't exist
|
|
19
|
+
# - associated class's table doesn't exist
|
|
19
20
|
def preconditions
|
|
20
21
|
%i[
|
|
21
22
|
has_one
|
|
22
23
|
has_many
|
|
23
|
-
].include?(association.macro) && association.through_reflection.nil? &&
|
|
24
|
+
].include?(association.macro) && association.through_reflection.nil? &&
|
|
25
|
+
association.klass.table_exists?
|
|
24
26
|
rescue StandardError
|
|
25
27
|
false
|
|
26
28
|
end
|
|
@@ -39,7 +41,7 @@ module DatabaseConsistency
|
|
|
39
41
|
end
|
|
40
42
|
|
|
41
43
|
def check_unique_has_one
|
|
42
|
-
if unique_index
|
|
44
|
+
if unique_index || primary_key_columns.sort == association_keys
|
|
43
45
|
report_template(:ok)
|
|
44
46
|
else
|
|
45
47
|
report_template(:fail, error_slug: :has_one_missing_unique_index)
|
|
@@ -47,7 +49,7 @@ module DatabaseConsistency
|
|
|
47
49
|
end
|
|
48
50
|
|
|
49
51
|
def check_remaining
|
|
50
|
-
if index
|
|
52
|
+
if index || primary_key_columns.first(association_keys.size).sort == association_keys
|
|
51
53
|
report_template(:ok)
|
|
52
54
|
else
|
|
53
55
|
report_template(:fail, error_slug: :association_missing_index)
|
|
@@ -70,17 +72,28 @@ module DatabaseConsistency
|
|
|
70
72
|
end
|
|
71
73
|
|
|
72
74
|
def unique_index
|
|
73
|
-
@unique_index ||= association.klass.
|
|
75
|
+
@unique_index ||= association.klass.connection_pool
|
|
76
|
+
.with_connection { |conn| conn.indexes(association.klass.table_name) }
|
|
77
|
+
.find do |index|
|
|
74
78
|
index_keys(index) == association_keys && index.unique
|
|
75
79
|
end
|
|
76
80
|
end
|
|
77
81
|
|
|
78
82
|
def index
|
|
79
|
-
@index ||= association.klass.
|
|
83
|
+
@index ||= association.klass.connection_pool
|
|
84
|
+
.with_connection { |conn| conn.indexes(association.klass.table_name) }
|
|
85
|
+
.find do |index|
|
|
80
86
|
index_keys(index, limit: association_keys.size) == association_keys
|
|
81
87
|
end
|
|
82
88
|
end
|
|
83
89
|
|
|
90
|
+
# The primary key is an implicit unique index, so it covers the association as well.
|
|
91
|
+
def primary_key_columns
|
|
92
|
+
@primary_key_columns ||= Array(
|
|
93
|
+
association.klass.connection_pool.with_connection { |conn| conn.primary_key(association.klass.table_name) }
|
|
94
|
+
).map(&:to_s)
|
|
95
|
+
end
|
|
96
|
+
|
|
84
97
|
def association_keys
|
|
85
98
|
@association_keys ||= [association.foreign_key, association.type].compact.map(&:to_s).sort
|
|
86
99
|
end
|
|
@@ -36,8 +36,8 @@ module DatabaseConsistency
|
|
|
36
36
|
|
|
37
37
|
def enum_column_values # rubocop:disable Metrics/AbcSize
|
|
38
38
|
@enum_column_values ||=
|
|
39
|
-
if model.
|
|
40
|
-
_, values = model.
|
|
39
|
+
if model.connection_pool.with_connection(&:enum_types).is_a?(Array)
|
|
40
|
+
_, values = model.connection_pool.with_connection(&:enum_types).find { |(enum, _)| enum == column.sql_type }
|
|
41
41
|
case values
|
|
42
42
|
when Array then values
|
|
43
43
|
else
|
|
@@ -45,7 +45,7 @@ module DatabaseConsistency
|
|
|
45
45
|
end
|
|
46
46
|
else
|
|
47
47
|
# active_record-postgres_enum gem
|
|
48
|
-
model.
|
|
48
|
+
model.connection_pool.with_connection(&:enum_types)[column.sql_type.to_sym]
|
|
49
49
|
end
|
|
50
50
|
end
|
|
51
51
|
|
|
@@ -65,13 +65,13 @@ module DatabaseConsistency
|
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
def indexed?
|
|
68
|
-
model.
|
|
68
|
+
model.connection_pool.with_connection { |conn| conn.indexes(model.table_name) }.any? do |index|
|
|
69
69
|
Helper.extract_index_columns(index.columns).first == column.name.to_s
|
|
70
70
|
end
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
def primary_key_column?
|
|
74
|
-
primary_key = model.
|
|
74
|
+
primary_key = model.connection_pool.with_connection { |conn| conn.primary_key(model.table_name) }
|
|
75
75
|
|
|
76
76
|
column.name.to_s == Array(primary_key).first.to_s
|
|
77
77
|
end
|
|
@@ -14,7 +14,7 @@ module DatabaseConsistency
|
|
|
14
14
|
|
|
15
15
|
# column should be a boolean and table shouldn't be a view
|
|
16
16
|
def preconditions
|
|
17
|
-
column.type == :boolean && model.
|
|
17
|
+
column.type == :boolean && model.connection_pool.with_connection { |conn| conn.table_exists?(model.table_name) }
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def check
|
|
@@ -47,7 +47,7 @@ module DatabaseConsistency
|
|
|
47
47
|
|
|
48
48
|
def covered_by_index
|
|
49
49
|
@covered_by_index ||=
|
|
50
|
-
model.
|
|
50
|
+
model.connection_pool.with_connection { |conn| conn.indexes(model.table_name) }.find do |another_index|
|
|
51
51
|
next if index.name == another_index.name || !Helper.btree_index?(another_index)
|
|
52
52
|
|
|
53
53
|
clause_equals?(another_index) && include_index_as_prefix?(another_index)
|
|
@@ -47,7 +47,7 @@ module DatabaseConsistency
|
|
|
47
47
|
|
|
48
48
|
def covered_by_index
|
|
49
49
|
@covered_by_index ||=
|
|
50
|
-
model.
|
|
50
|
+
model.connection_pool.with_connection { |conn| conn.indexes(model.table_name) }.find do |another_index|
|
|
51
51
|
next if index.name == another_index.name
|
|
52
52
|
|
|
53
53
|
another_index.unique && clause_equals?(another_index) && contain_index?(another_index)
|
|
@@ -9,7 +9,7 @@ module DatabaseConsistency
|
|
|
9
9
|
def preconditions
|
|
10
10
|
ActiveRecord::VERSION::MAJOR >= 5 &&
|
|
11
11
|
!model.abstract_class? &&
|
|
12
|
-
model.
|
|
12
|
+
model.connection_pool.with_connection { |conn| conn.view_exists?(model.table_name) }
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
# Table of possible statuses
|
|
@@ -47,7 +47,8 @@ module DatabaseConsistency
|
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
def unique_index
|
|
50
|
-
@unique_index ||= model.
|
|
50
|
+
@unique_index ||= model.connection_pool.with_connection { |conn| conn.indexes(model.table_name) }
|
|
51
|
+
.find { |index| index_matches?(index) }
|
|
51
52
|
end
|
|
52
53
|
|
|
53
54
|
def index_matches?(index)
|
|
@@ -57,7 +58,7 @@ module DatabaseConsistency
|
|
|
57
58
|
end
|
|
58
59
|
|
|
59
60
|
def primary_key_covers_validation?
|
|
60
|
-
primary_key = model.
|
|
61
|
+
primary_key = model.connection_pool.with_connection { |conn| conn.primary_key(model.table_name) }
|
|
61
62
|
|
|
62
63
|
return false if primary_key.blank?
|
|
63
64
|
|
data/lib/database_consistency/checkers/validators_fraction_checkers/column_presence_checker.rb
CHANGED
|
@@ -19,7 +19,9 @@ module DatabaseConsistency
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def preconditions
|
|
22
|
-
(regular_column || association) &&
|
|
22
|
+
(regular_column || association) &&
|
|
23
|
+
model.connection_pool.with_connection { |conn| conn.table_exists?(model.table_name) } &&
|
|
24
|
+
validators.any?
|
|
23
25
|
end
|
|
24
26
|
|
|
25
27
|
def report_template(status, column_name:, error_slug: nil)
|
|
@@ -33,8 +33,8 @@ module DatabaseConsistency
|
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
def preconditions
|
|
36
|
-
model.
|
|
37
|
-
model.
|
|
36
|
+
model.connection_pool.with_connection { |conn| conn.respond_to?(:check_constraints) } &&
|
|
37
|
+
model.connection_pool.with_connection { |conn| conn.table_exists?(model.table_name) } &&
|
|
38
38
|
column &&
|
|
39
39
|
validators.any?
|
|
40
40
|
end
|
|
@@ -54,7 +54,7 @@ module DatabaseConsistency
|
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
def check_constraints
|
|
57
|
-
@check_constraints ||= model.
|
|
57
|
+
@check_constraints ||= model.connection_pool.with_connection { |conn| conn.check_constraints(model.table_name) }
|
|
58
58
|
rescue StandardError
|
|
59
59
|
[]
|
|
60
60
|
end
|
|
@@ -47,7 +47,7 @@ module DatabaseConsistency
|
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
def connected?(klass)
|
|
50
|
-
klass.
|
|
50
|
+
klass.connection_pool.with_connection { true }
|
|
51
51
|
rescue ActiveRecord::ConnectionNotEstablished
|
|
52
52
|
puts "#{klass} does not have an active connection, skipping"
|
|
53
53
|
false
|
|
@@ -66,7 +66,11 @@ module DatabaseConsistency
|
|
|
66
66
|
def project_klass?(klass)
|
|
67
67
|
return true unless Module.respond_to?(:const_source_location) && defined?(Bundler)
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
source_path = Module.const_source_location(klass.to_s).first.to_s
|
|
70
|
+
bundle_path = Bundler.bundle_path
|
|
71
|
+
bundle_paths = [bundle_path]
|
|
72
|
+
bundle_paths << bundle_path.realpath if bundle_path.exist?
|
|
73
|
+
bundle_paths.none? { |path| source_path.include?(path.to_s) }
|
|
70
74
|
rescue NameError
|
|
71
75
|
false
|
|
72
76
|
end
|
|
@@ -9,7 +9,7 @@ module DatabaseConsistency
|
|
|
9
9
|
def check # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
10
10
|
Helper.parent_models(configuration).flat_map do |model|
|
|
11
11
|
DebugContext.with(model: model.name) do
|
|
12
|
-
indexes = model.
|
|
12
|
+
indexes = model.connection_pool.with_connection { |conn| conn.indexes(model.table_name) }
|
|
13
13
|
|
|
14
14
|
indexes.flat_map do |index|
|
|
15
15
|
DebugContext.with(index: index.name) do
|
|
@@ -40,10 +40,10 @@ module DatabaseConsistency
|
|
|
40
40
|
return ActiveRecord::MigrationContext.new(ActiveRecord::Migrator.migrations_paths)
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
-
if ActiveRecord::Base.
|
|
43
|
+
if ActiveRecord::Base.connection_pool.with_connection { |conn| conn.respond_to?(:schema_migration) }
|
|
44
44
|
return ActiveRecord::MigrationContext.new(
|
|
45
45
|
ActiveRecord::Migrator.migrations_paths,
|
|
46
|
-
ActiveRecord::Base.
|
|
46
|
+
ActiveRecord::Base.connection_pool.with_connection(&:schema_migration)
|
|
47
47
|
)
|
|
48
48
|
end
|
|
49
49
|
|
|
@@ -7,15 +7,22 @@ module DatabaseConsistency
|
|
|
7
7
|
private
|
|
8
8
|
|
|
9
9
|
def template
|
|
10
|
-
'should have a foreign key
|
|
10
|
+
'should have a foreign key %<cascade_option>s in the database'
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def attributes
|
|
14
14
|
{
|
|
15
|
-
cascade_option:
|
|
15
|
+
cascade_option: cascade_option_text
|
|
16
16
|
}
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
+
# nil stands for a foreign key without an on_delete option
|
|
20
|
+
def cascade_option_text
|
|
21
|
+
options = report.cascade_option.compact.map { |option| "with on_delete: :#{option}" }
|
|
22
|
+
options << 'without on_delete' if report.cascade_option.include?(nil)
|
|
23
|
+
options.join(' or ')
|
|
24
|
+
end
|
|
25
|
+
|
|
19
26
|
def unique_attributes
|
|
20
27
|
{
|
|
21
28
|
foreign_table: report.foreign_table,
|
|
@@ -31,7 +31,7 @@ module DatabaseConsistency
|
|
|
31
31
|
klass =
|
|
32
32
|
if report.error_slug
|
|
33
33
|
begin
|
|
34
|
-
"DatabaseConsistency::Writers::Simple::#{report.error_slug.to_s.
|
|
34
|
+
"DatabaseConsistency::Writers::Simple::#{report.error_slug.to_s.camelize}".constantize
|
|
35
35
|
rescue NameError
|
|
36
36
|
Simple::DefaultMessage
|
|
37
37
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: database_consistency
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Evgeniy Demin
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activerecord
|