schema_validations 2.2.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/prs.yml +134 -0
  3. data/.gitignore +1 -0
  4. data/.simplecov +20 -0
  5. data/.travis.yml +6 -3
  6. data/Gemfile +5 -0
  7. data/README.md +25 -6
  8. data/Rakefile +2 -0
  9. data/gemfiles/Gemfile.base +1 -1
  10. data/gemfiles/activerecord-5.2/Gemfile.base +4 -0
  11. data/gemfiles/activerecord-5.2/Gemfile.mysql2 +10 -0
  12. data/gemfiles/activerecord-5.2/Gemfile.postgresql +10 -0
  13. data/gemfiles/{activerecord-5.0 → activerecord-5.2}/Gemfile.sqlite3 +3 -3
  14. data/gemfiles/activerecord-6.0/Gemfile.base +4 -0
  15. data/gemfiles/activerecord-6.0/Gemfile.mysql2 +10 -0
  16. data/gemfiles/activerecord-6.0/Gemfile.postgresql +10 -0
  17. data/gemfiles/{activerecord-4.2 → activerecord-6.0}/Gemfile.sqlite3 +3 -3
  18. data/init.rb +2 -0
  19. data/lib/schema_validations/active_record/type.rb +2 -0
  20. data/lib/schema_validations/active_record/validations.rb +8 -1
  21. data/lib/schema_validations/railtie.rb +2 -0
  22. data/lib/schema_validations/validators/not_nil_validator.rb +13 -0
  23. data/lib/schema_validations/version.rb +3 -1
  24. data/lib/schema_validations.rb +3 -0
  25. data/schema_dev.yml +5 -3
  26. data/schema_validations.gemspec +23 -27
  27. data/spec/spec_helper.rb +22 -18
  28. data/spec/support/active_model.rb +2 -0
  29. data/spec/validations_spec.rb +138 -73
  30. metadata +38 -94
  31. data/gemfiles/activerecord-4.2/Gemfile.base +0 -3
  32. data/gemfiles/activerecord-4.2/Gemfile.mysql2 +0 -10
  33. data/gemfiles/activerecord-4.2/Gemfile.postgresql +0 -10
  34. data/gemfiles/activerecord-5.0/Gemfile.base +0 -3
  35. data/gemfiles/activerecord-5.0/Gemfile.mysql2 +0 -10
  36. data/gemfiles/activerecord-5.0/Gemfile.postgresql +0 -10
  37. data/spec/schema_validations.sqlite3 +0 -0
@@ -1,38 +1,40 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
4
 
3
5
  describe "Validations" do
4
6
 
5
7
  before(:each) do
6
- ActiveRecord::Schema.define do
8
+ define_schema do
7
9
 
8
- create_table :articles, :force => true do |t|
9
- t.string :title, :limit => 50
10
- t.text :content, :null => false
10
+ create_table :articles, force: true do |t|
11
+ t.string :title, limit: 50
12
+ t.text :content, null: false
11
13
  t.integer :state
12
14
  t.integer :votes
13
- t.float :average_mark, :null => false
14
- t.boolean :active, :null => false
15
- t.decimal :max10, :precision => 2, :scale => 1
16
- t.decimal :arbitrary, :precision => nil, :scale => nil
17
- t.decimal :max100, :precision => 2, :scale => nil
15
+ t.float :average_mark, null: false
16
+ t.boolean :active, null: false
17
+ t.decimal :max10, precision: 2, scale: 1
18
+ t.decimal :arbitrary, precision: nil, scale: nil
19
+ t.decimal :max100, precision: 2, scale: nil
18
20
  end
19
- add_index :articles, :title, :unique => true
20
- add_index :articles, [:state, :active], :unique => true
21
+ add_index :articles, :title, unique: true
22
+ add_index :articles, [:state, :active], unique: true
21
23
 
22
- create_table :reviews, :force => true do |t|
23
- t.integer :article_id, :null => false
24
- t.string :author, :null => false
25
- t.string :content, :limit => 200
24
+ create_table :reviews, force: true do |t|
25
+ t.integer :article_id, null: false
26
+ t.string :author, null: false
27
+ t.string :content, limit: 200
26
28
  t.string :type
27
- t.timestamps :null => false
29
+ t.timestamps null: false
28
30
  end
29
- add_index :reviews, :article_id, :unique => true
31
+ add_index :reviews, :article_id, unique: true
30
32
 
31
- create_table :article_reviews, :force => true do |t|
33
+ create_table :article_reviews, force: true do |t|
32
34
  t.integer :article_id
