database_consistency 1.3.5 → 1.3.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/lib/database_consistency/checkers/association_checkers/foreign_key_checker.rb +22 -22
  3. data/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb +10 -16
  4. data/lib/database_consistency/checkers/association_checkers/missing_index_checker.rb +5 -9
  5. data/lib/database_consistency/checkers/column_checkers/null_constraint_checker.rb +16 -16
  6. data/lib/database_consistency/checkers/column_checkers/primary_key_type_checker.rb +20 -20
  7. data/lib/database_consistency/checkers/index_checkers/redundant_index_checker.rb +18 -18
  8. data/lib/database_consistency/checkers/index_checkers/redundant_unique_index_checker.rb +18 -18
  9. data/lib/database_consistency/checkers/validator_checkers/missing_unique_index_checker.rb +18 -18
  10. data/lib/database_consistency/checkers/validators_fraction_checkers/column_presence_checker.rb +16 -9
  11. data/lib/database_consistency/report.rb +9 -12
  12. data/lib/database_consistency/report_builder.rb +24 -0
  13. data/lib/database_consistency/version.rb +1 -1
  14. data/lib/database_consistency/writers/autofix_writer.rb +2 -2
  15. data/lib/database_consistency/writers/simple/association_missing_index.rb +22 -0
  16. data/lib/database_consistency/writers/simple/association_missing_null_constraint.rb +22 -0
  17. data/lib/database_consistency/writers/simple/base.rb +9 -1
  18. data/lib/database_consistency/writers/simple/{error_message.rb → default_message.rb} +5 -1
  19. data/lib/database_consistency/writers/simple/has_one_missing_unique_index.rb +23 -0
  20. data/lib/database_consistency/writers/simple/inconsistent_types.rb +10 -1
  21. data/lib/database_consistency/writers/simple/length_validator_greater_limit.rb +22 -0
  22. data/lib/database_consistency/writers/simple/length_validator_lower_limit.rb +22 -0
  23. data/lib/database_consistency/writers/simple/length_validator_missing.rb +22 -0
  24. data/lib/database_consistency/writers/simple/missing_foreign_key.rb +24 -0
  25. data/lib/database_consistency/writers/simple/missing_unique_index.rb +23 -0
  26. data/lib/database_consistency/writers/simple/missing_uniqueness_validation.rb +22 -0
  27. data/lib/database_consistency/writers/simple/null_constraint_association_misses_validator.rb +7 -0
  28. data/lib/database_consistency/writers/simple/null_constraint_misses_validator.rb +22 -0
  29. data/lib/database_consistency/writers/simple/null_constraint_missing.rb +22 -0
  30. data/lib/database_consistency/writers/simple/possible_null.rb +22 -0
  31. data/lib/database_consistency/writers/simple/redundant_index.rb +6 -0
  32. data/lib/database_consistency/writers/simple/redundant_unique_index.rb +6 -0
  33. data/lib/database_consistency/writers/simple/small_primary_key.rb +22 -0
  34. data/lib/database_consistency/writers/simple_writer.rb +28 -22
  35. data/lib/database_consistency.rb +15 -1
  36. metadata +17 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8f935ca51faca06dad689d217e897a035253f4ce9884f1826befdf1bcbbee3b5
4
- data.tar.gz: 38bde32ffee8b05b04bc8a1af261764f967b64f322352ef8d79729f1de485e13
3
+ metadata.gz: 3977b5e14b960051dad79361a32e435e511707612a269512fd42dcbac389216f
4
+ data.tar.gz: 95aba2661c7724aca4cee0e386b8f5e12e59f62b6444f35c66ebcabba2a6f9be
5
5
  SHA512:
6
- metadata.gz: 2352fa358c91e6dbec9a22c9abac34fb27b45e662c1402e88cfe94864b7bfa4966628f246a6f6f5d6c6af323e1320a3fe03c74df644f86ec6d14e4bde7c81962
7
- data.tar.gz: ad812a3ce4c8d4d0a7d24d9031815a26ae2c32bfca6d0721430f3c31f01d8c5910f4af091fb7d088e4860d65d887ba0a27531bdd0d8aefc50b589a944ef29290
6
+ metadata.gz: d71ae7f118719222bfcdb11329d8f0be6ca5c62d8f54ca145cd08f26d982e7e7b0a1b848397b19aa4e4a4c35e88602be24fd384896ed58cf6221f83e7d87280c
7
+ data.tar.gz: 0b1efa4b1c268d3959eae583bd4b2e3dc6da2585ac64a6ebf4b4a83ad73710f1a0c704ff1fdee4e13c01b5170c41bf593f31bd77a7f6bea9b6d417fe892208d6
@@ -4,17 +4,13 @@ module DatabaseConsistency
4
4
  module Checkers
5
5
  # This class checks if non polymorphic +belongs_to+ association has foreign key constraint
6
6
  class ForeignKeyChecker < AssociationChecker
