database_validations 0.8.5 → 0.8.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (23) hide show
  1. checksums.yaml +4 -4
  2. data/lib/database_validations.rb +11 -10
  3. data/lib/database_validations/{validations → lib}/adapters.rb +4 -4
  4. data/lib/database_validations/{validations → lib}/adapters/base_adapter.rb +0 -0
  5. data/lib/database_validations/{validations → lib}/adapters/mysql_adapter.rb +0 -0
  6. data/lib/database_validations/{validations → lib}/adapters/postgresql_adapter.rb +0 -0
  7. data/lib/database_validations/{validations → lib}/adapters/sqlite_adapter.rb +0 -0
  8. data/lib/database_validations/lib/db_belongs_to/belongs_to_handlers.rb +20 -0
  9. data/lib/database_validations/{validations → lib/db_belongs_to}/belongs_to_options.rb +4 -4
  10. data/lib/database_validations/lib/db_belongs_to/db_presence_validator.rb +30 -0
  11. data/lib/database_validations/{validations → lib}/errors.rb +0 -0
  12. data/lib/database_validations/{validations → lib}/helpers.rb +18 -2
  13. data/lib/database_validations/{validations → lib}/options_storage.rb +0 -0
  14. data/lib/database_validations/lib/rescuer.rb +31 -0
  15. data/lib/database_validations/lib/validates_db_uniqueness_of/db_uniqueness_validator.rb +14 -0
  16. data/lib/database_validations/lib/validates_db_uniqueness_of/uniqueness_handlers.rb +20 -0
  17. data/lib/database_validations/{validations → lib/validates_db_uniqueness_of}/uniqueness_options.rb +8 -26
  18. data/lib/database_validations/version.rb +1 -1
  19. metadata +17 -16
  20. data/lib/database_validations/validations/belongs_to_handlers.rb +0 -58
  21. data/lib/database_validations/validations/belongs_to_presence_validator.rb +0 -25
  22. data/lib/database_validations/validations/uniqueness_handlers.rb +0 -56
  23. data/lib/database_validations/validations/valid_without_database_validations.rb +0 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 51bc2df5e836cbe85e6ec06cc3446652458093b3dba7d7dbd9123e579d67d6ce
4
- data.tar.gz: 82b5fdfec69d72f1fecf811f6add8f4e5d606ed2adbd2a6fab1a90125b0e57e2
3
+ metadata.gz: b696cae920dc9834393d2cf25127c7d9c9504750ec32d58f57c2bc873f735709
4
+ data.tar.gz: d2235fff367e21b9684d245b13773099bc1a1c292b1590a9888be33ae4bd1ad9
5
5
  SHA512:
6
- metadata.gz: 7a97f163683bc28f3884dbdd5b8d26a4059443199211bd4e5c980e5abdd1ef2b5d37efcc6c8557e0a853fe0fdb1f247f5677b6c0534b7f632bfb25af20e86606
7
- data.tar.gz: 556d083c72c34d0b90e381e052999289eb797ba74cd1b938fe5a1a53cdd47511d41472671ea5c10902b6bc02049e1772a2d7b83f0ec0fd1ff43c8298235e4a50
6
+ metadata.gz: 9c5740414831fa3fffcd45d4acbc5771c6b4eb49eb30de1a221ecca7dd801b841a4c55939911fab66a30f5a641a8cef19ecd5a4efb13b2a2dfd2a8f1ae80864a
7
+ data.tar.gz: d3dd1b8fda9f3c187f0ecf14ecdc24322e76583bb9278cb0e1adb38decbb325be7064d24ec1ccf6cc393c5a2b72a86a7ce4e57b4026260ba0b31f88bb00b2085
@@ -4,18 +4,19 @@ require 'database_validations/version'
4
4
 
5
5
  require 'database_validations/rails/railtie' if defined?(Rails)
6
6
 
7
- require 'database_validations/validations/uniqueness_handlers'
8
- require 'database_validations/validations/uniqueness_options'
7
+ require 'database_validations/lib/validates_db_uniqueness_of/db_uniqueness_validator'
8
+ require 'database_validations/lib/validates_db_uniqueness_of/uniqueness_handlers'
9
+ require 'database_validations/lib/validates_db_uniqueness_of/uniqueness_options'
9
10
 
10
- require 'database_validations/validations/belongs_to_presence_validator'
11
- require 'database_validations/validations/belongs_to_handlers'
12
- require 'database_validations/validations/belongs_to_options'
11
+ require 'database_validations/lib/db_belongs_to/db_presence_validator'
12
+ require 'database_validations/lib/db_belongs_to/belongs_to_handlers'
13
+ require 'database_validations/lib/db_belongs_to/belongs_to_options'
13
14
 