33
35
  t.integer :review_id
34
36
  end
35
- add_index :article_reviews, [:article_id, :review_id], :unique => true
37
+ add_index :article_reviews, [:article_id, :review_id], unique: true
36
38
  end
37
39
  end
38
40
 
@@ -43,8 +45,8 @@ describe "Validations" do
43
45
 
44
46
  class Review < ActiveRecord::Base
45
47
  belongs_to :article
46
- belongs_to :news_article, :class_name => 'Article', :foreign_key => :article_id
47
- schema_validations :except => :content
48
+ belongs_to :news_article, class_name: 'Article', foreign_key: :article_id
49
+ schema_validations except: :content
48
50
  end
49
51
 
50
52
  class ArticleReview < ActiveRecord::Base
@@ -81,15 +83,15 @@ describe "Validations" do
81
83
  end
82
84
 
83
85
  it "should check title length" do
84
- expect(Article.new(:title => 'a' * 100).error_on(:title).size).to eq(1)
86
+ expect(Article.new(title: 'a' * 100).error_on(:title).size).to eq(1)
85
87
  end
86
88
 
87
89
  it "should validate state numericality" do
88
- expect(Article.new(:state => 'unknown').error_on(:state).size).to eq(1)
90
+ expect(Article.new(state: 'unknown').error_on(:state).size).to eq(1)
89
91
  end
90
92
 
91
93
  it "should validate if state is integer" do
92
- expect(Article.new(:state => 1.23).error_on(:state).size).to eq(1)
94
+ expect(Article.new(state: 1.23).error_on(:state).size).to eq(1)
93
95
  end
94
96
 
95
97
  it "should validate the range of votes" do
@@ -115,28 +117,28 @@ describe "Validations" do
115
117
  expect(Article.new(max100: -100).error_on(:max100).size).to eq(1)
116
118
  end
117
119
 
118
- it "should not validate the range of arbitrary decimal", :mysql => :skip do # mysql provides a default precision
120
+ it "should not validate the range of arbitrary decimal", mysql: :skip do # mysql provides a default precision
119
121
  expect(Article.new(arbitrary: Float::MAX).error_on(:arbitrary).size).to eq(0)
120
122
  end
121
123
 
122
124
  it "should validate average_mark numericality" do
123
- expect(Article.new(:average_mark => "high").error_on(:average_mark).size).to eq(1)
125
+ expect(Article.new(average_mark: "high").error_on(:average_mark).size).to eq(1)
124
126
  end
125
127
 
126
128
  it "should validate boolean fields" do
127
- expect(Article.new(:active => nil).error_on(:active).size).to eq(1)
129
+ expect(Article.new(active: nil).error_on(:active).size).to eq(1)
128
130
  end
129
131
 
130
132
  it "should validate title uniqueness" do
131
133
  article1 = Article.create(valid_article_attributes)
132
- article2 = Article.new(:title => valid_article_attributes[:title])
134
+ article2 = Article.new(title: valid_article_attributes[:title])
133
135
  expect(article2.error_on(:title).size).to eq(1)
134
136
  article1.destroy
135
137
  end
136
138
 
137
139
  it "should validate state uniqueness in scope of 'active' value" do
138
140
  article1 = Article.create(valid_article_attributes)
139
- article2 = Article.new(valid_article_attributes.merge(:title => 'SchemaPlus 2.0 released'))
141
+ article2 = Article.new(valid_article_attributes.merge(title: 'SchemaPlus 2.0 released'))
140
142
  expect(article2).not_to be_valid
141
143
  article2.toggle(:active)
142
144
  expect(article2).to be_valid
@@ -151,9 +153,9 @@ describe "Validations" do
151
153
  it "should validate uniqueness of belongs_to association" do
152
154
  article = Article.create(valid_article_attributes)
153
155
  expect(article).to be_valid
154
- review1 = Review.create(:article => article, :author => 'michal')
156
+ review1 = Review.create(article: article, author: 'michal')
155
157
  expect(review1).to be_valid
156
- review2 = Review.new(:article => article, :author => 'michal')
158
+ review2 = Review.new(article: article, author: 'michal')
157
159
  expect(review2.error_on(:article_id).size).to be >= 1
158
160
  end
159
161
 
@@ -162,18 +164,81 @@ describe "Validations" do
162
164
  end
163
165
 
164
166
  it "should not validate uniqueness when scope is absent" do
