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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 047eabab521a0b04f0385213e7b20a34cb192576935d3e9c2f70aeab28df6ca0
4
- data.tar.gz: 61fe8cac30624557d22ff059b2738ccdddbf0bbaa99eb9ac67a74f943fe39abf
3
+ metadata.gz: d49b81e66a19302fc586225b0b9b53d307daacc5da01b876bdb882c2b2be3c8e
4
+ data.tar.gz: 52aac6177166296c0500d2a60b9e7fba9c5ed5215a31db57feec17d6fe7b0937
5
5
  SHA512:
6
- metadata.gz: c99d04c4d975a9f50781422c409fa2e08fe3cc0fbc2ec8bdc015ab766b8c7e45ed646de43cf30c3c23512cc01877462cd16896034b03e390c3fb7309242c0fc0
7
- data.tar.gz: '098fa9d49805b3379fa0fa5b95d3c93771be64b709c7cda5c42aecdf2fa33945bf59d3076a7035f548d1dd0de362d9684053330db5118635a1fef60bc1124f57'
6
+ metadata.gz: 1776e46980f98dc20f4a68da11f0a24a540b41d63721425fc8c3d31a9985f86a98143862b822925ec3695a03ccd8de027b6e4b7ea0261732a74d8deba10bc096
7
+ data.tar.gz: c7e121bb64826de63415dbbb5a385d3f85c2862dd20f5ed2678bfa7b02e63442c277faa68d1f3bc6d3babe2ad88b0626391748478647ea13bda47735a8034f5e
@@ -20,6 +20,4 @@ module DatabaseValidations
20
20
  extend ActiveSupport::Concern
21
21
  end
22
22
 
23
- if defined?(ActiveRecord::Base)
24
- ActiveRecord::Base.include(DatabaseValidations)
25
- end
23
+ ActiveRecord::Base.include(DatabaseValidations) if defined?(ActiveRecord::Base)
@@ -17,10 +17,10 @@
17
17
  #
18
18
  # is the same as
19
19
  #
20
- #```ruby
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: validator.field,
52
- scope: validator.scope,
53
- where: validator.where_clause,
54
- message: validator.message,
55
- index_name: validator.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 += "With options - " if @message || @scope || @where
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 += "be case insensitive." if @case_sensitive === false
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
@@ -0,0 +1,2 @@
1
+ require 'database_validations/rubocop/cop/belongs_to'
2
+ require 'database_validations/rubocop/cop/uniqueness_of'
@@ -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.new(database)
16
+ raise Errors::UnknownDatabase, database
17
17
  end
18
18
  end
19
19
  end
@@ -47,6 +47,11 @@ module DatabaseValidations
47
47
  self.class::SUPPORTED_OPTIONS
48
48
  end
49
49
 
50
+ # @return [String]
51
+ def table_name
52
+ model.table_name
53
+ end
54
+
50
55
  private
51
56
 
52
57
  attr_reader :model
@@ -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
- "No unique index found with #{columns_and_where_text(columns, where_clause)}. "\
23
- "Available indexes are: [#{self.available_indexes.map { |ind| columns_and_where_text(ind.columns, ind.where) }.join(', ')}]. "
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,6 +1,5 @@
1
1
  module DatabaseValidations
2
2
  class OptionsStorage
3
-
4
3
  def initialize(klass)
5
4
  @adapter = Adapters.factory(klass)
6
5
  @storage = {}
@@ -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 == 0
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
- (!index_name && adapter.find_index(columns, where_clause))
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
@@ -1,3 +1,3 @@
1
1
  module DatabaseValidations
2
- VERSION = '0.8.0'
2
+ VERSION = '0.8.1'.freeze
3
3
  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.0
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: 2018-11-30 00:00:00.000000000 Z
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: sqlite3
48
+ name: bundler
49
49
  requirement: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '1.3'
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.3'
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: mysql2
90
+ name: rake
77
91
  requirement: !ruby/object:Gem::Requirement
78
92
  requirements:
79
93
  - - "~>"
80
94
  - !ruby/object:Gem::Version
81
- version: '0.5'
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.5'
102
+ version: '10.0'
89
103
  - !ruby/object:Gem::Dependency
90
- name: bundler
104
+ name: rspec
91
105
  requirement: !ruby/object:Gem::Requirement
92
106
  requirements:
93
107
  - - "~>"
94
108
  - !ruby/object:Gem::Version
95
- version: '1.16'
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: '1.16'
116
+ version: '3.0'
103
117
  - !ruby/object:Gem::Dependency
104
- name: rake
118
+ name: rubocop
105
119
  requirement: !ruby/object:Gem::Requirement
106
120
  requirements:
107
121
  - - "~>"
108
122
  - !ruby/object:Gem::Version
109
- version: '10.0'
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: '10.0'
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: '3.0'
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: '3.0'
144
+ version: '1.30'
131
145
  - !ruby/object:Gem::Dependency
132
- name: climate_control
146
+ name: sqlite3
133
147
  requirement: !ruby/object:Gem::Requirement
134
148
  requirements:
135
149
  - - "~>"
136
150
  - !ruby/object:Gem::Version
137
- version: '0.2'
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: '0.2'
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