7
- class Report < DatabaseConsistency::Report # :nodoc:
8
- attr_reader :primary_table, :primary_key, :foreign_table, :foreign_key
9
-
10
- def initialize(primary_table:, foreign_table:, primary_key:, foreign_key:, **args)
11
- super(**args)
12
- @primary_table = primary_table
13
- @primary_key = primary_key
14
- @foreign_table = foreign_table
15
- @foreign_key = foreign_key
16
- end
17
- end
7
+ Report = ReportBuilder.define(
8
+ DatabaseConsistency::Report,
9
+ :primary_table,
10
+ :primary_key,
11
+ :foreign_table,
12
+ :foreign_key
13
+ )
18
14
 
19
15
  private
20
16
 
@@ -43,22 +39,26 @@ module DatabaseConsistency
43
39
  # | ----------- | ------ |
44
40
  # | persisted | ok |
45
41
  # | missing | fail |
46
- def check # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
42
+ def check
47
43
  if model.connection.foreign_keys(model.table_name).find { |fk| fk.column == association.foreign_key.to_s }
48
44
  report_template(:ok)
49
45
  else
50
- Report.new(
51
- status: :fail,
52
- error_message: nil,
53
- error_slug: :missing_foreign_key,
54
- primary_table: association.table_name.to_s,
55
- primary_key: association.association_primary_key.to_s,
56
- foreign_table: association.active_record.table_name.to_s,
57
- foreign_key: association.foreign_key.to_s,
58
- **report_attributes
59
- )
46
+ report_template(:fail, error_slug: :missing_foreign_key)
60
47
  end
61
48
  end
49
+
50
+ def report_template(status, error_slug: nil)
51
+ Report.new(
52
+ status: status,
53
+ error_message: nil,
54
+ error_slug: error_slug,
55
+ primary_table: association.table_name.to_s,
56
+ primary_key: association.association_primary_key.to_s,
57
+ foreign_table: association.active_record.table_name.to_s,
58
+ foreign_key: association.foreign_key.to_s,
59
+ **report_attributes
60
+ )
61
+ end
62
62
  end
63
63
  end
64
64
  end
@@ -4,21 +4,15 @@ module DatabaseConsistency
4
4
  module Checkers
5
5
  # This class checks if association's foreign key type covers associated model's primary key (same or bigger)
6
6
  class ForeignKeyTypeChecker < AssociationChecker
7
- ALLOWED_TYPES =
8
-
9
- class Report < DatabaseConsistency::Report # :nodoc:
10
- attr_reader :pk_name, :pk_type, :fk_name, :fk_type, :table_to_change, :type_to_set
11
-
12
- def initialize(fk_name: nil, fk_type: nil, pk_name: nil, pk_type: nil, table_to_change: nil, type_to_set: nil, **args) # rubocop:disable Metrics/ParameterLists, Layout/LineLength
13
- super(**args)
14
- @table_to_change = table_to_change
15
- @type_to_set = type_to_set
16
- @fk_name = fk_name
17
- @fk_type = fk_type
18
- @pk_name = pk_name
19
- @pk_type = pk_type
20
- end
21
- end
7
+ Report = ReportBuilder.define(
8
+ DatabaseConsistency::Report,
9
+ :pk_name,
10
+ :pk_type,
11
+ :fk_name,
12
+ :fk_type,
13
+ :table_to_change,
14
+ :type_to_set
15
+ )
22
16
 
23
17
  private
24
18
 
@@ -50,7 +44,7 @@ module DatabaseConsistency
50
44
  report_template(:fail, error_slug: :inconsistent_types)
51
45
  end
52
46
  rescue Errors::MissingField => e