165
- article_review_1 = ArticleReview.create(:article_id => 1, :review_id => nil)
167
+ article_review_1 = ArticleReview.create(article_id: 1, review_id: nil)
166
168
  expect(article_review_1).to be_valid
167
169
 
168
- article_review_2 = ArticleReview.create(:article_id => 1, :review_id => nil)
170
+ article_review_2 = ArticleReview.create(article_id: 1, review_id: nil)
169
171
  expect(article_review_2).to be_valid
170
172
 
171
- article_review_3 = ArticleReview.create(:article_id => nil, :review_id => 1)
173
+ article_review_3 = ArticleReview.create(article_id: nil, review_id: 1)
172
174
  expect(article_review_3).to be_valid
173
175
 
174
- article_review_4 = ArticleReview.create(:article_id => nil, :review_id => 1)
176
+ article_review_4 = ArticleReview.create(article_id: nil, review_id: 1)
175
177
  expect(article_review_4).to be_valid
176
178
  end
179
+
180
+ context 'when NOT NULL validations' do
181
+ before(:each) do
182
+ ActiveRecord::Schema.define do
183
+ create_table :anti_nulls, force: true do |t|
184
+ t.string :no_default, null: false
185
+ t.string :blank_default, default: '', null: false
186
+ t.string :non_blank_default, default: 'not blank', null: false
187
+ end
188
+ end
189
+ with_auto_validations do
190
+ class AntiNull < ActiveRecord::Base
191
+ def self.all_blank
192
+ @all_blank ||= AntiNull.new(
193
+ no_default: '',
194
+ blank_default: '',
195
+ non_blank_default: ''
196
+ )
197
+ end
198
+
199
+ def self.all_non_blank
200
+ @all_non_blank ||= AntiNull.new(
201
+ no_default: 'foo',
202
+ blank_default: 'bar',
203
+ non_blank_default: 'baz'
204
+ )
205
+ end
206
+
207
+ def self.all_nil
208
+ @all_nil ||= AntiNull.new(
209
+ no_default: nil,
210
+ blank_default: nil,
211
+ non_blank_default: nil
212
+ )
213
+ end
214
+
215
+ def self.non_null_with(**fields)
216
+ opts = { no_default: 'foo' }.merge!(fields)
217
+ AntiNull.new **opts
218
+ end
219
+ end
220
+ end
221
+
222
+
223
+ end
224
+
225
+ it 'should fail validation on empty fields only if the default value is not blank' do
226
+ expect(AntiNull.all_nil.error_on(:no_default).size).to eq(1)
227
+ expect(AntiNull.all_nil.error_on(:blank_default).size).to eq(1)
228
+ expect(AntiNull.all_nil.error_on(:non_blank_default).size).to eq(1)
229
+ end
230
+
231
+ it 'should fail validation on empty fields only if the default value is not blank' do
232
+ expect(AntiNull.all_blank.error_on(:no_default).size).to eq(1)
233
+ expect(AntiNull.all_blank.error_on(:non_blank_default).size).to eq(1)
234
+ expect(AntiNull.all_blank.error_on(:blank_default)).to be_empty
235
+ end
236
+
237
+ it 'should not fail if fields are neither nil nor empty' do
238
+ expect(AntiNull.all_non_blank).to be_valid
239
+ end
240
+
241
+ end
177
242
  end
178
243
 
179
244
  context "auto-created but changed" do
@@ -182,62 +247,62 @@ describe "Validations" do
182
247
  class Article < ActiveRecord::Base ; end
183
248
  class Review < ActiveRecord::Base
184
249
  belongs_to :article
185
- belongs_to :news_article, :class_name => 'Article', :foreign_key => :article_id
250
+ belongs_to :news_article, class_name: 'Article', foreign_key: :article_id
186
251
  end
187
252
  end
188
253
  @too_big_content = 'a' * 1000
189
254
  end
190
255
 
191
256
  it "would normally have an error" do
192
- @review = Review.new(:content => @too_big_content)
257
+ @review = Review.new(content: @too_big_content)
193
258
  expect(@review.error_on(:content).size).to eq(1)
194
259
  expect(@review.error_on(:author).size).to eq(1)
195
260
  end
196
261
 
197
262
  it "shouldn't validate fields passed to :except option" do
198
- Review.schema_validations :except => :content
199
- @review = Review.new(:content => @too_big_content)
263
+ Review.schema_validations except: :content
264
+ @review = Review.new(content: @too_big_content)
200
265
  expect(@review.errors_on(:content).size).to eq(0)
