activerecord-databasevalidations 0.5.1 → 1.0.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 +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +2 -4
- data/activerecord-databasevalidations.gemspec +0 -1
- data/lib/active_record/database_validations/locale/en.yml +0 -1
- data/lib/active_record/database_validations/version.rb +1 -1
- data/lib/active_record/validations/database_constraints.rb +1 -9
- data/test/data_loss_test.rb +1 -8
- data/test/database.yml +3 -1
- data/test/database_constraints_validator_test.rb +6 -23
- metadata +6 -23
- data/lib/active_model/validations/basic_multilingual_plane.rb +0 -27
- data/test/basic_multilingual_plane_validator_test.rb +0 -54
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2f077f16b8f0e2832a0e5d50c3e4ce45953725296ce0bcf31f1715413e362c2e
|
4
|
+
data.tar.gz: 8f82f37b686c7cdd222dae109c1a13caabfcc1086e5be71d0defee5b02dc89a8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5e34412eb9b7662b4a972de4bfff63cc7ff5eb40880965ad9531ce8aed174d0d203015481f6b7c2b4bfe16bc0a1ffd9081ea88e4ceefb2d0f2ddf886cad6457e
|
7
|
+
data.tar.gz: e36e86a6bbbc6ed588a23a2b509193f0dfa788957a3d1c2b7ea06e81e8e957f41b8e529a2be5f24d087d83f1a67f63e00e06d7278a9289d800d561f1f6a8b22e
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -30,7 +30,7 @@ to validate based on the database constraints.
|
|
30
30
|
``` ruby
|
31
31
|
class Foo < ActiveRecord::Base
|
32
32
|
validates :boolean_field, database_constraints: :not_null
|
33
|
-
validates :string_field, database_constraints: [:size
|
33
|
+
validates :string_field, database_constraints: [:size]
|
34
34
|
validates :decimal_field, :integer_field, database_constraints: :range
|
35
35
|
end
|
36
36
|
```
|
@@ -50,8 +50,6 @@ You have to specify what conatrints you want to validate for. Valid values are:
|
|
50
50
|
- `:range` to validate the numeric range of a column based on it's type.
|
51
51
|
- `:size` to validate for the size of textual and binary columns. It will pick character
|
52
52
|
size or bytesize based on the column's type.
|
53
|
-
- `:basic_multilingual_plane` to validate that all characters for text fields are inside
|
54
|
-
the basic multilingual plane of unicode (unless you use the utf8mb4 character set).
|
55
53
|
- `:not_null` to validate a NOT NULL contraint.
|
56
54
|
|
57
55
|
The validations will only be created if it makes sense for the column, e.g. a `:not_null`
|
@@ -63,7 +61,7 @@ You can also instantiate the validators yourself:
|
|
63
61
|
|
64
62
|
``` ruby
|
65
63
|
class Bar < ActiveRecord::Base
|
66
|
-
validates :string_field, bytesize: { maximum: 255 }
|
64
|
+
validates :string_field, bytesize: { maximum: 255 }
|
67
65
|
validates :string_field, not_null: true
|
68
66
|
end
|
69
67
|
```
|
@@ -21,7 +21,6 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.required_ruby_version = '>= 2.5'
|
22
22
|
|
23
23
|
spec.add_runtime_dependency "activerecord", ">= 5.2"
|
24
|
-
spec.add_runtime_dependency "rejectu"
|
25
24
|
|
26
25
|
spec.add_development_dependency "bundler"
|
27
26
|
spec.add_development_dependency "rake"
|
@@ -4,5 +4,4 @@ en:
|
|
4
4
|
# The value :count is available when applicable. Can be used for pluralization.
|
5
5
|
messages:
|
6
6
|
too_many_bytes: "is too long (maximum is %{count} bytes)"
|
7
|
-
characters_outside_basic_multilingual_plane: "contains characters outside Unicode's basic multilingual plane"
|
8
7
|
must_be_set: "must be set"
|
@@ -1,13 +1,12 @@
|
|
1
1
|
require 'active_model/validations/bytesize'
|
2
2
|
require 'active_model/validations/not_null'
|
3
|
-
require 'active_model/validations/basic_multilingual_plane'
|
4
3
|
|
5
4
|
module ActiveRecord
|
6
5
|
module Validations
|
7
6
|
class DatabaseConstraintsValidator < ActiveModel::EachValidator
|
8
7
|
attr_reader :constraints
|
9
8
|
|
10
|
-
VALID_CONSTRAINTS = Set[:size, :
|
9
|
+
VALID_CONSTRAINTS = Set[:size, :not_null, :range]
|
11
10
|
|
12
11
|
SIZE_VALIDATORS_FOR_TYPE = {
|
13
12
|
characters: ActiveModel::Validations::LengthValidator,
|
@@ -55,12 +54,6 @@ module ActiveRecord
|
|
55
54
|
ActiveModel::Validations::NumericalityValidator.new(args)
|
56
55
|
end
|
57
56
|
|
58
|
-
def basic_multilingual_plane_validator(klass, column)
|
59
|
-
return unless constraints.include?(:basic_multilingual_plane)
|
60
|
-
return unless column.text? && column.collation =~ /\Autf8(?:mb3)?_/
|
61
|
-
ActiveModel::Validations::BasicMultilingualPlaneValidator.new(attributes: [column.name.to_sym], class: klass)
|
62
|
-
end
|
63
|
-
|
64
57
|
def attribute_validators(klass, attribute)
|
65
58
|
@constraint_validators[attribute] ||= begin
|
66
59
|
column_definition = klass.columns_hash[attribute.to_s]
|
@@ -74,7 +67,6 @@ module ActiveRecord
|
|
74
67
|
[
|
75
68
|
not_null_validator(klass, column),
|
76
69
|
size_validator(klass, column),
|
77
|
-
basic_multilingual_plane_validator(klass, column),
|
78
70
|
range_validator(klass, column),
|
79
71
|
].compact
|
80
72
|
end
|
data/test/data_loss_test.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
require 'test_helper'
|
4
4
|
|
5
5
|
ActiveRecord::Migration.suppress_messages do
|
6
|
-
ActiveRecord::Migration.create_table("unicorns", force: true
|
6
|
+
ActiveRecord::Migration.create_table("unicorns", force: true) do |t|
|
7
7
|
t.column :string, "VARCHAR(40)"
|
8
8
|
t.column :tinytext, "TINYTEXT"
|
9
9
|
t.column :blob, "BLOB"
|
@@ -97,11 +97,4 @@ class DataLossTest < Minitest::Test
|
|
97
97
|
refute_data_loss Unicorn.new(blob: [].pack('x65535')) # 65535 is bytesize limit of blob field
|
98
98
|
assert_data_loss Unicorn.new(blob: [].pack('x65536'))
|
99
99
|
end
|
100
|
-
|
101
|
-
def test_utf8mb3_field_sliently_truncates_strings_after_first_4byte_character
|
102
|
-
emoji = "\u{1F4A9}"
|
103
|
-
assert_equal 1, emoji.length
|
104
|
-
assert_equal 4, emoji.bytesize
|
105
|
-
assert_data_loss Unicorn.new(string: emoji)
|
106
|
-
end
|
107
100
|
end
|
data/test/database.yml
CHANGED
@@ -13,10 +13,6 @@ ActiveRecord::Migration.suppress_messages do
|
|
13
13
|
t.integer :unchecked, null: false
|
14
14
|
end
|
15
15
|
|
16
|
-
ActiveRecord::Migration.create_table("bars", force: true, options: "CHARACTER SET utf8mb4") do |t|
|
17
|
-
t.string :mb4_string
|
18
|
-
end
|
19
|
-
|
20
16
|
ActiveRecord::Migration.create_table("empties", force: true)
|
21
17
|
|
22
18
|
ActiveRecord::Migration.create_table("nums", force: true) do |t|
|
@@ -34,11 +30,7 @@ end
|
|
34
30
|
class Foo < ActiveRecord::Base
|
35
31
|
validates :string, :tinytext, :varbinary, :blob, database_constraints: :size
|
36
32
|
validates :checked, database_constraints: :not_null
|
37
|
-
validates :not_null_text, database_constraints: [:size
|
38
|
-
end
|
39
|
-
|
40
|
-
class Bar < ActiveRecord::Base
|
41
|
-
validates :mb4_string, database_constraints: :basic_multilingual_plane
|
33
|
+
validates :not_null_text, database_constraints: [:size]
|
42
34
|
end
|
43
35
|
|
44
36
|
class Empty < ActiveRecord::Base
|
@@ -55,10 +47,10 @@ class DatabaseConstraintsValidatorTest < Minitest::Test
|
|
55
47
|
include DataLossAssertions
|
56
48
|
|
57
49
|
def test_argument_validation
|
58
|
-
assert_raises(ArgumentError) {
|
59
|
-
assert_raises(ArgumentError) {
|
60
|
-
assert_raises(ArgumentError) {
|
61
|
-
assert_raises(ArgumentError) {
|
50
|
+
assert_raises(ArgumentError) { Foo.validates(:string, database_constraints: []) }
|
51
|
+
assert_raises(ArgumentError) { Foo.validates(:string, database_constraints: true) }
|
52
|
+
assert_raises(ArgumentError) { Foo.validates(:string, database_constraints: :bogus) }
|
53
|
+
assert_raises(ArgumentError) { Foo.validates(:string, database_constraints: [:size, :bogus]) }
|
62
54
|
end
|
63
55
|
|
64
56
|
def test_column_validation
|
@@ -104,10 +96,9 @@ class DatabaseConstraintsValidatorTest < Minitest::Test
|
|
104
96
|
def test_not_null_text_field_defines_requested_bytesize_validator_and_unicode_validator
|
105
97
|
validator = Foo._validators[:not_null_text].first
|
106
98
|
subvalidators = validator.attribute_validators(Foo, :not_null_text)
|
107
|
-
assert_equal
|
99
|
+
assert_equal 1, subvalidators.length
|
108
100
|
|
109
101
|
assert_kind_of ActiveModel::Validations::BytesizeValidator, subvalidators.first
|
110
|
-
assert_kind_of ActiveModel::Validations::BasicMultilingualPlaneValidator, subvalidators.second
|
111
102
|
assert_equal 65535, subvalidators.first.options[:maximum]
|
112
103
|
assert_equal Encoding.find('utf-8'), subvalidators.first.encoding
|
113
104
|
end
|
@@ -118,13 +109,6 @@ class DatabaseConstraintsValidatorTest < Minitest::Test
|
|
118
109
|
refute Foo.new(checked: nil).valid?
|
119
110
|
end
|
120
111
|
|
121
|
-
def test_should_not_create_a_validator_for_a_utf8mb4_field
|
122
|
-
assert Bar._validators[:mb4_string].first.attribute_validators(Bar, :mb4_string).empty?
|
123
|
-
emoji = Bar.new(mb4_string: '')
|
124
|
-
assert emoji.valid?
|
125
|
-
refute_data_loss emoji
|
126
|
-
end
|
127
|
-
|
128
112
|
def test_decimal_range
|
129
113
|
subvalidators = Num._validators[:decimal].first.attribute_validators(Num, :decimal)
|
130
114
|
assert_equal 1, subvalidators.length
|
@@ -219,7 +203,6 @@ class DatabaseConstraintsValidatorTest < Minitest::Test
|
|
219
203
|
|
220
204
|
assert_equal ["is too long (maximum is 40 characters)"], foo.errors[:string]
|
221
205
|
assert_equal ["must be set"], foo.errors[:checked]
|
222
|
-
assert_equal ["contains characters outside Unicode's basic multilingual plane"], foo.errors[:not_null_text]
|
223
206
|
end
|
224
207
|
|
225
208
|
def test_encoding_craziness
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-databasevalidations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Willem van Bergen
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-05-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -24,20 +24,6 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '5.2'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: rejectu
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
28
|
name: bundler
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -112,7 +98,6 @@ files:
|
|
112
98
|
- activerecord-databasevalidations.gemspec
|
113
99
|
- gemfiles/Gemfile.activerecord52
|
114
100
|
- gemfiles/Gemfile.activerecord60
|
115
|
-
- lib/active_model/validations/basic_multilingual_plane.rb
|
116
101
|
- lib/active_model/validations/bytesize.rb
|
117
102
|
- lib/active_model/validations/not_null.rb
|
118
103
|
- lib/active_record/database_validations.rb
|
@@ -126,7 +111,6 @@ files:
|
|
126
111
|
- lib/active_record/validations/typed_column.rb
|
127
112
|
- lib/activerecord-databasevalidations.rb
|
128
113
|
- lib/activerecord/databasevalidations.rb
|
129
|
-
- test/basic_multilingual_plane_validator_test.rb
|
130
114
|
- test/bytesize_validator_test.rb
|
131
115
|
- test/data_loss_test.rb
|
132
116
|
- test/database.yml
|
@@ -139,7 +123,7 @@ homepage: https://github.com/wvanbergen/activerecord-database_validations
|
|
139
123
|
licenses:
|
140
124
|
- MIT
|
141
125
|
metadata: {}
|
142
|
-
post_install_message:
|
126
|
+
post_install_message:
|
143
127
|
rdoc_options: []
|
144
128
|
require_paths:
|
145
129
|
- lib
|
@@ -154,12 +138,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
154
138
|
- !ruby/object:Gem::Version
|
155
139
|
version: '0'
|
156
140
|
requirements: []
|
157
|
-
rubygems_version: 3.1.
|
158
|
-
signing_key:
|
141
|
+
rubygems_version: 3.1.4
|
142
|
+
signing_key:
|
159
143
|
specification_version: 4
|
160
144
|
summary: Add validations to your ActiveRecord models based on MySQL database constraints.
|
161
145
|
test_files:
|
162
|
-
- test/basic_multilingual_plane_validator_test.rb
|
163
146
|
- test/bytesize_validator_test.rb
|
164
147
|
- test/data_loss_test.rb
|
165
148
|
- test/database.yml
|
@@ -1,27 +0,0 @@
|
|
1
|
-
require 'rejectu/rejectu'
|
2
|
-
|
3
|
-
module ActiveModel
|
4
|
-
module Validations
|
5
|
-
class BasicMultilingualPlaneValidator < ActiveModel::EachValidator
|
6
|
-
OUTSIDE_BMP = /[^\u{0}-\u{FFFF}]/
|
7
|
-
|
8
|
-
def validate_each(record, attribute, value)
|
9
|
-
return if value.nil?
|
10
|
-
return if value.to_s.encoding != Encoding::UTF_8
|
11
|
-
|
12
|
-
unless Rejectu.valid?(value.to_s)
|
13
|
-
errors_options = options.except(:characters_outside_basic_multilingual_plane)
|
14
|
-
default_message = options[:characters_outside_basic_multilingual_plane]
|
15
|
-
errors_options[:message] ||= default_message if default_message
|
16
|
-
record.errors.add(attribute, :characters_outside_basic_multilingual_plane, **errors_options)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
module HelperMethods
|
22
|
-
def validates_basic_multilingual_plane_of(*attr_names)
|
23
|
-
validates_with ActiveModel::Validations::BasicMultilingualPlaneValidator, _merge_attributes(attr_names)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,54 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
require 'test_helper'
|
3
|
-
|
4
|
-
class BasicMultilingualPlaneValidatorTest < Minitest::Test
|
5
|
-
|
6
|
-
class Model
|
7
|
-
include ActiveModel::Validations
|
8
|
-
|
9
|
-
attr_accessor :unicode
|
10
|
-
validates :unicode, basic_multilingual_plane: true
|
11
|
-
end
|
12
|
-
|
13
|
-
def setup
|
14
|
-
@model = Model.new
|
15
|
-
end
|
16
|
-
|
17
|
-
def test_basic_multilingual_plane_string
|
18
|
-
@model.unicode = 'basic multilingual ünicode'
|
19
|
-
assert @model.valid?
|
20
|
-
|
21
|
-
end
|
22
|
-
|
23
|
-
def test_emoji
|
24
|
-
@model.unicode = '💩'
|
25
|
-
assert @model.invalid?
|
26
|
-
assert_equal ["contains characters outside Unicode's basic multilingual plane"], @model.errors[:unicode]
|
27
|
-
end
|
28
|
-
|
29
|
-
def test_nil
|
30
|
-
@model.unicode = nil
|
31
|
-
assert @model.valid?
|
32
|
-
end
|
33
|
-
|
34
|
-
def test_different_type
|
35
|
-
@model.unicode = 1
|
36
|
-
assert @model.valid?
|
37
|
-
end
|
38
|
-
|
39
|
-
def test_non_unicode_encoding
|
40
|
-
@model.unicode = 'ü'.encode('ISO-8859-15')
|
41
|
-
assert @model.valid?
|
42
|
-
end
|
43
|
-
|
44
|
-
def test_utf8mb3_japanese
|
45
|
-
@model.unicode = 'これは普通なストリングです'
|
46
|
-
assert @model.valid?
|
47
|
-
end
|
48
|
-
|
49
|
-
def test_utf8mb4_kanji
|
50
|
-
@model.unicode = '𠜎𠜱𠝹𠱓𠱸𠲖𠳏𠳕𠴕𠵼𠵿𠸎𠸏𠹷'
|
51
|
-
assert @model.invalid?
|
52
|
-
assert_equal ["contains characters outside Unicode's basic multilingual plane"], @model.errors[:unicode]
|
53
|
-
end
|
54
|
-
end
|