database_consistency 1.3.3 → 1.3.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.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/lib/database_consistency/checkers/association_checkers/foreign_key_checker.rb +0 -9
  3. data/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb +28 -21
  4. data/lib/database_consistency/checkers/association_checkers/missing_index_checker.rb +21 -0
  5. data/lib/database_consistency/checkers/column_checkers/null_constraint_checker.rb +0 -4
  6. data/lib/database_consistency/checkers/column_checkers/primary_key_type_checker.rb +29 -2
  7. data/lib/database_consistency/checkers/index_checkers/redundant_index_checker.rb +0 -4
  8. data/lib/database_consistency/checkers/index_checkers/redundant_unique_index_checker.rb +6 -8
  9. data/lib/database_consistency/checkers/validator_checkers/missing_unique_index_checker.rb +19 -2
  10. data/lib/database_consistency/checkers/validators_fraction_checkers/column_presence_checker.rb +0 -4
  11. data/lib/database_consistency/databases/types/base.rb +6 -0
  12. data/lib/database_consistency/report.rb +0 -7
  13. data/lib/database_consistency/version.rb +1 -1
  14. data/lib/database_consistency/writers/autofix/association_missing_index.rb +39 -0
  15. data/lib/database_consistency/writers/autofix/has_one_missing_unique_index.rb +19 -0
  16. data/lib/database_consistency/writers/autofix/inconsistent_types.rb +27 -0
  17. data/lib/database_consistency/writers/autofix/migration_base.rb +5 -1
  18. data/lib/database_consistency/writers/autofix/missing_foreign_key.rb +9 -0
  19. data/lib/database_consistency/writers/autofix/null_constraint_missing.rb +7 -0
  20. data/lib/database_consistency/writers/autofix/redundant_index.rb +6 -0
  21. data/lib/database_consistency/writers/autofix/templates/association_missing_index.tt +5 -0
  22. data/lib/database_consistency/writers/autofix/templates/has_one_missing_unique_index.tt +5 -0
  23. data/lib/database_consistency/writers/autofix/templates/inconsistent_types.tt +5 -0
  24. data/lib/database_consistency/writers/autofix/templates/null_constraint_missing.tt +1 -1
  25. data/lib/database_consistency/writers/autofix_writer.rb +20 -12
  26. data/lib/database_consistency/writers/simple/base.rb +67 -0
  27. data/lib/database_consistency/writers/simple/error_message.rb +15 -0
  28. data/lib/database_consistency/writers/simple/inconsistent_types.rb +24 -0
  29. data/lib/database_consistency/writers/simple/null_constraint_association_misses_validator.rb +21 -0
  30. data/lib/database_consistency/writers/simple/redundant_index.rb +21 -0
  31. data/lib/database_consistency/writers/simple/redundant_unique_index.rb +21 -0
  32. data/lib/database_consistency/writers/simple_writer.rb +24 -54
  33. data/lib/database_consistency.rb +11 -3
  34. metadata +14 -3
  35. data/lib/database_consistency/writers/helpers/pipes.rb +0 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 857156332ffa36d32216953b8bd1f798ae27dcb2037e873c93d08fa55a01bd47
4
- data.tar.gz: f1aa19a34377de90e606b1e8272d9444992e44f6487c0ac28d913298d5ef6df9
3
+ metadata.gz: 8f935ca51faca06dad689d217e897a035253f4ce9884f1826befdf1bcbbee3b5
4
+ data.tar.gz: 38bde32ffee8b05b04bc8a1af261764f967b64f322352ef8d79729f1de485e13
5
5
  SHA512:
