sequel 1.4.0 → 1.5.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.
data/spec/record_spec.rb CHANGED
@@ -6,9 +6,7 @@ describe "Model#save" do
6
6
  MODEL_DB.reset
7
7
 
8
8
  @c = Class.new(Sequel::Model(:items)) do
9
- def columns
10
- [:id, :x, :y]
11
- end
9
+ columns :id, :x, :y
12
10
  end
13
11
  end
14
12
 
@@ -52,9 +50,7 @@ describe "Model#save_changes" do
52
50
  MODEL_DB.reset
53
51
 
54
52
  @c = Class.new(Sequel::Model(:items)) do
55
- def columns
56
- [:id, :x, :y]
57
- end
53
+ columns :id, :x, :y
58
54
  end
59
55
  end
60
56
 
@@ -109,47 +105,67 @@ describe "Model#save_changes" do
109
105
  end
110
106
  end
111
107
 
112
- describe "Model#set" do
113
-
108
+ describe "Model#update_values" do
114
109
  before(:each) do
115
110
  MODEL_DB.reset
116
111
 
117
112
  @c = Class.new(Sequel::Model(:items)) do
118
- def columns
119
- [:id, :x, :y]
120
- end
113
+ columns :id, :x, :y
121
114
  end
122
115
  end
123
116
 
124
117
  it "should generate an update statement" do
125
118
  o = @c.new(:id => 1)
126
- o.set(:x => 1)
119
+ o.update_values(:x => 1)
127
120
  MODEL_DB.sqls.first.should == "UPDATE items SET x = 1 WHERE (id = 1)"
128
121
  end
129
122
 
130
123
  it "should update attribute values" do
131
124
  o = @c.new(:id => 1)
132
125
  o.x.should be_nil
133
- o.set(:x => 1)
126
+ o.update_values(:x => 1)
134
127
  o.x.should == 1
135
128
  end
136
129
 
137
130
  it "should support string keys" do
138
131
  o = @c.new(:id => 1)
139
132
  o.x.should be_nil
140
- o.set('x' => 1)
133
+ o.update_values('x' => 1)
141
134
  o.x.should == 1
142
135
  MODEL_DB.sqls.first.should == "UPDATE items SET x = 1 WHERE (id = 1)"
143
136
  end
137
+ end
138
+
139
+ describe "Model#set_values" do
140
+ before(:each) do
141
+ MODEL_DB.reset
142
+
143
+ @c = Class.new(Sequel::Model(:items)) do
144
+ columns :id, :x, :y
145
+ end
146
+ end
144
147
 
145
- it "should be aliased by #update" do
148
+ it "should not touch the database" do
146
149
  o = @c.new(:id => 1)
147
- o.update(:x => 1)
148
- MODEL_DB.sqls.first.should == "UPDATE items SET x = 1 WHERE (id = 1)"
150
+ o.set_values(:x => 1)
151
+ MODEL_DB.sqls.should == []
152
+ end
153
+
154
+ it "should update attribute values" do
155
+ o = @c.new(:id => 1)
156
+ o.x.should be_nil
157
+ o.set_values(:x => 1)
158
+ o.x.should == 1
159
+ end
160
+
161
+ it "should support string keys" do
162
+ o = @c.new(:id => 1)
163
+ o.x.should be_nil
164
+ o.set_values('x' => 1)
165
+ o.x.should == 1
149
166
  end
150
167
  end
151
168
 
152
-
153
169
  describe "Model#new?" do
154
170
 
155
171
  before(:each) do
@@ -170,6 +186,7 @@ describe "Model#new?" do
170
186
  n.should_not be_new
171
187
  end
172
188
 
189
+ ### DEPRECATED
173
190
  it "should alias new_record? to new?" do
174
191
  n = @c.new(:x => 1)
175
192
  n.should respond_to(:new_record?)
@@ -217,7 +234,7 @@ end
217
234
 
218
235
  describe Sequel::Model, "with this" do
219
236
 
220
- before { @example = Class.new Sequel::Model(:examples) }
237
+ before { @example = Class.new Sequel::Model(:examples); @example.columns :id, :a, :x, :y }
221
238
 
222
239
  it "should return a dataset identifying the record" do