53
- Report.new(
47
+ DatabaseConsistency::Report.new(
54
48
  status: :fail,
55
49
  error_slug: nil,
56
50
  error_message: e.message,
@@ -4,15 +4,11 @@ module DatabaseConsistency
4
4
  module Checkers
5
5
  # This class checks if association's foreign key has index in the database
6
6
  class MissingIndexChecker < AssociationChecker
7
- class Report < DatabaseConsistency::Report # :nodoc:
8
- attr_reader :table_name, :columns
9
-
10
- def initialize(table_name:, columns:, **args)
11
- super(**args)
12
- @table_name = table_name
13
- @columns = columns
14
- end
15
- end
7
+ Report = ReportBuilder.define(
8
+ DatabaseConsistency::Report,
9
+ :table_name,
10
+ :columns
11
+ )
16
12
 
17
13
  private
18
14
 
@@ -4,14 +4,10 @@ module DatabaseConsistency
4
4
  module Checkers
5
5
  # This class checks missing presence validator
6
6
  class NullConstraintChecker < ColumnChecker
7
- class Report < DatabaseConsistency::Report # :nodoc:
8
- attr_reader :association_name
9
-
10
- def initialize(association_name:, **args)
11
- super(**args)
12
- @association_name = association_name
13
- end
14
- end
7
+ Report = ReportBuilder.define(
8
+ DatabaseConsistency::Report,
9
+ :association_name
10
+ )
15
11
 
16
12
  private
17
13
 
@@ -33,22 +29,26 @@ module DatabaseConsistency
33
29
  #
34
30
  # We consider PresenceValidation, InclusionValidation, ExclusionValidation, NumericalityValidator with nil,
35
31
  # or required BelongsTo association using this column
36
- def check # rubocop:disable Metrics/MethodLength
32
+ def check
37
33
  if valid?
38
34
  report_template(:ok)
39
35
  elsif belongs_to_association
40
- Report.new(
41
- status: :fail,
42
- error_slug: :null_constraint_association_misses_validator,
43
- error_message: nil,
44
- association_name: belongs_to_association.name.to_s,
45
- **report_attributes
46
- )
36
+ report_template(:fail, error_slug: :null_constraint_association_misses_validator)
47
37
  else
48
38
  report_template(:fail, error_slug: :null_constraint_misses_validator)
49
39
  end
50
40
  end
51
41
 
42
+ def report_template(status, error_slug: nil)
43
+ Report.new(
44
+ status: status,
45
+ error_slug: error_slug,
46
+ error_message: nil,
47
+ association_name: belongs_to_association&.name&.to_s,
48
+ **report_attributes
49
+ )
50
+ end
51
+
52
52
  def valid?
53
53
  validator?(:presence, column.name) ||
54
54
  validator?(:inclusion, column.name) ||
@@ -4,16 +4,12 @@ module DatabaseConsistency
4
4
  module Checkers
5
5
  # This class checks missing presence validator
6
6
  class PrimaryKeyTypeChecker < ColumnChecker
7
- class Report < DatabaseConsistency::Report # :nodoc:
8
- attr_reader :fk_name, :table_to_change, :type_to_set
9
-
10
- def initialize(fk_name: nil, table_to_change: nil, type_to_set: nil, **args)
11
- super(**args)
12
- @table_to_change = table_to_change
13
- @type_to_set = type_to_set
14
- @fk_name = fk_name
15
- end
16
- end
7
+ Report = ReportBuilder.define(
8
+ DatabaseConsistency::Report,
9
+ :fk_name,
10
+ :table_to_change,
11
+ :type_to_set
12
+ )
17
13
 
18
14
  private
19
15
 
@@ -36,22 +32,26 @@ module DatabaseConsistency
36
32
  # | --------------------- | ------ |
37
33
  # | yes | ok |
38
34
  # | no | fail |
39
- def check # rubocop:disable Metrics/MethodLength
35
+ def check
40
36
  if valid?
41
37
  report_template(:ok)
42
38
  else
43
- Report.new(
44
- status: :fail,
45
- error_slug: :small_primary_key,
46
- error_message: nil,
47
- table_to_change: model.table_name,
48
- fk_name: column.name,
49
- type_to_set: type_to_set,
50
- **report_attributes
51
- )
39
+ report_template(:fail, error_slug: :small_primary_key)
52
40
  end
53
41
  end
54
42
 
43
+ def report_template(status, error_slug: nil)
44
+ Report.new(
45
+ status: status,
46
+ error_slug: error_slug,
47
+ error_message: nil,
48
+ table_to_change: model.table_name,
49
+ fk_name: column.name,
50
+ type_to_set: type_to_set,
51
+ **report_attributes
52
+ )
53
+ end
54
+
55
55
  def type_to_set
56
56
  VALID_TYPES_MAP[column.sql_type.to_s] || 'bigserial'
57
57
  end
@@ -4,15 +4,11 @@ module DatabaseConsistency
4
4
  module Checkers
5
5
  # This class checks redundant database indexes
6
6
  class RedundantIndexChecker < IndexChecker
7
- class Report < DatabaseConsistency::Report # :nodoc:
8
- attr_reader :covered_index_name, :index_name
9
-
10
- def initialize(covered_index_name:, index_name:, **args)
11
- super(**args)
12
- @covered_index_name = covered_index_name
13
- @index_name = index_name
14
- end
15
- end
7
+ Report = ReportBuilder.define(
8
+ DatabaseConsistency::Report,
9
+ :covered_index_name,
10
+ :index_name
11
+ )
16
12
 
17
13
  private
18
14
 
@@ -28,21 +24,25 @@ module DatabaseConsistency
28
24
  # | provided | ok |
29
25
  # | redundant | fail |
30
26
  #
31
- def check # rubocop:disable Metrics/MethodLength
27
+ def check
32
28
  if covered_by_index
33
- Report.new(
34
- status: :fail,
35
- error_slug: :redundant_index,
36
- error_message: nil,
37
- covered_index_name: covered_by_index.name,
38
- index_name: index.name,
39
- **report_attributes
40
- )
29
+ report_template(:fail, error_slug: :redundant_index)
41
30
  else
42
31
  report_template(:ok)
43
32
  end
44
33
  end
45
34
 
35
+ def report_template(status, error_slug: nil)
36
+ Report.new(
37
+ status: status,
38
+ error_slug: error_slug,
39
+ error_message: nil,
40
+ covered_index_name: covered_by_index&.name,
41
+ index_name: index.name,
42
+ **report_attributes
43
+ )
44
+ end
45
+
46
46
  def covered_by_index
47
47
  @covered_by_index ||=
48
48
  model.connection.indexes(model.table_name).find do |another_index|
@@ -4,15 +4,11 @@ module DatabaseConsistency
4
4
  module Checkers
5
5
  # This class checks redundant database indexes
6
6
  class RedundantUniqueIndexChecker < IndexChecker
7
- class Report < DatabaseConsistency::Report # :nodoc:
8
- attr_reader :index_name, :covered_index_name
9
-
10
- def initialize(covered_index_name:, index_name:, **args)
11
- super(**args)
12
- @index_name = index_name
13
- @covered_index_name = covered_index_name
14
- end
15
- end
7
+ Report = ReportBuilder.define(
8
+ DatabaseConsistency::Report,
9
+ :index_name,
10
+ :covered_index_name
11
+ )
16
12
 
17
13
  private
18
14
 
@@ -28,21 +24,25 @@ module DatabaseConsistency
28
24
  # | provided | ok |
29
25
  # | redundant | fail |
30
26
  #
31
- def check # rubocop:disable Metrics/MethodLength
27
+ def check
32
28
  if covered_by_index
33
- Report.new(
34
- status: :fail,
35
- error_slug: :redundant_unique_index,
36
- error_message: nil,
37
- index_name: index.name,
38
- covered_index_name: covered_by_index.name,
39
- **report_attributes
40
- )
29
+ report_template(:fail, error_slug: :redundant_unique_index)
41
30
  else
42
31
  report_template(:ok)
43
32
  end
44
33
  end
45
34
 
35
+ def report_template(status, error_slug: nil)
36
+ Report.new(
37
+ status: status,
38
+ error_slug: error_slug,
39
+ error_message: nil,
40
+ index_name: index.name,
41
+ covered_index_name: covered_by_index&.name,
42
+ **report_attributes
43
+ )
44
+ end
45
+
46
46
  def covered_by_index
47
47
  @covered_by_index ||=
48
48
  model.connection.indexes(model.table_name).find do |another_index|
@@ -4,15 +4,11 @@ module DatabaseConsistency
4
4
  module Checkers
5
5
  # This class checks if uniqueness validator has unique index in the database
6
6
  class MissingUniqueIndexChecker < ValidatorChecker
7
- class Report < DatabaseConsistency::Report # :nodoc:
8
- attr_reader :table_name, :columns
9
-
10
- def initialize(table_name:, columns:, **args)
11
- super(**args)
12
- @table_name = table_name
13
- @columns = columns
14
- end
15
- end
7
+ Report = ReportBuilder.define(
8
+ DatabaseConsistency::Report,
9
+ :table_name,
10
+ :columns
11
+ )
16
12
 
17
13
  def column_or_attribute_name
18
14
  @column_or_attribute_name ||= Helper.uniqueness_validator_columns(attribute, validator, model).join('+')
@@ -31,21 +27,25 @@ module DatabaseConsistency
31
27
  # | ------------ | ------ |
32
28
  # | persisted | ok |
33
29
  # | missing | fail |
34
- def check # rubocop:disable Metrics/MethodLength
30
+ def check
35
31
  if unique_index
36
32
  report_template(:ok)
37
33
  else
38
- Report.new(
39
- status: :fail,
40
- error_slug: :missing_unique_index,
41
- error_message: nil,
42
- table_name: model.table_name,
43
- columns: sorted_uniqueness_validator_columns,
44
- **report_attributes
45
- )
34
+ report_template(:fail, error_slug: :missing_unique_index)
46
35
  end
47
36
  end
48
37
 
38
+ def report_template(status, error_slug: nil)
39
+ Report.new(
40
+ status: status,
41
+ error_slug: error_slug,
42
+ error_message: nil,
43
+ table_name: model.table_name,
44
+ columns: sorted_uniqueness_validator_columns,
45
+ **report_attributes
46
+ )
47
+ end
48
+
49
49
  def unique_index
50
50
  @unique_index ||= model.connection.indexes(model.table_name).find do |index|
51
51
  index.unique && Helper.extract_index_columns(index.columns).sort == sorted_uniqueness_validator_columns
@@ -6,15 +6,11 @@ module DatabaseConsistency
6
6
  class ColumnPresenceChecker < ValidatorsFractionChecker
7
7
  WEAK_OPTIONS = %i[allow_nil allow_blank if unless on].freeze
8
8
 
9
- class Report < DatabaseConsistency::Report # :nodoc:
10
- attr_reader :table_name, :column_name
11
-
12
- def initialize(table_name:, column_name:, **args)
13
- super(**args)
14
- @table_name = table_name
15
- @column_name = column_name
16
- end
17
- end
9
+ Report = ReportBuilder.define(
10
+ DatabaseConsistency::Report,
11
+ :table_name,
12
+ :column_name
13
+ )
18
14
 
19
15
  private
20
16
 
@@ -44,6 +40,17 @@ module DatabaseConsistency
44
40
  report_template(:fail, error_message: e.message)
45
41
  end
46
42
 
43
+ def report_template(status, error_message: nil, error_slug: nil)
44
+ Report.new(
45
+ status: status,
46
+ error_slug: error_slug,
47
+ error_message: error_message,
48
+ table_name: model.table_name.to_s,
49
+ column_name: attribute.to_s,
50
+ **report_attributes
51
+ )
52
+ end
53
+
47
54
  def weak_option?
48
55
  validators.all? { |validator| validator.options.slice(*WEAK_OPTIONS).any? }
49
56
  end
@@ -1,16 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DatabaseConsistency
4
- class Report # :nodoc:
5
- attr_reader :checker_name, :table_or_model_name, :column_or_attribute_name, :status, :error_slug, :error_message
6
-
7
- def initialize(checker_name:, table_or_model_name:, column_or_attribute_name:, status:, error_slug:, error_message:) # rubocop:disable Metrics/ParameterLists
8
- @checker_name = checker_name
9
- @table_or_model_name = table_or_model_name
10
- @column_or_attribute_name = column_or_attribute_name
11
- @status = status
12
- @error_slug = error_slug
13
- @error_message = error_message
14
- end
15
- end
4
+ Report = ReportBuilder.define(
5
+ Class.new,
6
+ :checker_name,
7
+ :table_or_model_name,
8
+ :column_or_attribute_name,
9
+ :status,
10
+ :error_slug,
11
+ :error_message
12
+ )
16
13
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DatabaseConsistency
4
+ class ReportBuilder # :nodoc:
5
+ def self.define(klass, *attrs) # rubocop:disable Metrics/MethodLength
6
+ Class.new(klass) do
7
+ attr_reader(*attrs)
8
+
9
+ class_eval(<<~DEF, __FILE__, __LINE__ + 1)
10
+ def initialize(#{attrs.map { |attr| "#{attr}:" }.join(', ')}, **opts)
11
+ super(**opts) if opts.any?
12
+ #{attrs.map { |attr| "@#{attr} = #{attr}" }.join("\n")}
13
+ end
14
+
15
+ def to_h
16
+ h = defined?(super) ? super : {}
17
+ #{attrs.map { |attr| "h[#{attr}] = #{attr}" }.join("\n")}
18
+ h
19
+ end
20
+ DEF
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DatabaseConsistency
4
- VERSION = '1.3.5'
4
+ VERSION = '1.3.7'
5
5
  end
@@ -41,8 +41,8 @@ module DatabaseConsistency
41
41
  klass&.new(report)
42
42
  end
43
43
 
44
- def unique_key(report)
45
- [report.class, report.attributes]
44
+ def unique_key(generator)
45
+ [generator.class, generator.attributes]
46
46
  end
47
47
  end
48
48
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DatabaseConsistency
4
+ module Writers
5
+ module Simple
6
+ class AssociationMissingIndex < Base # :nodoc:
7
+ private
8
+
9
+ def template
10
+ 'associated model should have proper index in the database'
11
+ end
12
+
13
+ def unique_attributes
14
+ {
15
+ table_name: report.table_name,
16
+ columns: report.columns
17
+ }
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DatabaseConsistency
4
+ module Writers
5
+ module Simple
6
+ class AssociationMissingNullConstraint < Base # :nodoc:
7
+ private
8
+
9
+ def template
10
+ 'association foreign key 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
@@ -33,11 +33,19 @@ module DatabaseConsistency
33
33
  end
34
34
 
35
35
  def msg
36
- "#{report.checker_name} #{status_text} #{key_text} #{message_text}"
36
+ "#{report.checker_name} #{status_text} #{key_text} #{message_text}".strip
37
+ end
38
+
39
+ def unique_key
40
+ { class: self.class }.merge(unique_attributes)
37
41
  end
38
42
 
39
43
  private
40
44
 
45
+ def unique_attributes
46
+ raise StandardError, 'Missing the implementation'
47
+ end
48
+
41
49
  def message_text
42
50
  template % attributes
43
51
  end
@@ -3,12 +3,16 @@
3
3
  module DatabaseConsistency
4
4
  module Writers
5
5
  module Simple
6
- class ErrorMessage < Base # :nodoc:
6
+ class DefaultMessage < Base # :nodoc:
7
7
  private
8
8
 
9
9
  def template
10
10
  report.error_message || ''
11
11
  end
12
+
13
+ def unique_attributes
14
+ report.to_h
15
+ end
12
16
  end
13
17
  end
14
18
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DatabaseConsistency
4
+ module Writers
5
+ module Simple
6
+ class HasOneMissingUniqueIndex < Base # :nodoc:
7
+ private
8
+
9
+ def template
10
+ 'associated model should have proper unique index in the database'
11
+ end
12
+
13
+ def unique_attributes
14
+ {
15
+ table_name: report.table_name,
16
+ columns: report.columns,
17
+ unique: true
18
+ }
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -7,7 +7,8 @@ module DatabaseConsistency
7
7
  private
8
8
 
9
9
  def template
10
- "foreign key %<fk_name>s with type %<fk_type>s doesn't cover primary key %<pk_name>s with type %<pk_type>s"
10
+ "foreign key (%<fk_name>s) with type (%<fk_type>s) doesn't "\
11
+ 'cover primary key (%<pk_name>s) with type (%<pk_type>s)'
11
12
  end
12
13
 
13
14
  def attributes
@@ -18,6 +19,14 @@ module DatabaseConsistency
18
19
  pk_type: report.pk_type
19
20
  }
20
21
  end
22
+
23
+ def unique_attributes
24
+ {
25
+ table_to_change: report.table_to_change,
26
+ type_to_set: report.type_to_set,
27
+ fk_name: report.fk_name
28
+ }
29
+ end
21
30
  end
22
31
  end
23
32
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DatabaseConsistency
4
+ module Writers
5
+ module Simple
6
+ class LengthValidatorGreaterLimit < Base # :nodoc:
7
+ private
8
+
9
+ def template
10
+ 'column has greater limit in the database than in length validator'
11
+ end
12
+
13
+ def unique_attributes
14
+ {
15
+ table_or_model_name: report.table_or_model_name,
16
+ column_or_attribute_name: report.column_or_attribute_name
17
+ }
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DatabaseConsistency
4
+ module Writers
5
+ module Simple
6
+ class LengthValidatorLowerLimit < Base # :nodoc:
7
+ private
8
+
9
+ def template
10
+ 'column has lower limit in the database than in length validator'
11
+ end
12
+
13
+ def unique_attributes
14
+ {
15
+ table_or_model_name: report.table_or_model_name,
16
+ column_or_attribute_name: report.column_or_attribute_name
17
+ }
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DatabaseConsistency
4
+ module Writers
5
+ module Simple
6
+ class LengthValidatorMissing < Base # :nodoc:
7
+ private
8
+
9
+ def template
10
+ 'column has limit in the database but do not have length validator'
11
+ end
12
+
13
+ def unique_attributes
14
+ {
15
+ table_or_model_name: report.table_or_model_name,
16
+ column_or_attribute_name: report.column_or_attribute_name
17
+ }
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DatabaseConsistency
4
+ module Writers
5
+ module Simple
6
+ class MissingForeignKey < Base # :nodoc:
7
+ private
8
+
9
+ def template
10
+ 'should have foreign key in the database'
11
+ end
12
+
13
+ def unique_attributes
14
+ {
15
+ foreign_table: report.foreign_table,
16
+ foreign_key: report.foreign_key,
17
+ primary_table: report.primary_table,
18
+ primary_key: report.primary_key
19
+ }
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DatabaseConsistency
4
+ module Writers
5
+ module Simple
6
+ class MissingUniqueIndex < Base # :nodoc:
7
+ private
8
+
9
+ def template
10
+ 'model should have proper unique index in the database'
11
+ end
12
+
13
+ def unique_attributes
14
+ {
15
+ table_name: report.table_name,
16
+ columns: report.columns,
17
+ unique: true
18
+ }
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DatabaseConsistency
4
+ module Writers
5
+ module Simple
6
+ class MissingUniquenessValidation < Base # :nodoc:
7
+ private
8
+
9
+ def template
10
+ 'index is unique in the database but do not have uniqueness validator'
11
+ end
12
+
13
+ def unique_attributes
14
+ {
15
+ table_or_model_name: report.table_or_model_name,
16
+ column_or_attribute_name: report.column_or_attribute_name
17
+ }
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -15,6 +15,13 @@ module DatabaseConsistency
15
15
  association_name: report.association_name
16
16
  }
17
17
  end
18
+
19
+ def unique_attributes
20
+ {
21
+ table_or_model_name: report.table_or_model_name,
22
+ column_or_attribute_name: report.column_or_attribute_name
23
+ }
24
+ end
18
25
  end
19
26
  end
20
27
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DatabaseConsistency
4
+ module Writers
5
+ module Simple
6
+ class NullConstraintMissesValidator < Base # :nodoc:
7
+ private
8
+
9
+ def template
10
+ 'column is required in the database but do not have presence validator'
11
+ end
12
+
13
+ def unique_attributes
14
+ {
15
+ table_or_model_name: report.table_or_model_name,
16
+ column_or_attribute_name: report.column_or_attribute_name
17
+ }
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DatabaseConsistency
4
+ module Writers
5
+ module Simple
6
+ class NullConstraintMissing < Base # :nodoc:
7
+ private
8
+
9
+ def template
10
+ '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,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DatabaseConsistency
4
+ module Writers
5
+ module Simple
6
+ class PossibleNull < Base # :nodoc:
7
+ private
8
+
9
+ def template
10
+ 'column is required but there is possible null value insert'
11
+ end
12
+
13
+ def unique_attributes
14
+ {
15
+ table_or_model_name: report.table_or_model_name,
16
+ column_or_attribute_name: report.column_or_attribute_name
17
+ }
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -15,6 +15,12 @@ module DatabaseConsistency
15
15
  covered_index_name: report.covered_index_name
16
16
  }
