database_consistency 1.0.0 → 1.1.3

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: b074df0ae4a1316afdb9874c811a02189fd664e00b85220730dd0ae985a36c76
4
- data.tar.gz: f870f9f74117a6ea1b5592e7610becc5f854c375ee4a82f9720b287ae9288462
3
+ metadata.gz: 9e4c24aeb235c8283ce761d7b4d1e3511246eae28c761a55b4f8ef180a090b22
4
+ data.tar.gz: d8e3b783eae3e68e88126c7f9d77de062748201652ec46492522eda6af0722bf
5
5
  SHA512:
6
- metadata.gz: 99e298ec2e58c3bfcc5c10a9e294891b14eee23b1a4c9ccbf3e78f5e500480baf1c3ec397d0a19f5af6e83f05dbe9a297e062358eab9699d324b6b06a1255889
7
- data.tar.gz: 7d742b1d5985792e2fa3b3a6d5195ccb91c4b49cdbcbce800de6db29a16ef1045f4bf786b3d88e981d23b573282d4ddb821ede90951890ab45682c16b37ede7b
6
+ metadata.gz: 005c1fa13f5aab3d833c9fd0690907f5df81a0d34ee2dcb5ea19ace51ed41f1438c803d56b95d3573eaa0938b8d9295a04dd5e2dafb6a6ab6ca48c6fcba3af4e
7
+ data.tar.gz: fab16372c3782df28f84aac35b997c31ccbb68d3be8ee0b8442e09061c8a85797da584153fc3de151ff1761227348b17041302260daede249b3b10753a1d610b
@@ -38,10 +38,14 @@ module DatabaseConsistency
38
38
  model.connection.indexes(model.table_name).find do |another_index|
39
39
  next if index.name == another_index.name
40
40
 
41
- include_index_as_prefix?(another_index)
41
+ clause_equals?(another_index) && include_index_as_prefix?(another_index)
42
42
  end
43
43
  end
44
44
 
45
+ def clause_equals?(another_index)
46
+ another_index.where == index.where
47
+ end
48
+
45
49
  def include_index_as_prefix?(another_index)
46
50
  another_index_columns = Helper.extract_index_columns(another_index.columns)
47
51
  index_columns == another_index_columns.first(index_columns.size)
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DatabaseConsistency
4
+ module Checkers
5
+ # This class checks redundant database indexes
6
+ class RedundantUniqueIndexChecker < IndexChecker
7
+ # Message templates
8
+ REDUNDANT_UNIQUE_INDEX = 'index uniqueness is redundant as (%index) covers it'
9
+
10
+ private
11
+
12
+ # We skip check when:
13
+ # - index is not unique
14
+ def preconditions
15
+ index.unique
16
+ end
17
+
18
+ # Table of possible statuses
19
+ # | validation | status |
20
+ # | ---------- | ------ |
21
+ # | provided | ok |
22
+ # | redundant | fail |
23
+ #
24
+ def check
25
+ if covered_by_index
26
+ report_template(:fail, render_message)
27
+ else
28
+ report_template(:ok)
29
+ end
30
+ end
31
+
32
+ def render_message
33
+ REDUNDANT_UNIQUE_INDEX.sub('%index', covered_by_index.name)
34
+ end
35
+
36
+ def covered_by_index
37
+ @covered_by_index ||=
38
+ model.connection.indexes(model.table_name).find do |another_index|
39
+ next if index.name == another_index.name
40
+
41
+ another_index.unique && clause_equals?(another_index) && contain_index?(another_index)
42
+ end
43
+ end
44
+
45
+ def clause_equals?(another_index)
46
+ another_index.where == index.where
47
+ end
48
+
49
+ def contain_index?(another_index)
50
+ another_index_columns = Helper.extract_index_columns(another_index.columns)
51
+ index_columns & another_index_columns == another_index_columns
52
+ end
53
+
54
+ def index_columns
55
+ @index_columns ||= Helper.extract_index_columns(index.columns)
56
+ end
57
+ end
58
+ end
59
+ end
@@ -7,6 +7,7 @@ module DatabaseConsistency
7
7
  WEAK_OPTIONS = %i[allow_nil allow_blank if unless on].freeze
8
8
  # Message templates
9
9
  CONSTRAINT_MISSING = 'column should be required in the database'
10
+ ASSOCIATION_FOREIGN_KEY_CONSTRAINT_MISSING = 'association foreign key column should be required in the database'
10
11
  POSSIBLE_NULL = 'column is required but there is possible null value insert'
11
12
 
12
13
  private
