database_validations 0.8.5 → 0.8.6

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.
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