database_consistency 1.3.3 → 1.3.5

Sign up to get free protection for your applications and to get access to all the features.
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