17
17
  end
18
+
19
+ def unique_attributes
20
+ {
21
+ index_name: report.index_name
22
+ }
23
+ end
18
24
  end
19
25
  end
20
26
  end
@@ -15,6 +15,12 @@ module DatabaseConsistency
15
15
  covered_index_name: report.covered_index_name
16
16
  }
17
17
  end
18
+
19
+ def unique_attributes
20
+ {
21
+ index_name: report.index_name
22
+ }
23
+ end
18
24
  end
19
25
  end
20
26
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DatabaseConsistency
4
+ module Writers
5
+ module Simple
6
+ class SmallPrimaryKey < Base # :nodoc:
7
+ private
8
+
9
+ def template
10
+ 'column has int/serial type but recommended to have bigint/bigserial/uuid'
11
+ end
12
+
13
+ def unique_attributes
14
+ {
15
+ table_or_model_name: report.table_or_model_name,
16
+ column_or_attribute_name: report.column_or_attribute_name
17
+ }
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -6,43 +6,49 @@ module DatabaseConsistency
6
6
  # The simplest formatter
7
7
  class SimpleWriter < BaseWriter
8
8
  SLUG_TO_WRITER = {
9
- association_missing_index: Simple::Base.with('associated model should have proper index in the database'),
10
- association_missing_null_constraint: Simple::Base.with('association foreign key column should be required in the database'), # rubocop:disable Layout/LineLength
11
- has_one_missing_unique_index: Simple::Base.with('associated model should have proper unique index in the database'), # rubocop:disable Layout/LineLength
9
+ association_missing_index: Simple::AssociationMissingIndex,
10
+ association_missing_null_constraint: Simple::AssociationMissingNullConstraint,
11
+ has_one_missing_unique_index: Simple::HasOneMissingUniqueIndex,
12
12
  inconsistent_types: Simple::InconsistentTypes,
13
- length_validator_greater_limit: Simple::Base.with('column has greater limit in the database than in length validator'), # rubocop:disable Layout/LineLength
14
- length_validator_lower_limit: Simple::Base.with('column has lower limit in the database than in length validator'), # rubocop:disable Layout/LineLength
15
- length_validator_missing: Simple::Base.with('column has limit in the database but do not have length validator'), # rubocop:disable Layout/LineLength
16
- missing_foreign_key: Simple::Base.with('should have foreign key in the database'),
17
- missing_unique_index: Simple::Base.with('model should have proper unique index in the database'),
18
- missing_uniqueness_validation: Simple::Base.with('index is unique in the database but do not have uniqueness validator'), # rubocop:disable Layout/LineLength
13
+ length_validator_greater_limit: Simple::LengthValidatorGreaterLimit,
14
+ length_validator_lower_limit: Simple::LengthValidatorLowerLimit,
15
+ length_validator_missing: Simple::LengthValidatorMissing,
16
+ missing_foreign_key: Simple::MissingForeignKey,
17
+ missing_unique_index: Simple::MissingUniqueIndex,
18
+ missing_uniqueness_validation: Simple::MissingUniquenessValidation,
19
19
  null_constraint_association_misses_validator: Simple::NullConstraintAssociationMissesValidator,
20
- null_constraint_misses_validator: Simple::Base.with('column is required in the database but do not have presence validator'), # rubocop:disable Layout/LineLength
21
- null_constraint_missing: Simple::Base.with('column should be required in the database'),
22
- possible_null: Simple::Base.with('column is required but there is possible null value insert'),
20
+ null_constraint_misses_validator: Simple::NullConstraintMissesValidator,
21
+ null_constraint_missing: Simple::NullConstraintMissing,
22
+ possible_null: Simple::PossibleNull,
23
23
  redundant_index: Simple::RedundantIndex,
24
24
  redundant_unique_index: Simple::RedundantUniqueIndex,
25
- small_primary_key: Simple::Base.with('column has int/serial type but recommended to have bigint/bigserial/uuid')
25
+ small_primary_key: Simple::SmallPrimaryKey
26
26
  }.freeze
