database_consistency 0.1.0 → 0.2.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: 814513a9fa9c4a886a0181cbb09e71fb35ed3ec722404746f827fe754067df01
4
- data.tar.gz: 1638aee8d2c92c761905e6a0b433581d6f996bb3f7c871dc2a75c84956cbb12c
3
+ metadata.gz: c50d282f04ae0e4003a596551369213ea66ee986a6f2486a3761ec36af6d87b3
4
+ data.tar.gz: 14141f85bb9ced24c2cf4fe69d2ace3a0aa0218e4f181846d2c0dfcf88569d9d
5
5
  SHA512:
6
- metadata.gz: 47ef92e9038f22b807588f560e3c66f95a776e8c07b47633b8f6352935ffdb2bf8e22e6f21178b9ca1a946d84ab345fb4fdf600f2d69bed5935bdf7c5e328eea
7
- data.tar.gz: feb38ceb958dc96139b4cca1a3dd70d884c4955203227a0f4d7402ee7d3c0128983c3205f414590829eae508a9d412cd2fd67a80c955b318a327b50cb2b6189f
6
+ metadata.gz: 90577c3faf083a0c694ac8d1146d5980e7ff69df6be7578cb57069bf62a4bc3455c2f8b4a639ccae2b75f8db8473c3c5e1733e407ca0e3292a5610062e48313b
7
+ data.tar.gz: 1d638396701af3be6591db67d5782cae92d4af14fb38a4a076834836b2b7988772ee053056247d56984f2830185dd9b7703464efabec21d99e8674b112b0abfa
@@ -0,0 +1,23 @@
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
@@ -0,0 +1,26 @@
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
+ result(:fail, Helper.message(column, VALIDATOR_MISSING)) unless skip? || validator?
9
+ end
10
+
11
+ private
12
+
13
+ def skip?
14
+ column.null ||
15
+ column.name == model.primary_key ||
16
+ (model.record_timestamps? && %w[created_at updated_at].include?(column.name))
17
+ end
18
+
19
+ def validator?
20
+ model.validators.grep(ActiveModel::Validations::PresenceValidator).any? do |validator|
21
+ validator.attributes.include?(column.name) || validator.attributes.include?(column.name.to_sym)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -4,17 +4,15 @@ module DatabaseConsistency
4
4
  class BaseComparator
5
5
  attr_reader :validator, :column
6
6
 
7
- delegate :result, to: :comparison
8
-
9
- private_class_method :new
7
+ delegate :result, to: :report
10
8
 
11
9
  def initialize(validator, column)
12
10
  @validator = validator
13
11
  @column = column
14
12
  end
15
13
 
16
- def comparison
17
- Comparison.for(validator, column)
14
+ def report
15
+ Report.new(validator: validator, column: column)
18
16
  end
19
17
 
20
18
  def self.compare(validator, column)
@@ -3,8 +3,9 @@ module DatabaseConsistency
3
3
  # The comparator class for {{ActiveModel::Validations::PresenceValidator}}
4
4
  class PresenceComparator < BaseComparator
5
5
  WEAK_OPTIONS = %i[allow_nil allow_blank if unless].freeze
6
- CONSTRAINT_MISSING = 'database field should have: "null: false"'.freeze
7
- POSSIBLE_NULL = 'possible null value insert'.freeze
6
+ # Message templates
7
+ CONSTRAINT_MISSING = 'should be required in the database'.freeze
8
+ POSSIBLE_NULL = 'is required but possible null value insert'.freeze
8
9
 
9
10
  # Table of possible statuses
10
11
  # | allow_nil/allow_blank/if/unless | database | status |
@@ -18,13 +19,19 @@ module DatabaseConsistency
18
19
  has_weak_option = validator.options.slice(*WEAK_OPTIONS).any?
19
20
 
20
21
  if can_be_null == has_weak_option
21
- result(:ok)
22
+ result(:ok, message)
22
23
  elsif can_be_null
23
- result(:fail, CONSTRAINT_MISSING)
24
+ result(:fail, message(CONSTRAINT_MISSING))
24
25
  else
25
- result(:fail, POSSIBLE_NULL)
26
+ result(:fail, message(POSSIBLE_NULL))
26
27
  end
27
28
  end
29
+
30
+ private
31
+
32
+ def message(template = nil)
33
+ Helper.message(column, template)
34
+ end
28
35
  end
29
36
  end
30
37
  end
@@ -0,0 +1,18 @@
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.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
@@ -17,5 +17,12 @@ module DatabaseConsistency
17
17
  def find_field(model, attribute)
18
18
  model.columns.select.find { |field| field.name == attribute }
19
19
  end
20
+
21
+ # @return [String]
22
+ def message(column, template = nil)
23
+ str = "column #{column.name} of table #{column.table_name}"
24
+ str += " #{template}" if template
25
+ str
26
+ end
20
27
  end
21
28
  end
@@ -0,0 +1,17 @@
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,13 +1,13 @@
1
1
  module DatabaseConsistency
2
- # The class to begin
3
- class Processor
2
+ # The class to process all comparators
3
+ class ValidatorsProcessor
4
4
  COMPARATORS = {
5
5
  presence: DatabaseConsistency::Comparators::PresenceComparator
6
6
  }.freeze
7
7
 
