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