colincasey-sequel 2.10.0 → 2.10.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (137) hide show
  1. data/CHANGELOG +7 -1
  2. data/doc/advanced_associations.rdoc +614 -0
  3. data/doc/cheat_sheet.rdoc +223 -0
  4. data/doc/dataset_filtering.rdoc +158 -0
  5. data/doc/prepared_statements.rdoc +104 -0
  6. data/doc/release_notes/1.0.txt +38 -0
  7. data/doc/release_notes/1.1.txt +143 -0
  8. data/doc/release_notes/1.3.txt +101 -0
  9. data/doc/release_notes/1.4.0.txt +53 -0
  10. data/doc/release_notes/1.5.0.txt +155 -0
  11. data/doc/release_notes/2.0.0.txt +298 -0
  12. data/doc/release_notes/2.1.0.txt +271 -0
  13. data/doc/release_notes/2.10.0.txt +328 -0
  14. data/doc/release_notes/2.2.0.txt +253 -0
  15. data/doc/release_notes/2.3.0.txt +88 -0
  16. data/doc/release_notes/2.4.0.txt +106 -0
  17. data/doc/release_notes/2.5.0.txt +137 -0
  18. data/doc/release_notes/2.6.0.txt +157 -0
  19. data/doc/release_notes/2.7.0.txt +166 -0
  20. data/doc/release_notes/2.8.0.txt +171 -0
  21. data/doc/release_notes/2.9.0.txt +97 -0
  22. data/doc/schema.rdoc +29 -0
  23. data/doc/sharding.rdoc +113 -0
  24. data/lib/sequel.rb +1 -0
  25. data/lib/sequel_core/adapters/ado.rb +89 -0
  26. data/lib/sequel_core/adapters/db2.rb +143 -0
  27. data/lib/sequel_core/adapters/dbi.rb +112 -0
  28. data/lib/sequel_core/adapters/do/mysql.rb +38 -0
  29. data/lib/sequel_core/adapters/do/postgres.rb +92 -0
  30. data/lib/sequel_core/adapters/do/sqlite.rb +31 -0
  31. data/lib/sequel_core/adapters/do.rb +205 -0
  32. data/lib/sequel_core/adapters/firebird.rb +298 -0
  33. data/lib/sequel_core/adapters/informix.rb +85 -0
  34. data/lib/sequel_core/adapters/jdbc/h2.rb +69 -0
  35. data/lib/sequel_core/adapters/jdbc/mysql.rb +66 -0
  36. data/lib/sequel_core/adapters/jdbc/oracle.rb +23 -0
  37. data/lib/sequel_core/adapters/jdbc/postgresql.rb +113 -0
  38. data/lib/sequel_core/adapters/jdbc/sqlite.rb +43 -0
  39. data/lib/sequel_core/adapters/jdbc.rb +491 -0
  40. data/lib/sequel_core/adapters/mysql.rb +369 -0
  41. data/lib/sequel_core/adapters/odbc.rb +174 -0
  42. data/lib/sequel_core/adapters/openbase.rb +68 -0
  43. data/lib/sequel_core/adapters/oracle.rb +107 -0
  44. data/lib/sequel_core/adapters/postgres.rb +456 -0
  45. data/lib/sequel_core/adapters/shared/ms_access.rb +110 -0
  46. data/lib/sequel_core/adapters/shared/mssql.rb +102 -0
  47. data/lib/sequel_core/adapters/shared/mysql.rb +325 -0
  48. data/lib/sequel_core/adapters/shared/oracle.rb +61 -0
  49. data/lib/sequel_core/adapters/shared/postgres.rb +715 -0
  50. data/lib/sequel_core/adapters/shared/progress.rb +31 -0
  51. data/lib/sequel_core/adapters/shared/sqlite.rb +265 -0
  52. data/lib/sequel_core/adapters/sqlite.rb +248 -0
  53. data/lib/sequel_core/connection_pool.rb +258 -0
  54. data/lib/sequel_core/core_ext.rb +217 -0
  55. data/lib/sequel_core/core_sql.rb +202 -0
  56. data/lib/sequel_core/database/schema.rb +164 -0
  57. data/lib/sequel_core/database.rb +691 -0
  58. data/lib/sequel_core/dataset/callback.rb +13 -0
  59. data/lib/sequel_core/dataset/convenience.rb +237 -0
  60. data/lib/sequel_core/dataset/pagination.rb +96 -0
  61. data/lib/sequel_core/dataset/prepared_statements.rb +220 -0
  62. data/lib/sequel_core/dataset/query.rb +41 -0
  63. data/lib/sequel_core/dataset/schema.rb +15 -0
  64. data/lib/sequel_core/dataset/sql.rb +1010 -0
  65. data/lib/sequel_core/dataset/stored_procedures.rb +75 -0
  66. data/lib/sequel_core/dataset/unsupported.rb +43 -0
  67. data/lib/sequel_core/dataset.rb +511 -0
  68. data/lib/sequel_core/deprecated.rb +26 -0
  69. data/lib/sequel_core/exceptions.rb +44 -0
  70. data/lib/sequel_core/migration.rb +212 -0
  71. data/lib/sequel_core/object_graph.rb +230 -0
  72. data/lib/sequel_core/pretty_table.rb +71 -0
  73. data/lib/sequel_core/schema/generator.rb +320 -0
  74. data/lib/sequel_core/schema/sql.rb +325 -0
  75. data/lib/sequel_core/schema.rb +2 -0
  76. data/lib/sequel_core/sql.rb +887 -0
  77. data/lib/sequel_core/version.rb +11 -0
  78. data/lib/sequel_core.rb +172 -0
  79. data/lib/sequel_model/association_reflection.rb +267 -0
  80. data/lib/sequel_model/associations.rb +499 -0
  81. data/lib/sequel_model/base.rb +523 -0
  82. data/lib/sequel_model/caching.rb +82 -0
  83. data/lib/sequel_model/dataset_methods.rb +26 -0
  84. data/lib/sequel_model/eager_loading.rb +370 -0
  85. data/lib/sequel_model/exceptions.rb +7 -0
  86. data/lib/sequel_model/hooks.rb +101 -0
  87. data/lib/sequel_model/inflector.rb +281 -0
  88. data/lib/sequel_model/plugins.rb +62 -0
  89. data/lib/sequel_model/record.rb +568 -0
  90. data/lib/sequel_model/schema.rb +49 -0
  91. data/lib/sequel_model/validations.rb +429 -0
  92. data/lib/sequel_model.rb +91 -0
  93. data/spec/adapters/ado_spec.rb +46 -0
  94. data/spec/adapters/firebird_spec.rb +376 -0
  95. data/spec/adapters/informix_spec.rb +96 -0
  96. data/spec/adapters/mysql_spec.rb +881 -0
  97. data/spec/adapters/oracle_spec.rb +244 -0
  98. data/spec/adapters/postgres_spec.rb +687 -0
  99. data/spec/adapters/spec_helper.rb +10 -0
  100. data/spec/adapters/sqlite_spec.rb +555 -0
  101. data/spec/integration/dataset_test.rb +134 -0
  102. data/spec/integration/eager_loader_test.rb +696 -0
  103. data/spec/integration/prepared_statement_test.rb +130 -0
  104. data/spec/integration/schema_test.rb +180 -0
  105. data/spec/integration/spec_helper.rb +58 -0
  106. data/spec/integration/type_test.rb +96 -0
  107. data/spec/rcov.opts +6 -0
  108. data/spec/sequel_core/connection_pool_spec.rb +526 -0
  109. data/spec/sequel_core/core_ext_spec.rb +156 -0
  110. data/spec/sequel_core/core_sql_spec.rb +522 -0
  111. data/spec/sequel_core/database_spec.rb +1188 -0
  112. data/spec/sequel_core/dataset_spec.rb +3481 -0
  113. data/spec/sequel_core/expression_filters_spec.rb +363 -0
  114. data/spec/sequel_core/migration_spec.rb +261 -0
  115. data/spec/sequel_core/object_graph_spec.rb +272 -0
  116. data/spec/sequel_core/pretty_table_spec.rb +58 -0
  117. data/spec/sequel_core/schema_generator_spec.rb +167 -0
  118. data/spec/sequel_core/schema_spec.rb +780 -0
  119. data/spec/sequel_core/spec_helper.rb +55 -0
  120. data/spec/sequel_core/version_spec.rb +7 -0
  121. data/spec/sequel_model/association_reflection_spec.rb +93 -0
  122. data/spec/sequel_model/associations_spec.rb +1767 -0
  123. data/spec/sequel_model/base_spec.rb +419 -0
  124. data/spec/sequel_model/caching_spec.rb +215 -0
  125. data/spec/sequel_model/dataset_methods_spec.rb +78 -0
  126. data/spec/sequel_model/eager_loading_spec.rb +1165 -0
  127. data/spec/sequel_model/hooks_spec.rb +485 -0
  128. data/spec/sequel_model/inflector_spec.rb +119 -0
  129. data/spec/sequel_model/model_spec.rb +588 -0
  130. data/spec/sequel_model/plugins_spec.rb +80 -0
  131. data/spec/sequel_model/record_spec.rb +1184 -0
  132. data/spec/sequel_model/schema_spec.rb +90 -0
  133. data/spec/sequel_model/spec_helper.rb +78 -0
  134. data/spec/sequel_model/validations_spec.rb +1067 -0
  135. data/spec/spec.opts +0 -0
  136. data/spec/spec_config.rb.example +10 -0
  137. metadata +177 -3
