database_consistency 1.3.6 → 1.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ad00c3759184fa0098812d4cb79169f109205bff2861c37965d56c42c4da568f
4
- data.tar.gz: 579087c2a52d57bac85af5fc7f9e86fa31b6c78bbaab1583128e319f9156dafb
3
+ metadata.gz: 3977b5e14b960051dad79361a32e435e511707612a269512fd42dcbac389216f
4
+ data.tar.gz: 95aba2661c7724aca4cee0e386b8f5e12e59f62b6444f35c66ebcabba2a6f9be
5
5
  SHA512:
6
- metadata.gz: 206324a83d7f850bde79bb8a4399362ba7ff4f94cf848139d55781cf7e6f54d8b03d5e4641928193689c0c818c803badbcbb4f72685031f72dab26eea1f4a80a
7
- data.tar.gz: 2cbaed407b168b1100de5cb6962d2fedac6ce2e8f955a5ed4811ef9d80227a2f3f396de98c9ed0a9de8c5ca751c092f389b482852663a510860cbaad85866643
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.6'
4
+ VERSION = '1.3.7'
5
5
  end
@@ -33,7 +33,7 @@ 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
37
  end
38
38
 
39
39
  def unique_key
@@ -3,7 +3,7 @@
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
@@ -11,10 +11,7 @@ module DatabaseConsistency
11
11
  end
12
12
 
13
13
  def unique_attributes
14
- {
15
- template: template,
16
- checker_name: report.checker_name
17
- }
14
+ report.to_h
18
15
  end
19
16
  end
20
17
  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
@@ -28,20 +28,27 @@ module DatabaseConsistency
28
28
  def write
29
29
  results.select(&method(:write?))
30
30
  .map(&method(:writer))
31
- .uniq(&:unique_key)
32
- .each do |writer|
33
- puts writer.msg
31
+ .group_by(&:unique_key)
32
+ .each_value do |writers|
33
+ puts message(writers)
34
34
  end
35
35
  end
36
36
 
37
37
  private
38
38
 
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
+
39
46
  def write?(report)
40
47
  report.status == :fail || config.debug?
41
48
  end
42
49
 
43
50
  def writer(report)
44
- klass = SLUG_TO_WRITER[report.error_slug] || Simple::ErrorMessage
51
+ klass = SLUG_TO_WRITER[report.error_slug] || Simple::DefaultMessage
45
52
  klass.new(report, config: config)
46
53
  end
47
54
  end
@@ -7,13 +7,14 @@ 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'
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.6
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-19 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
@@ -199,7 +200,7 @@ files:
199
200
  - lib/database_consistency/writers/simple/association_missing_index.rb
200
201
  - lib/database_consistency/writers/simple/association_missing_null_constraint.rb
201
202
  - lib/database_consistency/writers/simple/base.rb
202
- - lib/database_consistency/writers/simple/error_message.rb
203
+ - lib/database_consistency/writers/simple/default_message.rb
203
204
  - lib/database_consistency/writers/simple/has_one_missing_unique_index.rb
204
205
  - lib/database_consistency/writers/simple/inconsistent_types.rb
205
206
  - lib/database_consistency/writers/simple/length_validator_greater_limit.rb