201
266
  expect(@review.error_on(:author).size).to eq(1)
202
267
  end
203
268
 
204
269
  it "shouldn't validate the fields in default whitelist" do
205
- Review.schema_validations :except => :content
270
+ Review.schema_validations except: :content
206
271
  expect(Review.new.error_on(:updated_at).size).to eq(0)
207
272
  expect(Review.new.error_on(:created_at).size).to eq(0)
208
273
  end
209
274
 
210
275
  it "shouldn't validate the fields in whitelist" do
211
- Review.schema_validations :except => :content, whitelist: [:updated_at]
276
+ Review.schema_validations except: :content, whitelist: [:updated_at]
212
277
  expect(Review.new.error_on(:updated_at).size).to eq(0)
213
278
  expect(Review.new.error_on(:created_at).size).to eq(1)
214
279
  end
215
280
 
216
281
  it "shouldn't validate types passed to :except_type option using full validation" do
217
- Review.schema_validations :except_type => :validates_length_of
218
- @review = Review.new(:content => @too_big_content)
282
+ Review.schema_validations except_type: :validates_length_of
283
+ @review = Review.new(content: @too_big_content)
219
284
  expect(@review.errors_on(:content).size).to eq(0)
220
285
  expect(@review.error_on(:author).size).to eq(1)
221
286
  end
222
287
 
223
288
  it "shouldn't validate types passed to :except_type option using shorthand" do
224
- Review.schema_validations :except_type => :length
225
- @review = Review.new(:content => @too_big_content)
289
+ Review.schema_validations except_type: :length
290
+ @review = Review.new(content: @too_big_content)
226
291
  expect(@review.errors_on(:content).size).to eq(0)
227
292
  expect(@review.error_on(:author).size).to eq(1)
228
293
  end
229
294
 
230
295
  it "should only validate type passed to :only_type option" do
231
- Review.schema_validations :only_type => :length
232
- @review = Review.new(:content => @too_big_content)
296
+ Review.schema_validations only_type: :length
297
+ @review = Review.new(content: @too_big_content)
233
298
  expect(@review.error_on(:content).size).to eq(1)
234
299
  expect(@review.errors_on(:author).size).to eq(0)
235
300
  end
236
301
 
237
302
 
238
303
  it "shouldn't create validations if locally disabled" do
239
- Review.schema_validations :auto_create => false
240
- @review = Review.new(:content => @too_big_content)
304
+ Review.schema_validations auto_create: false
305
+ @review = Review.new(content: @too_big_content)
241
306
  expect(@review.errors_on(:content).size).to eq(0)
242
307
  expect(@review.error_on(:author).size).to eq(0)
243
308
  end
@@ -251,23 +316,23 @@ describe "Validations" do
251
316
  before(:each) do
252
317
  class Review < ActiveRecord::Base
253
318
  belongs_to :article
254
- belongs_to :news_article, :class_name => 'Article', :foreign_key => :article_id
319
+ belongs_to :news_article, class_name: 'Article', foreign_key: :article_id
255
320
  end
256
321
  @too_big_content = 'a' * 1000
257
322
  end
258
323
 
259
324
  it "should not create validation" do
260
- expect(Review.new(:content => @too_big_title).errors_on(:content).size).to eq(0)
325
+ expect(Review.new(content: @too_big_title).errors_on(:content).size).to eq(0)
261
326
  end
262
327
 
263
328
  it "should create validation if locally enabled explicitly" do
264
- Review.schema_validations :auto_create => true
265
- expect(Review.new(:content => @too_big_content).error_on(:content).size).to eq(1)
329
+ Review.schema_validations auto_create: true
330
+ expect(Review.new(content: @too_big_content).error_on(:content).size).to eq(1)
266
331
  end
267
332
 
268
333
  it "should create validation if locally enabled implicitly" do
269
334
  Review.schema_validations
270
- expect(Review.new(:content => @too_big_content).error_on(:content).size).to eq(1)
335
+ expect(Review.new(content: @too_big_content).error_on(:content).size).to eq(1)
271
336
  end
272
337
 
273
338
  end
@@ -275,18 +340,18 @@ describe "Validations" do
275
340
  context "manually invoked" do
276
341
  before(:each) do
277
342
  class Article < ActiveRecord::Base ; end
278
- Article.schema_validations :only => [:title, :state]
343
+ Article.schema_validations only: [:title, :state]
279
344
 
280
345
  class Review < ActiveRecord::Base