6
- metadata.gz: 635ac9cfa1426f77ec59647e7282887fcfc81ec2db8217a545f791383bc1e3538f8f2e5bcb55c1aedee194b27287063a0ee330ffafe0068a7c219f2350a421b9
7
- data.tar.gz: f72cf3ef8ac71296984002d798b895740fc15ec91e582503fde012d8b58986956e36bd41bfae5453abb374da27a20f92bbcf96fbfe2abdddf3fe8f2569be3f48
6
+ metadata.gz: 2352fa358c91e6dbec9a22c9abac34fb27b45e662c1402e88cfe94864b7bfa4966628f246a6f6f5d6c6af323e1320a3fe03c74df644f86ec6d14e4bde7c81962
7
+ data.tar.gz: ad812a3ce4c8d4d0a7d24d9031815a26ae2c32bfca6d0721430f3c31f01d8c5910f4af091fb7d088e4860d65d887ba0a27531bdd0d8aefc50b589a944ef29290
@@ -14,15 +14,6 @@ module DatabaseConsistency
14
14
  @foreign_table = foreign_table
15
15
  @foreign_key = foreign_key
16
16
  end
17
-
18
- def attributes
19
- super.merge(
20
- primary_table: primary_table,
21
- primary_key: primary_key,
22
- foreign_table: foreign_table,
23
- foreign_key: foreign_key
24
- )
25
- end
26
17
  end
27
18
 
28
19
  private
@@ -4,27 +4,22 @@ 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
- class Report < DatabaseConsistency::Report # :nodoc:
8
- attr_reader :pk_name, :pk_type, :fk_name, :fk_type
9
-
10
- def initialize(fk_name: nil, fk_type: nil, pk_name: nil, pk_type: nil, **args)
11
- super(**args)
12
- @fk_name = fk_name
13
- @fk_type = fk_type
14
- @pk_name = pk_name
15
- @pk_type = pk_type
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
16
21
  end
17
22
 
18
- def attributes
19
- super.merge(
20
- fk_name: fk_name,
21
- fk_type: fk_type,
22
- pk_name: pk_name,
23
- pk_type: pk_type
24
- )
25
- end
26
- end
27
-
28
23
  private
29
24
 
30
25
  # We skip check when:
@@ -46,9 +41,11 @@ module DatabaseConsistency
46
41
  # | ------------- | ------ |
47
42
  # | covers | ok |
48
43
  # | doesn't cover | fail |
49
- def check # rubocop:disable Metrics/MethodLength
44
+ def check # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
50
45
  if converted_type(associated_column).cover?(converted_type(primary_column))
51
46
  report_template(:ok)
47
+ elsif !(converted_type(associated_column).numeric? && converted_type(primary_column).numeric?)
48
+ report_template(:ok)
52
49
  else
53
50
  report_template(:fail, error_slug: :inconsistent_types)
54
51
  end
@@ -61,11 +58,13 @@ module DatabaseConsistency
61
58
  )
62
59
  end
63
60
 
64
- def report_template(status, error_slug: nil)
61
+ def report_template(status, error_slug: nil) # rubocop:disable Metrics/MethodLength
65
62
  Report.new(
66
63
  status: status,
67
64
  error_slug: error_slug,
68
65
  error_message: nil,
66
+ table_to_change: table_to_change,
67
+ type_to_set: converted_type(primary_column).convert,
69
68
  fk_type: converted_type(associated_column).type,
70
69
  fk_name: associated_key,
71
70
  pk_type: converted_type(primary_column).type,
@@ -74,6 +73,14 @@ module DatabaseConsistency
74
73
  )
75
74
  end
76
75
 
76
+ def table_to_change
77
+ @table_to_change ||= if belongs_to_association?
78
+ association.active_record.table_name
79
+ else
80
+ association.klass.table_name
81
+ end
82
+ end
83
+
77
84
  # @return [String]
78
85
  def primary_key
79
86
  @primary_key ||= if belongs_to_association?
@@ -4,6 +4,16 @@ 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
16
+
7
17
  private
8
18
 
9
19
  # We skip check when:
@@ -48,6 +58,17 @@ module DatabaseConsistency
48
58
  end
49
59
  end
50
60
 
61
+ def report_template(status, error_slug: nil)
62
+ Report.new(
63
+ status: status,
64
+ error_slug: error_slug,
65
+ error_message: nil,
66
+ table_name: association.klass.table_name,
67
+ columns: association_keys,
68
+ **report_attributes
69
+ )
70
+ end
71
+
51
72
  def unique_has_one_association?
