database_consistency 1.4.0 → 1.5.0

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: 9bc1994c7c24ab9a38d97c764fb0d9ce55e4fa71934df313f2cc693c466cecb7
4
- data.tar.gz: 04110bdba61254592c2b22323555948ad06a78b8a63ce78a40175005096acb54
3
+ metadata.gz: 24c245f8df70e4e98c102b52a56ead68364ba0613a67d1d60d499c36ddfae5b2
4
+ data.tar.gz: c1d8ce538657703f75a56f3fa462922ddbc5176d328e94665c83f71fd92bb3ed
5
5
  SHA512:
6
- metadata.gz: 581c8660605072f0cd877310813d71781b50de0af57aa5d85b216b57dd3ed040dc90944e165e51ff9b4728d180474157281ce1e028d9295b7137657367a4fa80
7
- data.tar.gz: 0c9d42d9902485c01d208ac38110aa4c7742b4ceca00c369c4fc4c014e84df038b708f17b084f9cee7da8eef28a1f31b52d4a29fa2f597f7cf454af1cefc828c
6
+ metadata.gz: 00614cf53933e47d9599698d6b412294446b50c6757ea042374247b2b400b4fec12743d00a02401040630e9912aee54fa65e472a4d683e5a2116e93e5f7f48a6
7
+ data.tar.gz: 5b87a53b2566b6892920ff883909f0a3ae871f137c8ed482b85fdc1a4ece3bd83eb1f68218a391a75dbdfa977a66cd2a34e9eb33810083a024039ccd636ff833
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DatabaseConsistency
4
+ module Checkers
5
+ # This class checks if non polymorphic +belongs_to+ association has foreign key constraint
6
+ class ForeignKeyCascadeChecker < AssociationChecker
7
+ Report = ReportBuilder.define(
8
+ DatabaseConsistency::Report,
9
+ :cascade_option,
10
+ :primary_table,
11
+ :foreign_table,
12
+ :primary_key,
13
+ :foreign_key
14
+ )
15
+
16
+ OPTION_TO_CASCADE = {
17
+ delete: :cascade,
18
+ delete_all: :cascade,
19
+ nullify: :nullify,
20
+ restrict_with_exception: :restrict,
21
+ restrict_with_error: :restrict
22
+ }.freeze
23
+
24
+ DEPENDENT_OPTIONS = OPTION_TO_CASCADE.keys.freeze
25
+
26
+ private
27
+
28
+ def preconditions
29
+ !association.polymorphic? &&
30
+ !association.belongs_to? &&
31
+ foreign_key &&
32
+ DEPENDENT_OPTIONS.include?(dependent_option)
33
+ rescue StandardError
34
+ false
35
+ end
36
+
37
+ # Table of possible statuses
38
+ # | foreign key | status |
39
+ # | ----------- | ------ |
40
+ # | persisted | ok |
41
+ # | missing | fail |
42
+ def check
43
+ if correlated_cascade_constraint?
44
+ report_template(:ok)
45
+ else
46
+ report_template(:fail, error_slug: :missing_foreign_key_cascade)
47
+ end
48
+ end
49
+
50
+ def required_foreign_key_cascade
51
+ OPTION_TO_CASCADE[dependent_option]
52
+ end
53
+
54
+ def correlated_cascade_constraint?
55
+ required_foreign_key_cascade == foreign_key_on_delete_option
56
+ end
57
+
58
+ def dependent_option
59
+ association.options[:dependent]
60
+ end
61
+
62
+ def foreign_key_on_delete_option
63
+ foreign_key.options[:on_delete]
64
+ end
65
+
66
+ def foreign_key
67
+ @foreign_key ||=
68
+ association.klass
69
+ .connection
70
+ .foreign_keys(association.klass.table_name)
71
+ .find { |fk| fk.column == association.foreign_key.to_s }
72
+ end
73
+
74
+ def report_template(status, error_slug: nil)
75
+ Report.new(
76
+ status: status,
77
+ error_message: nil,
78
+ error_slug: error_slug,
79
+ primary_table: association.table_name.to_s,
80
+ primary_key: association.association_primary_key.to_s,
81
+ foreign_table: association.active_record.table_name.to_s,
82
+ foreign_key: association.foreign_key.to_s,
83
+ cascade_option: required_foreign_key_cascade,
84
+ **report_attributes
85
+ )
86
+ end
87
+ end
88
+ end
89
+ end
@@ -4,8 +4,6 @@ module DatabaseConsistency
4
4
  module Checkers