27
27
 
28
28
  def write
29
- results.each do |result|
30
- next unless write?(result.status)
31
-
32
- writer = writer(result)
33
-
34
- puts writer.msg
29
+ results.select(&method(:write?))
30
+ .map(&method(:writer))
31
+ .group_by(&:unique_key)
32
+ .each_value do |writers|
33
+ puts message(writers)
35
34
  end
36
35
  end
37
36
 
38
37
  private
39
38
 
40
- def write?(status)
41
- status == :fail || config.debug?
39
+ def message(writers)
40
+ msg = writers.first.msg
41
+ return msg if writers.size == 1
42
+
43
+ "#{msg}. Total grouped offenses: #{writers.size}"
44
+ end
45
+
46
+ def write?(report)
47
+ report.status == :fail || config.debug?
42
48
  end
43
49
 
44
50
  def writer(report)
45
- klass = SLUG_TO_WRITER[report.error_slug] || Simple::ErrorMessage
51
+ klass = SLUG_TO_WRITER[report.error_slug] || Simple::DefaultMessage
46
52
  klass.new(report, config: config)
47
53
  end
48
54
  end
@@ -7,17 +7,31 @@ require 'database_consistency/helper'
7
7
  require 'database_consistency/configuration'
8
8
  require 'database_consistency/rescue_error'