@@ -15,11 +16,9 @@ module DatabaseConsistency
15
16
  validator.kind == :presence
16
17
  end
17
18
 
18
- # We skip check when:
19
- # - there is no presence validators
20
- # - there is no column in the database with given name
19
+ # We skip the check when there are no presence validators
21
20
  def preconditions
22
- validators.any? && column
21
+ validators.any?
23
22
  end
24
23
 
25
24
  # Table of possible statuses
@@ -33,17 +32,39 @@ module DatabaseConsistency
33
32
  can_be_null = column.null
34
33
  has_weak_option = validators.all? { |validator| validator.options.slice(*WEAK_OPTIONS).any? }
35
34
 
36
- if can_be_null == has_weak_option
37
- report_template(:ok)
38
- elsif can_be_null
35
+ return report_template(:ok) if can_be_null == has_weak_option
36
+ return report_template(:fail, POSSIBLE_NULL) unless can_be_null
37
+
38
+ if regular_column
39
39
  report_template(:fail, CONSTRAINT_MISSING)
40
40
  else
41
- report_template(:fail, POSSIBLE_NULL)
41
+ report_template(:fail, ASSOCIATION_FOREIGN_KEY_CONSTRAINT_MISSING)
42
42
  end
43
43
  end
44
44
 
45
45
  def column
46
- @column ||= model.columns.select.find { |field| field.name == attribute.to_s }
46
+ @column ||= regular_column || association_reference_column ||
47
+ (raise Errors::MissingField, "Missing column in #{model.table_name} for #{attribute}")
48
+ end
49
+
50
+ def regular_column
51
+ @regular_column ||= column_for_name(attribute.to_s)
52
+ end
53
+
54
+ def column_for_name(name)
55
+ model.columns.find { |field| field.name == name.to_s }
56
+ end
57
+
58
+ def association_reference_column
59
+ return unless association_reflection
60
+
61
+ column_for_name(association_reflection.foreign_key)
62
+ end
63
+
64
+ def association_reflection
65
+ model
66
+ .reflect_on_all_associations
67
+ .find { |reflection| reflection.belongs_to? && reflection.name == attribute }
47
68
  end
48
69
  end
49
70
  end
@@ -6,7 +6,8 @@ module DatabaseConsistency
6
6
  class IndexesProcessor < BaseProcessor
7
7
  CHECKERS = [
8
8
  Checkers::UniqueIndexChecker,
9
- Checkers::RedundantIndexChecker
9
+ Checkers::RedundantIndexChecker,
10
+ Checkers::RedundantUniqueIndexChecker
10
11
  ].freeze
11
12
 
12
13
  private
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DatabaseConsistency
4
- VERSION = '1.0.0'
4
+ VERSION = '1.1.3'
5
5
  end
@@ -21,9 +21,7 @@ module DatabaseConsistency
21
21
  end
22
22
 
23
23
  def msg(result)
24
- msg = "#{status_text(result)} #{key_text(result)} #{result.message}"
25
- msg += " (checker: #{result.checker_name})" if config.debug?
26
- msg
24
+ "#{result.checker_name} #{status_text(result)} #{key_text(result)} #{result.message}"
27
25
  end
28
26
 
29
27
  private
@@ -36,6 +36,7 @@ require 'database_consistency/checkers/validators_fraction_checkers/column_prese
36
36
  require 'database_consistency/checkers/index_checkers/index_checker'
37
37
  require 'database_consistency/checkers/index_checkers/unique_index_checker'
38
38
  require 'database_consistency/checkers/index_checkers/redundant_index_checker'
39
+ require 'database_consistency/checkers/index_checkers/redundant_unique_index_checker'
39
40
 
40
41
  require 'database_consistency/processors/base_processor'
41
42
  require 'database_consistency/processors/associations_processor'
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.0.0
4
+ version: 1.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evgeniy Demin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-24 00:00:00.000000000 Z
11
+ date: 2021-10-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -142,6 +142,7 @@ files:
142
142
  - lib/database_consistency/checkers/column_checkers/primary_key_type_checker.rb
143
143
  - lib/database_consistency/checkers/index_checkers/index_checker.rb
144
144
  - lib/database_consistency/checkers/index_checkers/redundant_index_checker.rb
145
+ - lib/database_consistency/checkers/index_checkers/redundant_unique_index_checker.rb
145
146
  - lib/database_consistency/checkers/index_checkers/unique_index_checker.rb
146
147
  - lib/database_consistency/checkers/validator_checkers/belongs_to_presence_checker.rb
147
148
  - lib/database_consistency/checkers/validator_checkers/missing_unique_index_checker.rb