223
240
  instance = @example.new :id => 3
@@ -250,6 +267,7 @@ end
250
267
  describe "Model#pk" do
251
268
  before(:each) do
252
269
  @m = Class.new(Sequel::Model)
270
+ @m.columns :id, :x, :y
253
271
  end
254
272
 
255
273
  it "should be default return the value of the :id column" do
@@ -283,6 +301,7 @@ end
283
301
  describe "Model#pk_hash" do
284
302
  before(:each) do
285
303
  @m = Class.new(Sequel::Model)
304
+ @m.columns :id, :x, :y
286
305
  end
287
306
 
288
307
  it "should be default return the value of the :id column" do
@@ -313,14 +332,59 @@ describe "Model#pk_hash" do
313
332
  end
314
333
  end
315
334
 
335
+ describe Sequel::Model, "set_with_params" do
336
+
337
+ before(:each) do
338
+ MODEL_DB.reset
339
+
340
+ @c = Class.new(Sequel::Model(:items)) do
341
+ columns :x, :y, :id
342
+ end
343
+ @c.instance_variable_set(:@columns, true)
344
+ @o1 = @c.new
345
+ @o2 = @c.load(:id => 5)
346
+ end
347
+
348
+ it "should filter the given params using the model columns" do
349
+ @o1.set_with_params(:x => 1, :z => 2)
350
+ @o1.values.should == {:x => 1}
351
+ MODEL_DB.sqls.should == []
352
+
353
+ @o2.set_with_params(:y => 1, :abc => 2)
354
+ @o2.values.should == {:y => 1, :id=> 5}
355
+ MODEL_DB.sqls.should == []
356
+ end
357
+
358
+ it "should work with both strings and symbols" do
359
+ @o1.set_with_params('x'=> 1, 'z'=> 2)
360
+ @o1.values.should == {:x => 1}
361
+ MODEL_DB.sqls.should == []
362
+
363
+ @o2.set_with_params('y'=> 1, 'abc'=> 2)
364
+ @o2.values.should == {:y => 1, :id=> 5}
365
+ MODEL_DB.sqls.should == []
366
+ end
367
+
368
+ it "should support virtual attributes" do
369
+ @c.class_def(:blah=) {|v| self.x = v}
370
+ @o1.set_with_params(:blah => 333)
371
+ @o1.values.should == {:x => 333}
372
+ MODEL_DB.sqls.should == []
373
+ @o1.set_with_params('blah'=> 334)
374
+ @o1.values.should == {:x => 334}
375
+ MODEL_DB.sqls.should == []
376
+ end
377
+ end
378
+
316
379
  describe Sequel::Model, "update_with_params" do
317
380
 
318
381
  before(:each) do
319
382
  MODEL_DB.reset
320
383
 
321
384
  @c = Class.new(Sequel::Model(:items)) do
322
- def self.columns; [:x, :y]; end
385
+ columns :x, :y, :id
323
386
  end
387
+ @c.instance_variable_set(:@columns, true)
324
388
  @o1 = @c.new
325
389
  @o2 = @c.load(:id => 5)
326
390
  end
@@ -334,7 +398,8 @@ describe Sequel::Model, "update_with_params" do
334
398
  MODEL_DB.sqls.first.should == "UPDATE items SET y = 1 WHERE (id = 5)"
335
399
  end
336
400
 
337
- it "should be aliased by create_with" do
401
+ ### DEPRECATE
402
+ it "should be aliased by update_with" do
338
403
  @o1.update_with(:x => 1, :z => 2)
339
404
  MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
340
405
 
@@ -345,19 +410,21 @@ describe Sequel::Model, "update_with_params" do
345
410
 
346
411
  it "should support virtual attributes" do
347
412
  @c.class_def(:blah=) {|v| self.x = v}
348
- @o1.update_with(:blah => 333)
413
+ @o1.update_with_params(:blah => 333)
349
414
  MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (333)"
350
415
  end
351
416
  end
352
417
 
418
+ ### DEPRECATE
353
419
  describe Sequel::Model, "create_with_params" do
354
420
 
355
421
  before(:each) do
356
422
  MODEL_DB.reset
357
423
 