9
9
  require 'database_consistency/errors'
10
+ require 'database_consistency/report_builder'
10
11
  require 'database_consistency/report'
11
12
 
12
13
  require 'database_consistency/writers/base_writer'
13
14
  require 'database_consistency/writers/todo_writer'
14
15
 
15
16
  require 'database_consistency/writers/simple/base'
16
- require 'database_consistency/writers/simple/error_message'
17
+ require 'database_consistency/writers/simple/default_message'
17
18
  require 'database_consistency/writers/simple/inconsistent_types'
18
19
  require 'database_consistency/writers/simple/null_constraint_association_misses_validator'
19
20
  require 'database_consistency/writers/simple/redundant_index'
20
21
  require 'database_consistency/writers/simple/redundant_unique_index'
22
+ require 'database_consistency/writers/simple/association_missing_index'
23
+ require 'database_consistency/writers/simple/association_missing_null_constraint'
24
+ require 'database_consistency/writers/simple/has_one_missing_unique_index'
25
+ require 'database_consistency/writers/simple/length_validator_lower_limit'
26
+ require 'database_consistency/writers/simple/length_validator_greater_limit'
27
+ require 'database_consistency/writers/simple/length_validator_missing'
28
+ require 'database_consistency/writers/simple/missing_foreign_key'
29
+ require 'database_consistency/writers/simple/missing_unique_index'
30
+ require 'database_consistency/writers/simple/missing_uniqueness_validation'
31
+ require 'database_consistency/writers/simple/null_constraint_misses_validator'
32
+ require 'database_consistency/writers/simple/null_constraint_missing'
33
+ require 'database_consistency/writers/simple/possible_null'
34
+ require 'database_consistency/writers/simple/small_primary_key'
21
35
  require 'database_consistency/writers/simple_writer'
