database_consistency 0.2.5 → 0.3.0
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 +4 -4
- data/lib/database_consistency/checkers/base_checker.rb +52 -0
- data/lib/database_consistency/checkers/null_constraint_checker.rb +66 -0
- data/lib/database_consistency/{comparators/presence_comparator.rb → checkers/presence_validation_checker.rb} +31 -12
- data/lib/database_consistency/configuration.rb +24 -5
- data/lib/database_consistency/helper.rb +2 -7
- data/lib/database_consistency/processors/base_processor.rb +33 -0
- data/lib/database_consistency/processors/models_processor.rb +28 -0
- data/lib/database_consistency/processors/tables_processor.rb +25 -0
- data/lib/database_consistency/version.rb +3 -1
- data/lib/database_consistency/writers/base_writer.rb +3 -1
- data/lib/database_consistency/writers/simple_writer.rb +5 -7
- data/lib/database_consistency.rb +11 -30
- metadata +8 -9
- data/lib/database_consistency/column_verifiers/base_verifier.rb +0 -23
- data/lib/database_consistency/column_verifiers/presence_missing_verifier.rb +0 -45
- data/lib/database_consistency/comparators/base_comparator.rb +0 -24
- data/lib/database_consistency/database_processor.rb +0 -18
- data/lib/database_consistency/report.rb +0 -17
- data/lib/database_consistency/validators_processor.rb +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0cb421a3fbd1c94df1816ecaf52487578c2a68c2aa13f384d1f80a9c68b35613
|
4
|
+
data.tar.gz: 5a38ad0d44e448e08e7474e74ecd0f934f0b9bf86e2fe43a80c2bb4540b154e8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a6195f162dac4165dd70ce10fddc1dde43527f2d3dd845f9a4f2f4b9f0def589ed125fbe5cce3a5e61eb80c91ccefb609de4bc42ea0dcbe4ff26edd556522884
|
7
|
+
data.tar.gz: 47ebc91829df9bc38a2f518b0b5d4b938a51d79d441984c257c9fa7429d12cc22d3d6184029396d29c0e422ac890c9311391ae9cbc6e2d052fae33e22694f11c
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DatabaseConsistency
|
4
|
+
module Checkers
|
5
|
+
# The base class for checkers
|
6
|
+
class BaseChecker
|
7
|
+
def initialize(table_or_model, column_or_attribute, opts = {})
|
8
|
+
@table_or_model = table_or_model
|
9
|
+
@column_or_attribute = column_or_attribute
|
10
|
+
@opts = opts
|
11
|
+
end
|
12
|
+
|
13
|
+
# @return [Hash]
|
14
|
+
def report
|
15
|
+
@report ||= check
|
16
|
+
end
|
17
|
+
|
18
|
+
# @param [DatabaseConsistency::Configuration] configuration
|
19
|
+
def enabled?(configuration)
|
20
|
+
configuration.enabled?(checker_name, table_or_model_name, column_or_attribute_name)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
attr_reader :table_or_model, :column_or_attribute, :opts
|
26
|
+
|
27
|
+
# @return [String]
|
28
|
+
def checker_name
|
29
|
+
@checker_name ||= self.class.name.split('::').last
|
30
|
+
end
|
31
|
+
|
32
|
+
def table_or_model_name
|
33
|
+
raise NotImplementedError
|
34
|
+
end
|
35
|
+
|
36
|
+
def column_or_attribute_name
|
37
|
+
raise NotImplementedError
|
38
|
+
end
|
39
|
+
|
40
|
+
# @return [Hash]
|
41
|
+
def report_template(status, message = nil)
|
42
|
+
OpenStruct.new(
|
43
|
+
checker_name: checker_name,
|
44
|
+
table_or_model_name: table_or_model_name,
|
45
|
+
column_or_attribute_name: column_or_attribute_name,
|
46
|
+
status: status,
|
47
|
+
message: message
|
48
|
+
)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DatabaseConsistency
|
4
|
+
module Checkers
|
5
|
+
# This class checks missing presence validator
|
6
|
+
class NullConstraintChecker < BaseChecker
|
7
|
+
# Message templates
|
8
|
+
VALIDATOR_MISSING = 'is required but do not have presence validator'
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
# Table of possible statuses
|
13
|
+
# | validation | database | status |
|
14
|
+
# | ---------- | -------- | ------ |
|
15
|
+
# | missed | required | fail |
|
16
|
+
#
|
17
|
+
# We skip check when:
|
18
|
+
# - column hasn't null constraint
|
19
|
+
# - column has default value
|
20
|
+
# - column is a primary key
|
21
|
+
# - column is a timestamp
|
22
|
+
# - presence validation exists
|
23
|
+
# - inclusion validation exists
|
24
|
+
# - belongs_to reflection exists with given column as foreign key or foreign type
|
25
|
+
def check
|
26
|
+
return if skip? ||
|
27
|
+
validator?(ActiveModel::Validations::PresenceValidator) ||
|
28
|
+
validator?(ActiveModel::Validations::InclusionValidator) ||
|
29
|
+
belongs_to_reflection?
|
30
|
+
|
31
|
+
report_template(:fail, VALIDATOR_MISSING)
|
32
|
+
end
|
33
|
+
|
34
|
+
def column_or_attribute_name
|
35
|
+
column_or_attribute.name.to_s
|
36
|
+
end
|
37
|
+
|
38
|
+
def table_or_model_name
|
39
|
+
table_or_model.name.to_s
|
40
|
+
end
|
41
|
+
|
42
|
+
def skip?
|
43
|
+
column_or_attribute.null ||
|
44
|
+
!column_or_attribute.default.nil? ||
|
45
|
+
column_or_attribute.name == table_or_model.primary_key ||
|
46
|
+
timestamp_field?
|
47
|
+
end
|
48
|
+
|
49
|
+
def timestamp_field?
|
50
|
+
table_or_model.record_timestamps? && %w[created_at updated_at].include?(column_or_attribute.name)
|
51
|
+
end
|
52
|
+
|
53
|
+
def validator?(validator_class)
|
54
|
+
table_or_model.validators.grep(validator_class).any? do |validator|
|
55
|
+
Helper.check_inclusion?(validator.attributes, column_or_attribute.name)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def belongs_to_reflection?
|
60
|
+
table_or_model.reflect_on_all_associations.grep(ActiveRecord::Reflection::BelongsToReflection).any? do |r|
|
61
|
+
Helper.check_inclusion?([r.foreign_key, r.foreign_type], column_or_attribute.name)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -1,11 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module DatabaseConsistency
|
2
|
-
module
|
3
|
-
#
|
4
|
-
class
|
4
|
+
module Checkers
|
5
|
+
# This class checks PresenceValidator
|
6
|
+
class PresenceValidationChecker < BaseChecker
|
5
7
|
WEAK_OPTIONS = %i[allow_nil allow_blank if unless].freeze
|
6
8
|
# Message templates
|
7
|
-
CONSTRAINT_MISSING = 'should be required in the database'
|
8
|
-
POSSIBLE_NULL = 'is required but possible null value insert'
|
9
|
+
CONSTRAINT_MISSING = 'should be required in the database'
|
10
|
+
POSSIBLE_NULL = 'is required but possible null value insert'
|
11
|
+
|
12
|
+
private
|
9
13
|
|
10
14
|
# Table of possible statuses
|
11
15
|
# | allow_nil/allow_blank/if/unless | database | status |
|
@@ -14,23 +18,38 @@ module DatabaseConsistency
|
|
14
18
|
# | at least one provided | optional | ok |
|
15
19
|
# | all missed | required | ok |
|
16
20
|
# | all missed | optional | fail |
|
17
|
-
|
21
|
+
#
|
22
|
+
# We skip check when:
|
23
|
+
# - there is no column in the database with given name
|
24
|
+
def check
|
25
|
+
return unless column
|
26
|
+
|
18
27
|
can_be_null = column.null
|
19
28
|
has_weak_option = validator.options.slice(*WEAK_OPTIONS).any?
|
20
29
|
|
21
30
|
if can_be_null == has_weak_option
|
22
|
-
|
31
|
+
report_template(:ok)
|
23
32
|
elsif can_be_null
|
24
|
-
|
33
|
+
report_template(:fail, CONSTRAINT_MISSING)
|
25
34
|
else
|
26
|
-
|
35
|
+
report_template(:fail, POSSIBLE_NULL)
|
27
36
|
end
|
28
37
|
end
|
29
38
|
|
30
|
-
|
39
|
+
def column
|
40
|
+
@column ||= Helper.find_field(table_or_model, column_or_attribute.to_s)
|
41
|
+
end
|
42
|
+
|
43
|
+
def column_or_attribute_name
|
44
|
+
column_or_attribute.to_s
|
45
|
+
end
|
46
|
+
|
47
|
+
def table_or_model_name
|
48
|
+
table_or_model.name.to_s
|
49
|
+
end
|
31
50
|
|
32
|
-
def
|
33
|
-
|
51
|
+
def validator
|
52
|
+
opts[:validator]
|
34
53
|
end
|
35
54
|
end
|
36
55
|
end
|
@@ -1,19 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'yaml'
|
2
4
|
|
3
5
|
module DatabaseConsistency
|
4
6
|
# The class to access configuration options
|
5
7
|
class Configuration
|
6
|
-
|
7
|
-
|
8
|
+
CONFIGURATION_PATH = '.database_consistency.yml'
|
9
|
+
|
10
|
+
def initialize(filepath = CONFIGURATION_PATH)
|
11
|
+
@configuration = if filepath && File.exist?(filepath)
|
8
12
|
YAML.load_file(filepath)
|
9
13
|
else
|
10
14
|
{}
|
11
15
|
end
|
12
16
|
end
|
13
17
|
|
14
|
-
|
15
|
-
|
16
|
-
|
18
|
+
# @return [Boolean]
|
19
|
+
def enabled?(*path)
|
20
|
+
current = configuration
|
21
|
+
|
22
|
+
path.each do |key|
|
23
|
+
current = current[key.to_s]
|
24
|
+
return true unless current.is_a?(Hash)
|
25
|
+
|
26
|
+
next if current['enabled'].nil?
|
27
|
+
|
28
|
+
return false unless current['enabled']
|
29
|
+
end
|
30
|
+
|
31
|
+
true
|
17
32
|
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
attr_reader :configuration
|
18
37
|
end
|
19
38
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module DatabaseConsistency
|
2
4
|
# The module contains helper methods
|
3
5
|
module Helper
|
@@ -25,13 +27,6 @@ module DatabaseConsistency
|
|
25
27
|
model.columns.select.find { |field| field.name == attribute }
|
26
28
|
end
|
27
29
|
|
28
|
-
# @return [String]
|
29
|
-
def message(model, column, template = nil)
|
30
|
-
str = "column #{column.name} of table #{model.table_name} of model #{model.name}"
|
31
|
-
str += " #{template}" if template
|
32
|
-
str
|
33
|
-
end
|
34
|
-
|
35
30
|
# @return [Boolean]
|
36
31
|
def check_inclusion?(array, element)
|
37
32
|
array.include?(element.to_s) || array.include?(element.to_sym)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DatabaseConsistency
|
4
|
+
# The module for processors
|
5
|
+
module Processors
|
6
|
+
def self.reports(configuration)
|
7
|
+
[ModelsProcessor, TablesProcessor].flat_map do |processor|
|
8
|
+
processor.new(configuration).reports
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# The base class for processors
|
13
|
+
class BaseProcessor
|
14
|
+
attr_reader :configuration
|
15
|
+
|
16
|
+
# @param [DatabaseConsistency::Configuration] configuration
|
17
|
+
def initialize(configuration = nil)
|
18
|
+
@configuration = configuration || Configuration.new
|
19
|
+
end
|
20
|
+
|
21
|
+
# @return [Array<Hash>]
|
22
|
+
def reports
|
23
|
+
@reports ||= check
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def check
|
29
|
+
raise NotImplementedError
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DatabaseConsistency
|
4
|
+
module Processors
|
5
|
+
# The class to process all comparators
|
6
|
+
class ModelsProcessor < BaseProcessor
|
7
|
+
CHECKERS = {
|
8
|
+
presence: Checkers::PresenceValidationChecker
|
9
|
+
}.freeze
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
# @return [Array<Hash>]
|
14
|
+
def check
|
15
|
+
Helper.parent_models.flat_map do |model|
|
16
|
+
model.validators.flat_map do |validator|
|
17
|
+
next unless (checker_class = CHECKERS[validator.kind])
|
18
|
+
|
19
|
+
validator.attributes.map do |attribute|
|
20
|
+
checker = checker_class.new(model, attribute, validator: validator)
|
21
|
+
checker.report if checker.enabled?(configuration)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end.compact
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DatabaseConsistency
|
4
|
+
module Processors
|
5
|
+
# The class to process missing validators
|
6
|
+
class TablesProcessor < BaseProcessor
|
7
|
+
CHECKERS = [
|
8
|
+
Checkers::NullConstraintChecker
|
9
|
+
].freeze
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def check
|
14
|
+
Helper.parent_models.flat_map do |model|
|
15
|
+
model.columns.flat_map do |column|
|
16
|
+
CHECKERS.map do |checker_class|
|
17
|
+
checker = checker_class.new(model, column)
|
18
|
+
checker.report if checker.enabled?(configuration)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end.compact
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module DatabaseConsistency
|
2
4
|
module Writers
|
3
5
|
# The base class for writers
|
@@ -10,7 +12,7 @@ module DatabaseConsistency
|
|
10
12
|
end
|
11
13
|
|
12
14
|
def write?(status)
|
13
|
-
status == :fail
|
15
|
+
status == :fail || debug?
|
14
16
|
end
|
15
17
|
|
16
18
|
def debug?
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module DatabaseConsistency
|
2
4
|
# The module contains formatters
|
3
5
|
module Writers
|
@@ -12,16 +14,12 @@ module DatabaseConsistency
|
|
12
14
|
next unless write?(result[:status])
|
13
15
|
|
14
16
|
line(result)
|
15
|
-
end.tap(&:compact!).map(&:lstrip).delete_if(&:empty?).join(
|
16
|
-
end
|
17
|
-
|
18
|
-
def delimiter
|
19
|
-
debug? ? "\n\n" : "\n"
|
17
|
+
end.tap(&:compact!).map(&:lstrip).delete_if(&:empty?).join("\n")
|
20
18
|
end
|
21
19
|
|
22
20
|
def line(result)
|
23
|
-
"#{result
|
24
|
-
|
21
|
+
"#{result.status} #{result.table_or_model_name} #{result.column_or_attribute_name} #{result.message}".tap do |s|
|
22
|
+
s.concat " (checker: #{result.checker_name})" if debug?
|
25
23
|
end
|
26
24
|
end
|
27
25
|
end
|
data/lib/database_consistency.rb
CHANGED
@@ -1,34 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_record'
|
2
4
|
|
3
5
|
require 'database_consistency/version'
|
4
|
-
require 'database_consistency/report'
|
5
6
|
require 'database_consistency/helper'
|
6
7
|
require 'database_consistency/configuration'
|
7
8
|
|
8
9
|
require 'database_consistency/writers/base_writer'
|
9
10
|
require 'database_consistency/writers/simple_writer'
|
10
11
|
|
11
|
-
require 'database_consistency/
|
12
|
-
require 'database_consistency/
|
13
|
-
require 'database_consistency/
|
12
|
+
require 'database_consistency/checkers/base_checker'
|
13
|
+
require 'database_consistency/checkers/presence_validation_checker'
|
14
|
+
require 'database_consistency/checkers/null_constraint_checker'
|
14
15
|
|
15
|
-
require 'database_consistency/
|
16
|
-
require 'database_consistency/
|
17
|
-
require 'database_consistency/
|
16
|
+
require 'database_consistency/processors/base_processor'
|
17
|
+
require 'database_consistency/processors/models_processor'
|
18
|
+
require 'database_consistency/processors/tables_processor'
|
18
19
|
|
19
20
|
# The root module
|
20
21
|
module DatabaseConsistency
|
21
|
-
CONFIGURATION_PATH = '.database_consistency.yml'.freeze
|
22
|
-
|
23
|
-
PROCESSORS = [
|
24
|
-
ValidatorsProcessor,
|
25
|
-
DatabaseProcessor
|
26
|
-
].freeze
|
27
|
-
|
28
22
|
class << self
|
29
23
|
def run
|
30
24
|
Helper.load_environment!
|
31
25
|
|
26
|
+
configuration = Configuration.new
|
27
|
+
reports = Processors.reports(configuration)
|
28
|
+
|
32
29
|
Writers::SimpleWriter.write(
|
33
30
|
reports,
|
34
31
|
ENV['LOG_LEVEL'] || 'INFO'
|
@@ -36,21 +33,5 @@ module DatabaseConsistency
|
|
36
33
|
|
37
34
|
reports.empty? ? 0 : 1
|
38
35
|
end
|
39
|
-
|
40
|
-
def enabled_processors
|
41
|
-
@enabled_processors ||= PROCESSORS.select { |processor| configuration.enabled?(processor) }
|
42
|
-
end
|
43
|
-
|
44
|
-
def reports
|
45
|
-
@reports ||= enabled_processors.map(&:new).flat_map(&:reports)
|
46
|
-
end
|
47
|
-
|
48
|
-
def configuration
|
49
|
-
@configuration ||= if File.exist?(CONFIGURATION_PATH)
|
50
|
-
Configuration.new(CONFIGURATION_PATH)
|
51
|
-
else
|
52
|
-
Configuration.new
|
53
|
-
end
|
54
|
-
end
|
55
36
|
end
|
56
37
|
end
|
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: 0.
|
4
|
+
version: 0.3.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:
|
11
|
+
date: 2019-01-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -110,15 +110,14 @@ extra_rdoc_files: []
|
|
110
110
|
files:
|
111
111
|
- bin/database_consistency
|
112
112
|
- lib/database_consistency.rb
|
113
|
-
- lib/database_consistency/
|
114
|
-
- lib/database_consistency/
|
115
|
-
- lib/database_consistency/
|
116
|
-
- lib/database_consistency/comparators/presence_comparator.rb
|
113
|
+
- lib/database_consistency/checkers/base_checker.rb
|
114
|
+
- lib/database_consistency/checkers/null_constraint_checker.rb
|
115
|
+
- lib/database_consistency/checkers/presence_validation_checker.rb
|
117
116
|
- lib/database_consistency/configuration.rb
|
118
|
-
- lib/database_consistency/database_processor.rb
|
119
117
|
- lib/database_consistency/helper.rb
|
120
|
-
- lib/database_consistency/
|
121
|
-
- lib/database_consistency/
|
118
|
+
- lib/database_consistency/processors/base_processor.rb
|
119
|
+
- lib/database_consistency/processors/models_processor.rb
|
120
|
+
- lib/database_consistency/processors/tables_processor.rb
|
122
121
|
- lib/database_consistency/version.rb
|
123
122
|
- lib/database_consistency/writers/base_writer.rb
|
124
123
|
- lib/database_consistency/writers/simple_writer.rb
|
@@ -1,23 +0,0 @@
|
|
1
|
-
module DatabaseConsistency
|
2
|
-
module ColumnVerifiers
|
3
|
-
# The base class for column verifiers
|
4
|
-
class BaseVerifier
|
5
|
-
attr_reader :model, :column
|
6
|
-
|
7
|
-
delegate :result, to: :report
|
8
|
-
|
9
|
-
def initialize(model, column)
|
10
|
-
@model = model
|
11
|
-
@column = column
|
12
|
-
end
|
13
|
-
|
14
|
-
def report
|
15
|
-
Report.new(column: column)
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.verify(model, column)
|
19
|
-
new(model, column).verify
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
module DatabaseConsistency
|
2
|
-
module ColumnVerifiers
|
3
|
-
# This class verifies that column needs a presence validator
|
4
|
-
class PresenceMissingVerifier < BaseVerifier
|
5
|
-
VALIDATOR_MISSING = 'is required but do not have presence validator'.freeze
|
6
|
-
|
7
|
-
def verify
|
8
|
-
return if skip? || presence_validator? || inclusion_validator? || belongs_to_reflection?
|
9
|
-
|
10
|
-
result(:fail, Helper.message(model, column, VALIDATOR_MISSING))
|
11
|
-
end
|
12
|
-
|
13
|
-
private
|
14
|
-
|
15
|
-
def skip?
|
16
|
-
column.null ||
|
17
|
-
!column.default.nil? ||
|
18
|
-
column.name == model.primary_key ||
|
19
|
-
timestamp_field?
|
20
|
-
end
|
21
|
-
|
22
|
-
def timestamp_field?
|
23
|
-
model.record_timestamps? && %w[created_at updated_at].include?(column.name)
|
24
|
-
end
|
25
|
-
|
26
|
-
def presence_validator?
|
27
|
-
model.validators.grep(ActiveModel::Validations::PresenceValidator).any? do |validator|
|
28
|
-
Helper.check_inclusion?(validator.attributes, column.name)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def inclusion_validator?
|
33
|
-
model.validators.grep(ActiveModel::Validations::InclusionValidator).any? do |validator|
|
34
|
-
Helper.check_inclusion?(validator.attributes, column.name)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def belongs_to_reflection?
|
39
|
-
model.reflect_on_all_associations.grep(ActiveRecord::Reflection::BelongsToReflection).any? do |reflection|
|
40
|
-
Helper.check_inclusion?([reflection.foreign_key, reflection.foreign_type], column.name)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
module DatabaseConsistency
|
2
|
-
module Comparators
|
3
|
-
# The base class for comparators
|
4
|
-
class BaseComparator
|
5
|
-
attr_reader :validator, :model, :column
|
6
|
-
|
7
|
-
delegate :result, to: :report
|
8
|
-
|
9
|
-
def initialize(validator, model, column)
|
10
|
-
@validator = validator
|
11
|
-
@model = model
|
12
|
-
@column = column
|
13
|
-
end
|
14
|
-
|
15
|
-
def report
|
16
|
-
Report.new(validator: validator, column: column)
|
17
|
-
end
|
18
|
-
|
19
|
-
def self.compare(validator, model, column)
|
20
|
-
new(validator, model, column).compare
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
module DatabaseConsistency
|
2
|
-
# The class to process missing validators
|
3
|
-
class DatabaseProcessor
|
4
|
-
VERIFIERS = [
|
5
|
-
ColumnVerifiers::PresenceMissingVerifier
|
6
|
-
].freeze
|
7
|
-
|
8
|
-
def reports
|
9
|
-
Helper.parent_models.flat_map do |model|
|
10
|
-
model.columns.flat_map do |column|
|
11
|
-
VERIFIERS.map do |verifier|
|
12
|
-
verifier.verify(model, column)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end.compact
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
module DatabaseConsistency
|
2
|
-
# This class outputs the report result
|
3
|
-
class Report
|
4
|
-
attr_reader :opts
|
5
|
-
|
6
|
-
def initialize(opts = {})
|
7
|
-
@opts = opts
|
8
|
-
end
|
9
|
-
|
10
|
-
def result(status, message)
|
11
|
-
{
|
12
|
-
status: status,
|
13
|
-
message: message
|
14
|
-
}.tap { |hash| hash[:opts] = opts unless opts.empty? }
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
module DatabaseConsistency
|
2
|
-
# The class to process all comparators
|
3
|
-
class ValidatorsProcessor
|
4
|
-
COMPARATORS = {
|
5
|
-
presence: DatabaseConsistency::Comparators::PresenceComparator
|
6
|
-
}.freeze
|
7
|
-
|
8
|
-
def reports
|
9
|
-
Helper.parent_models.flat_map do |model|
|
10
|
-
model.validators.flat_map do |validator|
|
11
|
-
next unless (comparator = COMPARATORS[validator.kind])
|
12
|
-
|
13
|
-
validator.attributes.map do |attribute|
|
14
|
-
next unless (column = Helper.find_field(model, attribute.to_s))
|
15
|
-
|
16
|
-
comparator.compare(validator, model, column)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end.compact
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|