358
424
  @c = Class.new(Sequel::Model(:items)) do
359
- def self.columns; [:x, :y]; end
425
+ columns :x, :y
360
426
  end
427
+ @c.instance_variable_set(:@columns, true)
361
428
  end
362
429
 
363
430
  it "should filter the given params using the model columns" do
@@ -390,12 +457,19 @@ describe Sequel::Model, "#destroy" do
390
457
  before(:each) do
391
458
  MODEL_DB.reset
392
459
  @model = Class.new(Sequel::Model(:items))
460
+ @model.columns :id
393
461
  @model.dataset.meta_def(:delete) {MODEL_DB.execute delete_sql}
394
462
 
395
463
  @instance = @model.new(:id => 1234)
396
464
  #@model.stub!(:delete).and_return(:true)
397
465
  end
398
466
 
467
+ it "should return self" do
468
+ @model.db.should_receive(:transaction)
469
+ @model.after_destroy{3}
470
+ @instance.destroy.should == @instance
471
+ end
472
+
399
473
  it "should run within a transaction" do
400
474
  @model.db.should_receive(:transaction)
401
475
  @instance.destroy
@@ -434,6 +508,7 @@ end
434
508
  describe Sequel::Model, "#each" do
435
509
  setup do
436
510
  @model = Class.new(Sequel::Model(:items))
511
+ @model.columns :a, :b, :id
437
512
  @m = @model.new(:a => 1, :b => 2, :id => 4444)
438
513
  end
439
514
 
@@ -447,6 +522,7 @@ end
447
522
  describe Sequel::Model, "#keys" do
448
523
  setup do
449
524
  @model = Class.new(Sequel::Model(:items))
525
+ @model.columns :a, :b, :id
450
526
  @m = @model.new(:a => 1, :b => 2, :id => 4444)
451
527
  end
452
528
 
@@ -459,32 +535,100 @@ describe Sequel::Model, "#keys" do
459
535
  end
460
536
  end
461
537
 
462
- describe Sequel::Model, "#===" do
538
+ describe Sequel::Model, "#==" do
463
539
  specify "should compare instances by values" do
464
- a = Sequel::Model.new(:id => 1, :x => 3)
465
- b = Sequel::Model.new(:id => 1, :x => 4)
466
- c = Sequel::Model.new(:id => 1, :x => 3)
540
+ z = Class.new(Sequel::Model)
541
+ z.columns :id, :x
542
+ a = z.new(:id => 1, :x => 3)
543
+ b = z.new(:id => 1, :x => 4)
544
+ c = z.new(:id => 1, :x => 3)
467
545
 
468
546
  a.should_not == b
469
547
  a.should == c
470
548
  b.should_not == c
471
549
  end
550
+
551
+ specify "should be aliased to #eql?" do
552
+ z = Class.new(Sequel::Model)
553
+ z.columns :id, :x
554
+ a = z.new(:id => 1, :x => 3)
555
+ b = z.new(:id => 1, :x => 4)
556
+ c = z.new(:id => 1, :x => 3)
557
+
558
+ a.eql?(b).should == false
559
+ a.eql?(c).should == true
560
+ b.eql?(c).should == false
561
+ end
472
562
  end
473
563
 
474
564
  describe Sequel::Model, "#===" do
475
- specify "should compare instances by pk only" do
476
- a = Sequel::Model.new(:id => 1, :x => 3)
477
- b = Sequel::Model.new(:id => 1, :x => 4)
478
- c = Sequel::Model.new(:id => 2, :x => 3)
565
+ specify "should compare instances by class and pk if pk is not nil" do
566
+ z = Class.new(Sequel::Model)
567
+ z.columns :id, :x
568
+ y = Class.new(Sequel::Model)
569
+ y.columns :id, :x
570
+ a = z.new(:id => 1, :x => 3)
571
+ b = z.new(:id => 1, :x => 4)
572
+ c = z.new(:id => 2, :x => 3)
573
+ d = y.new(:id => 1, :x => 3)
479
574
 
480
575
  a.should === b
481
576
  a.should_not === c