8
- def comparisons
9
- Helper.models.each_with_object({}) do |model, hash|
10
- hash[model.name] = model.validators.flat_map do |validator|
8
+ def reports
9
+ Helper.models.flat_map do |model|
10
+ model.validators.flat_map do |validator|
11
11
  next unless (comparator = COMPARATORS[validator.kind])
12
12
 
13
13
  validator.attributes.map do |attribute|
@@ -15,8 +15,8 @@ module DatabaseConsistency
15
15
 
16
16
  comparator.compare(validator, column)
17
17
  end
18
- end.compact
19
- end
18
+ end
19
+ end.compact
20
20
  end
21
21
  end
22
22
  end
@@ -1,3 +1,3 @@
1
1
  module DatabaseConsistency
2
- VERSION = '0.1.0'.freeze
2
+ VERSION = '0.2.0'.freeze
3
3
  end
@@ -10,7 +10,11 @@ module DatabaseConsistency
10
10
  end
11
11
 
12
12
  def write?(status)
13
- status == :fail || log_level == 'DEBUG'
13
+ status == :fail
14
+ end
15
+
16
+ def debug?
17
+ log_level == 'DEBUG'
14
18
  end
15
19
 
16
20
  def self.write(results, log_level)
@@ -8,18 +8,20 @@ module DatabaseConsistency
8
8
  end
9
9
 
10
10
  def format
11
- results.map do |model_name, comparisons|
12
- comparisons.map do |comparison|
13
- next unless write?(comparison[:status])
14
- line(model_name, comparison)
15
- end.tap(&:compact!).map(&:lstrip).join("\n")
16
- end.join("\n")
11
+ results.map do |result|
12
+ next unless write?(result[:status])
13
+ line(result)
14
+ end.tap(&:compact!).map(&:lstrip).delete_if(&:empty?).join(delimiter)
17
15
  end
18
16
 
19
- def line(model_name, comparison)
20
- <<-TEXT
21
- #{comparison[:status]} #{comparison[:message]} #{model_name} #{comparison[:validator].inspect} #{comparison[:column].inspect}
22
- TEXT
17
+ def delimiter
18
+ debug? ? "\n\n" : "\n"
19
+ end
20
+
21
+ def line(result)
22
+ "#{result[:status]} #{result[:message]}".tap do |str|
23
+ str.concat " #{result[:opts].inspect}" if debug?
24
+ end
23
25
  end
24
26
  end
25
27
  end
@@ -1,21 +1,32 @@
1
1
  require 'active_record'
2
2
 
3
3
  require 'database_consistency/version'
4
+ require 'database_consistency/report'
5
+ require 'database_consistency/helper'
6
+
4
7
  require 'database_consistency/writers/base_writer'
5
8
  require 'database_consistency/writers/simple_writer'
6
- require 'database_consistency/comparison'
7
- require 'database_consistency/helper'
9
+
8
10
  require 'database_consistency/comparators/base_comparator'
9
11
  require 'database_consistency/comparators/presence_comparator'
10
- require 'database_consistency/processor'
12
+ require 'database_consistency/validators_processor'
13
+
14
+ require 'database_consistency/column_verifiers/base_verifier'
15
+ require 'database_consistency/column_verifiers/presence_missing_verifier'
16
+ require 'database_consistency/database_processor'
11
17
 
12
18
  # The root module
13
19
  module DatabaseConsistency
14
20
  def self.run
15
21
  Helper.load_environment!
16
22
 
23
+ reports = [
24
+ ValidatorsProcessor.new,
25
+ DatabaseProcessor.new
26
+ ].flat_map(&:reports)
27
+
17
28
  Writers::SimpleWriter.write(
18
- Processor.new.comparisons,
29
+ reports,
19
30
  ENV['LOG_LEVEL'] || 'INFO'
20
31
  )
21
32
  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.1.0
4
+ version: 0.2.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: 2018-10-30 00:00:00.000000000 Z
11
+ date: 2018-10-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -110,11 +110,14 @@ extra_rdoc_files: []
110
110
  files:
111
111
  - bin/database_consistency
112
112
  - lib/database_consistency.rb
113
+ - lib/database_consistency/column_verifiers/base_verifier.rb
114
+ - lib/database_consistency/column_verifiers/presence_missing_verifier.rb
113
115
  - lib/database_consistency/comparators/base_comparator.rb
114
116
  - lib/database_consistency/comparators/presence_comparator.rb
115
- - lib/database_consistency/comparison.rb
117
+ - lib/database_consistency/database_processor.rb
116
118
  - lib/database_consistency/helper.rb
117
- - lib/database_consistency/processor.rb
119
+ - lib/database_consistency/report.rb
120
+ - lib/database_consistency/validators_processor.rb
118
121
  - lib/database_consistency/version.rb
119
122
  - lib/database_consistency/writers/base_writer.rb
120
123
  - lib/database_consistency/writers/simple_writer.rb
@@ -1,25 +0,0 @@
1
- module DatabaseConsistency
2
- # This class outputs the comparison result
3
- class Comparison
4
- attr_reader :validator, :column
5
-
6
- private_class_method :new
7
-
8
- def initialize(validator, column)
9
- @validator = validator
10
- @column = column
11
- end
12
-
13
- def result(status, message = nil)
14
- {
15
- column: column,
16
- validator: validator,
17
- status: status
18
- }.tap { |hash| hash[:message] = message if message }
19
- end
20
-
21
- def self.for(validator, column)
22
- new(validator, column)
23
- end
24
- end
25
- end