5
5
  # This class checks enum types consistency
6
6
  class EnumTypeChecker < EnumChecker
7
- MissingColumn = Class.new(StandardError)
8
-
9
7
  Report = DatabaseConsistency::ReportBuilder.define(
10
8
  DatabaseConsistency::Report,
11
9
  :column_type,
@@ -15,7 +13,7 @@ module DatabaseConsistency
15
13
  private
16
14
 
17
15
  def preconditions
18
- true
16
+ column.present?
19
17
  end
20
18
 
21
19
  def check
@@ -53,10 +51,11 @@ module DatabaseConsistency
53
51
  model.defined_enums[enum].values.map(&:class).uniq
54
52
  end
55
53
 
56
- def column_type
57
- column = model.columns.find { |c| c.name.to_s == enum.to_s }
58
- raise MissingColumn unless column
54
+ def column
55
+ @column ||= model.columns.find { |c| c.name.to_s == enum.to_s }
56
+ end
59
57
 
58
+ def column_type
60
59
  column.type.to_s
61
60
  end
62
61
 
@@ -20,26 +20,13 @@ module DatabaseConsistency
20
20
 
21
21
  # We skip the check when there are no presence validators
22
22
  def preconditions
23
- validators.any? && !association?
23
+ column && validators.any? && !association?
24
24
  end
25
25
 
26
26
  def association?
27
27
  model._reflect_on_association(attribute)&.macro == :has_one
28
28
  end
29
29
 
30
- # Table of possible statuses
31
- # | allow_nil/allow_blank/if/unless | database | status |
32
- # | ------------------------------- | -------- | ------ |
33
- # | at least one provided | required | fail |
34
- # | at least one provided | optional | ok |
35
- # | all missing | required | ok |
36
- # | all missing | optional | fail |
37
- def check
38
- report_message
39
- rescue Errors::MissingField => e
40
- report_template(:fail, error_message: e.message)
41
- end
42
-
43
30
  def report_template(status, error_message: nil, error_slug: nil)
44
31
  Report.new(
45
32
  status: status,
@@ -55,7 +42,7 @@ module DatabaseConsistency
55
42
  validators.all? { |validator| validator.options.slice(*WEAK_OPTIONS).any? }
56
43
  end
57
44
 
58
- def report_message # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
45
+ def check # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
59
46
  can_be_null = column.null
60
47
  has_weak_option = weak_option?
61
48
 
@@ -84,9 +71,7 @@ module DatabaseConsistency
84
71
  end
85
72
 
86
73
  def column
87
- @column ||= regular_column ||
88
- association_reference_column ||
89
- (raise Errors::MissingField, "column (#{attribute}) is missing in table (#{model.table_name}) but used for presence validation") # rubocop:disable Layout/LineLength
74
+ @column ||= (regular_column || association_reference_column)
90
75
  end
91
76
 
92
77
  def regular_column
@@ -7,7 +7,8 @@ module DatabaseConsistency
7
7
  CHECKERS = [
8
8
  Checkers::MissingIndexChecker,
9
9
  Checkers::ForeignKeyChecker,
10
- Checkers::ForeignKeyTypeChecker
10
+ Checkers::ForeignKeyTypeChecker,
11
+ Checkers::ForeignKeyCascadeChecker
11
12
  ].freeze
12
13
 
13
14
  private
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DatabaseConsistency
4
- VERSION = '1.4.0'
4
+ VERSION = '1.5.0'
5
5
  end
@@ -17,7 +17,9 @@ module DatabaseConsistency
17
17
  private
18
18
 
19
19
  def migration
20
- File.read(template_path) % attributes.merge(migration_configuration(migration_name))
20
+ attributes.merge(migration_configuration(migration_name)).reduce(File.read(template_path)) do |str, (k, v)|
21
+ str.gsub("%<#{k}>s", v.to_s)
22
+ end
21
23
  end
22
24
  end
23
25
  end
@@ -47,7 +47,9 @@ module DatabaseConsistency
47
47
  end
48
48
 
49
49
  def message_text
50
- template % attributes
50
+ attributes.reduce(template) do |str, (k, v)|
51
+ str.gsub("%<#{k}>s", v.to_s)
52
+ end
51
53
  end
52
54
 
53
55
  def attributes
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DatabaseConsistency
4
+ module Writers
5
+ module Simple
6
+ class MissingForeignKeyCascade < Base # :nodoc:
7
+ private
8
+
9
+ def template
10
+ 'should have foreign key with on_delete: :%<cascade_option>s in the database'
11
+ end
12
+
13
+ def attributes
14
+ {
15
+ cascade_option: report.cascade_option
16
+ }
17
+ end
18
+
19
+ def unique_attributes
20
+ {
21
+ foreign_table: report.foreign_table,
22
+ foreign_key: report.foreign_key,
23
+ primary_table: report.primary_table,
24
+ primary_key: report.primary_key,
25
+ cascade_option: report.cascade_option
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -23,7 +23,8 @@ module DatabaseConsistency
23
23
  redundant_index: Simple::RedundantIndex,
24
24
  redundant_unique_index: Simple::RedundantUniqueIndex,
25
25
  small_primary_key: Simple::SmallPrimaryKey,
26
- inconsistent_enum_type: Simple::InconsistentEnumType
26
+ inconsistent_enum_type: Simple::InconsistentEnumType,
27
+ missing_foreign_key_cascade: Simple::MissingForeignKeyCascade
27
28
  }.freeze
28
29
 
29
30
  def write
@@ -18,6 +18,7 @@ require 'database_consistency/writers/simple/default_message'
18
18
  require 'database_consistency/writers/simple/inconsistent_types'
19
19
  require 'database_consistency/writers/simple/null_constraint_association_misses_validator'
20
20
  require 'database_consistency/writers/simple/redundant_index'
21
+ require 'database_consistency/writers/simple/missing_foreign_key_cascade'
21
22
  require 'database_consistency/writers/simple/redundant_unique_index'
22
23
  require 'database_consistency/writers/simple/association_missing_index'
23
24
  require 'database_consistency/writers/simple/association_missing_null_constraint'
@@ -59,6 +60,7 @@ require 'database_consistency/checkers/association_checkers/association_checker'
59
60
  require 'database_consistency/checkers/association_checkers/missing_index_checker'
60
61
  require 'database_consistency/checkers/association_checkers/foreign_key_checker'
61
62
  require 'database_consistency/checkers/association_checkers/foreign_key_type_checker'
63
+ require 'database_consistency/checkers/association_checkers/foreign_key_cascade_checker'
62
64
 
63
65
  require 'database_consistency/checkers/column_checkers/column_checker'
64
66
  require 'database_consistency/checkers/column_checkers/null_constraint_checker'
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.4.0
4
+ version: 1.5.0
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-27 00:00:00.000000000 Z
11
+ date: 2022-11-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -147,6 +147,7 @@ files:
147
147
  - bin/database_consistency
148
148
  - lib/database_consistency.rb
149
149
  - lib/database_consistency/checkers/association_checkers/association_checker.rb
150
+ - lib/database_consistency/checkers/association_checkers/foreign_key_cascade_checker.rb
150
151
  - lib/database_consistency/checkers/association_checkers/foreign_key_checker.rb
151
152
  - lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb
152
153
  - lib/database_consistency/checkers/association_checkers/missing_index_checker.rb
@@ -211,6 +212,7 @@ files:
211
212
  - lib/database_consistency/writers/simple/length_validator_lower_limit.rb
212
213
  - lib/database_consistency/writers/simple/length_validator_missing.rb
213
214
  - lib/database_consistency/writers/simple/missing_foreign_key.rb
215
+ - lib/database_consistency/writers/simple/missing_foreign_key_cascade.rb
214
216
  - lib/database_consistency/writers/simple/missing_unique_index.rb
215
217
  - lib/database_consistency/writers/simple/missing_uniqueness_validation.rb
216
218
  - lib/database_consistency/writers/simple/null_constraint_association_misses_validator.rb