14
- require 'database_validations/validations/valid_without_database_validations'
15
- require 'database_validations/validations/options_storage'
16
- require 'database_validations/validations/errors'
17
- require 'database_validations/validations/helpers'
18
- require 'database_validations/validations/adapters'
15
+ require 'database_validations/lib/rescuer'
16
+ require 'database_validations/lib/options_storage'
17
+ require 'database_validations/lib/errors'
18
+ require 'database_validations/lib/helpers'
19
+ require 'database_validations/lib/adapters'
19
20
 
20
21
  module DatabaseValidations
21
22
  extend ActiveSupport::Concern
@@ -1,7 +1,7 @@
1
- require 'database_validations/validations/adapters/base_adapter'
2
- require 'database_validations/validations/adapters/sqlite_adapter'
3
- require 'database_validations/validations/adapters/postgresql_adapter'
4
- require 'database_validations/validations/adapters/mysql_adapter'
1
+ require 'database_validations/lib/adapters/base_adapter'
2
+ require 'database_validations/lib/adapters/sqlite_adapter'
3
+ require 'database_validations/lib/adapters/postgresql_adapter'
4
+ require 'database_validations/lib/adapters/mysql_adapter'
5
5
 
6
6
  module DatabaseValidations
7
7
  module Adapters
@@ -0,0 +1,20 @@
1
+ module DatabaseValidations
2
+ module ClassMethods
3
+ def db_belongs_to(name, scope = nil, **options)
4
+ Helpers.cache_valid_method!(self)
5
+
6
+ @database_validations_opts ||= DatabaseValidations::OptionsStorage.new(self)
7
+
8
+ belongs_to(name, scope, options.merge(optional: true))
9
+
10
+ foreign_key = reflections[name.to_s].foreign_key
11
+
12
+ @database_validations_opts.push_belongs_to(foreign_key, name)
13
+
14
+ validates_with DatabaseValidations::DBPresenceValidator,
15
+ DatabaseValidations::BelongsToOptions.validator_options(name, foreign_key)
16
+
17
+ include(DatabaseValidations::Rescuer)
18
+ end
19
+ end
20
+ end
@@ -1,5 +1,9 @@
1
1
  module DatabaseValidations
2
2
  class BelongsToOptions
3
+ def self.validator_options(association, foreign_key)
4
+ { attributes: association, foreign_key: foreign_key, message: :required }
5
+ end
6
+
3
7
  attr_reader :column, :adapter, :relation
4
8
 
5
9
  def initialize(column, relation, adapter)
@@ -27,10 +31,6 @@ module DatabaseValidations
27
31
  instance.errors.add(relation, :blank, message: :required)
28
32
  end
29
33
 
30
- def validates_presence_options
31
- { attributes: relation, message: :required }
32
- end
33
-
34
34
  private
35
35
 
36
36
  def raise_if_foreign_key_missed!
@@ -0,0 +1,30 @@
1
+ module DatabaseValidations
2
+ class DBPresenceValidator < ActiveRecord::Validations::PresenceValidator
3
+ # This is a hack to simulate presence validator
4
+ # It's used for cases when some 3rd parties are relies on the validators
5
+ # For example, +required+ option from simple_form checks the validator
6
+ def self.kind
7
+ :presence
8
+ end
9
+
10
+ attr_reader :foreign_key, :association
11
+
12
+ def initialize(options)
13
+ super(options)
14
+
15
+ @association = attributes.first
16
+ @foreign_key = options[:foreign_key]
17
+ end
18
+
19
+ # The else statement required only for optional: false
20
+ def validate(record)
21
+ if record._database_validations_fallback
22
+ super
23
+ else
24
+ return unless record.public_send(foreign_key).blank? && record.public_send(association).blank?
25
+
26
+ record.errors.add(association, :blank, message: :required)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -2,6 +2,22 @@ module DatabaseValidations
2
2
  module Helpers
3
3
  module_function
4
4
 
5
+ def cache_valid_method!(klass)
6
+ return if klass.method_defined?(:valid_without_database_validations?)
7
+
8
+ klass.alias_method(:valid_without_database_validations?, :valid?)
9
+ end
10
+
11
+ def handle_error!(instance, error)
12
+ case error
13
+ when ActiveRecord::RecordNotUnique
14
+ handle_unique_error!(instance, error)
15
+ when ActiveRecord::InvalidForeignKey
16
+ handle_foreign_key_error!(instance, error)
17
+ else false
18
+ end
19
+ end
20
+
5
21
  def handle_unique_error!(instance, error) # rubocop:disable Metrics/AbcSize