@@ -0,0 +1,1067 @@
1
+ require File.join(File.dirname(__FILE__), "spec_helper")
2
+
3
+ describe Sequel::Model::Validation::Errors do
4
+ setup do
5
+ @errors = Sequel::Model::Validation::Errors.new
6
+ end
7
+
8
+ specify "should be clearable using #clear" do
9
+ @errors.add(:a, 'b')
10
+ @errors.should == {:a=>['b']}
11
+ @errors.clear
12
+ @errors.should == {}
13
+ end
14
+
15
+ specify "should be empty if no errors are added" do
16
+ @errors.should be_empty
17
+ @errors[:blah] << "blah"
18
+ @errors.should_not be_empty
19
+ end
20
+
21
+ specify "should return errors for a specific attribute using #on or #[]" do
22
+ @errors[:blah].should == []
23
+ @errors.on(:blah).should == []
24
+
25
+ @errors[:blah] << 'blah'
26
+ @errors[:blah].should == ['blah']
27
+ @errors.on(:blah).should == ['blah']
28
+
29
+ @errors[:bleu].should == []
30
+ @errors.on(:bleu).should == []
31
+ end
32
+
33
+ specify "should accept errors using #[] << or #add" do
34
+ @errors[:blah] << 'blah'
35
+ @errors[:blah].should == ['blah']
36
+
37
+ @errors.add :blah, 'zzzz'
38
+ @errors[:blah].should == ['blah', 'zzzz']
39
+ end
40
+
41
+ specify "should return full messages using #full_messages" do
42
+ @errors.full_messages.should == []
43
+
44
+ @errors[:blow] << 'blieuh'
45
+ @errors[:blow] << 'blich'
46
+ @errors[:blay] << 'bliu'
47
+ msgs = @errors.full_messages
48
+ msgs.size.should == 3
49
+ msgs.should include('blow blieuh', 'blow blich', 'blay bliu')
50
+ end
51
+
52
+ specify "should return the number of error messages using #count" do
53
+ @errors.count.should == 0
54
+ @errors.add(:a, 'b')
55
+ @errors.count.should == 1
56
+ @errors.add(:a, 'c')
57
+ @errors.count.should == 2
58
+ @errors.add(:b, 'c')
59
+ @errors.count.should == 3
60
+ end
61
+
62
+ specify "should return the array of error messages for a given attribute using #on" do
63
+ @errors.add(:a, 'b')
64
+ @errors.on(:a).should == ['b']
65
+ @errors.add(:a, 'c')
66
+ @errors.on(:a).should == ['b', 'c']
67
+ @errors.add(:b, 'c')
68
+ @errors.on(:a).should == ['b', 'c']
69
+ end
70
+
71
+ specify "should return nil if there are no error messages for a given attribute using #on" do
72
+ @errors.on(:a).should == nil
73
+ @errors.add(:b, 'b')
74
+ @errors.on(:a).should == nil
75
+ end
76
+ end
77
+
78
+ describe Sequel::Model do
79
+ setup do
80
+ @c = Class.new(Sequel::Model) do
81
+ def self.validates_coolness_of(attr)
82
+ validates_each(attr) {|o, a, v| o.errors[a] << 'is not cool' if v != :cool}
83
+ end
84
+ end
85
+ end
86
+
87
+ specify "should respond to validates, validations, has_validations?" do
88
+ @c.should respond_to(:validations)
89
+ @c.should respond_to(:has_validations?)
90
+ end
91
+
92
+ specify "should acccept validation definitions using validates_each" do
93
+ @c.validates_each(:xx, :yy) {|o, a, v| o.errors[a] << 'too low' if v < 50}
94
+ o = @c.new
95
+ o.should_receive(:xx).once.and_return(40)
96
+ o.should_receive(:yy).once.and_return(60)
97
+ o.valid?.should == false
98
+ o.errors.full_messages.should == ['xx too low']
99
+ end
100
+
101
+ specify "should return true/false for has_validations?" do
102
+ @c.has_validations?.should == false
103
+ @c.validates_each(:xx) {1}
104
+ @c.has_validations?.should == true
105
+ end
106
+
107
+ specify "should validate multiple attributes at once" do
108
+ o = @c.new
109
+ def o.xx
110
+ 1
111
+ end
112
+ def o.yy
113
+ 2
114
+ end
115
+ vals = nil
116
+ atts = nil
117
+ @c.validates_each([:xx, :yy]){|obj,a,v| atts=a; vals=v}
118
+ o.valid?
119
+ vals.should == [1,2]
120
+ atts.should == [:xx, :yy]
121
+ end
122
+
123
+ specify "should respect allow_missing option when using multiple attributes" do
124
+ o = @c.new
125
+ def o.xx
126
+ self[:xx]
127
+ end
128
+ def o.yy
129
+ self[:yy]
130
+ end
131
+ vals = nil
132
+ atts = nil
133
+ @c.validates_each([:xx, :yy], :allow_missing=>true){|obj,a,v| atts=a; vals=v}
134
+
135
+ o.values[:xx] = 1
136
+ o.valid?
137
+ vals.should == [1,nil]
138
+ atts.should == [:xx, :yy]
139
+
140
+ vals = nil
141
+ atts = nil
142
+ o.values.clear
143
+ o.values[:yy] = 2
144
+ o.valid?
145
+ vals.should == [nil, 2]
146
+ atts.should == [:xx, :yy]
147
+
148
+ vals = nil
149
+ atts = nil
150
+ o.values.clear
151
+ o.valid?.should == true
152
+ vals.should == nil
153
+ atts.should == nil
154
+ end
155
+
156
+ specify "should overwrite existing validation with the same tag and attribute" do
157
+ @c.validates_each(:xx, :xx, :tag=>:low) {|o, a, v| o.xxx; o.errors[a] << 'too low' if v < 50}
158
+ @c.validates_each(:yy, :yy) {|o, a, v| o.yyy; o.errors[a] << 'too low' if v < 50}
159
+ @c.validates_presence_of(:zz, :zz)
160
+ @c.validates_length_of(:aa, :aa, :tag=>:blah)
161
+ o = @c.new
162
+ def o.zz
163
+ @a ||= 0
164
+ @a += 1
165
+ end
166
+ def o.aa
167
+ @b ||= 0
168
+ @b += 1
169
+ end
170
+ o.should_receive(:xx).once.and_return(40)
171
+ o.should_receive(:yy).once.and_return(60)
172
+ o.should_receive(:xxx).once
173
+ o.should_receive(:yyy).twice
174
+ o.valid?.should == false
175
+ o.zz.should == 2
176
+ o.aa.should == 2
177
+ o.errors.full_messages.should == ['xx too low']
178
+ end
179
+
180
+ specify "should provide a validates method that takes block with validation definitions" do
181
+ @c.validates do
182
+ coolness_of :blah
183
+ end
184
+ @c.validations[:blah].should_not be_empty
185
+ o = @c.new
186
+ o.should_receive(:blah).once.and_return(nil)
187
+ o.valid?.should == false
188
+ o.errors.full_messages.should == ['blah is not cool']
189
+ end
190
+ end
191
+
192
+ describe Sequel::Model do
193
+ setup do
194
+ @c = Class.new(Sequel::Model) do
195
+ columns :score
196
+ validates_each :score do |o, a, v|
197
+ o.errors[a] << 'too low' if v < 87
198
+ end
199
+ end
200
+
201
+ @o = @c.new
202
+ end
203
+
204
+ specify "should supply a #valid? method that returns true if validations pass" do
205
+ @o.score = 50
206
+ @o.should_not be_valid
207
+ @o.score = 100
208
+ @o.should be_valid
209
+ end
210
+
211
+ specify "should provide an errors object" do
212
+ @o.score = 100
213
+ @o.should be_valid
214
+ @o.errors.should be_empty
215
+
216
+ @o.score = 86
217
+ @o.should_not be_valid
218
+ @o.errors[:score].should == ['too low']
219
+ @o.errors[:blah].should be_empty
220
+ end
221
+ end
222
+
223
+ describe Sequel::Model::Validation::Generator do
224
+ setup do
225
+ $testit = nil
226
+
227
+ @c = Class.new(Sequel::Model) do
228
+ def self.validates_blah
229
+ $testit = 1324
230
+ end
231
+ end
232
+ end
233
+
234
+ specify "should instance_eval the block, sending everything to its receiver" do
235
+ Sequel::Model::Validation::Generator.new(@c) do
236
+ blah
237
+ end
238
+ $testit.should == 1324
239
+ end
240
+ end
241
+
242
+ describe Sequel::Model do
243
+ setup do
244
+ @c = Class.new(Sequel::Model) do
245
+ columns :value
246
+
247
+ def self.filter(*args)
248
+ o = Object.new
249
+ def o.count; 2; end
250
+ o
251
+ end
252
+
253
+ def skip; false; end
254
+ def dont_skip; true; end
255
+ end
256
+ @m = @c.new
257
+ end
258
+
259
+ specify "should validate acceptance_of" do
260
+ @c.validates_acceptance_of :value
261
+ @m.should be_valid
262
+ @m.value = '1'
263
+ @m.should be_valid
264
+ end
265
+
266
+ specify "should validate acceptance_of with accept" do
267
+ @c.validates_acceptance_of :value, :accept => 'true'
268
+ @m.value = '1'
269
+ @m.should_not be_valid
270
+ @m.value = 'true'
271
+ @m.should be_valid
272
+ end
273
+
274
+ specify "should validate acceptance_of with allow_nil => false" do
275
+ @c.validates_acceptance_of :value, :allow_nil => false
276
+ @m.should_not be_valid
277
+ end
278
+
279
+ specify "should validate acceptance_of with allow_missing => true" do
280
+ @c.validates_acceptance_of :value, :allow_missing => true
281
+ @m.should be_valid
282
+ end
283
+
284
+ specify "should validate acceptance_of with allow_missing => true and allow_nil => false" do
285
+ @c.validates_acceptance_of :value, :allow_missing => true, :allow_nil => false
286
+ @m.should be_valid
287
+ @m.value = nil
288
+ @m.should_not be_valid
289
+ end
290
+
291
+ specify "should validate acceptance_of with if => true" do
292
+ @c.validates_acceptance_of :value, :if => :dont_skip
293
+ @m.value = '0'
294
+ @m.should_not be_valid
295
+ end
296
+
297
+ specify "should validate acceptance_of with if => false" do
298
+ @c.validates_acceptance_of :value, :if => :skip
299
+ @m.value = '0'
300
+ @m.should be_valid
301
+ end
302
+
303
+ specify "should validate acceptance_of with if proc that evaluates to true" do
304
+ @c.validates_acceptance_of :value, :if => proc{true}
305
+ @m.value = '0'
306
+ @m.should_not be_valid
307
+ end
308
+
309
+ specify "should validate acceptance_of with if proc that evaluates to false" do
310
+ @c.validates_acceptance_of :value, :if => proc{false}
311
+ @m.value = '0'
312
+ @m.should be_valid
313
+ end
314
+
315
+ specify "should raise an error if :if option is not a Symbol, Proc, or nil" do
316
+ @c.validates_acceptance_of :value, :if => 1
317
+ @m.value = '0'
318
+ proc{@m.valid?}.should raise_error(Sequel::Error)
319
+ end
320
+
321
+ specify "should validate confirmation_of" do
322
+ @c.send(:attr_accessor, :value_confirmation)
323
+ @c.validates_confirmation_of :value
324
+
325
+ @m.value = 'blah'
326
+ @m.should_not be_valid
327
+
328
+ @m.value_confirmation = 'blah'
329
+ @m.should be_valid
330
+ end
331
+
332
+ specify "should validate confirmation_of with if => true" do
333
+ @c.send(:attr_accessor, :value_confirmation)
334
+ @c.validates_confirmation_of :value, :if => :dont_skip
335
+
336
+ @m.value = 'blah'
337
+ @m.should_not be_valid
338
+ end
339
+
340
+ specify "should validate confirmation_of with if => false" do
341
+ @c.send(:attr_accessor, :value_confirmation)
342
+ @c.validates_confirmation_of :value, :if => :skip
343
+
344
+ @m.value = 'blah'
345
+ @m.should be_valid
346
+ end
347
+
348
+ specify "should validate confirmation_of with allow_missing => true" do
349
+ @c.send(:attr_accessor, :value_confirmation)
350
+ @c.validates_acceptance_of :value, :allow_missing => true
351
+ @m.should be_valid
352
+ @m.value_confirmation = 'blah'
353
+ @m.should be_valid
354
+ @m.value = nil
355
+ @m.should_not be_valid
356
+ end
357
+
358
+ specify "should validate format_of" do
359
+ @c.validates_format_of :value, :with => /.+_.+/
360
+ @m.value = 'abc_'
361
+ @m.should_not be_valid
362
+ @m.value = 'abc_def'
363
+ @m.should be_valid
364
+ end
365
+
366
+ specify "should raise for validate_format_of without regexp" do
367
+ proc {@c.validates_format_of :value}.should raise_error(ArgumentError)
368
+ proc {@c.validates_format_of :value, :with => :blah}.should raise_error(ArgumentError)
369
+ end
370
+
371
+ specify "should validate format_of with if => true" do
372
+ @c.validates_format_of :value, :with => /_/, :if => :dont_skip
373
+
374
+ @m.value = 'a'
375
+ @m.should_not be_valid
376
+ end
377
+
378
+ specify "should validate format_of with if => false" do
379
+ @c.validates_format_of :value, :with => /_/, :if => :skip
380
+
381
+ @m.value = 'a'
382
+ @m.should be_valid
383
+ end
384
+
385
+ specify "should validate format_of with allow_missing => true" do
386
+ @c.validates_format_of :value, :allow_missing => true, :with=>/./
387
+ @m.should be_valid
388
+ @m.value = nil
389
+ @m.should_not be_valid
390
+ end
391
+
392
+ specify "should validate length_of with maximum" do
393
+ @c.validates_length_of :value, :maximum => 5
394
+ @m.should_not be_valid
395
+ @m.value = '12345'
396
+ @m.should be_valid
397
+ @m.value = '123456'
398
+ @m.should_not be_valid
399
+ end
400
+
401
+ specify "should validate length_of with minimum" do
402
+ @c.validates_length_of :value, :minimum => 5
403
+ @m.should_not be_valid
404
+ @m.value = '12345'
405
+ @m.should be_valid
406
+ @m.value = '1234'
407
+ @m.should_not be_valid
408
+ end
409
+
410
+ specify "should validate length_of with within" do
411
+ @c.validates_length_of :value, :within => 2..5
412
+ @m.should_not be_valid
413
+ @m.value = '12345'
414
+ @m.should be_valid
415
+ @m.value = '1'
416
+ @m.should_not be_valid
417
+ @m.value = '123456'
418
+ @m.should_not be_valid
419
+ end
420
+
421
+ specify "should validate length_of with is" do
422
+ @c.validates_length_of :value, :is => 3
423
+ @m.should_not be_valid
424
+ @m.value = '123'
425
+ @m.should be_valid
426
+ @m.value = '12'
427
+ @m.should_not be_valid
428
+ @m.value = '1234'
429
+ @m.should_not be_valid
430
+ end
431
+
432
+ specify "should validate length_of with allow_nil" do
433
+ @c.validates_length_of :value, :is => 3, :allow_nil => true
434
+ @m.should be_valid
435
+ end
436
+
437
+ specify "should validate length_of with if => true" do
438
+ @c.validates_length_of :value, :is => 3, :if => :dont_skip
439
+
440
+ @m.value = 'a'
441
+ @m.should_not be_valid
442
+ end
443
+
444
+ specify "should validate length_of with if => false" do
445
+ @c.validates_length_of :value, :is => 3, :if => :skip
446
+
447
+ @m.value = 'a'
448
+ @m.should be_valid
449
+ end
450
+
451
+ specify "should validate length_of with allow_missing => true" do
452
+ @c.validates_length_of :value, :allow_missing => true, :minimum => 5
453
+ @m.should be_valid
454
+ @m.value = nil
455
+ @m.should_not be_valid
456
+ end
457
+
458
+ specify "should allow multiple calls to validates_length_of with different options without overwriting" do
459
+ @c.validates_length_of :value, :maximum => 5
460
+ @c.validates_length_of :value, :minimum => 5
461
+ @m.should_not be_valid
462
+ @m.value = '12345'
463
+ @m.should be_valid
464
+ @m.value = '123456'
465
+ @m.should_not be_valid
466
+ @m.value = '12345'
467
+ @m.should be_valid
468
+ @m.value = '1234'
469
+ @m.should_not be_valid
470
+ end
471
+
472
+ specify "should validate numericality_of" do
473
+ @c.validates_numericality_of :value
474
+ @m.value = 'blah'
475
+ @m.should_not be_valid
476
+ @m.value = '123'
477
+ @m.should be_valid
478
+ @m.value = '123.1231'
479
+ @m.should be_valid
480
+ @m.value = '+1'
481
+ @m.should be_valid
482
+ @m.value = '-1'
483
+ @m.should be_valid
484
+ @m.value = '+1.123'
485
+ @m.should be_valid
486
+ @m.value = '-0.123'
487
+ @m.should be_valid
488
+ @m.value = '-0.123E10'
489
+ @m.should be_valid
490
+ @m.value = '32.123e10'
491
+ @m.should be_valid
492
+ @m.value = '+32.123E10'
493
+ @m.should be_valid
494
+ @m.should be_valid
495
+ @m.value = '.0123'
496
+ end
497
+
498
+ specify "should validate numericality_of with only_integer" do
499
+ @c.validates_numericality_of :value, :only_integer => true
500
+ @m.value = 'blah'
501
+ @m.should_not be_valid
502
+ @m.value = '123'
503
+ @m.should be_valid
504
+ @m.value = '123.1231'
505
+ @m.should_not be_valid
506
+ end
507
+
508
+ specify "should validate numericality_of with if => true" do
509
+ @c.validates_numericality_of :value, :if => :dont_skip
510
+
511
+ @m.value = 'a'
512
+ @m.should_not be_valid
513
+ end
514
+
515
+ specify "should validate numericality_of with if => false" do
516
+ @c.validates_numericality_of :value, :if => :skip
517
+
518
+ @m.value = 'a'
519
+ @m.should be_valid
520
+ end
521
+
522
+ specify "should validate numericality_of with allow_missing => true" do
523
+ @c.validates_numericality_of :value, :allow_missing => true
524
+ @m.should be_valid
525
+ @m.value = nil
526
+ @m.should_not be_valid
527
+ end
528
+
529
+ specify "should validate presence_of" do
530
+ @c.validates_presence_of :value
531
+ @m.should_not be_valid
532
+ @m.value = ''
533
+ @m.should_not be_valid
534
+ @m.value = 1234
535
+ @m.should be_valid
536
+ @m.value = nil
537
+ @m.should_not be_valid
538
+ @m.value = true
539
+ @m.should be_valid
540
+ @m.value = false
541
+ @m.should be_valid
542
+ end
543
+
544
+ specify "should validate inclusion_of with an array" do
545
+ @c.validates_inclusion_of :value, :in => [1,2]
546
+ @m.should_not be_valid
547
+ @m.value = 1
548
+ @m.should be_valid
549
+ @m.value = 1.5
550
+ @m.should_not be_valid
551
+ @m.value = 2
552
+ @m.should be_valid
553
+ @m.value = 3
554
+ @m.should_not be_valid
555
+ end
556
+
557
+ specify "should validate inclusion_of with a range" do
558
+ @c.validates_inclusion_of :value, :in => 1..4
559
+ @m.should_not be_valid
560
+ @m.value = 1
561
+ @m.should be_valid
562
+ @m.value = 1.5
563
+ @m.should be_valid
564
+ @m.value = 0
565
+ @m.should_not be_valid
566
+ @m.value = 5
567
+ @m.should_not be_valid
568
+ end
569
+
570
+ specify "should raise an error if inclusion_of doesn't receive a valid :in option" do
571
+ lambda {
572
+ @c.validates_inclusion_of :value
573
+ }.should raise_error(ArgumentError)
574
+
575
+ lambda {
576
+ @c.validates_inclusion_of :value, :in => 1
577
+ }.should raise_error(ArgumentError)
578
+ end
579
+
580
+ specify "should raise an error if inclusion_of handles :allow_nil too" do
581
+ @c.validates_inclusion_of :value, :in => 1..4, :allow_nil => true
582
+ @m.value = nil
583
+ @m.should be_valid
584
+ @m.value = 0
585
+ @m.should_not be_valid
586
+ end
587
+
588
+ specify "should validate presence_of with if => true" do
589
+ @c.validates_presence_of :value, :if => :dont_skip
590
+ @m.should_not be_valid
591
+ end
592
+
593
+ specify "should validate presence_of with if => false" do
594
+ @c.validates_presence_of :value, :if => :skip
595
+ @m.should be_valid
596
+ end
597
+
598
+ specify "should validate presence_of with allow_missing => true" do
599
+ @c.validates_presence_of :value, :allow_missing => true
600
+ @m.should be_valid
601
+ @m.value = nil
602
+ @m.should_not be_valid
603
+ end
604
+
605
+ specify "should validate uniqueness_of with if => true" do
606
+ @c.validates_uniqueness_of :value, :if => :dont_skip
607
+
608
+ @m.value = 'a'
609
+ @m.should_not be_valid
610
+ end
611
+
612
+ specify "should validate uniqueness_of with if => false" do
613
+ @c.validates_uniqueness_of :value, :if => :skip
614
+
615
+ @m.value = 'a'
616
+ @m.should be_valid
617
+ end
618
+
619
+ specify "should validate uniqueness_of with allow_missing => true" do
620
+ @c.validates_uniqueness_of :value, :allow_missing => true
621
+ @m.should be_valid
622
+ @m.value = nil
623
+ @m.should_not be_valid
624
+ end
625
+ end
626
+
627
+ context "Superclass validations" do
628
+ setup do
629
+ @c1 = Class.new(Sequel::Model) do
630
+ columns :value
631
+ validates_length_of :value, :minimum => 5
632
+ end
633
+
634
+ @c2 = Class.new(@c1) do
635
+ columns :value
636
+ validates_format_of :value, :with => /^[a-z]+$/
637
+ end
638
+ end
639
+
640
+ specify "should be checked when validating" do
641
+ o = @c2.new
642
+ o.value = 'ab'
643
+ o.valid?.should == false
644
+ o.errors.full_messages.should == [
645
+ 'value is too short'
646
+ ]
647
+
648
+ o.value = '12'
649
+ o.valid?.should == false
650
+ o.errors.full_messages.should == [
651
+ 'value is too short',
652
+ 'value is invalid'
653
+ ]
654
+
655
+ o.value = 'abcde'
656
+ o.valid?.should be_true
657
+ end
658
+
659
+ specify "should be skipped if skip_superclass_validations is called" do
660
+ @c2.skip_superclass_validations
661
+
662
+ o = @c2.new
663
+ o.value = 'ab'
664
+ o.valid?.should be_true
665
+
666
+ o.value = '12'
667
+ o.valid?.should == false
668
+ o.errors.full_messages.should == [
669
+ 'value is invalid'
670
+ ]
671
+
672
+ o.value = 'abcde'
673
+ o.valid?.should be_true
674
+ end
675
+ end
676
+
677
+ context ".validates with block" do
678
+ specify "should support calling .each" do
679
+ @c = Class.new(Sequel::Model) do
680
+ columns :vvv
681
+ validates do
682
+ each :vvv do |o, a, v|
683
+ o.errors[a] << "is less than zero" if v.to_i < 0
684
+ end
685
+ end
686
+ end
687
+
688
+ o = @c.new
689
+ o.vvv = 1
690
+ o.should be_valid
691
+ o.vvv = -1
692
+ o.should_not be_valid
693
+ end
694
+ end
695
+
696
+ describe Sequel::Model, "Validations" do
697
+
698
+ before(:all) do
699
+ class ::Person < Sequel::Model
700
+ columns :id,:name,:first_name,:last_name,:middle_name,:initials,:age, :terms
701
+ end
702
+
703
+ class ::Smurf < Person
704
+ end
705
+
706
+ class ::Cow < Sequel::Model
707
+ columns :id, :name, :got_milk
708
+ end
709
+
710
+ class ::User < Sequel::Model
711
+ columns :id, :username, :password
712
+ end
713
+
714
+ class ::Address < Sequel::Model
715
+ columns :id, :zip_code
716
+ end
717
+ end
718
+
719
+ it "should validate the acceptance of a column" do
720
+ class ::Cow < Sequel::Model
721
+ validations.clear
722
+ validates_acceptance_of :got_milk, :accept => 'blah', :allow_nil => false
723
+ end
724
+
725
+ @cow = Cow.new
726
+ @cow.should_not be_valid
727
+ @cow.errors.full_messages.should == ["got_milk is not accepted"]
728
+
729
+ @cow.got_milk = "blah"
730
+ @cow.should be_valid
731
+ end
732
+
733
+ it "should validate the confirmation of a column" do
734
+ class ::User < Sequel::Model
735
+ def password_confirmation
736
+ "test"
737
+ end
738
+
739
+ validations.clear
740
+ validates_confirmation_of :password
741
+ end
742
+
743
+ @user = User.new
744
+ @user.should_not be_valid
745
+ @user.errors.full_messages.should == ["password is not confirmed"]
746
+
747
+ @user.password = "test"
748
+ @user.should be_valid
749
+ end
750
+
751
+ it "should validate format of column" do
752
+ class ::Person < Sequel::Model
753
+ validates_format_of :first_name, :with => /^[a-zA-Z]+$/
754
+ end
755
+
756
+ @person = Person.new :first_name => "Lancelot99"
757
+ @person.valid?.should be_false
758
+ @person = Person.new :first_name => "Anita"
759
+ @person.valid?.should be_true
760
+ end
761
+
762
+ it "should validate length of column" do
763
+ class ::Person < Sequel::Model
764
+ validations.clear
765
+ validates_length_of :first_name, :maximum => 30
766
+ validates_length_of :last_name, :minimum => 30
767
+ validates_length_of :middle_name, :within => 1..5
768
+ validates_length_of :initials, :is => 2
769
+ end
770
+
771
+ @person = Person.new(
772
+ :first_name => "Anamethatiswaytofreakinglongandwayoverthirtycharacters",
773
+ :last_name => "Alastnameunderthirtychars",
774
+ :initials => "LGC",
775
+ :middle_name => "danger"
776
+ )
777
+
778
+ @person.should_not be_valid
779
+ @person.errors.full_messages.size.should == 4
780
+ @person.errors.full_messages.should include(
781
+ 'first_name is too long',
782
+ 'last_name is too short',
783
+ 'middle_name is the wrong length',
784
+ 'initials is the wrong length'
785
+ )
786
+
787
+ @person.first_name = "Lancelot"
788
+ @person.last_name = "1234567890123456789012345678901"
789
+ @person.initials = "LC"
790
+ @person.middle_name = "Will"
791
+ @person.should be_valid
792
+ end
793
+
794
+ it "should validate that a column doesn't have a string value" do
795
+ p = Class.new(Sequel::Model)
796
+ p.class_eval do
797
+ columns :age, :price, :confirmed
798
+ self.raise_on_typecast_failure = false
799
+ validates_not_string :age
800
+ validates_not_string :confirmed
801
+ validates_not_string :price, :message=>'is not valid'
802
+ @db_schema = {:age=>{:type=>:integer}}
803
+ end
804
+
805
+ @person = p.new
806
+ @person.should be_valid
807
+
808
+ @person.confirmed = 't'
809
+ @person.should_not be_valid
810
+ @person.errors.full_messages.should == ['confirmed is a string']
811
+ @person.confirmed = true
812
+ @person.should be_valid
813
+
814
+ @person.age = 'a'
815
+ @person.should_not be_valid
816
+ @person.errors.full_messages.should == ['age is not a valid integer']
817
+ @person.db_schema[:age][:type] = :datetime
818
+ @person.should_not be_valid
819
+ @person.errors.full_messages.should == ['age is not a valid datetime']
820
+ @person.age = 20
821
+ @person.should be_valid
822
+
823
+ @person.price = 'a'
824
+ @person.should_not be_valid
825
+ @person.errors.full_messages.should == ['price is not valid']
826
+ @person.price = 20
827
+ @person.should be_valid
828
+ end
829
+
830
+ it "should validate numericality of column" do
831
+ class ::Person < Sequel::Model
832
+ validations.clear
833
+ validates_numericality_of :age
834
+ end
835
+
836
+ @person = Person.new :age => "Twenty"
837
+ @person.should_not be_valid
838
+ @person.errors.full_messages.should == ['age is not a number']
839
+
840
+ @person.age = 20
841
+ @person.should be_valid
842
+ end
843
+
844
+ it "should validate the presence of a column" do
845
+ class ::Cow < Sequel::Model
846
+ validations.clear
847
+ validates_presence_of :name
848
+ end
849
+
850
+ @cow = Cow.new
851
+ @cow.should_not be_valid
852
+ @cow.errors.full_messages.should == ['name is not present']
853
+
854
+ @cow.name = "Betsy"
855
+ @cow.should be_valid
856
+ end
857
+
858
+ it "should validate the uniqueness of a column" do
859
+ class ::User < Sequel::Model
860
+ validations.clear
861
+ validates do
862
+ uniqueness_of :username
863
+ end
864
+ end
865
+ User.dataset.extend(Module.new {
866
+ def fetch_rows(sql)
867
+ @db << sql
868
+
869
+ case sql
870
+ when /COUNT.*username = '0records'/
871
+ yield({:v => 0})
872
+ when /COUNT.*username = '2records'/
873
+ yield({:v => 2})
874
+ when /COUNT.*username = '1record'/
875
+ yield({:v => 1})
876
+ when /username = '1record'/
877
+ yield({:id => 3, :username => "1record", :password => "test"})
878
+ end
879
+ end
880
+ })
881
+
882
+ @user = User.new(:username => "2records", :password => "anothertest")
883
+ @user.should_not be_valid
884
+ @user.errors.full_messages.should == ['username is already taken']
885
+
886
+ @user = User.new(:username => "1record", :password => "anothertest")
887
+ @user.should_not be_valid
888
+ @user.errors.full_messages.should == ['username is already taken']
889
+
890
+ @user = User.load(:id=>4, :username => "1record", :password => "anothertest")
891
+ @user.should_not be_valid
892
+ @user.errors.full_messages.should == ['username is already taken']
893
+
894
+ @user = User.load(:id=>3, :username => "1record", :password => "anothertest")
895
+ @user.should be_valid
896
+ @user.errors.full_messages.should == []
897
+
898
+ @user = User.new(:username => "0records", :password => "anothertest")
899
+ @user.should be_valid
900
+ @user.errors.full_messages.should == []
901
+ end
902
+
903
+ it "should validate the uniqueness of multiple columns" do
904
+ class ::User < Sequel::Model
905
+ validations.clear
906
+ validates do
907
+ uniqueness_of [:username, :password]
908
+ end
909
+ end
910
+ User.dataset.extend(Module.new {
911
+ def fetch_rows(sql)
912
+ @db << sql
913
+
914
+ case sql
915
+ when /COUNT.*username = '0records'/
916
+ yield({:v => 0})
917
+ when /COUNT.*username = '2records'/
918
+ yield({:v => 2})
919
+ when /COUNT.*username = '1record'/
920
+ yield({:v => 1})
921
+ when /username = '1record'/
922
+ if sql =~ /password = 'anothertest'/
923
+ yield({:id => 3, :username => "1record", :password => "anothertest"})
924
+ else
925
+ yield({:id => 4, :username => "1record", :password => "test"})
926
+ end
927
+ end
928
+ end
929
+ })
930
+
931
+ @user = User.new(:username => "2records", :password => "anothertest")
932
+ @user.should_not be_valid
933
+ @user.errors.full_messages.should == ['username and password is already taken']
934
+
935
+ @user = User.new(:username => "1record", :password => "anothertest")
936
+ @user.should_not be_valid
937
+ @user.errors.full_messages.should == ['username and password is already taken']
938
+
939
+ @user = User.load(:id=>4, :username => "1record", :password => "anothertest")
940
+ @user.should_not be_valid
941
+ @user.errors.full_messages.should == ['username and password is already taken']
942
+
943
+ @user = User.load(:id=>3, :username => "1record", :password => "test")
944
+ @user.should_not be_valid
945
+ @user.errors.full_messages.should == ['username and password is already taken']
946
+
947
+ @user = User.load(:id=>3, :username => "1record", :password => "anothertest")
948
+ @user.should be_valid
949
+ @user.errors.full_messages.should == []
950
+
951
+ @user = User.new(:username => "0records", :password => "anothertest")
952
+ @user.should be_valid
953
+ @user.errors.full_messages.should == []
954
+ end
955
+
956
+ it "should have a validates block that contains multiple validations" do
957
+ class ::Person < Sequel::Model
958
+ validations.clear
959
+ validates do
960
+ format_of :first_name, :with => /^[a-zA-Z]+$/
961
+ length_of :first_name, :maximum => 30
962
+ end
963
+ end
964
+
965
+ Person.validations[:first_name].size.should == 2
966
+
967
+ @person = Person.new :first_name => "Lancelot99"
968
+ @person.valid?.should be_false
969
+
970
+ @person2 = Person.new :first_name => "Wayne"
971
+ @person2.valid?.should be_true
972
+ end
973
+
974
+ it "should allow 'longhand' validations direcly within the model." do
975
+ lambda {
976
+ class ::Person < Sequel::Model
977
+ validations.clear
978
+ validates_length_of :first_name, :maximum => 30
979
+ end
980
+ }.should_not raise_error
981
+ Person.validations.length.should eql(1)
982
+ end
983
+
984
+ it "should define a has_validations? method which returns true if the model has validations, false otherwise" do
985
+ class ::Person < Sequel::Model
986
+ validations.clear
987
+ validates do
988
+ format_of :first_name, :with => /\w+/
989
+ length_of :first_name, :maximum => 30
990
+ end
991
+ end
992
+
993
+ class ::Smurf < Person
994
+ validations.clear
995
+ end
996
+
997
+ Person.should have_validations
998
+ Smurf.should_not have_validations
999
+ end
1000
+
1001
+ it "should validate correctly instances initialized with string keys" do
1002
+ class ::Can < Sequel::Model
1003
+ columns :id, :name
1004
+
1005
+ validates_length_of :name, :minimum => 4
1006
+ end
1007
+
1008
+ Can.new('name' => 'ab').should_not be_valid
1009
+ Can.new('name' => 'abcd').should be_valid
1010
+ end
1011
+
1012
+ end
1013
+
1014
+ describe "Model#save!" do
1015
+ setup do
1016
+ @c = Class.new(Sequel::Model(:people)) do
1017
+ def columns; [:id]; end
1018
+
1019
+ validates_each :id do |o, a, v|
1020
+ o.errors[a] << 'blah' unless v == 5
1021
+ end
1022
+ end
1023
+ @m = @c.load(:id => 4)
1024
+ MODEL_DB.reset
1025
+ end
1026
+
1027
+ specify "should save regardless of validations" do
1028
+ @m.should_not be_valid
1029
+ @m.save!
1030
+ MODEL_DB.sqls.should == ['UPDATE people SET id = 4 WHERE (id = 4)']
1031
+ end
1032
+ end
1033
+
1034
+ describe "Model#save" do
1035
+ setup do
1036
+ @c = Class.new(Sequel::Model(:people)) do
1037
+ columns :id
1038
+
1039
+ validates_each :id do |o, a, v|
1040
+ o.errors[a] << 'blah' unless v == 5
1041
+ end
1042
+ end
1043
+ @m = @c.load(:id => 4)
1044
+ MODEL_DB.reset
1045
+ end
1046
+
1047
+ specify "should save only if validations pass" do
1048
+ @m.raise_on_save_failure = false
1049
+ @m.should_not be_valid
1050
+ @m.save
1051
+ MODEL_DB.sqls.should be_empty
1052
+
1053
+ @m.id = 5
1054
+ @m.should be_valid
1055
+ @m.save.should_not be_false
1056
+ MODEL_DB.sqls.should == ['UPDATE people SET id = 5 WHERE (id = 5)']
1057
+ end
1058
+
1059
+ specify "should raise error if validations fail and raise_on_save_faiure is true" do
1060
+ proc{@m.save}.should raise_error(Sequel::ValidationFailed)
1061
+ end
1062
+
1063
+ specify "should return nil if validations fail and raise_on_save_faiure is false" do
1064
+ @m.raise_on_save_failure = false
1065
+ @m.save.should == nil
1066
+ end
1067
+ end