database_validations 0.9.2 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fc082896680bee591fcbf04d9f9fb469c72c9c1e2c259f5093341e2c1448cd15
4
- data.tar.gz: 474977490d71108f408c448bf9b18d404218b2b17f8f3cf7b48a2f945e4535d5
3
+ metadata.gz: 84632667aa6aec235e306d5443ca94804d19541330fe13ec52cfcc80c44e3719
4
+ data.tar.gz: f7619dd8fd5093302a959f978839433a38fa0735b4d6f105110b6042758eb64a
5
5
  SHA512:
6
- metadata.gz: eb8e2d716fa3bb7bcb0d04f9e9db16f00587d2a7a3742b3367a0b3bf9bee9c883d0ec4f7144f08f0f7045ebed8a7297f33ea77d4bd192102b56e4087f08cff15
7
- data.tar.gz: 0da69998634da7b5b9250ce11e1fda4f6dd3809c57bdf5e302a85ad5c7c25d728a57c21a00d98d5e948bac206ae2d46dab52aa0d01714628826f8691ab8883a4
6
+ metadata.gz: b38c529569458eac14defeec0216018f5db85f9a1a82dbf9793b3c32fc4d378dceafb3fbbb9a2094374db898a49f36fbef8be2d09f54b10c0f22fed036945a73
7
+ data.tar.gz: d6f93d5f638ee921f8d01980310866f0bc811909fd7963e7c901c9bc7e0122a891ed2813af37653e4c9ccb7bac92084593794f2d396f66fa4fb9b10ee9faca9d
@@ -9,18 +9,25 @@ module DatabaseValidations
9
9
  end
10
10
 
11
11
  # @param [String] index_name
12
- def find_index_by_name(index_name)
13
- indexes.find { |index| index.name == index_name }
12
+ def find_unique_index_by_name(index_name)
13
+ unique_indexes.find { |index| index.name == index_name }
14
14
  end
15
15
 
16
16
  # @param [Array<String>] columns
17
17
  # @param [String] where
18
- def find_index(columns, where)
19
- indexes.find { |index| Array.wrap(index.columns).map(&:to_s).sort == columns && index.where == where }
18
+ def find_unique_index(columns, where)
19
+ unique_indexes.find { |index| Array.wrap(index.columns).map(&:to_s).sort == columns && index.where == where }
20
20
  end
21
21
 
22
- def indexes
23
- model.connection.indexes(model.table_name).select(&:unique)
22
+ def unique_indexes
23
+ connection = model.connection
24
+
25
+ if connection.schema_cache.respond_to?(:indexes)
26
+ # Rails 6 only
27
+ connection.schema_cache.indexes(model.table_name).select(&:unique)
28
+ else
29
+ connection.indexes(model.table_name).select(&:unique)
30
+ end
24
31
  end
25
32
 
26
33
  def foreign_keys
@@ -8,7 +8,13 @@ module DatabaseValidations
8
8
  module_function
9
9
 
10
10
  def factory(model)
11
- case (database = model.connection_config[:adapter].downcase.to_sym)
11
+ database = if ActiveRecord.version < Gem::Version.new('6.1.0')
12
+ model.connection_config[:adapter].downcase.to_sym
13
+ else
14
+ model.connection_db_config.adapter.downcase.to_sym
15
+ end
16
+
17
+ case database
12
18
  when SqliteAdapter::ADAPTER then SqliteAdapter
13
19
  when PostgresqlAdapter::ADAPTER then PostgresqlAdapter
14
20
  when MysqlAdapter::ADAPTER then MysqlAdapter
@@ -38,8 +38,8 @@ module DatabaseValidations
38
38
 
39
39
  validator.attributes.map do |attribute|
40
40
  columns = KeyGenerator.unify_columns(attribute, validator.options[:scope])
41
- index = validator.index_name ? adapter.find_index_by_name(validator.index_name.to_s) : adapter.find_index(columns, validator.where) # rubocop:disable Metrics/LineLength
42
- raise Errors::IndexNotFound.new(columns, validator.where, validator.index_name, adapter.indexes, adapter.table_name) unless index && valid_index?(columns, index) # rubocop:disable Metrics/LineLength
41
+ index = validator.index_name ? adapter.find_unique_index_by_name(validator.index_name.to_s) : adapter.find_unique_index(columns, validator.where) # rubocop:disable Metrics/LineLength
42
+ raise Errors::IndexNotFound.new(columns, validator.where, validator.index_name, adapter.unique_indexes, adapter.table_name) unless index && valid_index?(columns, index) # rubocop:disable Metrics/LineLength
43
43
  end
44
44
  end
45
45
  end
@@ -24,13 +24,19 @@ module DatabaseValidations
24
24
  keys.each do |key|
25
25
  attribute_validator = instance._db_validators[key]
26
26
 
27
- if attribute_validator
28
- attribute_validator.validator.apply_error(instance, attribute_validator.attribute)
29
- return true
30
- end
27
+ next unless attribute_validator
28
+
29
+ return process_validator(instance, attribute_validator)
31
30
  end
32
31
 
33
32
  false