577
+ a.should_not === d
578
+ end
579
+
580
+ specify "should always be false if the primary key is nil" do
581
+ z = Class.new(Sequel::Model)
582
+ z.columns :id, :x
583
+ y = Class.new(Sequel::Model)
584
+ y.columns :id, :x
585
+ a = z.new(:x => 3)
586
+ b = z.new(:x => 4)
587
+ c = z.new(:x => 3)
588
+ d = y.new(:x => 3)
589
+
590
+ a.should_not === b
591
+ a.should_not === c
592
+ a.should_not === d
593
+ end
594
+ end
595
+
596
+ describe Sequel::Model, "#hash" do
597
+ specify "should be the same only for objects with the same class and pk if the pk is not nil" do
598
+ z = Class.new(Sequel::Model)
599
+ z.columns :id, :x
600
+ y = Class.new(Sequel::Model)
601
+ y.columns :id, :x
602
+ a = z.new(:id => 1, :x => 3)
603
+ b = z.new(:id => 1, :x => 4)
604
+ c = z.new(:id => 2, :x => 3)
605
+ d = y.new(:id => 1, :x => 3)
606
+
607
+ a.hash.should == b.hash
608
+ a.hash.should_not == c.hash
609
+ a.hash.should_not == d.hash
610
+ end
611
+
612
+ specify "should be the same only for objects with the same class and values if the pk is nil" do
613
+ z = Class.new(Sequel::Model)
614
+ z.columns :id, :x
615
+ y = Class.new(Sequel::Model)
616
+ y.columns :id, :x
617
+ a = z.new(:x => 3)
618
+ b = z.new(:x => 4)
619
+ c = z.new(:x => 3)
620
+ d = y.new(:x => 3)
621
+
622
+ a.hash.should_not == b.hash
623
+ a.hash.should == c.hash
624
+ a.hash.should_not == d.hash
482
625
  end
483
626
  end
484
627
 
485
628
  describe Sequel::Model, "#initialize" do
486
629
  setup do
487
630
  @c = Class.new(Sequel::Model) do
631
+ columns :id, :x
488
632
  end
489
633
  end
490
634
 
@@ -528,7 +672,7 @@ describe Sequel::Model, ".create" do
528
672
  before(:each) do
529
673
  MODEL_DB.reset
530
674
  @c = Class.new(Sequel::Model(:items)) do
531
- def columns; [:x]; end
675
+ columns :x
532
676
  end
533
677
  end
534
678
 
@@ -566,7 +710,7 @@ describe Sequel::Model, "#refresh" do
566
710
  setup do
567
711
  MODEL_DB.reset
568
712
  @c = Class.new(Sequel::Model(:items)) do
569
- def columns; [:x]; end
713
+ columns :x
570
714
  end
571
715
  end
572
716
 
@@ -590,4 +734,18 @@ describe Sequel::Model, "#refresh" do
590
734
  @m.reload
591
735
  @m[:x].should == 'kaboom'
592
736
  end
737
+
738
+ specify "should remove cached associations" do
739
+ @c.many_to_one :node, :class=>@c
740
+ @c.one_to_many :attributes, :class=>@c
741
+ @c.many_to_many :tags, :class=>@c
742
+ @m = @c.new(:id => 555)
743
+ @m.instance_variable_set(:@node, 15)
744
+ @m.instance_variable_set(:@attributes, [15])
745
+ @m.instance_variable_set(:@tags, [15])
746
+ @m.reload
747
+ @m.instance_variable_get(:@node).should == nil
748
+ @m.instance_variable_get(:@attributes).should == nil
749
+ @m.instance_variable_get(:@tags).should == nil
750
+ end
593
751
  end
data/spec/spec_helper.rb CHANGED
@@ -1,8 +1,12 @@
1
1
  require 'rubygems'
2
2
  unless Object.const_defined?('Sequel')
3
+ $:.unshift(File.join(File.dirname(__FILE__), "../../sequel_core/lib/"))
3
4
  require 'sequel_core'
4
5
  end
5
- require File.join(File.dirname(__FILE__), "../lib/sequel_model")
6
+ unless Sequel.const_defined?('Model')
7
+ $:.unshift(File.join(File.dirname(__FILE__), "../lib/"))
8
+ require 'sequel_model'
9
+ end
6
10
 
