database_validations 0.8.6 → 0.8.9

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: b696cae920dc9834393d2cf25127c7d9c9504750ec32d58f57c2bc873f735709
4
- data.tar.gz: d2235fff367e21b9684d245b13773099bc1a1c292b1590a9888be33ae4bd1ad9
3
+ metadata.gz: 9c5d3a56f3d69b34fdc1da4e3b74b9ff3797d0ca93772df93746e709f9b9fd64
4
+ data.tar.gz: db772a3a726ccce4ce21bfceb0ddac72da07d9da3650f89d1845e92e580519b2
5
5
  SHA512:
6
- metadata.gz: 9c5740414831fa3fffcd45d4acbc5771c6b4eb49eb30de1a221ecca7dd801b841a4c55939911fab66a30f5a641a8cef19ecd5a4efb13b2a2dfd2a8f1ae80864a
7
- data.tar.gz: d3dd1b8fda9f3c187f0ecf14ecdc24322e76583bb9278cb0e1adb38decbb325be7064d24ec1ccf6cc393c5a2b72a86a7ce4e57b4026260ba0b31f88bb00b2085
6
+ metadata.gz: da0b57c3e7203be84466c31f72a517852d1b4484a306607bf48e6d6f6d683e43dc1ebdcd678bc258075c5ce1f9c52af756805b749ab5562cc84ac83a6ac48ee4
7
+ data.tar.gz: 1580a4718c53aa42267a2d7efd04148df0de38ddba3ce7c4c5f6c4c226736e4f568919cbe600b79d269566f081c7c9537b09fca0f5b0d65cdd73378e81b9ae71
@@ -9,9 +9,9 @@ module DatabaseValidations
9
9
 
10
10
  def factory(model)
11
11
  case (database = model.connection_config[:adapter].downcase.to_sym)
12
- when SqliteAdapter::ADAPTER then SqliteAdapter.new(model)
13
- when PostgresqlAdapter::ADAPTER then PostgresqlAdapter.new(model)
14
- when MysqlAdapter::ADAPTER then MysqlAdapter.new(model)
12
+ when SqliteAdapter::ADAPTER then SqliteAdapter
13
+ when PostgresqlAdapter::ADAPTER then PostgresqlAdapter
14
+ when MysqlAdapter::ADAPTER then MysqlAdapter
15
15
  else
16
16
  raise Errors::UnknownDatabase, database
17
17
  end
@@ -28,7 +28,7 @@ module DatabaseValidations
28
28
  end
29
29
 
30
30
  def find_foreign_key_by_column(column)
31
- model.connection.foreign_key_exists?(model.table_name, column: column)
31
+ foreign_keys.find { |foreign_key| foreign_key.column.to_s == column.to_s }
32
32
  end
33
33
 
34
34
  # @return [Symbol]
@@ -4,16 +4,16 @@ module DatabaseValidations
4
4
  SUPPORTED_OPTIONS = %i[scope message if unless index_name].freeze
5
5
  ADAPTER = :mysql2
6
6
 
7
- def index_name(error_message)
8
- error_message[/key '([^']+)'/, 1]
9
- end
7
+ class << self
8
+ def unique_index_name(error_message)
9
+ error_message[/key '([^']+)'/, 1]
10
+ end
10
11
 
11
- def unique_error_columns(error_message)
12
- find_index_by_name(index_name(error_message)).columns
13
- end
12
+ def unique_error_columns(_error_message); end
14
13
 
15
- def foreign_key_error_column(error_message)
16
- error_message[/FOREIGN KEY \(`([^`]+)`\)/, 1]
14
+ def foreign_key_error_column(error_message)
15
+ error_message[/FOREIGN KEY \(`([^`]+)`\)/, 1]
16
+ end
17
17
  end
18
18
  end
19
19
  end
@@ -4,16 +4,18 @@ module DatabaseValidations
4
4
  SUPPORTED_OPTIONS = %i[scope message where if unless index_name case_sensitive].freeze
5
5
  ADAPTER = :postgresql
6
6
 
