database_consistency 0.1.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 +7 -0
- data/bin/database_consistency +20 -0
- data/lib/database_consistency/comparators/base_comparator.rb +25 -0
- data/lib/database_consistency/comparators/presence_comparator.rb +30 -0
- data/lib/database_consistency/comparison.rb +25 -0
- data/lib/database_consistency/helper.rb +21 -0
- data/lib/database_consistency/processor.rb +22 -0
- data/lib/database_consistency/version.rb +3 -0
- data/lib/database_consistency/writers/base_writer.rb +21 -0
- data/lib/database_consistency/writers/simple_writer.rb +26 -0
- data/lib/database_consistency.rb +22 -0
- metadata +146 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 814513a9fa9c4a886a0181cbb09e71fb35ed3ec722404746f827fe754067df01
|
4
|
+
data.tar.gz: 1638aee8d2c92c761905e6a0b433581d6f996bb3f7c871dc2a75c84956cbb12c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 47ef92e9038f22b807588f560e3c66f95a776e8c07b47633b8f6352935ffdb2bf8e22e6f21178b9ca1a946d84ab345fb4fdf600f2d69bed5935bdf7c5e328eea
|
7
|
+
data.tar.gz: feb38ceb958dc96139b4cca1a3dd70d884c4955203227a0f4d7402ee7d3c0128983c3205f414590829eae508a9d412cd2fd67a80c955b318a327b50cb2b6189f
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
base_dir = File.join(Dir.pwd, ARGV.first.to_s)
|
4
|
+
|
5
|
+
unless File.realpath(base_dir).start_with?(Dir.pwd)
|
6
|
+
puts "\nWarning! You are going out of current directory, ruby version may be wrong and some gems may be missing.\n"
|
7
|
+
end
|
8
|
+
|
9
|
+
begin
|
10
|
+
require File.join(base_dir, 'config', 'boot')
|
11
|
+
require File.join(base_dir, 'config', 'environment')
|
12
|
+
rescue LoadError
|
13
|
+
puts "\nUh-oh! You must be in the root directory of a Rails project.\n"
|
14
|
+
raise
|
15
|
+
end
|
16
|
+
|
17
|
+
$LOAD_PATH.unshift(File.expand_path('lib', __dir__))
|
18
|
+
require 'database_consistency'
|
19
|
+
|
20
|
+
DatabaseConsistency.run
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module DatabaseConsistency
|
2
|
+
module Comparators
|
3
|
+
# The base class for comparators
|
4
|
+
class BaseComparator
|
5
|
+
attr_reader :validator, :column
|
6
|
+
|
7
|
+
delegate :result, to: :comparison
|
8
|
+
|
9
|
+
private_class_method :new
|
10
|
+
|
11
|
+
def initialize(validator, column)
|
12
|
+
@validator = validator
|
13
|
+
@column = column
|
14
|
+
end
|
15
|
+
|
16
|
+
def comparison
|
17
|
+
Comparison.for(validator, column)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.compare(validator, column)
|
21
|
+
new(validator, column).compare
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module DatabaseConsistency
|
2
|
+
module Comparators
|
3
|
+
# The comparator class for {{ActiveModel::Validations::PresenceValidator}}
|
4
|
+
class PresenceComparator < BaseComparator
|
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
|
8
|
+
|
9
|
+
# Table of possible statuses
|
10
|
+
# | allow_nil/allow_blank/if/unless | database | status |
|
11
|
+
# | ------------------------------- | -------- | ------ |
|
12
|
+
# | at least one provided | required | fail |
|
13
|
+
# | at least one provided | optional | ok |
|
14
|
+
# | all missed | required | ok |
|
15
|
+
# | all missed | optional | fail |
|
16
|
+
def compare
|
17
|
+
can_be_null = column.null
|
18
|
+
has_weak_option = validator.options.slice(*WEAK_OPTIONS).any?
|
19
|
+
|
20
|
+
if can_be_null == has_weak_option
|
21
|
+
result(:ok)
|
22
|
+
elsif can_be_null
|
23
|
+
result(:fail, CONSTRAINT_MISSING)
|
24
|
+
else
|
25
|
+
result(:fail, POSSIBLE_NULL)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,25 @@
|
|
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
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module DatabaseConsistency
|
2
|
+
# The module contains helper methods
|
3
|
+
module Helper
|
4
|
+
module_function
|
5
|
+
|
6
|
+
# Returns list of models to check
|
7
|
+
def models
|
8
|
+
ActiveRecord::Base.descendants.select { |model| model.validators.any? }
|
9
|
+
end
|
10
|
+
|
11
|
+
# Loads all models
|
12
|
+
def load_environment!
|
13
|
+
Rails.application.eager_load! if defined?(Rails)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Find a database field with name equals to attribute
|
17
|
+
def find_field(model, attribute)
|
18
|
+
model.columns.select.find { |field| field.name == attribute }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module DatabaseConsistency
|
2
|
+
# The class to begin
|
3
|
+
class Processor
|
4
|
+
COMPARATORS = {
|
5
|
+
presence: DatabaseConsistency::Comparators::PresenceComparator
|
6
|
+
}.freeze
|
7
|
+
|
8
|
+
def comparisons
|
9
|
+
Helper.models.each_with_object({}) do |model, hash|
|
10
|
+
hash[model.name] = 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, column)
|
17
|
+
end
|
18
|
+
end.compact
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module DatabaseConsistency
|
2
|
+
module Writers
|
3
|
+
# The base class for writers
|
4
|
+
class BaseWriter
|
5
|
+
attr_reader :results, :log_level
|
6
|
+
|
7
|
+
def initialize(results, log_level)
|
8
|
+
@results = results
|
9
|
+
@log_level = log_level
|
10
|
+
end
|
11
|
+
|
12
|
+
def write?(status)
|
13
|
+
status == :fail || log_level == 'DEBUG'
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.write(results, log_level)
|
17
|
+
new(results, log_level).write
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module DatabaseConsistency
|
2
|
+
# The module contains formatters
|
3
|
+
module Writers
|
4
|
+
# The simplest formatter
|
5
|
+
class SimpleWriter < BaseWriter
|
6
|
+
def write
|
7
|
+
puts format
|
8
|
+
end
|
9
|
+
|
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")
|
17
|
+
end
|
18
|
+
|
19
|
+
def line(model_name, comparison)
|
20
|
+
<<-TEXT
|
21
|
+
#{comparison[:status]} #{comparison[:message]} #{model_name} #{comparison[:validator].inspect} #{comparison[:column].inspect}
|
22
|
+
TEXT
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
require 'database_consistency/version'
|
4
|
+
require 'database_consistency/writers/base_writer'
|
5
|
+
require 'database_consistency/writers/simple_writer'
|
6
|
+
require 'database_consistency/comparison'
|
7
|
+
require 'database_consistency/helper'
|
8
|
+
require 'database_consistency/comparators/base_comparator'
|
9
|
+
require 'database_consistency/comparators/presence_comparator'
|
10
|
+
require 'database_consistency/processor'
|
11
|
+
|
12
|
+
# The root module
|
13
|
+
module DatabaseConsistency
|
14
|
+
def self.run
|
15
|
+
Helper.load_environment!
|
16
|
+
|
17
|
+
Writers::SimpleWriter.write(
|
18
|
+
Processor.new.comparisons,
|
19
|
+
ENV['LOG_LEVEL'] || 'INFO'
|
20
|
+
)
|
21
|
+
end
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: database_consistency
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Evgeniy Demin
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-10-30 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activerecord
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.2'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '6'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '3.2'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '6'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: bundler
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '1.16'
|
40
|
+
type: :development
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.16'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rake
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '10.0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '10.0'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: rspec
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '3.0'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '3.0'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: rubocop
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0.55'
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0.55'
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: sqlite3
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '1.3'
|
96
|
+
type: :development
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - "~>"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '1.3'
|
103
|
+
description:
|
104
|
+
email:
|
105
|
+
- lawliet.djez@gmail.com
|
106
|
+
executables:
|
107
|
+
- database_consistency
|
108
|
+
extensions: []
|
109
|
+
extra_rdoc_files: []
|
110
|
+
files:
|
111
|
+
- bin/database_consistency
|
112
|
+
- lib/database_consistency.rb
|
113
|
+
- lib/database_consistency/comparators/base_comparator.rb
|
114
|
+
- lib/database_consistency/comparators/presence_comparator.rb
|
115
|
+
- lib/database_consistency/comparison.rb
|
116
|
+
- lib/database_consistency/helper.rb
|
117
|
+
- lib/database_consistency/processor.rb
|
118
|
+
- lib/database_consistency/version.rb
|
119
|
+
- lib/database_consistency/writers/base_writer.rb
|
120
|
+
- lib/database_consistency/writers/simple_writer.rb
|
121
|
+
homepage: https://github.com/djezzzl/database_consistency
|
122
|
+
licenses:
|
123
|
+
- MIT
|
124
|
+
metadata: {}
|
125
|
+
post_install_message:
|
126
|
+
rdoc_options: []
|
127
|
+
require_paths:
|
128
|
+
- lib
|
129
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - ">="
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
requirements: []
|
140
|
+
rubyforge_project:
|
141
|
+
rubygems_version: 2.7.7
|
142
|
+
signing_key:
|
143
|
+
specification_version: 4
|
144
|
+
summary: Provide an easy way to check the consistency of the database constraints
|
145
|
+
with the application validations.
|
146
|
+
test_files: []
|