7
11
  class MockDataset < Sequel::Dataset
8
12
  def insert(*args)
@@ -40,4 +44,15 @@ class MockDatabase < Sequel::Database
40
44
  def dataset; MockDataset.new(self); end
41
45
  end
42
46
 
43
- Sequel::Model.db = MODEL_DB = MockDatabase.new
47
+ class << Sequel::Model
48
+ alias orig_columns columns
49
+ def columns(*cols)
50
+ return if cols.empty?
51
+ define_method(:columns){cols}
52
+ @dataset.instance_variable_set(:@columns, cols) if @dataset
53
+ define_method(:str_columns){cols.map{|x|x.to_s.freeze}}
54
+ def_column_accessor(*cols)
55
+ end
56
+ end
57
+
58
+ Sequel::Model.db = MODEL_DB = MockDatabase.new
@@ -1,33 +1,386 @@
1
1
  require File.join(File.dirname(__FILE__), "spec_helper")
2
2
 
3
+ describe "Validation::Errors" do
4
+ setup do
5
+ @errors = Validation::Errors.new
6
+ class Validation::Errors
7
+ attr_accessor :errors
8
+ end
9
+ end
10
+
11
+ specify "should be clearable using #clear" do
12
+ @errors.errors = {1 => 2, 3 => 4}
13
+ @errors.clear
14
+ @errors.errors.should == {}
15
+ end
16
+
17
+ specify "should be empty if no errors are added" do
18
+ @errors.should be_empty
19
+ @errors[:blah] << "blah"
20
+ @errors.should_not be_empty
21
+ end
22
+
23
+ specify "should return errors for a specific attribute using #on or #[]" do
24
+ @errors[:blah].should == []
25
+ @errors.on(:blah).should == []
26
+
27
+ @errors[:blah] << 'blah'
28
+ @errors[:blah].should == ['blah']
29
+ @errors.on(:blah).should == ['blah']
30
+
31
+ @errors[:bleu].should == []
32
+ @errors.on(:bleu).should == []
33
+ end
34
+
35
+ specify "should accept errors using #[] << or #add" do
36
+ @errors[:blah] << 'blah'
37
+ @errors[:blah].should == ['blah']
38
+
39
+ @errors.add :blah, 'zzzz'
40
+ @errors[:blah].should == ['blah', 'zzzz']
41
+ end
42
+
43
+ specify "should return full messages using #full_messages" do
44
+ @errors.full_messages.should == []
45
+
46
+ @errors[:blow] << 'blieuh'
47
+ @errors[:blow] << 'blich'
48
+ @errors[:blay] << 'bliu'
49
+ msgs = @errors.full_messages
50
+ msgs.size.should == 3
51
+ msgs.should include('blow blieuh', 'blow blich', 'blay bliu')
52
+ end
53
+ end
54
+
55
+ describe Validation do
56
+ setup do
57
+ @c = Class.new do
58
+ include Validation
59
+
60
+ def self.validates_coolness_of(attr)
61
+ validates_each(attr) {|o, a, v| o.errors[a] << 'is not cool' if v != :cool}
62
+ end
63
+ end
64
+
65
+ @d = Class.new do
66
+ attr_accessor :errors
67
+ def initialize; @errors = Validation::Errors.new; end
68
+ end
69
+ end
70
+
71
+ specify "should respond to validates, validations, has_validations?" do
72
+ @c.should respond_to(:validations)
73
+ @c.should respond_to(:has_validations?)
74
+ end
75
+
76
+ specify "should acccept validation definitions using validates_each" do
77
+ @c.validates_each(:xx, :yy) {|o, a, v| o.errors[a] << 'too low' if v < 50}
78
+
79
+ @c.validations[:xx].size.should == 1
80
+ @c.validations[:yy].size.should == 1
81
+
82
+ o = @d.new
83
+ @c.validations[:xx].first.call(o, :aa, 40)
84
+ @c.validations[:yy].first.call(o, :bb, 60)
85
+
86
+ o.errors.full_messages.should == ['aa too low']
87
+ end
88
+
89
+ specify "should return true/false for has_validations?" do
90
+ @c.has_validations?.should == false
91
+ @c.validates_each(:xx) {1}
92
+ @c.has_validations?.should == true
93
+ end
94
+
95
+ specify "should provide a validates method that takes block with validation definitions" do
96
+ @c.validates do
97
+ coolness_of :blah
98
+ end
99
+ @c.validations[:blah].should_not be_empty
100
+
101
+ o = @d.new
102
+ @c.validations[:blah].first.call(o, :ttt, 40)
103
+ o.errors.full_messages.should == ['ttt is not cool']
104
+ o.errors.clear
105
+ @c.validations[:blah].first.call(o, :ttt, :cool)
106
+ o.errors.should be_empty
107
+ end
108
+ end
109
+
110
+ describe "A Validation instance" do
111
+ setup do
112
+ @c = Class.new do
113
+ attr_accessor :score
114
+
115
+ include Validation
116
+
117
+ validates_each :score do |o, a, v|
118
+ o.errors[a] << 'too low' if v < 87
119
+ end
120
+ end
121
+
122
+ @o = @c.new
123
+ end
124
+
125
+ specify "should supply a #valid? method that returns true if validations pass" do
126
+ @o.score = 50
127
+ @o.should_not be_valid
128
+ @o.score = 100
129
+ @o.should be_valid
130
+ end
131
+
132
+ specify "should provide an errors object" do
133
+ @o.score = 100
134
+ @o.should be_valid
135
+ @o.errors.should be_empty
136
+
137
+ @o.score = 86
138
+ @o.should_not be_valid
139
+ @o.errors[:score].should == ['too low']
140
+ @o.errors[:blah].should be_empty
141
+ end
142
+ end
143
+
144
+ describe Validation::Generator do
145
+ setup do
146
+ $testit = nil
147
+
148
+ @c = Class.new do
149
+ include Validation
150
+
151
+ def self.validates_blah
152
+ $testit = 1324
153
+ end
154
+ end
155
+ end
156
+
157
+ specify "should instance_eval the block, sending everything to its receiver" do
158
+ Validation::Generator.new(@c) do
159
+ blah
160
+ end
161
+ $testit.should == 1324
162
+ end
163
+ end
164
+
165
+ describe "Validations" do
166
+ setup do
167
+ @c = Class.new do
168
+ attr_accessor :value
169
+ include Validation
170
+ end
171
+ @m = @c.new
172
+ end
173
+
174
+ specify "should validate acceptance_of" do
175
+ @c.validates_acceptance_of :value
176
+ @m.should be_valid
177
+ @m.value = '1'
178
+ @m.should be_valid
179
+ end
180
+
181
+ specify "should validate acceptance_of with accept" do
182
+ @c.validates_acceptance_of :value, :accept => 'true'
183
+ @m.value = '1'
184
+ @m.should_not be_valid
185
+ @m.value = 'true'
186
+ @m.should be_valid
187
+ end
188
+
189
+ specify "should validate acceptance_of with allow_nil => false" do
190
+ @c.validates_acceptance_of :value, :allow_nil => false
191
+ @m.should_not be_valid
192
+ end
193
+
194
+ specify "should validate confirmation_of" do
195
+ @c.send(:attr_accessor, :value_confirmation)
196
+ @c.validates_confirmation_of :value
197
+
198
+ @m.value = 'blah'
199
+ @m.should_not be_valid
200
+
201
+ @m.value_confirmation = 'blah'
202
+ @m.should be_valid
203
+ end
204
+
205
+ specify "should validate format_of" do
206
+ @c.validates_format_of :value, :with => /.+_.+/
207
+ @m.value = 'abc_'
208
+ @m.should_not be_valid
209
+ @m.value = 'abc_def'
210
+ @m.should be_valid
211
+ end
212
+
213
+ specify "should raise for validate_format_of without regexp" do
214
+ proc {@c.validates_format_of :value}.should raise_error(ArgumentError)
215
+ proc {@c.validates_format_of :value, :with => :blah}.should raise_error(ArgumentError)
216
+ end
217
+
218
+ specify "should validate length_of with maximum" do
219
+ @c.validates_length_of :value, :maximum => 5
220
+ @m.should_not be_valid
221
+ @m.value = '12345'
222
+ @m.should be_valid
223
+ @m.value = '123456'
224
+ @m.should_not be_valid
225
+ end
226
+
227
+ specify "should validate length_of with minimum" do
228
+ @c.validates_length_of :value, :minimum => 5
229
+ @m.should_not be_valid
230
+ @m.value = '12345'
231
+ @m.should be_valid
232
+ @m.value = '1234'
233
+ @m.should_not be_valid
234
+ end
235
+
236
+ specify "should validate length_of with within" do
237
+ @c.validates_length_of :value, :within => 2..5
238
+ @m.should_not be_valid
239
+ @m.value = '12345'
240
+ @m.should be_valid
241
+ @m.value = '1'
242
+ @m.should_not be_valid
243
+ @m.value = '123456'
244
+ @m.should_not be_valid
245
+ end
246
+
247
+ specify "should validate length_of with is" do
248
+ @c.validates_length_of :value, :is => 3
249
+ @m.should_not be_valid
250
+ @m.value = '123'
251
+ @m.should be_valid
252
+ @m.value = '12'
253
+ @m.should_not be_valid
254
+ @m.value = '1234'
255
+ @m.should_not be_valid
256
+ end
257
+
258
+ specify "should validate length_of with allow_nil" do
259
+ @c.validates_length_of :value, :is => 3, :allow_nil => true
260
+ @m.should be_valid
261
+ end
262
+
263
+ specify "should validate numericality_of" do
264
+ @c.validates_numericality_of :value
265
+ @m.value = 'blah'
266
+ @m.should_not be_valid
267
+ @m.value = '123'
268
+ @m.should be_valid
269
+ @m.value = '123.1231'
270
+ @m.should be_valid
271
+ end
272
+
273
+ specify "should validate numericality_of with only_integer" do
274
+ @c.validates_numericality_of :value, :only_integer => true
275
+ @m.value = 'blah'
276
+ @m.should_not be_valid
277
+ @m.value = '123'
278
+ @m.should be_valid
279
+ @m.value = '123.1231'
280
+ @m.should_not be_valid
281
+ end
282
+
283
+ specify "should validate presence_of" do
284
+ @c.validates_presence_of :value
285
+ @m.should_not be_valid
286
+ @m.value = ''
287
+ @m.should_not be_valid
288
+ @m.value = 1234
289
+ @m.should be_valid
290
+ end
291
+ end
292
+
293
+ context "Superclass validations" do
294
+ setup do
295
+ @c1 = Class.new do
296
+ include Validation
297
+ attr_accessor :value
298
+ validates_length_of :value, :minimum => 5
299
+ end
300
+
301
+ @c2 = Class.new(@c1) do
302
+ validates_format_of :value, :with => /^[a-z]+$/
303
+ end
304
+ end
305
+
306
+ specify "should be checked when validating" do
307
+ o = @c2.new
308
+ o.value = 'ab'
309
+ o.valid?.should == false
310
+ o.errors.full_messages.should == [
311
+ 'value is too short'
312
+ ]
313
+
314
+ o.value = '12'
315
+ o.valid?.should == false
316
+ o.errors.full_messages.should == [
317
+ 'value is too short',
318
+ 'value is invalid'
319
+ ]
320
+
321
+ o.value = 'abcde'
322
+ o.valid?.should be_true
323
+ end
324
+
325
+ specify "should be skipped if skip_superclass_validations is called" do
326
+ @c2.skip_superclass_validations
327
+
328
+ o = @c2.new
329
+ o.value = 'ab'
330
+ o.valid?.should be_true
331
+
332
+ o.value = '12'
333
+ o.valid?.should == false
334
+ o.errors.full_messages.should == [
335
+ 'value is invalid'
336
+ ]
337
+
338
+ o.value = 'abcde'
339
+ o.valid?.should be_true
340
+ end
341
+ end
342
+
343
+ context ".validates with block" do
344
+ specify "should support calling .each" do
345
+ @c = Class.new do
346
+ attr_accessor :vvv
347
+
348
+ include Validation
349
+ validates do
350
+ each :vvv do |o, a, v|
351
+ o.errors[a] << "is less than zero" if v.to_i < 0
352
+ end
353
+ end
354
+ end
355
+
356
+ o = @c.new
357
+ o.vvv = 1
358
+ o.should be_valid
359
+ o.vvv = -1
360
+ o.should_not be_valid
361
+ end
362
+ end
363
+
3
364
  describe Sequel::Model, "Validations" do
