database_consistency 1.5.2 → 1.6.0
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/column_checkers/enum_value_checker.rb +91 -0
- data/lib/database_consistency/checkers/validators_fraction_checkers/column_presence_checker.rb +29 -48
- data/lib/database_consistency/processors/associations_processor.rb +1 -1
- data/lib/database_consistency/processors/columns_processor.rb +3 -2
- data/lib/database_consistency/processors/enums_processor.rb +1 -1
- data/lib/database_consistency/processors/indexes_processor.rb +1 -1
- data/lib/database_consistency/processors/validators_fractions_processor.rb +1 -1
- data/lib/database_consistency/processors/validators_processor.rb +1 -1
- data/lib/database_consistency/version.rb +1 -1
- data/lib/database_consistency/writers/autofix_writer.rb +1 -0
- data/lib/database_consistency/writers/simple/association_foreign_type_missing_null_constraint.rb +22 -0
- data/lib/database_consistency/writers/simple/enum_values_inconsistent_with_ar_enum.rb +30 -0
- data/lib/database_consistency/writers/simple/enum_values_inconsistent_with_inclusion.rb +30 -0
- data/lib/database_consistency/writers/simple_writer.rb +4 -1
- data/lib/database_consistency.rb +4 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: de35bff4be332ceca4a982d5cde674db49db44a53d3fce22e177cc561cfe6253
|
4
|
+
data.tar.gz: 9f519c9b7aef026da3033790b47690c513871b725b5271e77afa55f29014480f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bdbd9750c5a9f8470a0c73fbae78a50193b423367b934f244fe0132e0dc9af29011cf55b8ef67a6dbe22f7fee3b4bbc012069dac2ae329ccad6f43452f83c80d
|
7
|
+
data.tar.gz: 133abb119e8a80c25b6c4fe0936273dd328adbd6df7bc290ea16f97e695b6468f99a0b9c10bea0420dbc1788de88c73948ea429981b30812002a7b103b2f9ddf
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DatabaseConsistency
|
4
|
+
module Checkers
|
5
|
+
# This class checks missing presence validator
|
6
|
+
class EnumValueChecker < ColumnChecker
|
7
|
+
Report = ReportBuilder.define(
|
8
|
+
DatabaseConsistency::Report,
|
9
|
+
:enum_values,
|
10
|
+
:declared_values
|
11
|
+
)
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def report_template(status, declared_values, error_slug: nil)
|
16
|
+
Report.new(
|
17
|
+
status: status,
|
18
|
+
error_slug: error_slug,
|
19
|
+
error_message: nil,
|
20
|
+
enum_values: enum_column_values,
|
21
|
+
declared_values: declared_values,
|
22
|
+
**report_attributes
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
def preconditions
|
27
|
+
postgresql? && column.type == :enum && (enum || inclusion_validator)
|
28
|
+
end
|
29
|
+
|
30
|
+
def postgresql?
|
31
|
+
Helper.adapter == 'postgresql'
|
32
|
+
end
|
33
|
+
|
34
|
+
def check
|
35
|
+
[
|
36
|
+
(verify_enum if enum),
|
37
|
+
(verify_inclusion_validator if inclusion_validator)
|
38
|
+
].compact
|
39
|
+
end
|
40
|
+
|
41
|
+
def enum_column_values
|
42
|
+
@enum_column_values ||= begin
|
43
|
+
_, values = model.connection.enum_types.find { |(enum, _)| enum == column.sql_type }
|
44
|
+
values.split(',').map(&:strip)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def verify_enum
|
49
|
+
values = enum.values.uniq
|
50
|
+
|
51
|
+
if enum_column_values == values
|
52
|
+
report_template(:ok, values)
|
53
|
+
else
|
54
|
+
report_template(:fail, values, error_slug: :enum_values_inconsistent_with_ar_enum)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def verify_inclusion_validator
|
59
|
+
values = validator_values(inclusion_validator).uniq
|
60
|
+
|
61
|
+
if enum_column_values == values
|
62
|
+
report_template(:ok, values)
|
63
|
+
else
|
64
|
+
report_template(:fail, values, error_slug: :enum_values_inconsistent_with_inclusion)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def validator_values(validator)
|
69
|
+
validator.options[:in] || validator.options[:within]
|
70
|
+
end
|
71
|
+
|
72
|
+
def simple_values_validator?(validator)
|
73
|
+
values = validator_values(validator)
|
74
|
+
|
75
|
+
values.is_a?(Array) && values.all? { |val| val.is_a?(String) }
|
76
|
+
end
|
77
|
+
|
78
|
+
def inclusion_validator
|
79
|
+
@inclusion_validator ||= model.validators.find do |validator|
|
80
|
+
validator.kind == :inclusion &&
|
81
|
+
Helper.check_inclusion?(validator.attributes, column.name) &&
|
82
|
+
simple_values_validator?(validator)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def enum
|
87
|
+
@enum ||= model.defined_enums[column.name]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/lib/database_consistency/checkers/validators_fraction_checkers/column_presence_checker.rb
CHANGED
@@ -18,22 +18,17 @@ module DatabaseConsistency
|
|
18
18
|
validator.kind == :presence
|
19
19
|
end
|
20
20
|
|
21
|
-
# We skip the check when there are no presence validators
|
22
21
|
def preconditions
|
23
|
-
|
22
|
+
(regular_column || association) && validators.any?
|
24
23
|
end
|
25
24
|
|
26
|
-
def
|
27
|
-
model._reflect_on_association(attribute)&.macro == :has_one
|
28
|
-
end
|
29
|
-
|
30
|
-
def report_template(status, error_message: nil, error_slug: nil)
|
25
|
+
def report_template(status, column_name:, error_slug: nil)
|
31
26
|
Report.new(
|
32
27
|
status: status,
|
33
28
|
error_slug: error_slug,
|
34
|
-
error_message:
|
29
|
+
error_message: nil,
|
35
30
|
table_name: model.table_name.to_s,
|
36
|
-
column_name:
|
31
|
+
column_name: column_name,
|
37
32
|
**report_attributes
|
38
33
|
)
|
39
34
|
end
|
@@ -42,56 +37,42 @@ module DatabaseConsistency
|
|
42
37
|
validators.all? { |validator| validator.options.slice(*WEAK_OPTIONS).any? }
|
43
38
|
end
|
44
39
|
|
45
|
-
def check
|
46
|
-
|
47
|
-
has_weak_option = weak_option?
|
40
|
+
def check
|
41
|
+
return analyse(attribute.to_s, type: :null_constraint_missing) if regular_column
|
48
42
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
if regular_column
|
53
|
-
Report.new(
|
54
|
-
status: :fail,
|
55
|
-
error_slug: :null_constraint_missing,
|
56
|
-
error_message: nil,
|
57
|
-
table_name: model.table_name.to_s,
|
58
|
-
column_name: attribute.to_s,
|
59
|
-
**report_attributes
|
60
|
-
)
|
61
|
-
else
|
62
|
-
Report.new(
|
63
|
-
status: :fail,
|
64
|
-
error_slug: :association_missing_null_constraint,
|
65
|
-
error_message: nil,
|
66
|
-
table_name: model.table_name.to_s,
|
67
|
-
column_name: association_reflection.foreign_key.to_s,
|
68
|
-
**report_attributes
|
69
|
-
)
|
43
|
+
reports = [analyse(association.foreign_key.to_s, type: :association_missing_null_constraint)]
|
44
|
+
if association.polymorphic?
|
45
|
+
reports << analyse(association.foreign_type.to_s, type: :association_foreign_type_missing_null_constraint)
|
70
46
|
end
|
71
|
-
end
|
72
47
|
|
73
|
-
|
74
|
-
@column ||= (regular_column || association_reference_column)
|
48
|
+
reports
|
75
49
|
end
|
76
50
|
|
77
|
-
def
|
78
|
-
|
79
|
-
end
|
51
|
+
def analyse(column_name, type:)
|
52
|
+
field = column(column_name)
|
80
53
|
|
81
|
-
|
82
|
-
|
83
|
-
|
54
|
+
can_be_null = field.null
|
55
|
+
has_weak_option = weak_option?
|
56
|
+
|
57
|
+
return report_template(:ok, column_name: column_name) if can_be_null == has_weak_option
|
58
|
+
return report_template(:fail, error_slug: :possible_null, column_name: column_name) unless can_be_null
|
84
59
|
|
85
|
-
|
86
|
-
|
60
|
+
report_template(:fail, error_slug: type, column_name: column_name)
|
61
|
+
end
|
87
62
|
|
88
|
-
|
63
|
+
def regular_column
|
64
|
+
@regular_column ||= column(attribute.to_s)
|
89
65
|
end
|
90
66
|
|
91
|
-
def
|
92
|
-
|
67
|
+
def association
|
68
|
+
@association ||=
|
69
|
+
model
|
93
70
|
.reflect_on_all_associations
|
94
|
-
.find { |reflection| reflection.belongs_to? && reflection.name == attribute }
|
71
|
+
.find { |reflection| reflection.belongs_to? && reflection.name.to_s == attribute.to_s }
|
72
|
+
end
|
73
|
+
|
74
|
+
def column(name)
|
75
|
+
model.columns.find { |field| field.name == name.to_s }
|
95
76
|
end
|
96
77
|
end
|
97
78
|
end
|
@@ -18,7 +18,7 @@ module DatabaseConsistency
|
|
18
18
|
next unless configuration.enabled?(model.name.to_s)
|
19
19
|
|
20
20
|
Helper.first_level_associations(model).flat_map do |association|
|
21
|
-
enabled_checkers.
|
21
|
+
enabled_checkers.flat_map do |checker_class|
|
22
22
|
checker = checker_class.new(model, association)
|
23
23
|
checker.report_if_enabled?(configuration)
|
24
24
|
end
|
@@ -7,7 +7,8 @@ module DatabaseConsistency
|
|
7
7
|
CHECKERS = [
|
8
8
|
Checkers::NullConstraintChecker,
|
9
9
|
Checkers::LengthConstraintChecker,
|
10
|
-
Checkers::PrimaryKeyTypeChecker
|
10
|
+
Checkers::PrimaryKeyTypeChecker,
|
11
|
+
Checkers::EnumValueChecker
|
11
12
|
].freeze
|
12
13
|
|
13
14
|
private
|
@@ -17,7 +18,7 @@ module DatabaseConsistency
|
|
17
18
|
next unless configuration.enabled?(model.name.to_s)
|
18
19
|
|
19
20
|
model.columns.flat_map do |column|
|
20
|
-
enabled_checkers.
|
21
|
+
enabled_checkers.flat_map do |checker_class|
|
21
22
|
checker = checker_class.new(model, column)
|
22
23
|
checker.report_if_enabled?(configuration)
|
23
24
|
end
|
@@ -15,7 +15,7 @@ module DatabaseConsistency
|
|
15
15
|
next unless configuration.enabled?(model.name.to_s)
|
16
16
|
|
17
17
|
model.defined_enums.keys.flat_map do |enum|
|
18
|
-
enabled_checkers.
|
18
|
+
enabled_checkers.flat_map do |checker_class|
|
19
19
|
checker = checker_class.new(model, enum)
|
20
20
|
checker.report_if_enabled?(configuration)
|
21
21
|
end
|
@@ -19,7 +19,7 @@ module DatabaseConsistency
|
|
19
19
|
indexes = model.connection.indexes(model.table_name)
|
20
20
|
|
21
21
|
indexes.flat_map do |index|
|
22
|
-
enabled_checkers.
|
22
|
+
enabled_checkers.flat_map do |checker_class|
|
23
23
|
checker = checker_class.new(model, index)
|
24
24
|
checker.report_if_enabled?(configuration)
|
25
25
|
end
|
@@ -18,7 +18,7 @@ module DatabaseConsistency
|
|
18
18
|
model._validators.flat_map do |attribute, validators|
|
19
19
|
next unless attribute
|
20
20
|
|
21
|
-
enabled_checkers.
|
21
|
+
enabled_checkers.flat_map do |checker_class|
|
22
22
|
checker = checker_class.new(model, attribute, validators)
|
23
23
|
checker.report_if_enabled?(configuration)
|
24
24
|
end
|
@@ -19,7 +19,7 @@ module DatabaseConsistency
|
|
19
19
|
next unless validator.respond_to?(:attributes)
|
20
20
|
|
21
21
|
validator.attributes.flat_map do |attribute|
|
22
|
-
enabled_checkers.
|
22
|
+
enabled_checkers.flat_map do |checker_class|
|
23
23
|
checker = checker_class.new(model, attribute, validator)
|
24
24
|
checker.report_if_enabled?(configuration)
|
25
25
|
end
|
@@ -8,6 +8,7 @@ module DatabaseConsistency
|
|
8
8
|
SLUG_TO_GENERATOR = {
|
9
9
|
association_missing_index: Autofix::AssociationMissingIndex,
|
10
10
|
association_missing_null_constraint: Autofix::NullConstraintMissing,
|
11
|
+
association_foreign_type_missing_null_constraint: Autofix::NullConstraintMissing,
|
11
12
|
has_one_missing_unique_index: Autofix::HasOneMissingUniqueIndex,
|
12
13
|
inconsistent_types: Autofix::InconsistentTypes,
|
13
14
|
missing_foreign_key: Autofix::MissingForeignKey,
|
data/lib/database_consistency/writers/simple/association_foreign_type_missing_null_constraint.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DatabaseConsistency
|
4
|
+
module Writers
|
5
|
+
module Simple
|
6
|
+
class AssociationForeignTypeMissingNullConstraint < Base # :nodoc:
|
7
|
+
private
|
8
|
+
|
9
|
+
def template
|
10
|
+
'association foreign type column should be required in the database'
|
11
|
+
end
|
12
|
+
|
13
|
+
def unique_attributes
|
14
|
+
{
|
15
|
+
table_name: report.table_name,
|
16
|
+
column_name: report.column_name
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DatabaseConsistency
|
4
|
+
module Writers
|
5
|
+
module Simple
|
6
|
+
class EnumValuesInconsistentWithArEnum < Base # :nodoc:
|
7
|
+
private
|
8
|
+
|
9
|
+
def template
|
10
|
+
'enum has [%<enum_values>s] values but ActiveRecord enum has [%<declared_values>s] values'
|
11
|
+
end
|
12
|
+
|
13
|
+
def attributes
|
14
|
+
{
|
15
|
+
enum_values: report.enum_values.join(', '),
|
16
|
+
declared_values: report.declared_values.join(', ')
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def unique_attributes
|
21
|
+
{
|
22
|
+
table_or_model_name: report.table_or_model_name,
|
23
|
+
column_or_attribute_name: report.column_or_attribute_name,
|
24
|
+
ar_enum: true
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DatabaseConsistency
|
4
|
+
module Writers
|
5
|
+
module Simple
|
6
|
+
class EnumValuesInconsistentWithInclusion < Base # :nodoc:
|
7
|
+
private
|
8
|
+
|
9
|
+
def template
|
10
|
+
'enum has [%<enum_values>s] values but ActiveRecord inclusion validation has [%<declared_values>s] values'
|
11
|
+
end
|
12
|
+
|
13
|
+
def attributes
|
14
|
+
{
|
15
|
+
enum_values: report.enum_values.join(', '),
|
16
|
+
declared_values: report.declared_values.join(', ')
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def unique_attributes
|
21
|
+
{
|
22
|
+
table_or_model_name: report.table_or_model_name,
|
23
|
+
column_or_attribute_name: report.column_or_attribute_name,
|
24
|
+
inclusion: true
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -8,6 +8,7 @@ module DatabaseConsistency
|
|
8
8
|
SLUG_TO_WRITER = {
|
9
9
|
association_missing_index: Simple::AssociationMissingIndex,
|
10
10
|
association_missing_null_constraint: Simple::AssociationMissingNullConstraint,
|
11
|
+
association_foreign_type_missing_null_constraint: Simple::AssociationForeignTypeMissingNullConstraint,
|
11
12
|
has_one_missing_unique_index: Simple::HasOneMissingUniqueIndex,
|
12
13
|
inconsistent_types: Simple::InconsistentTypes,
|
13
14
|
length_validator_greater_limit: Simple::LengthValidatorGreaterLimit,
|
@@ -24,7 +25,9 @@ module DatabaseConsistency
|
|
24
25
|
redundant_unique_index: Simple::RedundantUniqueIndex,
|
25
26
|
small_primary_key: Simple::SmallPrimaryKey,
|
26
27
|
inconsistent_enum_type: Simple::InconsistentEnumType,
|
27
|
-
missing_foreign_key_cascade: Simple::MissingForeignKeyCascade
|
28
|
+
missing_foreign_key_cascade: Simple::MissingForeignKeyCascade,
|
29
|
+
enum_values_inconsistent_with_ar_enum: Simple::EnumValuesInconsistentWithArEnum,
|
30
|
+
enum_values_inconsistent_with_inclusion: Simple::EnumValuesInconsistentWithInclusion
|
28
31
|
}.freeze
|
29
32
|
|
30
33
|
def write
|
data/lib/database_consistency.rb
CHANGED
@@ -22,6 +22,7 @@ require 'database_consistency/writers/simple/missing_foreign_key_cascade'
|
|
22
22
|
require 'database_consistency/writers/simple/redundant_unique_index'
|
23
23
|
require 'database_consistency/writers/simple/association_missing_index'
|
24
24
|
require 'database_consistency/writers/simple/association_missing_null_constraint'
|
25
|
+
require 'database_consistency/writers/simple/association_foreign_type_missing_null_constraint'
|
25
26
|
require 'database_consistency/writers/simple/has_one_missing_unique_index'
|
26
27
|
require 'database_consistency/writers/simple/length_validator_lower_limit'
|
27
28
|
require 'database_consistency/writers/simple/length_validator_greater_limit'
|
@@ -34,6 +35,8 @@ require 'database_consistency/writers/simple/null_constraint_missing'
|
|
34
35
|
require 'database_consistency/writers/simple/possible_null'
|
35
36
|
require 'database_consistency/writers/simple/small_primary_key'
|
36
37
|
require 'database_consistency/writers/simple/inconsistent_enum_type'
|
38
|
+
require 'database_consistency/writers/simple/enum_values_inconsistent_with_ar_enum'
|
39
|
+
require 'database_consistency/writers/simple/enum_values_inconsistent_with_inclusion'
|
37
40
|
require 'database_consistency/writers/simple_writer'
|
38
41
|
|
39
42
|
require 'database_consistency/writers/autofix/helpers/migration'
|
@@ -66,6 +69,7 @@ require 'database_consistency/checkers/column_checkers/column_checker'
|
|
66
69
|
require 'database_consistency/checkers/column_checkers/null_constraint_checker'
|
67
70
|
require 'database_consistency/checkers/column_checkers/length_constraint_checker'
|
68
71
|
require 'database_consistency/checkers/column_checkers/primary_key_type_checker'
|
72
|
+
require 'database_consistency/checkers/column_checkers/enum_value_checker'
|
69
73
|
|
70
74
|
require 'database_consistency/checkers/validator_checkers/validator_checker'
|
71
75
|
require 'database_consistency/checkers/validator_checkers/missing_unique_index_checker'
|
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: 1.
|
4
|
+
version: 1.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Evgeniy Demin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-12-03 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
|
- lib/database_consistency/checkers/association_checkers/missing_index_checker.rb
|
154
154
|
- lib/database_consistency/checkers/base_checker.rb
|
155
155
|
- lib/database_consistency/checkers/column_checkers/column_checker.rb
|
156
|
+
- lib/database_consistency/checkers/column_checkers/enum_value_checker.rb
|
156
157
|
- lib/database_consistency/checkers/column_checkers/length_constraint_checker.rb
|
157
158
|
- lib/database_consistency/checkers/column_checkers/null_constraint_checker.rb
|
158
159
|
- lib/database_consistency/checkers/column_checkers/primary_key_type_checker.rb
|
@@ -201,10 +202,13 @@ files:
|
|
201
202
|
- lib/database_consistency/writers/autofix/templates/redundant_index.tt
|
202
203
|
- lib/database_consistency/writers/autofix_writer.rb
|
203
204
|
- lib/database_consistency/writers/base_writer.rb
|
205
|
+
- lib/database_consistency/writers/simple/association_foreign_type_missing_null_constraint.rb
|
204
206
|
- lib/database_consistency/writers/simple/association_missing_index.rb
|
205
207
|
- lib/database_consistency/writers/simple/association_missing_null_constraint.rb
|
206
208
|
- lib/database_consistency/writers/simple/base.rb
|
207
209
|
- lib/database_consistency/writers/simple/default_message.rb
|
210
|
+
- lib/database_consistency/writers/simple/enum_values_inconsistent_with_ar_enum.rb
|
211
|
+
- lib/database_consistency/writers/simple/enum_values_inconsistent_with_inclusion.rb
|
208
212
|
- lib/database_consistency/writers/simple/has_one_missing_unique_index.rb
|
209
213
|
- lib/database_consistency/writers/simple/inconsistent_enum_type.rb
|
210
214
|
- lib/database_consistency/writers/simple/inconsistent_types.rb
|