52
73
  association.scope.nil? && association.macro == :has_one && !association.options[:as].present?
53
74
  end
@@ -11,10 +11,6 @@ module DatabaseConsistency
11
11
  super(**args)
12
12
  @association_name = association_name
13
13
  end
14
-
15
- def attributes
16
- super.merge(association_name: association_name)
17
- end
18
14
  end
19
15
 
20
16
  private
@@ -4,9 +4,24 @@ 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
17
+
7
18
  private
8
19
 
9
20
  VALID_TYPES = %w[bigserial bigint uuid].freeze
21
+ VALID_TYPES_MAP = {
22
+ 'serial' => 'bigserial',
23
+ 'integer' => 'bigint'
24
+ }.freeze
10
25
  SQLITE_ADAPTER_NAME = 'SQLite'
11
26
 
12
27
  # We skip check when:
@@ -21,14 +36,26 @@ module DatabaseConsistency
21
36
  # | --------------------- | ------ |
22
37
  # | yes | ok |
23
38
  # | no | fail |
24
- def check
39
+ def check # rubocop:disable Metrics/MethodLength
25
40
  if valid?
26
41
  report_template(:ok)
27
42
  else
28
- report_template(:fail, error_slug: :small_primary_key)
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
+ )
29
52
  end
30
53
  end
31
54
 
55
+ def type_to_set
56
+ VALID_TYPES_MAP[column.sql_type.to_s] || 'bigserial'
57
+ end
58
+
32
59
  # @return [Boolean]
33
60
  def valid?
34
61
  VALID_TYPES.any? do |type|
@@ -12,10 +12,6 @@ module DatabaseConsistency
12
12
  @covered_index_name = covered_index_name
13
13
  @index_name = index_name
14
14
  end
15
-
16
- def attributes
17
- super.merge(covered_index_name: covered_index_name, index_name: index_name)
18
- end
19
15
  end
20
16
 
21
17
  private
@@ -5,15 +5,12 @@ module DatabaseConsistency
5
5
  # This class checks redundant database indexes
6
6
  class RedundantUniqueIndexChecker < IndexChecker
7
7
  class Report < DatabaseConsistency::Report # :nodoc:
8
- attr_reader :index_name
8
+ attr_reader :index_name, :covered_index_name
9
9
 
10
- def initialize(index_name:, **args)
10
+ def initialize(covered_index_name:, index_name:, **args)
11
11
  super(**args)
12
12
  @index_name = index_name
13
- end
14
-
15
- def attributes
16
- super.merge(index_name: index_name)
13
+ @covered_index_name = covered_index_name
17
14
  end
18
15
  end
19
16
 
@@ -31,13 +28,14 @@ module DatabaseConsistency
31
28
  # | provided | ok |
32
29
  # | redundant | fail |
33
30
  #
34
- def check
31
+ def check # rubocop:disable Metrics/MethodLength
35
32
  if covered_by_index
36
33
  Report.new(
37
34
  status: :fail,
38
35
  error_slug: :redundant_unique_index,
39
36
  error_message: nil,
40
- index_name: covered_by_index.name,
37
+ index_name: index.name,
38
+ covered_index_name: covered_by_index.name,
41
39
  **report_attributes
42
40
  )
43
41
  else
@@ -4,6 +4,16 @@ 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
16
+
7
17
  def column_or_attribute_name
8
18
  @column_or_attribute_name ||= Helper.uniqueness_validator_columns(attribute, validator, model).join('+')
9
19
  end
@@ -21,11 +31,18 @@ module DatabaseConsistency
21
31
  # | ------------ | ------ |
22
32
  # | persisted | ok |
23
33
  # | missing | fail |
24
- def check
34
+ def check # rubocop:disable Metrics/MethodLength
25
35
  if unique_index
26
36
  report_template(:ok)