7
- def index_name(error_message)
8
- error_message[/unique constraint "([^"]+)"/, 1]
9
- end
7
+ class << self
8
+ def unique_index_name(error_message)
9
+ error_message[/unique constraint "([^"]+)"/, 1]
10
+ end
10
11
 
11
- def unique_error_columns(error_message)
12
- find_index_by_name(index_name(error_message)).columns
13
- end
12
+ def unique_error_columns(error_message)
13
+ error_message[/Key \((.+)\)=/, 1].split(', ')
14
+ end
14
15
 
15
- def foreign_key_error_column(error_message)
16
- error_message[/Key \(([^)]+)\)/, 1]
16
+ def foreign_key_error_column(error_message)
17
+ error_message[/Key \(([^)]+)\)/, 1]
18
+ end
17
19
  end
18
20
  end
19
21
  end
@@ -4,18 +4,16 @@ module DatabaseValidations
4
4
  SUPPORTED_OPTIONS = %i[scope message if unless].freeze
5
5
  ADAPTER = :sqlite3
6
6
 
7
- def index_name(_error_message); end
7
+ class << self
8
+ def unique_index_name(_error_message); end
8
9
 
9
- def find_foreign_key_by_column(column)
10
- foreign_keys.find { |foreign_key| foreign_key.column.to_s == column.to_s }
11
- end
12
-
13
- def unique_error_columns(error_message)
14
- error_message.scan(/#{model.table_name}\.([^,:]+)/).flatten
15
- end
10
+ def unique_error_columns(error_message)
11
+ error_message.scan(/\w+\.([^,:]+)/).flatten
12
+ end
16
13
 
17
- def foreign_key_error_column(error_message)
18
- error_message[/\("([^"]+)"\) VALUES/, 1]
14
+ def foreign_key_error_column(error_message)
15
+ error_message[/\("([^"]+)"\) VALUES/, 1]
16
+ end
19
17
  end
20
18
  end
21
19
  end
@@ -3,13 +3,13 @@ module DatabaseValidations
3
3
  def db_belongs_to(name, scope = nil, **options)
4
4
  Helpers.cache_valid_method!(self)
5
5
 
6
- @database_validations_opts ||= DatabaseValidations::OptionsStorage.new(self)
6
+ @database_validations_storage ||= DatabaseValidations::OptionsStorage.new(self)
7
7
 
8
8
  belongs_to(name, scope, options.merge(optional: true))
9
9
 
10
10
  foreign_key = reflections[name.to_s].foreign_key
11
11
 
12
- @database_validations_opts.push_belongs_to(foreign_key, name)
12
+ @database_validations_storage.push_belongs_to(foreign_key, name)
13
13
 
14
14
  validates_with DatabaseValidations::DBPresenceValidator,
15
15
  DatabaseValidations::BelongsToOptions.validator_options(name, foreign_key)
@@ -17,12 +17,7 @@ module DatabaseValidations
17
17
 
18
18
  # @return [String]
19
19
  def key
20
- Helpers.generate_key_for_belongs_to(column)
21
- end
22
-
23
- # @return [Boolean]
24
- def column_and_relation_blank_for?(instance)
25
- instance.public_send(column).blank? && instance.public_send(relation).blank?
20
+ @key ||= Helpers.generate_key_for_belongs_to(column)
26
21
  end
27
22
 
28
23
  def handle_foreign_key_error(instance)
@@ -59,7 +59,7 @@ module DatabaseValidations
59
59
  @column = column
60
60
  @foreign_keys = foreign_keys
61
61
 
62
- super "No foreign key found with column: \"#{column}\". Founded foreign keys are: #{foreign_keys}. " + env_message
62
+ super "No foreign key found with column: \"#{column}\". Found foreign keys are: #{foreign_keys}. " + env_message
63
63
  end
64
64
  end
65
65
 
@@ -18,14 +18,16 @@ module DatabaseValidations
18
18
  end
19
19
  end
20
20
 
21
- def handle_unique_error!(instance, error) # rubocop:disable Metrics/AbcSize
21
+ def handle_unique_error!(instance, error)
22
22
  adapter = Adapters.factory(instance.class)
23
- index_key = generate_key_for_uniqueness_index(adapter.index_name(error.message))
24
- column_key = generate_key_for_uniqueness(adapter.unique_error_columns(error.message))
23
+
24
+ keys = [
25
+ generate_key_for_uniqueness_index(adapter.unique_index_name(error.message)),
26
+ generate_key_for_uniqueness(adapter.unique_error_columns(error.message))
27
+ ]
25
28
 
26
29
  each_options_storage(instance.class) do |storage|
27
- return storage[index_key].handle_unique_error(instance) if storage[index_key]
28
- return storage[column_key].handle_unique_error(instance) if storage[column_key]
30
+ keys.each { |key| return storage[key].handle_unique_error(instance) if storage[key] }
29
31
  end
30
32
 
31
33
  false
@@ -44,26 +46,18 @@ module DatabaseValidations
44
46
 
45
47
  def each_options_storage(klass)
46
48
  while klass.respond_to?(:validates_db_uniqueness_of)
47
- storage = klass.instance_variable_get(:'@database_validations_opts')
49
+ storage = storage_of(klass)
48
50
  yield(storage) if storage
49
51
  klass = klass.superclass
50
52
  end
51
53
  end
52
54
 
53
- def each_uniqueness_validator(klass)
54
- each_options_storage(klass) do |storage|
55
- storage.each_uniqueness_validator { |validator| yield(validator) }
56
- end
57
- end
58
-
59
- def each_belongs_to_presence_validator(klass)
60
- each_options_storage(klass) do |storage|
61
- storage.each_belongs_to_presence_validator { |validator| yield(validator) }
62
- end
55
+ def storage_of(klass)
56
+ klass.instance_variable_get(:'@database_validations_storage')
63
57
  end
64
58
 
65
- def unify_columns(*columns)
66
- columns.flatten.compact.map(&:to_s).sort
59
+ def unify_columns(*args)
60
+ args.flatten.compact.map(&:to_s).sort
67
61
  end
68
62
 
69
63
  def generate_key_for_uniqueness_index(index_name)
@@ -78,8 +72,8 @@ module DatabaseValidations
78
72
  generate_key(:belongs_to, column)
79
73
  end
80
74
 
81
- def generate_key(type, *columns)
82
- [type, *unify_columns(columns)].join('__')
75
+ def generate_key(type, *args)
76
+ [type, *unify_columns(args)].join('__')
83
77
  end
84
78
  end
85
79
  end
@@ -1,13 +1,14 @@
1
1
  module DatabaseValidations
2
2
  class OptionsStorage
3
3
  def initialize(klass)
4
- @adapter = Adapters.factory(klass)
4
+ @adapter = Adapters.factory(klass).new(klass)
5
5
  @storage = {}
6
6
  end
7
7
 
8
8
  def push_uniqueness(field, options)
9
9
  uniqueness_options = UniquenessOptions.new(field, options, adapter)
10
- storage[uniqueness_options.key] = uniqueness_options
10
+ storage[uniqueness_options.index_key] = uniqueness_options
11
+ storage[uniqueness_options.column_key] = uniqueness_options
11
12
  end
12
13
 
13
14
  def push_belongs_to(field, relation)
@@ -19,12 +20,8 @@ module DatabaseValidations
19
20
  storage[key]
20
21
  end
21
22
 
22
- def each_uniqueness_validator
23
- storage.values.grep(UniquenessOptions).each { |validator| yield(validator) }
24
- end
25
-
26
- def each_belongs_to_presence_validator
27
- storage.values.grep(BelongsToOptions).each { |validator| yield(validator) }
23
+ def options
24
+ storage.values
28
25
  end
29
26
 
30
27
  private
@@ -3,12 +3,12 @@ module DatabaseValidations
3
3
  def validates_db_uniqueness_of(*attributes)
4
4
  Helpers.cache_valid_method!(self)
5
5
 
6
- @database_validations_opts ||= DatabaseValidations::OptionsStorage.new(self)
6
+ @database_validations_storage ||= DatabaseValidations::OptionsStorage.new(self)
7
7
 
8
8
  options = attributes.extract_options!
9
9
 
10
10
  attributes.each do |attribute|
11
- @database_validations_opts.push_uniqueness(attribute, options.merge(attributes: attribute))
11
+ @database_validations_storage.push_uniqueness(attribute, options.merge(attributes: attribute))
12
12
  end
13
13
 
14
14
  validates_with DatabaseValidations::DBUniquenessValidator,
@@ -11,7 +11,7 @@ module DatabaseValidations
11
11
  .tap { |opts| opts[:conditions] = -> { where(options[:where]) } if options[:where] }
12
12
  end
13
13
 
14
- attr_reader :field
14
+ attr_reader :field, :calculated_index_name
15
15
 
16
16
  def initialize(field, options, adapter)
17
17
  @field = field
@@ -19,7 +19,13 @@ module DatabaseValidations
19
19
  @adapter = adapter
20
20
 
21
21
  raise_if_unsupported_options!
22
- raise_if_index_missed! unless ENV['SKIP_DB_UNIQUENESS_VALIDATOR_INDEX_CHECK']
22
+
23
+ return if ENV['SKIP_DB_UNIQUENESS_VALIDATOR_INDEX_CHECK']
24
+
25
+ index = responsible_index
26
+ raise_if_index_missed!(index)
27
+
28
+ @calculated_index_name = index.name
23
29
  end
24
30
 
25
31
  def handle_unique_error(instance)
@@ -30,8 +36,13 @@ module DatabaseValidations
30
36
  end
31
37
 
32
38
  # @return [String]
33
- def key
34
- @key ||= index_name ? Helpers.generate_key_for_uniqueness_index(index_name) : Helpers.generate_key_for_uniqueness(columns)
39
+ def index_key
40
+ @index_key ||= Helpers.generate_key_for_uniqueness_index(index_name || calculated_index_name)
41
+ end
42
+
43
+ # @return [String]
44
+ def column_key
45
+ @column_key ||= Helpers.generate_key_for_uniqueness(columns)
35
46
  end
36
47
 
37
48
  # @return [Array<String>]
@@ -76,11 +87,12 @@ module DatabaseValidations
76
87
  end
77
88
  end
78
89
 
79
- def raise_if_index_missed! # rubocop:disable Metrics/AbcSize
80
- unless (index_name && adapter.find_index_by_name(index_name.to_s)) ||
81
- (!index_name && adapter.find_index(columns, where_clause))
82
- raise Errors::IndexNotFound.new(columns, where_clause, index_name, adapter.indexes, adapter.table_name)
83
- end
90
+ def responsible_index
91
+ index_name ? adapter.find_index_by_name(index_name.to_s) : adapter.find_index(columns, where_clause)
92
+ end
93
+
94
+ def raise_if_index_missed!(index)
95
+ raise Errors::IndexNotFound.new(columns, where_clause, index_name, adapter.indexes, adapter.table_name) unless index
84
96
  end
85
97
  end
86
98
  end
@@ -46,15 +46,17 @@ RSpec::Matchers.define :validate_db_uniqueness_of do |field| # rubocop:disable M
46
46
 
47
47
  model = object.is_a?(Class) ? object : object.class
48
48
 
49
- DatabaseValidations::Helpers.each_uniqueness_validator(model) do |validator|
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,
56
- case_sensitive: validator.case_sensitive
57
- }
49
+ DatabaseValidations::Helpers.each_options_storage(model) do |storage|
50
+ storage.options.grep(DatabaseValidations::UniquenessOptions).each do |validator|
51
+ @validators << {
52
+ field: validator.field,
53
+ scope: validator.scope,
54
+ where: validator.where_clause,
55
+ message: validator.message,
56
+ index_name: validator.index_name,
57
+ case_sensitive: validator.case_sensitive
58
+ }
59
+ end
58
60
  end
59
61
 
60
62
  @validators.include?(
@@ -1,3 +1,3 @@
1
1
  module DatabaseValidations
2
- VERSION = '0.8.6'.freeze
2
+ VERSION = '0.8.9'.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.6
4
+ version: 0.8.9
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-11 00:00:00.000000000 Z
11
+ date: 2019-02-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord