database_consistency 1.3.4 → 1.3.5

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: 1f1aad5cf1e4812b31d9bc7df0402f64dd32bb7ebdb9ab4ec7bf41bb195622dc
4
- data.tar.gz: 1fc95e58bd89e9faf0004d7faf5cc2635d5432785d2e1a57d9965e413abf4c41
3
+ metadata.gz: 8f935ca51faca06dad689d217e897a035253f4ce9884f1826befdf1bcbbee3b5
4
+ data.tar.gz: 38bde32ffee8b05b04bc8a1af261764f967b64f322352ef8d79729f1de485e13
5
5
  SHA512:
6
- metadata.gz: 6d5d98750608c54e20a5f6990b54c37df89717d7009d46b099b62695b90c2a29ab44f35dab299c1e3e0f83ff4d77f5709e6a42aa7130190fcbb1807b5a6628b9
7
- data.tar.gz: ff7a4d0fa92518ed33393c8e1614852ef9ec168ee5a4ac857a653881a268511ad877b982633553e7341ce8a740dbf7ae402002e991210784614e397dbe07ed36
6
+ metadata.gz: 2352fa358c91e6dbec9a22c9abac34fb27b45e662c1402e88cfe94864b7bfa4966628f246a6f6f5d6c6af323e1320a3fe03c74df644f86ec6d14e4bde7c81962
7
+ data.tar.gz: ad812a3ce4c8d4d0a7d24d9031815a26ae2c32bfca6d0721430f3c31f01d8c5910f4af091fb7d088e4860d65d887ba0a27531bdd0d8aefc50b589a944ef29290
@@ -4,17 +4,21 @@ 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
- end
18
22
 
19
23
  private
20
24
 
@@ -37,9 +41,11 @@ module DatabaseConsistency
37
41
  # | ------------- | ------ |
38
42
  # | covers | ok |
39
43
  # | doesn't cover | fail |
40
- def check # rubocop:disable Metrics/MethodLength
44
+ def check # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
41
45
  if converted_type(associated_column).cover?(converted_type(primary_column))
42
46
  report_template(:ok)
47
+ elsif !(converted_type(associated_column).numeric? && converted_type(primary_column).numeric?)
48
+ report_template(:ok)
43
49
  else
44
50
  report_template(:fail, error_slug: :inconsistent_types)
45
51
  end
@@ -52,11 +58,13 @@ module DatabaseConsistency
52
58
  )
53
59
  end
54
60
 
55
- def report_template(status, error_slug: nil)
61
+ def report_template(status, error_slug: nil) # rubocop:disable Metrics/MethodLength
56
62
  Report.new(
57
63
  status: status,
58
64
  error_slug: error_slug,
59
65
  error_message: nil,
66
+ table_to_change: table_to_change,
67
+ type_to_set: converted_type(primary_column).convert,
60
68
  fk_type: converted_type(associated_column).type,
61
69
  fk_name: associated_key,
62
70
  pk_type: converted_type(primary_column).type,
@@ -65,6 +73,14 @@ module DatabaseConsistency
65
73
  )
66
74
  end
67
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
+
68
84
  # @return [String]
69
85
  def primary_key
70
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
@@ -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|
@@ -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
 
@@ -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]
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DatabaseConsistency
4
- VERSION = '1.3.4'
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
@@ -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,11 +6,16 @@ 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
16
  redundant_index: Autofix::RedundantIndex,
13
- redundant_unique_index: Autofix::RedundantIndex
17
+ redundant_unique_index: Autofix::RedundantIndex,
18
+ small_primary_key: Autofix::InconsistentTypes
14
19
  }.freeze
15
20
 
16
21
  def write
@@ -6,23 +6,23 @@ module DatabaseConsistency
6
6
  # The simplest formatter
7
7
  class SimpleWriter < BaseWriter
8
8
  SLUG_TO_WRITER = {
9
- missing_foreign_key: Simple::Base.with('should have foreign key in the database'),
10
- inconsistent_types: Simple::InconsistentTypes,
11
- has_one_missing_unique_index: Simple::Base.with('associated model should have proper unique index in the database'), # rubocop:disable Layout/LineLength
12
9
  association_missing_index: Simple::Base.with('associated model should have proper index in the database'),
13
- length_validator_missing: Simple::Base.with('column has limit in the database but do not have length validator'), # rubocop:disable Layout/LineLength
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,
14
13
  length_validator_greater_limit: Simple::Base.with('column has greater limit in the database than in length validator'), # rubocop:disable Layout/LineLength
15
14
  length_validator_lower_limit: Simple::Base.with('column has lower limit in the database than in length validator'), # rubocop:disable Layout/LineLength
16
- null_constraint_misses_validator: Simple::Base.with('column is required in the database but do not have presence validator'), # rubocop:disable Layout/LineLength
17
- small_primary_key: Simple::Base.with('column has int/serial type but recommended to have bigint/bigserial/uuid'), # rubocop:disable Layout/LineLength
18
- missing_uniqueness_validation: Simple::Base.with('index is unique in the database but do not have uniqueness 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'),
19
17
  missing_unique_index: Simple::Base.with('model should have proper unique index in the database'),
20
- possible_null: Simple::Base.with('column is required but there is possible null value insert'),
21
- null_constraint_missing: Simple::Base.with('column should be required in the database'),
22
- association_missing_null_constraint: Simple::Base.with('association foreign key column should be required in the database'), # rubocop:disable Layout/LineLength
18
+ missing_uniqueness_validation: Simple::Base.with('index is unique in the database but do not have uniqueness validator'), # rubocop:disable Layout/LineLength
23
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'),
24
23
  redundant_index: Simple::RedundantIndex,
25
- redundant_unique_index: Simple::RedundantUniqueIndex
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')
26
26
  }.freeze
27
27
 
28
28
  def write
@@ -24,6 +24,9 @@ require 'database_consistency/writers/autofix/helpers/migration'
24
24
  require 'database_consistency/writers/autofix/base'
25
25
  require 'database_consistency/writers/autofix/migration_base'
26
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'
27
30
  require 'database_consistency/writers/autofix/redundant_index'
28
31
  require 'database_consistency/writers/autofix/null_constraint_missing'
29
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.4
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,12 +179,18 @@ 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