281
346
  belongs_to :dummy_association
282
- schema_validations :except => :content
347
+ schema_validations except: :content
283
348
  end
284
349
  end
285
350
 
286
351
  it "should validate fields passed to :only option" do
287
352
  too_big_title = 'a' * 100
288
353
  wrong_state = 'unknown'
289
- article = Article.new(:title => too_big_title, :state => wrong_state)
354
+ article = Article.new(title: too_big_title, state: wrong_state)
290
355
  expect(article.error_on(:title).size).to eq(1)
291
356
  expect(article.error_on(:state).size).to eq(1)
292
357
  end
@@ -317,7 +382,7 @@ describe "Validations" do
317
382
  belongs_to :article
318
383
  end
319
384
  @columns = Review.content_columns.dup
320
- Review.schema_validations :only => [:title]
385
+ Review.schema_validations only: [:title]
321
386
  end
322
387
 
323
388
  it "shouldn't validate associations not included in :only option" do
@@ -352,9 +417,9 @@ describe "Validations" do
352
417
  context "when used with enum" do
353
418
  it "does not validate numericality" do
354
419
  class Article < ActiveRecord::Base
355
- enum :state => [:happy, :sad]
420
+ enum state: [:happy, :sad]
356
421
  end
357
- expect(Article.new(valid_article_attributes.merge(:state => :happy))).to be_valid
422
+ expect(Article.new(valid_article_attributes.merge(state: :happy))).to be_valid
358
423
  end
359
424
  end if ActiveRecord::Base.respond_to? :enum
360
425
 
@@ -366,11 +431,11 @@ describe "Validations" do
366
431
  context 'without scope' do
367
432
  before do
368
433
  ActiveRecord::Schema.define do
369
- create_table :books, :force => true do |t|
434
+ create_table :books, force: true do |t|
370
435
  t.string :title
371
436
  end
372
437
 
373
- add_index :books, :title, :unique => true
438
+ add_index :books, :title, unique: true
374
439
  end
375
440
 
376
441
  with_auto_validations do
@@ -390,12 +455,12 @@ describe "Validations" do
390
455
  context 'within a scope' do
391
456
  before do
392
457
  ActiveRecord::Schema.define do
393
- create_table :folders, :force => true do |t|
458
+ create_table :folders, force: true do |t|
394
459
  t.integer :parent_id
395
460
  t.string :name
396
461
  end
397
462
 
398
- add_index :folders, [:parent_id, :name], :unique => true
463
+ add_index :folders, [:parent_id, :name], unique: true
399
464
  end
400
465
 
401
466
  with_auto_validations do
@@ -408,10 +473,10 @@ describe "Validations" do
408
473
  it "should validate the uniqueness in a case insensitive manner" do
409
474
  mixed_case_name = 'Schema Validations'
410
475
  parent_folder = Folder.create
411
- Folder.create(:parent => parent_folder, :name => mixed_case_name)
476
+ Folder.create(parent: parent_folder, name: mixed_case_name)
412
477
 
413
- expect(Folder.new(:parent => parent_folder, :name => mixed_case_name)).not_to be_valid
414
- expect(Folder.new(:parent => parent_folder, :name => mixed_case_name.downcase)).not_to be_valid
478
+ expect(Folder.new(parent: parent_folder, name: mixed_case_name)).not_to be_valid
479
+ expect(Folder.new(parent: parent_folder, name: mixed_case_name.downcase)).not_to be_valid
415
480
  end
416
481
  end
417
482
  end
@@ -419,7 +484,7 @@ describe "Validations" do
419
484
  context 'with optimistic locking' do
420
485
  before do
421
486
  ActiveRecord::Schema.define do
422
- create_table :optimistics, :force => true do |t|
487
+ create_table :optimistics, force: true do |t|
423
488
  t.integer :lock_version
424
489
  end
425
490
  end
@@ -448,11 +513,11 @@ describe "Validations" do
448
513
 
449
514
  def valid_article_attributes
450
515
  {
451
- :title => 'SchemaPlus released!',
452
- :content => "Database matters. Get full use of it but don't write unecessary code. Get SchemaPlus!",
453
- :state => 3,
454
- :average_mark => 9.78,
455
- :active => true
516
+ title: 'SchemaPlus released!',
517
+ content: "Database matters. Get full use of it but don't write unecessary code. Get SchemaPlus!",
518
+ state: 3,
519
+ average_mark: 9.78,
520
+ active: true
456
521
  }
457
522
  end
458
523