database_validations 0.8.0 → 0.8.1
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_validations.rb +1 -3
- data/lib/database_validations/rspec/uniqueness_validator_matcher.rb +10 -10
- data/lib/database_validations/rubocop/cop/belongs_to.rb +46 -0
- data/lib/database_validations/rubocop/cop/uniqueness_of.rb +41 -0
- data/lib/database_validations/rubocop/cops.rb +2 -0
- data/lib/database_validations/validations/adapters.rb +1 -1
- data/lib/database_validations/validations/adapters/base_adapter.rb +5 -0
- data/lib/database_validations/validations/adapters/sqlite_adapter.rb +1 -2
- data/lib/database_validations/validations/belongs_to_options.rb +3 -7
- data/lib/database_validations/validations/errors.rb +6 -5
- data/lib/database_validations/validations/helpers.rb +1 -1
- data/lib/database_validations/validations/options_storage.rb +0 -1
- data/lib/database_validations/validations/uniqueness_options.rb +5 -5
- data/lib/database_validations/version.rb +1 -1
- metadata +37 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d49b81e66a19302fc586225b0b9b53d307daacc5da01b876bdb882c2b2be3c8e
|
4
|
+
data.tar.gz: 52aac6177166296c0500d2a60b9e7fba9c5ed5215a31db57feec17d6fe7b0937
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1776e46980f98dc20f4a68da11f0a24a540b41d63721425fc8c3d31a9985f86a98143862b822925ec3695a03ccd8de027b6e4b7ea0261732a74d8deba10bc096
|
7
|
+
data.tar.gz: c7e121bb64826de63415dbbb5a385d3f85c2862dd20f5ed2678bfa7b02e63442c277faa68d1f3bc6d3babe2ad88b0626391748478647ea13bda47735a8034f5e
|
data/lib/database_validations.rb
CHANGED
@@ -17,10 +17,10 @@
|
|
17
17
|
#
|
18
18
|
# is the same as
|
19
19
|
#
|
20
|
-
|
20
|
+
# ```ruby
|
21
21
|
# it { expect(Model.new).to validate_db_uniqueness_of(:field) }
|
22
22
|
# ```
|
23
|
-
RSpec::Matchers.define :validate_db_uniqueness_of do |field|
|
23
|
+
RSpec::Matchers.define :validate_db_uniqueness_of do |field| # rubocop:disable Metrics/BlockLength
|
24
24
|
chain(:with_message) do |message|
|
25
25
|
@message = message
|
26
26
|
end
|
@@ -48,11 +48,11 @@ RSpec::Matchers.define :validate_db_uniqueness_of do |field|
|
|
48
48
|
|
49
49
|
DatabaseValidations::Helpers.each_uniqueness_validator(model) do |validator|
|
50
50
|
@validators << {
|
51
|
-
field:
|
52
|
-
scope:
|
53
|
-
where:
|
54
|
-
message:
|
55
|
-
index_name:
|
51
|
+
field: validator.field,
|
52
|
+
scope: validator.scope,
|
53
|
+
where: validator.where_clause,
|
54
|
+
message: validator.message,
|
55
|
+
index_name: validator.index_name,
|
56
56
|
case_sensitive: validator.case_sensitive
|
57
57
|
}
|
58
58
|
end
|
@@ -69,18 +69,18 @@ RSpec::Matchers.define :validate_db_uniqueness_of do |field|
|
|
69
69
|
|
70
70
|
description do
|
71
71
|
desc = "validate database uniqueness of #{field}. "
|
72
|
-
desc +=
|
72
|
+
desc += 'With options - ' if @message || @scope || @where
|
73
73
|
desc += "message: '#{@message}'; " if @message
|
74
74
|
desc += "scope: #{@scope}; " if @scope
|
75
75
|
desc += "where: '#{@where}'; " if @where
|
76
76
|
desc += "index_name: '#{@index_name}'; " if @index_name
|
77
|
-
desc +=
|
77
|
+
desc += 'be case insensitive.' unless @case_sensitive
|
78
78
|
desc
|
79
79
|
end
|
80
80
|
|
81
81
|
failure_message do
|
82
82
|
<<-TEXT
|
83
|
-
There is no such database uniqueness validator.
|
83
|
+
There is no such database uniqueness validator.
|
84
84
|
Available validators are: #{@validators}.
|
85
85
|
TEXT
|
86
86
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module RuboCop
|
2
|
+
module Cop
|
3
|
+
module DatabaseValidations
|
4
|
+
# Use `db_belongs`_to instead of `belongs_to`.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# # bad
|
8
|
+
# belongs_to :company
|
9
|
+
#
|
10
|
+
# # good
|
11
|
+
# db_belongs_to :company
|
12
|
+
#
|
13
|
+
class BelongsTo < Cop
|
14
|
+
MSG = 'Use `db_belongs_to`.'.freeze
|
15
|
+
|
16
|
+
NON_SUPPORTED_OPTIONS = %i[
|
17
|
+
optional
|
18
|
+
required
|
19
|
+
polymorphic
|
20
|
+
foreign_type
|
21
|
+
].freeze
|
22
|
+
|
23
|
+
def_node_matcher :belongs_to?, '(send nil? :belongs_to ...)'
|
24
|
+
def_node_matcher :option_name, '(pair (sym $_) ...)'
|
25
|
+
|
26
|
+
def on_send(node)
|
27
|
+
return unless belongs_to?(node)
|
28
|
+
return unless supported?(node)
|
29
|
+
|
30
|
+
add_offense(node, location: :selector)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def supported?(node)
|
36
|
+
options = node.arguments.last
|
37
|
+
return true unless options.hash_type?
|
38
|
+
|
39
|
+
options.each_child_node.none? do |option|
|
40
|
+
NON_SUPPORTED_OPTIONS.include? option_name(option)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module RuboCop
|
2
|
+
module Cop
|
3
|
+
module DatabaseValidations
|
4
|
+
# Use `validates_db_uniqueness_of` for uniqueness validation.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# # bad
|
8
|
+
# validates :slug, uniqueness: true
|
9
|
+
# validates :address, uniqueness: { scope: :user_id }
|
10
|
+
#
|
11
|
+
# # good
|
12
|
+
# validates_db_uniqueness_of :slug
|
13
|
+
# validates_db_uniqueness_of :address, scope: :user_id
|
14
|
+
#
|
15
|
+
class UniquenessOf < Cop
|
16
|
+
MSG = 'Use `validates_db_uniqueness_of`.'.freeze
|
17
|
+
|
18
|
+
def_node_matcher :uniquness_validation?, '(pair (sym :uniqueness) $_)'
|
19
|
+
|
20
|
+
def on_send(node)
|
21
|
+
return unless node.method_name == :validates
|
22
|
+
|
23
|
+
uniqueness(node) do |option|
|
24
|
+
add_offense(option)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def uniqueness(node)
|
31
|
+
options = node.arguments.last
|
32
|
+
return unless options.hash_type?
|
33
|
+
|
34
|
+
options.each_child_node do |child|
|
35
|
+
yield child if uniquness_validation?(child)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -13,7 +13,7 @@ module DatabaseValidations
|
|
13
13
|
when PostgresqlAdapter::ADAPTER then PostgresqlAdapter.new(model)
|
14
14
|
when MysqlAdapter::ADAPTER then MysqlAdapter.new(model)
|
15
15
|
else
|
16
|
-
raise Errors::UnknownDatabase
|
16
|
+
raise Errors::UnknownDatabase, database
|
17
17
|
end
|
18
18
|
end
|
19
19
|
end
|
@@ -4,8 +4,7 @@ module DatabaseValidations
|
|
4
4
|
SUPPORTED_OPTIONS = %i[scope message if unless].freeze
|
5
5
|
ADAPTER = :sqlite3
|
6
6
|
|
7
|
-
def index_name(_error_message)
|
8
|
-
end
|
7
|
+
def index_name(_error_message); end
|
9
8
|
|
10
9
|
def find_foreign_key_by_column(column)
|
11
10
|
foreign_keys.find { |foreign_key| foreign_key.column.to_s == column.to_s }
|
@@ -23,21 +23,17 @@ module DatabaseValidations
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def validates_presence_options
|
26
|
-
{attributes: relation, message: :required}
|
26
|
+
{ attributes: relation, message: :required }
|
27
27
|
end
|
28
28
|
|
29
29
|
private
|
30
30
|
|
31
31
|
def raise_if_foreign_key_missed!
|
32
|
-
unless adapter.find_foreign_key_by_column(column)
|
33
|
-
raise Errors::ForeignKeyNotFound.new(column, adapter.foreign_keys)
|
34
|
-
end
|
32
|
+
raise Errors::ForeignKeyNotFound.new(column, adapter.foreign_keys) unless adapter.find_foreign_key_by_column(column)
|
35
33
|
end
|
36
34
|
|
37
35
|
def raise_if_unsupported_database!
|
38
|
-
if adapter.adapter_name == :sqlite3
|
39
|
-
raise Errors::UnsupportedDatabase.new(:db_belongs_to, adapter.adapter_name)
|
40
|
-
end
|
36
|
+
raise Errors::UnsupportedDatabase.new(:db_belongs_to, adapter.adapter_name) if adapter.adapter_name == :sqlite3
|
41
37
|
end
|
42
38
|
end
|
43
39
|
end
|
@@ -7,20 +7,21 @@ module DatabaseValidations
|
|
7
7
|
end
|
8
8
|
|
9
9
|
class IndexNotFound < Base
|
10
|
-
attr_reader :columns, :where_clause, :index_name, :available_indexes
|
10
|
+
attr_reader :columns, :where_clause, :index_name, :available_indexes, :table_name
|
11
11
|
|
12
|
-
def initialize(columns, where_clause, index_name, available_indexes)
|
12
|
+
def initialize(columns, where_clause, index_name, available_indexes, table_name)
|
13
13
|
@columns = columns
|
14
14
|
@where_clause = where_clause
|
15
15
|
@available_indexes = available_indexes
|
16
16
|
@index_name = index_name
|
17
17
|
|
18
18
|
text = if index_name
|
19
|
-
"No unique index found with name: \"#{index_name}\". "\
|
19
|
+
"No unique index found with name: \"#{index_name}\" in table \"#{table_name}\". "\
|
20
20
|
"Available indexes are: #{self.available_indexes.map(&:name)}. "
|
21
21
|
else
|
22
|
-
|
23
|
-
"
|
22
|
+
available_indexes = self.available_indexes.map { |ind| columns_and_where_text(ind.columns, ind.where) }.join(', ')
|
23
|
+
"No unique index found with #{columns_and_where_text(columns, where_clause)} in table \"#{table_name}\". "\
|
24
|
+
"Available indexes are: [#{available_indexes}]. "
|
24
25
|
end
|
25
26
|
|
26
27
|
super text + env_message
|
@@ -2,7 +2,7 @@ module DatabaseValidations
|
|
2
2
|
module Helpers
|
3
3
|
module_function
|
4
4
|
|
5
|
-
def handle_unique_error!(instance, error)
|
5
|
+
def handle_unique_error!(instance, error) # rubocop:disable Metrics/AbcSize
|
6
6
|
adapter = Adapters.factory(instance.class)
|
7
7
|
index_key = generate_key_for_uniqueness_index(adapter.index_name(error.message))
|
8
8
|
column_key = generate_key_for_uniqueness(adapter.unique_error_columns(error.message))
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module DatabaseValidations
|
2
2
|
class UniquenessOptions
|
3
3
|
CUSTOM_OPTIONS = %i[where index_name].freeze
|
4
|
-
DEFAULT_OPTIONS = {allow_nil: true, case_sensitive: true, allow_blank: false}.freeze
|
4
|
+
DEFAULT_OPTIONS = { allow_nil: true, case_sensitive: true, allow_blank: false }.freeze
|
5
5
|
|
6
6
|
attr_reader :field
|
7
7
|
|
@@ -79,7 +79,7 @@ module DatabaseValidations
|
|
79
79
|
def condition_passes?(condition, instance)
|
80
80
|
if condition.is_a?(Symbol)
|
81
81
|
instance.__send__(condition)
|
82
|
-
elsif condition.is_a?(Proc) && condition.arity
|
82
|
+
elsif condition.is_a?(Proc) && condition.arity.zero?
|
83
83
|
instance.instance_exec(&condition)
|
84
84
|
else
|
85
85
|
instance.instance_eval(&condition)
|
@@ -94,10 +94,10 @@ module DatabaseValidations
|
|
94
94
|
end
|
95
95
|
end
|
96
96
|
|
97
|
-
def raise_if_index_missed!
|
97
|
+
def raise_if_index_missed! # rubocop:disable Metrics/AbcSize
|
98
98
|
unless (index_name && adapter.find_index_by_name(index_name.to_s)) ||
|
99
|
-
|
100
|
-
raise Errors::IndexNotFound.new(columns, where_clause, index_name, adapter.indexes)
|
99
|
+
(!index_name && adapter.find_index(columns, where_clause))
|
100
|
+
raise Errors::IndexNotFound.new(columns, where_clause, index_name, adapter.indexes, adapter.table_name)
|
101
101
|
end
|
102
102
|
end
|
103
103
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: database_validations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.1
|
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-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -45,19 +45,33 @@ dependencies:
|
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: '2.7'
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
|
-
name:
|
48
|
+
name: bundler
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
50
50
|
requirements:
|
51
51
|
- - "~>"
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version: '1.
|
53
|
+
version: '1.16'
|
54
54
|
type: :development
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
57
|
requirements:
|
58
58
|
- - "~>"
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version: '1.
|
60
|
+
version: '1.16'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: mysql2
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0.5'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0.5'
|
61
75
|
- !ruby/object:Gem::Dependency
|
62
76
|
name: pg
|
63
77
|
requirement: !ruby/object:Gem::Requirement
|
@@ -73,75 +87,75 @@ dependencies:
|
|
73
87
|
- !ruby/object:Gem::Version
|
74
88
|
version: '1.1'
|
75
89
|
- !ruby/object:Gem::Dependency
|
76
|
-
name:
|
90
|
+
name: rake
|
77
91
|
requirement: !ruby/object:Gem::Requirement
|
78
92
|
requirements:
|
79
93
|
- - "~>"
|
80
94
|
- !ruby/object:Gem::Version
|
81
|
-
version: '0
|
95
|
+
version: '10.0'
|
82
96
|
type: :development
|
83
97
|
prerelease: false
|
84
98
|
version_requirements: !ruby/object:Gem::Requirement
|
85
99
|
requirements:
|
86
100
|
- - "~>"
|
87
101
|
- !ruby/object:Gem::Version
|
88
|
-
version: '0
|
102
|
+
version: '10.0'
|
89
103
|
- !ruby/object:Gem::Dependency
|
90
|
-
name:
|
104
|
+
name: rspec
|
91
105
|
requirement: !ruby/object:Gem::Requirement
|
92
106
|
requirements:
|
93
107
|
- - "~>"
|
94
108
|
- !ruby/object:Gem::Version
|
95
|
-
version: '
|
109
|
+
version: '3.0'
|
96
110
|
type: :development
|
97
111
|
prerelease: false
|
98
112
|
version_requirements: !ruby/object:Gem::Requirement
|
99
113
|
requirements:
|
100
114
|
- - "~>"
|
101
115
|
- !ruby/object:Gem::Version
|
102
|
-
version: '
|
116
|
+
version: '3.0'
|
103
117
|
- !ruby/object:Gem::Dependency
|
104
|
-
name:
|
118
|
+
name: rubocop
|
105
119
|
requirement: !ruby/object:Gem::Requirement
|
106
120
|
requirements:
|
107
121
|
- - "~>"
|
108
122
|
- !ruby/object:Gem::Version
|
109
|
-
version: '
|
123
|
+
version: '0.60'
|
110
124
|
type: :development
|
111
125
|
prerelease: false
|
112
126
|
version_requirements: !ruby/object:Gem::Requirement
|
113
127
|
requirements:
|
114
128
|
- - "~>"
|
115
129
|
- !ruby/object:Gem::Version
|
116
|
-
version: '
|
130
|
+
version: '0.60'
|
117
131
|
- !ruby/object:Gem::Dependency
|
118
|
-
name: rspec
|
132
|
+
name: rubocop-rspec
|
119
133
|
requirement: !ruby/object:Gem::Requirement
|
120
134
|
requirements:
|
121
135
|
- - "~>"
|
122
136
|
- !ruby/object:Gem::Version
|
123
|
-
version: '
|
137
|
+
version: '1.30'
|
124
138
|
type: :development
|
125
139
|
prerelease: false
|
126
140
|
version_requirements: !ruby/object:Gem::Requirement
|
127
141
|
requirements:
|
128
142
|
- - "~>"
|
129
143
|
- !ruby/object:Gem::Version
|
130
|
-
version: '
|
144
|
+
version: '1.30'
|
131
145
|
- !ruby/object:Gem::Dependency
|
132
|
-
name:
|
146
|
+
name: sqlite3
|
133
147
|
requirement: !ruby/object:Gem::Requirement
|
134
148
|
requirements:
|
135
149
|
- - "~>"
|
136
150
|
- !ruby/object:Gem::Version
|
137
|
-
version: '
|
151
|
+
version: '1.3'
|
138
152
|
type: :development
|
139
153
|
prerelease: false
|
140
154
|
version_requirements: !ruby/object:Gem::Requirement
|
141
155
|
requirements:
|
142
156
|
- - "~>"
|
143
157
|
- !ruby/object:Gem::Version
|
144
|
-
version: '
|
158
|
+
version: '1.3'
|
145
159
|
description: |-
|
146
160
|
ActiveRecord provides validations on app level but it won't guarantee the
|
147
161
|
consistent. In some cases, like `validates_uniqueness_of` it executes
|
@@ -159,6 +173,9 @@ files:
|
|
159
173
|
- lib/database_validations/rails/railtie.rb
|
160
174
|
- lib/database_validations/rspec/matchers.rb
|
161
175
|
- lib/database_validations/rspec/uniqueness_validator_matcher.rb
|
176
|
+
- lib/database_validations/rubocop/cop/belongs_to.rb
|
177
|
+
- lib/database_validations/rubocop/cop/uniqueness_of.rb
|
178
|
+
- lib/database_validations/rubocop/cops.rb
|
162
179
|
- lib/database_validations/tasks/database_validations.rake
|
163
180
|
- lib/database_validations/validations/adapters.rb
|
164
181
|
- lib/database_validations/validations/adapters/base_adapter.rb
|