database_validations 0.8.6 → 0.8.9

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