27
37
  else
28
- report_template(:fail, error_slug: :missing_unique_index)
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
+ )
29
46
  end
30
47
  end
31
48
 
@@ -14,10 +14,6 @@ module DatabaseConsistency
14
14
  @table_name = table_name
15
15
  @column_name = column_name
16
16
  end
17
-
18
- def attributes
19
- super.merge(table_name: table_name, column_name: column_name)
20
- end
21
17
  end
22
18
 
23
19
  private
@@ -7,6 +7,8 @@ module DatabaseConsistency
7
7
  class Base
8
8
  attr_reader :type
9
9
 
10
+ NUMERIC_TYPES = %w[bigserial serial bigint integer smallint].freeze
11
+
10
12
  COVERED_TYPES = {
11
13
  'bigint' => %w[integer bigint],
12
14
  'integer' => %w[integer smallint]
@@ -22,6 +24,10 @@ module DatabaseConsistency
22
24
  type
23
25
  end
24
26
 
27
+ def numeric?
28
+ NUMERIC_TYPES.include?(convert)
29
+ end
30
+
25
31
  # @param [DatabaseConsistency::Databases::Types::Base]
26
32
  #
27
33
  # @return [Boolean]
@@ -12,12 +12,5 @@ module DatabaseConsistency
12
12
  @error_slug = error_slug
13
13
  @error_message = error_message
14
14
  end
15
-
16
- def attributes
17
- {
18
- error_slug: error_slug,
19
- error_message: error_message
20
- }
21
- end
22
15
  end
23
16
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DatabaseConsistency
4
- VERSION = '1.3.3'
4
+ VERSION = '1.3.5'
5
5
  end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DatabaseConsistency
4
+ module Writers
5
+ module Autofix
6
+ class AssociationMissingIndex < MigrationBase # :nodoc:
7
+ def attributes
8
+ {
9
+ table_name: report.table_name,
10
+ columns: columns,
11
+ index_name: index_name
12
+ }
13
+ end
14
+
15
+ private
16
+
17
+ def migration_name
18
+ "add_#{report.table_name}_#{columns_key}_index"
19
+ end
20
+
21
+ def template_path
22
+ File.join(__dir__, 'templates', 'association_missing_index.tt')
23
+ end
24
+
25
+ def columns
26
+ "%w[#{report.columns.join(' ')}]"
27
+ end
28
+
29
+ def columns_key
30
+ report.columns.join('_').gsub('(', '_').gsub(')', '_')
31
+ end
32
+
33
+ def index_name
34
+ "index_#{report.table_name}_#{columns_key}".first(63)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DatabaseConsistency
4
+ module Writers
5
+ module Autofix
6
+ class HasOneMissingUniqueIndex < AssociationMissingIndex # :nodoc:
7
+ def attributes
8
+ super.merge(unique: true)
9
+ end
10
+
11
+ private
12
+
13
+ def template_path
14
+ File.join(__dir__, 'templates', 'has_one_missing_unique_index.tt')
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DatabaseConsistency
4
+ module Writers
5
+ module Autofix
6
+ class InconsistentTypes < MigrationBase # :nodoc:
7
+ def attributes
8
+ {
9
+ table_to_change: report.table_to_change,
10
+ type_to_set: report.type_to_set,
11
+ fk_name: report.fk_name
12
+ }
13
+ end
14
+
15
+ private
16
+
17
+ def migration_name
18
+ "change_#{report.table_to_change}_#{report.fk_name}_to_#{report.type_to_set}"
19
+ end
20
+
21
+ def template_path
22
+ File.join(__dir__, 'templates', 'inconsistent_types.tt')
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -10,10 +10,14 @@ module DatabaseConsistency
10
10
  File.write(migration_path(migration_name), migration)
11
11
  end
12
12
 
13
+ def attributes
14
+ {}
15
+ end
16
+
13
17
  private
14
18
 
15
19
  def migration
16
- File.read(template_path) % report.attributes.merge(migration_configuration(migration_name))
20
+ File.read(template_path) % attributes.merge(migration_configuration(migration_name))
17
21
  end
18
22
  end
19
23
  end
@@ -4,6 +4,15 @@ module DatabaseConsistency
4
4
  module Writers
5
5
  module Autofix
6
6
  class MissingForeignKey < MigrationBase # :nodoc:
7
+ def attributes
8
+ {
9
+ foreign_table: report.foreign_table,
10
+ foreign_key: report.foreign_key,
11
+ primary_table: report.primary_table,
12
+ primary_key: report.primary_key
13
+ }
14
+ end
15
+
7
16
  private
8
17
 
9
18
  def migration_name
@@ -4,6 +4,13 @@ module DatabaseConsistency
4
4
  module Writers
5
5
  module Autofix
6
6
  class NullConstraintMissing < MigrationBase # :nodoc:
7
+ def attributes
8
+ {
9
+ table_name: report.table_name,
10
+ column_name: report.column_name
11
+ }
12
+ end
13
+
7
14
  private
8
15
 
9
16
  def migration_name
@@ -4,6 +4,12 @@ module DatabaseConsistency
4
4
  module Writers
5
5
  module Autofix
6
6
  class RedundantIndex < MigrationBase # :nodoc:
7
+ def attributes
8
+ {
9
+ index_name: report.index_name
10
+ }
11
+ end
12
+
7
13
  private
8
14
 
9
15
  def migration_name
@@ -0,0 +1,5 @@
1
+ class %<migration_name>s < ActiveRecord::Migration[%<migration_version>s]
2
+ def change
3
+ add_index :%<table_name>s, %<columns>s, name: :%<index_name>s
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class %<migration_name>s < ActiveRecord::Migration[%<migration_version>s]
2
+ def change
3
+ add_index :%<table_name>s, %<columns>s, name: :%<index_name>s, unique: true
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class %<migration_name>s < ActiveRecord::Migration[%<migration_version>s]
2
+ def change
3
+ change_column :%<table_to_change>s, :%<fk_name>s, :%<type_to_set>s
4
+ end
5
+ end
@@ -1,5 +1,5 @@
1
1
  class %<migration_name>s < ActiveRecord::Migration[%<migration_version>s]
2
2
  def change
3
- change_column_null(:%<table_name>s, :%<column_name>s, false)
3
+ change_column_null :%<table_name>s, :%<column_name>s, false
4
4
  end
5
5
  end
@@ -6,35 +6,43 @@ module DatabaseConsistency
6
6
  # The simplest formatter
7
7
  class AutofixWriter < BaseWriter
8
8
  SLUG_TO_GENERATOR = {
9
+ association_missing_index: Autofix::AssociationMissingIndex,
10
+ association_missing_null_constraint: Autofix::NullConstraintMissing,
11
+ has_one_missing_unique_index: Autofix::HasOneMissingUniqueIndex,
12
+ inconsistent_types: Autofix::InconsistentTypes,
9
13
  missing_foreign_key: Autofix::MissingForeignKey,
14
+ missing_unique_index: Autofix::HasOneMissingUniqueIndex,
10
15
  null_constraint_missing: Autofix::NullConstraintMissing,
11
- association_missing_null_constraint: Autofix::NullConstraintMissing,
12
- redundant_index: Autofix::RedundantIndex
16
+ redundant_index: Autofix::RedundantIndex,
17
+ redundant_unique_index: Autofix::RedundantIndex,
18
+ small_primary_key: Autofix::InconsistentTypes
13
19
  }.freeze
14
20
 
15
21
  def write
16
- reports.each do |report|
17
- next unless fix?(report)
18
-
19
- fix(report)
20
- end
22
+ unique_generators.each(&:fix!)
21
23
  end
22
24
 
23
25
  private
24
26
 
25
- def reports
26
- results.then(&Helpers::Pipes.method(:unique))
27
+ def unique_generators
28
+ results
29
+ .select(&method(:fix?))
30
+ .map(&method(:generator))
31
+ .compact
32
+ .uniq(&method(:unique_key))
27
33
  end
28
34
 
29
35
  def fix?(report)
30
36
  report.status == :fail
31
37
  end
32
38
 
33
- def fix(report)
39
+ def generator(report)
34
40
  klass = SLUG_TO_GENERATOR[report.error_slug]
35
- return unless klass
41
+ klass&.new(report)
42
+ end
36
43
 
37
- klass.new(report).fix!
44
+ def unique_key(report)
45
+ [report.class, report.attributes]
38
46
  end
39
47
  end
40
48
  end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DatabaseConsistency
4
+ module Writers
5
+ module Simple
6
+ class Base # :nodoc:
7
+ COLORS = {
8
+ blue: "\e[34m",
9
+ yellow: "\e[33m",
10
+ green: "\e[32m",
11
+ red: "\e[31m"
12
+ }.freeze
13
+
14
+ COLOR_BY_STATUS = {
15
+ ok: :green,
16
+ warning: :yellow,
17
+ fail: :red
18
+ }.freeze
19
+
20
+ def self.with(text)
21
+ Class.new(self) do
22
+ define_method :template do
23
+ text
24
+ end
25
+ end
26
+ end
27
+
28
+ attr_reader :report, :config
29
+
30
+ def initialize(report, config:)
31
+ @report = report
32
+ @config = config
33
+ end
34
+
35
+ def msg
36
+ "#{report.checker_name} #{status_text} #{key_text} #{message_text}"
37
+ end
38
+
39
+ private
40
+
41
+ def message_text
42
+ template % attributes
43
+ end
44
+
45
+ def attributes
46
+ {}
47
+ end
48
+
49
+ def key_text
50
+ "#{colorize(report.table_or_model_name, :blue)} #{colorize(report.column_or_attribute_name, :yellow)}"
51
+ end
52
+
53
+ def colorize(text, color)
54
+ return text unless config.colored? && color
55
+
56
+ "#{COLORS[color]}#{text}\e[0m"
57
+ end
58
+
59
+ def status_text
60
+ color = COLOR_BY_STATUS[report.status]
61
+
62
+ colorize(report.status, color)
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DatabaseConsistency
4
+ module Writers
5
+ module Simple
6
+ class ErrorMessage < Base # :nodoc:
7
+ private
8
+
9
+ def template
10
+ report.error_message || ''
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DatabaseConsistency
4
+ module Writers
5
+ module Simple
6
+ class InconsistentTypes < Base # :nodoc:
7
+ private
8
+
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"
11
+ end
12
+
13
+ def attributes
14
+ {
15
+ fk_name: report.fk_name,
16
+ fk_type: report.fk_type,
17
+ pk_name: report.pk_name,
18
+ pk_type: report.pk_type
19
+ }
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DatabaseConsistency
4
+ module Writers
5
+ module Simple
6
+ class NullConstraintAssociationMissesValidator < Base # :nodoc:
7
+ private
8
+
9
+ def template
10
+ 'column is required in the database but do not have presence validator for association %<association_name>s'
11
+ end
12
+
13
+ def attributes
14
+ {
15
+ association_name: report.association_name
16
+ }
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DatabaseConsistency
4
+ module Writers
5
+ module Simple
6
+ class RedundantIndex < Base # :nodoc:
7
+ private
8
+
9
+ def template
10
+ 'index is redundant as %<covered_index_name>s covers it'
11
+ end
12
+
13
+ def attributes
14
+ {
15
+ covered_index_name: report.covered_index_name
16
+ }
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DatabaseConsistency
4
+ module Writers
5
+ module Simple
6
+ class RedundantUniqueIndex < Base # :nodoc:
7
+ private
8
+
9
+ def template
10
+ 'index uniqueness is redundant as %<covered_index_name>s covers it'
11
+ end
12
+
13
+ def attributes
14
+ {
15
+ covered_index_name: report.covered_index_name
16
+ }
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -5,75 +5,45 @@ module DatabaseConsistency
5
5
  module Writers
6
6
  # The simplest formatter
7
7
  class SimpleWriter < BaseWriter
8
- COLORS = {
9
- blue: "\e[34m",
10
- yellow: "\e[33m",
11
- green: "\e[32m",
12
- red: "\e[31m"
13
- }.freeze
14
-
15
- COLOR_BY_STATUS = {
16
- ok: :green,
17
- warning: :yellow,
18
- fail: :red
19
- }.freeze
20
-
21
- SLUG_TO_MESSAGE = {
22
- missing_foreign_key: 'should have foreign key in the database',
23
- inconsistent_types: "foreign key %<fk_name>s with type %<fk_type>s doesn't cover primary key %<pk_name>s with type %<pk_type>s", # rubocop:disable Layout/LineLength
24
- has_one_missing_unique_index: 'associated model should have proper unique index in the database',
25
- association_missing_index: 'associated model should have proper index in the database',
26
- length_validator_missing: 'column has limit in the database but do not have length validator',
27
- length_validator_greater_limit: 'column has greater limit in the database than in length validator',
28
- length_validator_lower_limit: 'column has lower limit in the database than in length validator',
29
- null_constraint_association_misses_validator: 'column is required in the database but do not have presence validator for association %<association_name>s', # rubocop:disable Layout/LineLength
30
- null_constraint_misses_validator: 'column is required in the database but do not have presence validator',
31
- small_primary_key: 'column has int/serial type but recommended to have bigint/bigserial/uuid',
32
- redundant_index: 'index is redundant as %<covered_index_name>s covers it',
33
- redundant_unique_index: 'index uniqueness is redundant as %<index_name>s covers it',
34
- missing_uniqueness_validation: 'index is unique in the database but do not have uniqueness validator',
35
- missing_unique_index: 'model should have proper unique index in the database',
36
- possible_null: 'column is required but there is possible null value insert',
37
- null_constraint_missing: 'column should be required in the database',
38
- association_missing_null_constraint: 'association foreign key column should be required in the database'
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
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
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'),
23
+ redundant_index: Simple::RedundantIndex,
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')
39
26
  }.freeze
40
27
 
41
28
  def write
42
29
  results.each do |result|
43
30
  next unless write?(result.status)
44
31
 
45
- puts msg(result)
32
+ writer = writer(result)
33
+
34
+ puts writer.msg
46
35
  end
47
36
  end
48
37
 
49
38
  private
50
39
 
51
- def msg(result)
52
- "#{result.checker_name} #{status_text(result)} #{key_text(result)} #{message_text(result)}"
53
- end
54
-
55
40
  def write?(status)
56
41
  status == :fail || config.debug?
57
42
  end
58
43
 
59
- def message_text(result)
60
- (SLUG_TO_MESSAGE[result.error_slug] || result.error_message || '') % result.attributes
61
- end
62
-
63
- def key_text(result)
64
- "#{colorize(result.table_or_model_name, :blue)} #{colorize(result.column_or_attribute_name, :yellow)}"
65
- end
66
-
67
- def status_text(result)
68
- color = COLOR_BY_STATUS[result.status]
69
-
70
- colorize(result.status, color)
71
- end
72
-
73
- def colorize(text, color)
74
- return text unless config.colored? && color
75
-
76
- "#{COLORS[color]}#{text}\e[0m"
44
+ def writer(report)
45
+ klass = SLUG_TO_WRITER[report.error_slug] || Simple::ErrorMessage
46
+ klass.new(report, config: config)
77
47
  end
78
48
  end
79
49
  end
@@ -9,16 +9,24 @@ require 'database_consistency/rescue_error'
9
9
  require 'database_consistency/errors'
10
10
  require 'database_consistency/report'
11
11
 
12
- require 'database_consistency/writers/helpers/pipes'
13
-
14
12
  require 'database_consistency/writers/base_writer'
15
- require 'database_consistency/writers/simple_writer'
16
13
  require 'database_consistency/writers/todo_writer'
17
14
 
15
+ require 'database_consistency/writers/simple/base'
16
+ require 'database_consistency/writers/simple/error_message'
17
+ require 'database_consistency/writers/simple/inconsistent_types'
18
+ require 'database_consistency/writers/simple/null_constraint_association_misses_validator'
19
+ require 'database_consistency/writers/simple/redundant_index'
20
+ require 'database_consistency/writers/simple/redundant_unique_index'
21
+ require 'database_consistency/writers/simple_writer'
22
+
18
23
  require 'database_consistency/writers/autofix/helpers/migration'
19
24
  require 'database_consistency/writers/autofix/base'
20
25
  require 'database_consistency/writers/autofix/migration_base'
21
26
  require 'database_consistency/writers/autofix/missing_foreign_key'
27
+ require 'database_consistency/writers/autofix/inconsistent_types'
28
+ require 'database_consistency/writers/autofix/association_missing_index'
29
+ require 'database_consistency/writers/autofix/has_one_missing_unique_index'
22
30
  require 'database_consistency/writers/autofix/redundant_index'
23
31
  require 'database_consistency/writers/autofix/null_constraint_missing'
24
32
  require 'database_consistency/writers/autofix_writer'
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.3
4
+ version: 1.3.5
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-12 00:00:00.000000000 Z
11
+ date: 2022-11-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -179,18 +179,29 @@ files:
179
179
  - lib/database_consistency/rescue_error.rb
180
180
  - lib/database_consistency/templates/rails_defaults.yml
181
181
  - lib/database_consistency/version.rb
182
+ - lib/database_consistency/writers/autofix/association_missing_index.rb
182
183
  - lib/database_consistency/writers/autofix/base.rb
184
+ - lib/database_consistency/writers/autofix/has_one_missing_unique_index.rb
183
185
  - lib/database_consistency/writers/autofix/helpers/migration.rb
186
+ - lib/database_consistency/writers/autofix/inconsistent_types.rb
184
187
  - lib/database_consistency/writers/autofix/migration_base.rb
185
188
  - lib/database_consistency/writers/autofix/missing_foreign_key.rb
186
189
  - lib/database_consistency/writers/autofix/null_constraint_missing.rb
187
190
  - lib/database_consistency/writers/autofix/redundant_index.rb
191
+ - lib/database_consistency/writers/autofix/templates/association_missing_index.tt
192
+ - lib/database_consistency/writers/autofix/templates/has_one_missing_unique_index.tt
193
+ - lib/database_consistency/writers/autofix/templates/inconsistent_types.tt
188
194
  - lib/database_consistency/writers/autofix/templates/missing_foreign_key.tt
189
195
  - lib/database_consistency/writers/autofix/templates/null_constraint_missing.tt
190
196
  - lib/database_consistency/writers/autofix/templates/redundant_index.tt
191
197
  - lib/database_consistency/writers/autofix_writer.rb
192
198
  - lib/database_consistency/writers/base_writer.rb
193
- - lib/database_consistency/writers/helpers/pipes.rb
199
+ - lib/database_consistency/writers/simple/base.rb
200
+ - lib/database_consistency/writers/simple/error_message.rb
201
+ - lib/database_consistency/writers/simple/inconsistent_types.rb
202
+ - lib/database_consistency/writers/simple/null_constraint_association_misses_validator.rb
203
+ - lib/database_consistency/writers/simple/redundant_index.rb
204
+ - lib/database_consistency/writers/simple/redundant_unique_index.rb
194
205
  - lib/database_consistency/writers/simple_writer.rb
195
206
  - lib/database_consistency/writers/todo_writer.rb
196
207
  homepage: https://github.com/djezzzl/database_consistency
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module DatabaseConsistency
4
- module Writers
5
- module Helpers
6
- module Pipes # :nodoc:
7
- module_function
8
-
9
- def unique(reports)
10
- reports.uniq(&:attributes)
11
- end
12
- end
13
- end
14
- end
15
- end