database_validations 0.3.7 → 0.4.0

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: aefb40cecf33b68606f21a491cd41ffa3e1bc4ffcf891b837b9b8693e04f2239
4
- data.tar.gz: ec3c2ab6955ec4f5da93804bcb6f2382d577331553b9d710af75a62cf9e8ccea
3
+ metadata.gz: 0a94ceacef368255d4e55eaf4ac852a839b78238ca47a0d3bceac249e4a1ded3
4
+ data.tar.gz: a38b1061a9c345543aa353c5048b2472026c4cb806991c64c5e2b23e48ac6fd7
5
5
  SHA512:
6
- metadata.gz: 1c341fa892d214a3fce105e683c90b5633c7c8ccc5917c675762e710cde2443e332bf66768831b772436c6eb6bfd823136411f409e0c16ef58cb85347f8b87c8
7
- data.tar.gz: c6a838adc69c1558acede0e38df24d30bac20d7c348951c8059966daf59e649ae7887879810e68f88df88d69b277451a7fe476bca8a237842c970103184c073b
6
+ metadata.gz: 3f1543f0a6b04ce50064e74bc56fa059153f7660774932008c5ef50699bb02c31b88f9cee8fa01ef519128932caefe770364536867a5c108ec42fee3e6a31984
7
+ data.tar.gz: b0d74dc13be3a54b9bc95c20f5ce24673e5a586392f3d63d3e5f4ad171fadf49bf3b202e4e3e12480af5bf3eba4ed935c9a4cb75a2638248e09c1ae835a634a2
data/README.md CHANGED
@@ -77,7 +77,7 @@ User.create!(email: 'email@mail.com')
77
77
 
78
78
  We want to provide full compatibility with existing `validates_uniqueness_of` validator.
79
79
 
80
- This list of supported options from `validates_uniqueness_of` validator:
80
+ List of supported options from `validates_uniqueness_of` validator:
81
81
 
82
82
  - `scope`: One or more columns by which to limit the scope of the uniqueness constraint.
83
83
  - `message`: Specifies a custom error message (default is: "has already been taken").
@@ -88,16 +88,21 @@ This list of supported options from `validates_uniqueness_of` validator:
88
88
  validates_db_uniqueness_of :email
89
89
  ```
90
90
 
91
- Is the same by default as following
91
+ Is the same by default as the following
92
92
 
93
93
  ```ruby
94
94
  validates_uniqueness_of :email, allow_nil: true, allow_blank: false, case_sensitive: true
