database_consistency 0.8.0 → 0.8.5
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/bin/database_consistency +20 -4
- data/lib/database_consistency.rb +5 -0
- data/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb +106 -0
- data/lib/database_consistency/checkers/column_checkers/length_constraint_checker.rb +7 -1
- data/lib/database_consistency/checkers/column_checkers/null_constraint_checker.rb +9 -1
- data/lib/database_consistency/checkers/validator_checkers/missing_unique_index_checker.rb +7 -1
- data/lib/database_consistency/checkers/validators_fraction_checkers/column_presence_checker.rb +1 -1
- data/lib/database_consistency/databases/factory.rb +27 -0
- data/lib/database_consistency/databases/types/base.rb +22 -0
- data/lib/database_consistency/databases/types/sqlite.rb +22 -0
- data/lib/database_consistency/processors/associations_processor.rb +2 -1
- data/lib/database_consistency/rescue_error.rb +1 -1
- data/lib/database_consistency/templates/rails_defaults.yml +7 -0
- data/lib/database_consistency/version.rb +1 -1
- metadata +12 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ed9a2103f6e588628f52a00ddd933b0dc899fac0d6e8752a3bf1111a3894fb17
|
4
|
+
data.tar.gz: d8bf6a551c55fc3e4a33d837354f1b3d777c6171b48aa84d2cce5bbba478e0d5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a1c59e4de257fdaa7aae63725abcc82f7da1f4ea98f51fc804162b8c5488021c3c665f7e7298b135eaddd50560415b563f0cd608fdaaee81519e44af74966bb2
|
7
|
+
data.tar.gz: 516f5102afb3234eb88d8a8039b584c9210b33d78401290423032cbd017df5218aa6a455ae5faeffb54dd9bad7ea82a17a40f1729255c7ea2ed988924bad3ea9
|
data/bin/database_consistency
CHANGED
@@ -1,9 +1,25 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
if ARGV.include?('install')
|
4
|
+
require_relative '../lib/database_consistency/configuration'
|
5
|
+
config_filename = DatabaseConsistency::Configuration::CONFIGURATION_PATH
|
6
|
+
file_exists = File.exists?(config_filename)
|
7
|
+
rules = Pathname.new(__FILE__).dirname.join('..', 'lib', 'database_consistency', 'templates', 'rails_defaults.yml').read
|
8
|
+
if file_exists && File.foreach(config_filename).grep(Regexp.new(rules.lines.first.chomp)).any?
|
9
|
+
puts "#{config_filename} is already present"
|
10
|
+
else
|
11
|
+
File.open(config_filename, 'a') do |file|
|
12
|
+
file << "\n" * 2 if file_exists
|
13
|
+
file << rules
|
14
|
+
end
|
15
|
+
puts "#{config_filename} #{file_exists ? 'updated' : 'added'}"
|
16
|
+
end
|
17
|
+
exit 0
|
18
|
+
else
|
19
|
+
base_dir = File.join(Dir.pwd, ARGV.first.to_s)
|
20
|
+
unless File.realpath(base_dir).start_with?(Dir.pwd)
|
21
|
+
puts "\nWarning! You are going out of current directory, ruby version may be wrong and some gems may be missing.\n"
|
22
|
+
end
|
7
23
|
end
|
8
24
|
|
9
25
|
# Load Rails project
|
data/lib/database_consistency.rb
CHANGED
@@ -10,10 +10,15 @@ require 'database_consistency/rescue_error'
|
|
10
10
|
require 'database_consistency/writers/base_writer'
|
11
11
|
require 'database_consistency/writers/simple_writer'
|
12
12
|
|
13
|
+
require 'database_consistency/databases/factory'
|
14
|
+
require 'database_consistency/databases/types/base'
|
15
|
+
require 'database_consistency/databases/types/sqlite'
|
16
|
+
|
13
17
|
require 'database_consistency/checkers/base_checker'
|
14
18
|
|
15
19
|
require 'database_consistency/checkers/association_checkers/association_checker'
|
16
20
|
require 'database_consistency/checkers/association_checkers/missing_index_checker'
|
21
|
+
require 'database_consistency/checkers/association_checkers/foreign_key_type_checker'
|
17
22
|
|
18
23
|
require 'database_consistency/checkers/column_checkers/column_checker'
|
19
24
|
require 'database_consistency/checkers/column_checkers/null_constraint_checker'
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DatabaseConsistency
|
4
|
+
module Checkers
|
5
|
+
# This class checks if association's foreign key type is the same as associated model's primary key
|
6
|
+
class ForeignKeyTypeChecker < AssociationChecker
|
7
|
+
INCONSISTENT_TYPE = 'associated model key (%a_f) with type (%a_t) mismatches key (%b_f) with type (%b_t)'
|
8
|
+
|
9
|
+
TYPES = {
|
10
|
+
'serial' => 'integer',
|
11
|
+
'integer' => 'integer',
|
12
|
+
'int' => 'integer',
|
13
|
+
'bigserial' => 'bigint',
|
14
|
+
'bigint' => 'bigint',
|
15
|
+
'bigint unsigned' => 'bigint unsigned'
|
16
|
+
}.freeze
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def preconditions
|
21
|
+
!association.polymorphic? && association.klass.present?
|
22
|
+
rescue NameError
|
23
|
+
false
|
24
|
+
end
|
25
|
+
|
26
|
+
# Table of possible statuses
|
27
|
+
# | type | status |
|
28
|
+
# | ------------ | ------ |
|
29
|
+
# | consistent | ok |
|
30
|
+
# | inconsistent | fail |
|
31
|
+
def check
|
32
|
+
if converted_type(base_column) == converted_type(associated_column)
|
33
|
+
report_template(:ok)
|
34
|
+
else
|
35
|
+
report_template(:fail, render_text)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [String]
|
40
|
+
def render_text
|
41
|
+
INCONSISTENT_TYPE
|
42
|
+
.gsub('%a_t', type(associated_column))
|
43
|
+
.gsub('%a_f', associated_key)
|
44
|
+
.gsub('%b_t', type(base_column))
|
45
|
+
.gsub('%b_f', base_key)
|
46
|
+
end
|
47
|
+
|
48
|
+
# @return [String]
|
49
|
+
def base_key
|
50
|
+
@base_key ||= belongs_to_association? ? association.foreign_key : association.active_record_primary_key
|
51
|
+
end
|
52
|
+
|
53
|
+
# @return [String]
|
54
|
+
def associated_key
|
55
|
+
@associated_key ||= belongs_to_association? ? association.active_record_primary_key : association.foreign_key
|
56
|
+
end
|
57
|
+
|
58
|
+
# @return [ActiveRecord::ConnectionAdapters::Column]
|
59
|
+
def base_column
|
60
|
+
@base_column ||= column(association.active_record, base_key)
|
61
|
+
end
|
62
|
+
|
63
|
+
# @return [ActiveRecord::ConnectionAdapters::Column]
|
64
|
+
def associated_column
|
65
|
+
@associated_column ||= column(association.klass, associated_key)
|
66
|
+
end
|
67
|
+
|
68
|
+
# @return [DatabaseConsistency::Databases::Factory]
|
69
|
+
def database_factory
|
70
|
+
@database_factory ||= Databases::Factory.new(association.active_record.connection.adapter_name)
|
71
|
+
end
|
72
|
+
|
73
|
+
# @param [ActiveRecord::Base] model
|
74
|
+
# @param [String] column_name
|
75
|
+
#
|
76
|
+
# @return [ActiveRecord::ConnectionAdapters::Column]
|
77
|
+
def column(model, column_name)
|
78
|
+
model.connection.columns(model.table_name).find { |column| column.name == column_name }
|
79
|
+
end
|
80
|
+
|
81
|
+
# @param [ActiveRecord::ConnectionAdapters::Column] column
|
82
|
+
#
|
83
|
+
# @return [String]
|
84
|
+
def type(column)
|
85
|
+
column.sql_type
|
86
|
+
end
|
87
|
+
|
88
|
+
# @param [ActiveRecord::ConnectionAdapters::Column]
|
89
|
+
#
|
90
|
+
# @return [String]
|
91
|
+
def converted_type(column)
|
92
|
+
database_factory.type(type(column)).convert
|
93
|
+
end
|
94
|
+
|
95
|
+
# @return [Boolean]
|
96
|
+
def supported_type?(column)
|
97
|
+
database_factory.type(type(column)).supported?
|
98
|
+
end
|
99
|
+
|
100
|
+
# @return [Boolean]
|
101
|
+
def belongs_to_association?
|
102
|
+
association.macro == :belongs_to
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -21,8 +21,14 @@ module DatabaseConsistency
|
|
21
21
|
# We skip check when:
|
22
22
|
# - column hasn't limit constraint
|
23
23
|
# - column insn't string nor text
|
24
|
+
# - column is array (PostgreSQL only)
|
24
25
|
def preconditions
|
25
|
-
!column.limit.nil? && %i[string text].include?(column.type)
|
26
|
+
!column.limit.nil? && %i[string text].include?(column.type) && !postgresql_array?
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [Boolean] true if it is an array (PostgreSQL only)
|
30
|
+
def postgresql_array?
|
31
|
+
column.respond_to?(:array) && column.array
|
26
32
|
end
|
27
33
|
|
28
34
|
# Table of possible statuses
|
@@ -25,7 +25,7 @@ module DatabaseConsistency
|
|
25
25
|
# | provided | ok |
|
26
26
|
# | missing | fail |
|
27
27
|
#
|
28
|
-
# We consider PresenceValidation, InclusionValidation, ExclusionValidation with nil,
|
28
|
+
# We consider PresenceValidation, InclusionValidation, ExclusionValidation, NumericalityValidator with nil,
|
29
29
|
# or BelongsTo association using this column
|
30
30
|
def check
|
31
31
|
if valid?
|
@@ -38,6 +38,7 @@ module DatabaseConsistency
|
|
38
38
|
def valid?
|
39
39
|
validator?(ActiveModel::Validations::PresenceValidator) ||
|
40
40
|
validator?(ActiveModel::Validations::InclusionValidator) ||
|
41
|
+
numericality_validator_without_allow_nil? ||
|
41
42
|
nil_exclusion_validator? ||
|
42
43
|
belongs_to_association?
|
43
44
|
end
|
@@ -57,6 +58,13 @@ module DatabaseConsistency
|
|
57
58
|
end
|
58
59
|
end
|
59
60
|
|
61
|
+
def numericality_validator_without_allow_nil?
|
62
|
+
model.validators.grep(ActiveModel::Validations::NumericalityValidator).any? do |validator|
|
63
|
+
Helper.check_inclusion?(validator.attributes, column.name) &&
|
64
|
+
!validator.options[:allow_nil]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
60
68
|
def validator?(validator_class)
|
61
69
|
model.validators.grep(validator_class).any? do |validator|
|
62
70
|
Helper.check_inclusion?(validator.attributes, column.name)
|
@@ -48,7 +48,13 @@ module DatabaseConsistency
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def index_columns
|
51
|
-
@index_columns ||= ([wrapped_attribute_name] +
|
51
|
+
@index_columns ||= ([wrapped_attribute_name] + scope_columns).map(&:to_s)
|
52
|
+
end
|
53
|
+
|
54
|
+
def scope_columns
|
55
|
+
@scope_columns ||= Array.wrap(validator.options[:scope]).map do |scope_item|
|
56
|
+
model._reflect_on_association(scope_item)&.foreign_key || scope_item
|
57
|
+
end
|
52
58
|
end
|
53
59
|
|
54
60
|
def sorted_index_columns
|
data/lib/database_consistency/checkers/validators_fraction_checkers/column_presence_checker.rb
CHANGED
@@ -4,7 +4,7 @@ module DatabaseConsistency
|
|
4
4
|
module Checkers
|
5
5
|
# This class checks if presence validator has non-null constraint in the database
|
6
6
|
class ColumnPresenceChecker < ValidatorsFractionChecker
|
7
|
-
WEAK_OPTIONS = %i[allow_nil allow_blank if unless].freeze
|
7
|
+
WEAK_OPTIONS = %i[allow_nil allow_blank if unless on].freeze
|
8
8
|
# Message templates
|
9
9
|
CONSTRAINT_MISSING = 'column should be required in the database'
|
10
10
|
POSSIBLE_NULL = 'column is required but there is possible null value insert'
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DatabaseConsistency
|
4
|
+
module Databases
|
5
|
+
# Factory for database adapters
|
6
|
+
class Factory
|
7
|
+
attr_reader :adapter
|
8
|
+
|
9
|
+
# @param [String] adapter
|
10
|
+
def initialize(adapter)
|
11
|
+
@adapter = adapter
|
12
|
+
end
|
13
|
+
|
14
|
+
# @return [DatabaseConsistency::Databases::Types::Base]
|
15
|
+
def type(type)
|
16
|
+
sqlite? ? Types::Sqlite.new(type) : Types::Base.new(type)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
# @return [Boolean]
|
22
|
+
def sqlite?
|
23
|
+
adapter == 'SQLite'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DatabaseConsistency
|
4
|
+
module Databases
|
5
|
+
module Types
|
6
|
+
# Base wrapper for database types
|
7
|
+
class Base
|
8
|
+
attr_reader :type
|
9
|
+
|
10
|
+
# @param [String] type
|
11
|
+
def initialize(type)
|
12
|
+
@type = type
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [String]
|
16
|
+
def convert
|
17
|
+
type
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DatabaseConsistency
|
4
|
+
module Databases
|
5
|
+
module Types
|
6
|
+
# Wraps types for SQLite database
|
7
|
+
class Sqlite < Base
|
8
|
+
TYPES = {
|
9
|
+
'bigserial' => 'bigint',
|
10
|
+
'bigint' => 'bigint',
|
11
|
+
'serial' => 'integer',
|
12
|
+
'integer' => 'integer'
|
13
|
+
}.freeze
|
14
|
+
|
15
|
+
# @return [String]
|
16
|
+
def convert
|
17
|
+
TYPES[type]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
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.8.
|
4
|
+
version: 0.8.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Evgeniy Demin
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-09-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -122,7 +122,7 @@ dependencies:
|
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '1.3'
|
125
|
-
description:
|
125
|
+
description:
|
126
126
|
email:
|
127
127
|
- lawliet.djez@gmail.com
|
128
128
|
executables:
|
@@ -133,6 +133,7 @@ files:
|
|
133
133
|
- bin/database_consistency
|
134
134
|
- lib/database_consistency.rb
|
135
135
|
- lib/database_consistency/checkers/association_checkers/association_checker.rb
|
136
|
+
- lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb
|
136
137
|
- lib/database_consistency/checkers/association_checkers/missing_index_checker.rb
|
137
138
|
- lib/database_consistency/checkers/base_checker.rb
|
138
139
|
- lib/database_consistency/checkers/column_checkers/column_checker.rb
|
@@ -145,6 +146,9 @@ files:
|
|
145
146
|
- lib/database_consistency/checkers/validators_fraction_checkers/column_presence_checker.rb
|
146
147
|
- lib/database_consistency/checkers/validators_fraction_checkers/validators_fraction_checker.rb
|
147
148
|
- lib/database_consistency/configuration.rb
|
149
|
+
- lib/database_consistency/databases/factory.rb
|
150
|
+
- lib/database_consistency/databases/types/base.rb
|
151
|
+
- lib/database_consistency/databases/types/sqlite.rb
|
148
152
|
- lib/database_consistency/helper.rb
|
149
153
|
- lib/database_consistency/processors/associations_processor.rb
|
150
154
|
- lib/database_consistency/processors/base_processor.rb
|
@@ -152,6 +156,7 @@ files:
|
|
152
156
|
- lib/database_consistency/processors/validators_fractions_processor.rb
|
153
157
|
- lib/database_consistency/processors/validators_processor.rb
|
154
158
|
- lib/database_consistency/rescue_error.rb
|
159
|
+
- lib/database_consistency/templates/rails_defaults.yml
|
155
160
|
- lib/database_consistency/version.rb
|
156
161
|
- lib/database_consistency/writers/base_writer.rb
|
157
162
|
- lib/database_consistency/writers/simple_writer.rb
|
@@ -159,7 +164,7 @@ homepage: https://github.com/djezzzl/database_consistency
|
|
159
164
|
licenses:
|
160
165
|
- MIT
|
161
166
|
metadata: {}
|
162
|
-
post_install_message:
|
167
|
+
post_install_message:
|
163
168
|
rdoc_options: []
|
164
169
|
require_paths:
|
165
170
|
- lib
|
@@ -174,9 +179,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
174
179
|
- !ruby/object:Gem::Version
|
175
180
|
version: '0'
|
176
181
|
requirements: []
|
177
|
-
|
178
|
-
|
179
|
-
signing_key:
|
182
|
+
rubygems_version: 3.0.8
|
183
|
+
signing_key:
|
180
184
|
specification_version: 4
|
181
185
|
summary: Provide an easy way to check the consistency of the database constraints
|
182
186
|
with the application validations.
|