database_consistency 1.3.6 → 1.3.7

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