95
95
  ```
96
96
 
97
+ List of supported options for `PostgreSQL` only:
98
+
99
+ - `where`: Specify the conditions to be included as a <tt>WHERE</tt> SQL fragment to
100
+ limit the uniqueness constraint lookup (e.g. <tt>where: "(status = 'active')"</tt>).
101
+ For backward compatibility, this will be converted automatically
102
+ to <tt>conditions: -> { where("(status = 'active')") }</tt> for `valid?` method.
103
+
97
104
  The list of options to add support:
98
105
 
99
- - `conditions`: Specify the conditions to be included as a <tt>WHERE</tt> SQL fragment to
100
- limit the uniqueness constraint lookup (e.g. <tt>conditions: -> { where(status: 'active') }</tt>).
101
106
  - `case_sensitive`: Looks for an exact match. Ignored by non-text columns (`true` by default).
102
107
  - `allow_nil`: If set to `true`, skips this validation if the attribute is `nil` (default is `false`).
103
108
  - `allow_blank`: If set to `true`, skips this validation if the attribute is blank (default is `false`).
@@ -12,8 +12,8 @@ module DatabaseValidations
12
12
  indexes.find { |index| index.name == index_name }
13
13
  end
14
14
 
15
- def find_index_by_columns(index_columns)
16
- indexes.find { |index| index.columns.map(&:to_s).sort == index_columns }
15
+ def find_index(columns, where)
16
+ indexes.find { |index| index.columns.map(&:to_s).sort == columns && index.where == where }
17
17
  end
18
18
 
19
19
  def indexes
@@ -1,7 +1,7 @@
1
1
  module DatabaseValidations
2
2
  module Adapters
3
3
  class PostgresqlAdapter < BaseAdapter
4
- SUPPORTED_OPTIONS = %i[scope message].freeze
4
+ SUPPORTED_OPTIONS = %i[scope message where].freeze
5
5
  ADAPTER = :postgresql
6
6
 
7
7
  def error_columns(error_message)
@@ -3,14 +3,22 @@ module DatabaseValidations
3
3
  class Base < StandardError; end
4
4
 
5
5
  class IndexNotFound < Base
6
- attr_reader :columns
6
+ attr_reader :columns, :where_clause, :available_indexes
7
7
 
8
- def initialize(columns)
8
+ def initialize(columns, where_clause, available_indexes)
9
9
  @columns = columns.map(&:to_s)
10
- super "No unique index found with columns: #{self.columns}. "\
10
+ @where_clause = where_clause
11
+ @available_indexes = available_indexes
12
+
13
+ super "No unique index found with #{columns_and_where_text(columns, where_clause)}. "\
14
+ "Available indexes are: [#{self.available_indexes.map { |ind| columns_and_where_text(ind.columns, ind.where) }.join(', ')}]. "\
11
15
  "Use ENV['SKIP_DB_UNIQUENESS_VALIDATOR_INDEX_CHECK']=true in case you want to skip the check. "\
12
16
  "For example, when you run migrations."
13
17
  end
18
+
19
+ def columns_and_where_text(columns, where)
20
+ "columns: #{columns}#{" and where: #{where}" if where}"
21
+ end
14
22
  end
15
23
 
16
24
  class UnknownDatabase < Base
@@ -6,7 +6,6 @@ module DatabaseValidations
6
6
  key = generate_key(Adapters.factory(instance.class).error_columns(error.message))
7
7
 
8
8
  each_options_storage(instance.class) do |storage|
9
- # storage has this then return
10
9
  return storage[key].handle_unique_error(instance) if storage[key]
11
10
  end
12
11
 
@@ -10,14 +10,18 @@ module DatabaseValidations
10
10
  end
11
11
 
12
12
  def handle_unique_error(instance)
13
- error_options = options.except(:case_sensitive, :scope, :conditions, :attributes)
13
+ error_options = options.except(:case_sensitive, :scope, :conditions, :attributes, :where)
14
14
  error_options[:value] = instance.public_send(options[:attributes])
15
15
 
16
16
  instance.errors.add(options[:attributes], :taken, error_options)
17
17
  end
18
18
 
19
19
  def validates_uniqueness_options
20
- options.merge(allow_nil: true, case_sensitive: true, allow_blank: false)
20
+ where_clause_str = where_clause
21
+
22
+ options.except(:where)
23
+ .merge(allow_nil: true, case_sensitive: true, allow_blank: false)
24
+ .tap { |opts| opts[:conditions] = -> { where(where_clause_str) } if where_clause }
21
25
  end
22
26
 
23
27
  def key
@@ -28,6 +32,10 @@ module DatabaseValidations
28
32
  @columns ||= Helpers.unify_columns(field, Array.wrap(options[:scope]))
29
33
  end
30
34
 
35
+ def where_clause
36
+ @where_clause ||= options[:where]
37
+ end
38
+
31
39
  def raise_if_unsupported_options!
32
40
  options.except(:attributes).each_key do |option|
33
41
  unless adapter.support_option?(option)
@@ -37,7 +45,7 @@ module DatabaseValidations
37
45
  end
38
46
 
39
47
  def raise_if_index_missed!
40
- raise Errors::IndexNotFound.new(columns) unless adapter.find_index_by_columns(columns)
48
+ raise Errors::IndexNotFound.new(columns, where_clause, adapter.indexes) unless adapter.find_index(columns, where_clause)
41
49
  end
42
50
 
43
51
  private
@@ -1,3 +1,3 @@
1
1
  module DatabaseValidations
2
- VERSION = "0.3.7"
2
+ VERSION = "0.4.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: database_validations
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.7
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evgeniy Demin