22
36
 
23
37
  require 'database_consistency/writers/autofix/helpers/migration'
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.3.5
4
+ version: 1.3.7
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-13 00:00:00.000000000 Z
11
+ date: 2022-11-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -176,6 +176,7 @@ files:
176
176
  - lib/database_consistency/processors/validators_fractions_processor.rb
177
177
  - lib/database_consistency/processors/validators_processor.rb
178
178
  - lib/database_consistency/report.rb
179
+ - lib/database_consistency/report_builder.rb
179
180
  - lib/database_consistency/rescue_error.rb
180
181
  - lib/database_consistency/templates/rails_defaults.yml
181
182
  - lib/database_consistency/version.rb
@@ -196,12 +197,25 @@ files:
196
197
  - lib/database_consistency/writers/autofix/templates/redundant_index.tt
197
198
  - lib/database_consistency/writers/autofix_writer.rb
198
199
  - lib/database_consistency/writers/base_writer.rb
200
+ - lib/database_consistency/writers/simple/association_missing_index.rb
201
+ - lib/database_consistency/writers/simple/association_missing_null_constraint.rb
199
202
  - lib/database_consistency/writers/simple/base.rb
200
- - lib/database_consistency/writers/simple/error_message.rb
203
+ - lib/database_consistency/writers/simple/default_message.rb
204
+ - lib/database_consistency/writers/simple/has_one_missing_unique_index.rb
201
205
  - lib/database_consistency/writers/simple/inconsistent_types.rb
206
+ - lib/database_consistency/writers/simple/length_validator_greater_limit.rb
207
+ - lib/database_consistency/writers/simple/length_validator_lower_limit.rb
208
+ - lib/database_consistency/writers/simple/length_validator_missing.rb
209
+ - lib/database_consistency/writers/simple/missing_foreign_key.rb
210
+ - lib/database_consistency/writers/simple/missing_unique_index.rb
211
+ - lib/database_consistency/writers/simple/missing_uniqueness_validation.rb
202
212
  - lib/database_consistency/writers/simple/null_constraint_association_misses_validator.rb
213
+ - lib/database_consistency/writers/simple/null_constraint_misses_validator.rb
214
+ - lib/database_consistency/writers/simple/null_constraint_missing.rb
215
+ - lib/database_consistency/writers/simple/possible_null.rb
203
216
  - lib/database_consistency/writers/simple/redundant_index.rb
204
217
  - lib/database_consistency/writers/simple/redundant_unique_index.rb
218
+ - lib/database_consistency/writers/simple/small_primary_key.rb
205
219
  - lib/database_consistency/writers/simple_writer.rb
206
220
  - lib/database_consistency/writers/todo_writer.rb
207
221
  homepage: https://github.com/djezzzl/database_consistency