34
33
  end
34
+
35
+ def process_validator(instance, attribute_validator)
36
+ return false unless attribute_validator.validator.perform_db_validation?
37
+
38
+ attribute_validator.validator.apply_error(instance, attribute_validator.attribute)
39
+ true
40
+ end
35
41
  end
36
42
  end
@@ -22,7 +22,7 @@ module DatabaseValidations
22
22
  else
23
23
  validator.attributes.map do |attribute|
24
24
  columns = KeyGenerator.unify_columns(attribute, validator.options[:scope])
25
- index = adapter.find_index(columns, validator.where)
25
+ index = adapter.find_unique_index(columns, validator.where)
26
26
  [KeyGenerator.for_unique_index(index.name), attribute]
27
27
  end.to_h
28
28
  end
@@ -14,16 +14,26 @@ module DatabaseValidations
14
14
  end
15
15
 
16
16
  def create_or_update(*args, &block)
17
+ options = args.extract_options!
18
+
19
+ if options[:validate] == false
20
+ super
21
+ else
22
+ rescue_from_database_exceptions { super }
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def rescue_from_database_exceptions(&block)
17
29
  self._database_validations_fallback = false
18
- ActiveRecord::Base.connection.transaction(requires_new: true) { super }
30
+ self.class.connection.transaction(requires_new: true, &block)
19
31
  rescue ActiveRecord::InvalidForeignKey, ActiveRecord::RecordNotUnique => e
20
32
  raise e unless Rescuer.handled?(self, e)
21
33
 
22
34
  raise ActiveRecord::RecordInvalid, self
23
35
  end
24
36
 
25
- private
26
-
27
37
  def perform_validations(options = {})
28
38
  options[:validate] == false || valid_without_database_validations?(options[:context])
29
39
  end
@@ -21,6 +21,10 @@ module DatabaseValidations
21
21
  Checkers::DbPresenceValidator.validate!(self)
22
22
  end
23
23
 
24
+ def perform_db_validation?
25
+ true
26
+ end
27
+
24
28
  # TODO: add support of optional db_belongs_to
25
29
  def validate(record)
26
30
  if record._database_validations_fallback
@@ -1,5 +1,7 @@
1
1
  module DatabaseValidations
2
2
  class DbUniquenessValidator < ActiveRecord::Validations::UniquenessValidator
3
+ DEFAULT_MODE = :optimized
4
+
3
5
  attr_reader :index_name, :where, :klass
4
6
 
5
7
  # Used to make 3rd party libraries work correctly
@@ -19,8 +21,7 @@ module DatabaseValidations
19
21
  options[:conditions] = -> { where(condition) }
20
22
  end
21
23
 
22
- @index_name = options.delete(:index_name) if options.key?(:index_name)
23
- @where = options.delete(:where) if options.key?(:where)
24
+ handle_custom_options(options)
24
25
 
25
26
  super
26
27
 
@@ -28,15 +29,31 @@ module DatabaseValidations
28
29
  Checkers::DbUniquenessValidator.validate!(self)
29
30
  end
30
31
 
32
+ def perform_db_validation?
33
+ @mode != :standard
34
+ end
35
+
31
36
  def validate(record)
32
- super if record._database_validations_fallback
37
+ super if perform_query? || record._database_validations_fallback
33
38
  end
34
39
 
35
40
  def apply_error(instance, attribute)
36
41
  error_options = options.except(:case_sensitive, :scope, :conditions)
37
42
  error_options[:value] = instance.public_send(attribute)
38
43
 
39
- instance.errors.add(attribute, :taken, error_options)
44
+ instance.errors.add(attribute, :taken, **error_options)
45
+ end
46
+
47
+ private
48
+
49
+ def handle_custom_options(options)
50
+ @index_name = options.delete(:index_name) if options.key?(:index_name)
51
+ @where = options.delete(:where) if options.key?(:where)
52
+ @mode = (options.delete(:mode).presence || DEFAULT_MODE).to_sym
53
+ end
54
+
55
+ def perform_query?
56
+ @mode != :optimized
40
57
  end
41
58
  end
42
59
 
@@ -1,3 +1,3 @@
1
1
  module DatabaseValidations
2
- VERSION = '0.9.2'.freeze
2
+ VERSION = '1.0.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.9.2
4
+ version: 1.0.1
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-09-16 00:00:00.000000000 Z
11
+ date: 2021-09-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -208,7 +208,7 @@ homepage: https://github.com/toptal/database_validations
208
208
  licenses:
209
209
  - MIT
210
210
  metadata: {}
211
- post_install_message:
211
+ post_install_message:
212
212
  rdoc_options: []
213
213
  require_paths:
214
214
  - lib
@@ -223,8 +223,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
223
223
  - !ruby/object:Gem::Version
224
224
  version: '0'
225
225
  requirements: []
226
- rubygems_version: 3.1.2
227
- signing_key:
226
+ rubygems_version: 3.2.22
227
+ signing_key:
228
228
  specification_version: 4
229
229
  summary: Provide compatibility between database constraints and ActiveRecord validations
230
230
  with better performance and consistency.