6
22
  adapter = Adapters.factory(instance.class)
7
23
  index_key = generate_key_for_uniqueness_index(adapter.index_name(error.message))
@@ -12,7 +28,7 @@ module DatabaseValidations
12
28
  return storage[column_key].handle_unique_error(instance) if storage[column_key]
13
29
  end
14
30
 
15
- raise error
31
+ false
16
32
  end
17
33
 
18
34
  def handle_foreign_key_error!(instance, error)
@@ -23,7 +39,7 @@ module DatabaseValidations
23
39
  return storage[column_key].handle_foreign_key_error(instance) if storage[column_key]
24
40
  end
25
41
 
26
- raise error
42
+ false
27
43
  end
28
44
 
29
45
  def each_options_storage(klass)
@@ -0,0 +1,31 @@
1
+ module DatabaseValidations
2
+ module Rescuer
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ alias_method :validate, :valid?
7
+ end
8
+
9
+ attr_accessor :_database_validations_fallback
10
+
11
+ def valid?(context = nil)
12
+ self._database_validations_fallback = true
13
+ super(context)
14
+ end
15
+
16
+ def create_or_update(*args, &block)
17
+ self._database_validations_fallback = false
18
+ ActiveRecord::Base.connection.transaction(requires_new: true) { super }
19
+ rescue ActiveRecord::InvalidForeignKey, ActiveRecord::RecordNotUnique => error
20
+ raise error unless Helpers.handle_error!(self, error)
21
+
22
+ raise ActiveRecord::RecordInvalid, self
23
+ end
24
+
25
+ private
26
+
27
+ def perform_validations(options = {})
28
+ options[:validate] == false || valid_without_database_validations?(options[:context])
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,14 @@
1
+ module DatabaseValidations
2
+ class DBUniquenessValidator < ActiveRecord::Validations::UniquenessValidator
3
+ # This is a hack to simulate presence validator
4
+ # It's used for cases when some 3rd parties are relies on the validators
5
+ # For example, +required+ option from simple_form checks the validator
6
+ def self.kind
7
+ :uniqueness
8
+ end
9
+
10
+ def validate(record)
11
+ super if record._database_validations_fallback
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,20 @@
1
+ module DatabaseValidations
2
+ module ClassMethods
3
+ def validates_db_uniqueness_of(*attributes)
4
+ Helpers.cache_valid_method!(self)
5
+
6
+ @database_validations_opts ||= DatabaseValidations::OptionsStorage.new(self)
7
+
8
+ options = attributes.extract_options!
9
+
10
+ attributes.each do |attribute|
11
+ @database_validations_opts.push_uniqueness(attribute, options.merge(attributes: attribute))
12
+ end
13
+
14
+ validates_with DatabaseValidations::DBUniquenessValidator,
15
+ DatabaseValidations::UniquenessOptions.validator_options(attributes, options)
16
+
17
+ include(DatabaseValidations::Rescuer)
18
+ end
19
+ end
20
+ end
@@ -3,6 +3,14 @@ module DatabaseValidations
3
3
  CUSTOM_OPTIONS = %i[where index_name].freeze
4
4
  DEFAULT_OPTIONS = { allow_nil: true, case_sensitive: true, allow_blank: false }.freeze
5
5
 
6
+ def self.validator_options(attributes, options)
7
+ DEFAULT_OPTIONS
8
+ .merge(attributes: attributes)
9
+ .merge(options)
10
+ .except(*CUSTOM_OPTIONS)
11
+ .tap { |opts| opts[:conditions] = -> { where(options[:where]) } if options[:where] }
12
+ end
13
+
6
14
  attr_reader :field
7
15
 
8
16
  def initialize(field, options, adapter)
@@ -21,22 +29,6 @@ module DatabaseValidations
21
29
  instance.errors.add(options[:attributes], :taken, error_options)
22
30
  end
23
31
 
24
- # @return [Hash<Symbol, Object>]
25
- def validates_uniqueness_options
26
- where_clause_str = where_clause
27
-
28
- DEFAULT_OPTIONS
29
- .merge(options)
30
- .except(*CUSTOM_OPTIONS)
31
- .tap { |opts| opts[:conditions] = -> { where(where_clause_str) } if where_clause }
32
- end
33
-
34
- # @return [Boolean]
35
- def if_and_unless_pass?(instance)
36
- (options[:if].nil? || condition_passes?(options[:if], instance)) &&
37
- (options[:unless].nil? || !condition_passes?(options[:unless], instance))
38
- end
39
-
40
32
  # @return [String]