4
365
 
5
366
  before(:all) do
6
367
  class Person < Sequel::Model
7
- def columns
8
- [:id,:name,:first_name,:last_name,:middle_name,:initials,:age, :terms]
9
- end
368
+ columns :id,:name,:first_name,:last_name,:middle_name,:initials,:age, :terms
10
369
  end
11
370
 
12
371
  class Smurf < Person
13
372
  end
14
373
 
15
374
  class Cow < Sequel::Model
16
- def columns
17
- [:id, :name, :got_milk]
18
- end
375
+ columns :id, :name, :got_milk
19
376
  end
20
377
 
21
378
  class User < Sequel::Model
22
- def columns
23
- [:id, :username, :password]
24
- end
379
+ columns :id, :username, :password
25
380
  end
26
381
 
27
382
  class Address < Sequel::Model
28
- def columns
29
- [:id, :zip_code]
30
- end
383
+ columns :id, :zip_code
31
384
  end
32
385
  end
33
386
 
@@ -137,6 +490,52 @@ describe Sequel::Model, "Validations" do
137
490
  @cow.name = "Betsy"
138
491
  @cow.should be_valid
139
492
  end
493
+
494
+ it "should validate the uniqueness of a column" do
495
+ class User < Sequel::Model
496
+ validations.clear
497
+ validates do
498
+ uniqueness_of :username
499
+ end
500
+ end
501
+ User.dataset.extend(Module.new {
502
+ def fetch_rows(sql)
503
+ @db << sql
504
+
505
+ case sql
506
+ when /COUNT.*username = '0records'/
507
+ when /COUNT.*username = '2records'/
508
+ yield({:v => 2})
509
+ when /COUNT.*username = '1record'/
510
+ yield({:v => 1})
511
+ when /username = '1record'/
512
+ yield({:id => 3, :username => "1record", :password => "test"})
513
+ end
514
+ end
515
+ })
516
+
517
+ @user = User.new(:username => "2records", :password => "anothertest")
518
+ @user.should_not be_valid
519
+ @user.errors.full_messages.should == ['username is already taken']
520
+
521
+ @user = User.new(:username => "1record", :password => "anothertest")
522
+ @user.should_not be_valid
523
+ @user.errors.full_messages.should == ['username is already taken']
524
+
525
+ @user = User.new(:id=>4, :username => "1record", :password => "anothertest")
526
+ @user.instance_variable_set(:@new, false)
527
+ @user.should_not be_valid
528
+ @user.errors.full_messages.should == ['username is already taken']
529
+
530
+ @user = User.new(:id=>3, :username => "1record", :password => "anothertest")
531
+ @user.instance_variable_set(:@new, false)
532
+ @user.should be_valid
533
+ @user.errors.full_messages.should == []
534
+
535
+ @user = User.new(:username => "0records", :password => "anothertest")
536
+ @user.should be_valid
537
+ @user.errors.full_messages.should == []
538
+ end
140
539
 
141
540
  it "should have a validates block that contains multiple validations" do
142
541
  class Person < Sequel::Model
@@ -185,7 +584,7 @@ describe Sequel::Model, "Validations" do
185
584
 
186
585
  it "should validate correctly instances initialized with string keys" do
187
586
  class Can < Sequel::Model
188
- def columns; [:id, :name]; end
587
+ columns :id, :name
189
588
 
190
589
  validates_length_of :name, :minimum => 4
191
590
  end
@@ -219,7 +618,7 @@ end
219
618
  describe "Model#save" do
220
619
  setup do
221
620
  @c = Class.new(Sequel::Model(:people)) do
222
- def columns; [:id]; end
621
+ columns :id
223
622
 
224
623
  validates_each :id do |o, a, v|
225
624
  o.errors[a] << 'blah' unless v == 5
@@ -243,4 +642,4 @@ describe "Model#save" do
243
642
  specify "should return false if validations fail" do
244
643
  @m.save.should == false
245
644
  end
246
- end
645
+ end