41
33
  def key
42
34
  @key ||= index_name ? Helpers.generate_key_for_uniqueness_index(index_name) : Helpers.generate_key_for_uniqueness(columns)
@@ -76,16 +68,6 @@ module DatabaseValidations
76
68
 
77
69
  attr_reader :adapter, :options
78
70
 
79
- def condition_passes?(condition, instance)
80
- if condition.is_a?(Symbol)
81
- instance.__send__(condition)
82
- elsif condition.is_a?(Proc) && condition.arity.zero?
83
- instance.instance_exec(&condition)
84
- else
85
- instance.instance_eval(&condition)
86
- end
87
- end
88
-
89
71
  def raise_if_unsupported_options!
90
72
  options.except(:attributes).each_key do |option|
91
73
  unless adapter.support_option?(option)
@@ -1,3 +1,3 @@
1
1
  module DatabaseValidations
2
- VERSION = '0.8.5'.freeze
2
+ VERSION = '0.8.6'.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.5
4
+ version: 0.8.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evgeniy Demin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-02-06 00:00:00.000000000 Z
11
+ date: 2019-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -170,6 +170,21 @@ extensions: []
170
170
  extra_rdoc_files: []
171
171
  files:
172
172
  - lib/database_validations.rb
173
+ - lib/database_validations/lib/adapters.rb
174
+ - lib/database_validations/lib/adapters/base_adapter.rb
175
+ - lib/database_validations/lib/adapters/mysql_adapter.rb
176
+ - lib/database_validations/lib/adapters/postgresql_adapter.rb
177
+ - lib/database_validations/lib/adapters/sqlite_adapter.rb
178
+ - lib/database_validations/lib/db_belongs_to/belongs_to_handlers.rb
179
+ - lib/database_validations/lib/db_belongs_to/belongs_to_options.rb
180
+ - lib/database_validations/lib/db_belongs_to/db_presence_validator.rb
181
+ - lib/database_validations/lib/errors.rb
182
+ - lib/database_validations/lib/helpers.rb
183
+ - lib/database_validations/lib/options_storage.rb
184
+ - lib/database_validations/lib/rescuer.rb
185
+ - lib/database_validations/lib/validates_db_uniqueness_of/db_uniqueness_validator.rb
186
+ - lib/database_validations/lib/validates_db_uniqueness_of/uniqueness_handlers.rb
187
+ - lib/database_validations/lib/validates_db_uniqueness_of/uniqueness_options.rb
173
188
  - lib/database_validations/rails/railtie.rb
174
189
  - lib/database_validations/rspec/matchers.rb
175
190
  - lib/database_validations/rspec/uniqueness_validator_matcher.rb
@@ -177,20 +192,6 @@ files:
177
192
  - lib/database_validations/rubocop/cop/uniqueness_of.rb
178
193
  - lib/database_validations/rubocop/cops.rb
179
194
  - lib/database_validations/tasks/database_validations.rake
180
- - lib/database_validations/validations/adapters.rb
181
- - lib/database_validations/validations/adapters/base_adapter.rb
182
- - lib/database_validations/validations/adapters/mysql_adapter.rb
183
- - lib/database_validations/validations/adapters/postgresql_adapter.rb
184
- - lib/database_validations/validations/adapters/sqlite_adapter.rb
185
- - lib/database_validations/validations/belongs_to_handlers.rb
186
- - lib/database_validations/validations/belongs_to_options.rb
187
- - lib/database_validations/validations/belongs_to_presence_validator.rb
188
- - lib/database_validations/validations/errors.rb
189
- - lib/database_validations/validations/helpers.rb
190
- - lib/database_validations/validations/options_storage.rb
191
- - lib/database_validations/validations/uniqueness_handlers.rb
192
- - lib/database_validations/validations/uniqueness_options.rb
193
- - lib/database_validations/validations/valid_without_database_validations.rb
194
195
  - lib/database_validations/version.rb
195
196
  homepage: https://github.com/toptal/database_validations
196
197
  licenses:
@@ -1,58 +0,0 @@
1
- module DatabaseValidations
2
- module BelongsToHandlers
3
- extend ActiveSupport::Concern
4
-
5
- included do
6
- alias_method :validate, :valid?
7
- end
8
-
9
- def valid?(context = nil)
10
- output = super(context)
11
-
12
- Helpers.each_belongs_to_presence_validator(self.class) do |validator|
13
- next if validator.column_and_relation_blank_for?(self)
14
-
15
- validates_with(ActiveRecord::Validations::PresenceValidator, validator.validates_presence_options)
16
- end
17
-
18
- errors.empty? && output
19
- end
20
-
21
- def save(opts = {})
22
- ActiveRecord::Base.connection.transaction(requires_new: true) { super }
23
- rescue ActiveRecord::InvalidForeignKey => e
24
- Helpers.handle_foreign_key_error!(self, e)
25
- false
26
- end
27
-
28
- def save!(opts = {})
29
- ActiveRecord::Base.connection.transaction(requires_new: true) { super }
30
- rescue ActiveRecord::InvalidForeignKey => e
31
- Helpers.handle_foreign_key_error!(self, e)
32
- raise ActiveRecord::RecordInvalid, self
33
- end
34
-
35
- private
36
-
37
- def perform_validations(options = {})
38
- options[:validate] == false || valid_without_database_validations?(options[:context])
39
- end
40
- end
41
-
42
- module ClassMethods
43
- def db_belongs_to(name, scope = nil, **options)
44
- include(DatabaseValidations::ValidWithoutDatabaseValidations)
45
- @database_validations_opts ||= DatabaseValidations::OptionsStorage.new(self)
46
-
47
- belongs_to(name, scope, options.merge(optional: true))
48
-
49
- foreign_key = reflections[name.to_s].foreign_key
50
-
51
- validates_with DatabaseValidations::Validations::BelongsToPresenceValidator, column: foreign_key, relation: name
52
-
53
- @database_validations_opts.push_belongs_to(foreign_key, name)
54
-
55
- include(DatabaseValidations::BelongsToHandlers)
56
- end
57
- end
58
- end
@@ -1,25 +0,0 @@
1
- module DatabaseValidations
2
- module Validations
3
- class BelongsToPresenceValidator < ActiveModel::Validator
4
- attr_reader :attributes
5
-
6
- # This is a hack to simulate presence validator
7
- # It's used for cases when some 3rd parties are relies on the validators
8
- # For example, required option from simple_form checks the validator
9
- def self.kind
10
- :presence
11
- end
12
-
13
- def initialize(options = {})
14
- @attributes = [options[:relation]]
15
- super
16
- end
17
-
18
- def validate(record)
19
- return unless record.public_send(options[:column]).blank? && record.public_send(options[:relation]).blank?
20
-
21
- record.errors.add(options[:relation], :blank, message: :required)
22
- end
23
- end
24
- end
25
- end
@@ -1,56 +0,0 @@
1
- module DatabaseValidations
2
- module UniquenessHandlers
3
- extend ActiveSupport::Concern
4
-
5
- included do
6
- alias_method :validate, :valid?
7
- end
8
-
9
- def valid?(context = nil)
10
- output = super(context)
11
-
12
- Helpers.each_uniqueness_validator(self.class) do |validator|
13
- if validator.if_and_unless_pass?(self)
14
- validates_with(ActiveRecord::Validations::UniquenessValidator, validator.validates_uniqueness_options)
15
- end
16
- end
17
-
18
- errors.empty? && output
19
- end
20
-
21
- def save(options = {})
22
- ActiveRecord::Base.connection.transaction(requires_new: true) { super }
23
- rescue ActiveRecord::RecordNotUnique => e
24
- Helpers.handle_unique_error!(self, e)
25
- false
26
- end
27
-
28
- def save!(options = {})
29
- ActiveRecord::Base.connection.transaction(requires_new: true) { super }
30
- rescue ActiveRecord::RecordNotUnique => e
31
- Helpers.handle_unique_error!(self, e)
32
- raise ActiveRecord::RecordInvalid, self
33
- end
34
-
35
- private
36
-
37
- def perform_validations(options = {})
38
- options[:validate] == false || valid_without_database_validations?(options[:context])
39
- end
40
- end
41
-
42
- module ClassMethods
43
- def validates_db_uniqueness_of(*attributes)
44
- include(DatabaseValidations::ValidWithoutDatabaseValidations)
45
- @database_validations_opts ||= DatabaseValidations::OptionsStorage.new(self)
46
-
47
- options = attributes.extract_options!
48
-
49
- attributes.each do |attribute|
50
- @database_validations_opts.push_uniqueness(attribute, options.merge(attributes: attribute))
51
- end
52
-
53
- include(DatabaseValidations::UniquenessHandlers)
54
- end
55
- end
56
- end
@@ -1,9 +0,0 @@
1
- module DatabaseValidations
2
- module ValidWithoutDatabaseValidations
3
- extend ActiveSupport::Concern
4
-
5
- included do
6
- alias_method :valid_without_database_validations?, :valid?
7
- end
8
- end
9
- end