viking-sequel 3.10.0

Sign up to get free protection for your applications and to get access to all the features.
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,438 @@
1
+ require File.join(File.dirname(__FILE__), "spec_helper")
2
+
3
+ describe "Sequel::Plugins::ValidationHelpers" do
4
+ before do
5
+ @c = Class.new(Sequel::Model) do
6
+ def self.set_validations(&block)
7
+ define_method(:validate, &block)
8
+ end
9
+ columns :value
10
+ end
11
+ @c.plugin :validation_helpers
12
+ @m = @c.new
13
+ end
14
+
15
+ specify "should take an :allow_blank option" do
16
+ @c.set_validations{validates_format(/.+_.+/, :value, :allow_blank=>true)}
17
+ @m.value = 'abc_'
18
+ @m.should_not be_valid
19
+ @m.value = '1_1'
20
+ @m.should be_valid
21
+ o = Object.new
22
+ @m.value = o
23
+ @m.should_not be_valid
24
+ def o.blank?
25
+ true
26
+ end
27
+ @m.should be_valid
28
+ end
29
+
30
+ specify "should take an :allow_missing option" do
31
+ @c.set_validations{validates_format(/.+_.+/, :value, :allow_missing=>true)}
32
+ @m.values.clear
33
+ @m.should be_valid
34
+ @m.value = nil
35
+ @m.should_not be_valid
36
+ @m.value = '1_1'
37
+ @m.should be_valid
38
+ end
39
+
40
+ specify "should take an :allow_nil option" do
41
+ @c.set_validations{validates_format(/.+_.+/, :value, :allow_nil=>true)}
42
+ @m.value = 'abc_'
43
+ @m.should_not be_valid
44
+ @m.value = '1_1'
45
+ @m.should be_valid
46
+ @m.value = nil
47
+ @m.should be_valid
48
+ end
49
+
50
+ specify "should take a :message option" do
51
+ @c.set_validations{validates_format(/.+_.+/, :value, :message=>"is so blah")}
52
+ @m.value = 'abc_'
53
+ @m.should_not be_valid
54
+ @m.errors.full_messages.should == ['value is so blah']
55
+ @m.value = '1_1'
56
+ @m.should be_valid
57
+ end
58
+
59
+ specify "should allow a proc for the :message option" do
60
+ @c.set_validations{validates_format(/.+_.+/, :value, :message=>proc{|f| "doesn't match #{f.inspect}"})}
61
+ @m.value = 'abc_'
62
+ @m.should_not be_valid
63
+ @m.errors.should == {:value=>["doesn't match /.+_.+/"]}
64
+ end
65
+
66
+ specify "should take multiple attributes in the same call" do
67
+ @c.columns :value, :value2
68
+ @c.set_validations{validates_presence([:value, :value2])}
69
+ @m.should_not be_valid
70
+ @m.value = 1
71
+ @m.should_not be_valid
72
+ @m.value2 = 1
73
+ @m.should be_valid
74
+ end
75
+
76
+ specify "should support modifying default options for all models" do
77
+ @c.set_validations{validates_presence(:value)}
78
+ @m.should_not be_valid
79
+ @m.errors.should == {:value=>['is not present']}
80
+ o = Sequel::Plugins::ValidationHelpers::DEFAULT_OPTIONS[:presence].dup
81
+ Sequel::Plugins::ValidationHelpers::DEFAULT_OPTIONS[:presence][:message] = lambda{"was not entered"}
82
+ @m.should_not be_valid
83
+ @m.errors.should == {:value=>["was not entered"]}
84
+ @m.value = 1
85
+ @m.should be_valid
86
+
87
+ @m.values.clear
88
+ Sequel::Plugins::ValidationHelpers::DEFAULT_OPTIONS[:presence][:allow_missing] = true
89
+ @m.should be_valid
90
+ @m.value = nil
91
+ @m.should_not be_valid
92
+ @m.errors.should == {:value=>["was not entered"]}
93
+
94
+
95
+ c = Class.new(Sequel::Model)
96
+ c.class_eval do
97
+ plugin :validation_helpers
98
+ set_columns([:value])
99
+ def validate
100
+ validates_presence(:value)
101
+ end
102
+ end
103
+ m = c.new(:value=>nil)
104
+ m.should_not be_valid
105
+ m.errors.should == {:value=>["was not entered"]}
106
+ Sequel::Plugins::ValidationHelpers::DEFAULT_OPTIONS[:presence] = o
107
+ end
108
+
109
+ specify "should support modifying default validation options for a particular model" do
110
+ @c.set_validations{validates_presence(:value)}
111
+ @m.should_not be_valid
112
+ @m.errors.should == {:value=>['is not present']}
113
+ @c.class_eval do
114
+ def default_validation_helpers_options(type)
115
+ {:allow_missing=>true, :message=>proc{'was not entered'}}
116
+ end
117
+ end
118
+ @m.value = nil
119
+ @m.should_not be_valid
120
+ @m.errors.should == {:value=>["was not entered"]}
121
+ @m.value = 1
122
+ @m.should be_valid
123
+
124
+ @m.values.clear
125
+ @m.should be_valid
126
+
127
+ c = Class.new(Sequel::Model)
128
+ c.class_eval do
129
+ plugin :validation_helpers
130
+ attr_accessor :value
131
+ def validate
132
+ validates_presence(:value)
133
+ end
134
+ end
135
+ m = c.new
136
+ m.should_not be_valid
137
+ m.errors.should == {:value=>['is not present']}
138
+ end
139
+
140
+ specify "should support validates_exact_length" do
141
+ @c.set_validations{validates_exact_length(3, :value)}
142
+ @m.should_not be_valid
143
+ @m.value = '123'
144
+ @m.should be_valid
145
+ @m.value = '12'
146
+ @m.should_not be_valid
147
+ @m.value = '1234'
148
+ @m.should_not be_valid
149
+ end
150
+
151
+ specify "should support validate_format" do
152
+ @c.set_validations{validates_format(/.+_.+/, :value)}
153
+ @m.value = 'abc_'
154
+ @m.should_not be_valid
155
+ @m.value = 'abc_def'
156
+ @m.should be_valid
157
+ end
158
+
159
+ specify "should support validates_includes with an array" do
160
+ @c.set_validations{validates_includes([1,2], :value)}
161
+ @m.should_not be_valid
162
+ @m.value = 1
163
+ @m.should be_valid
164
+ @m.value = 1.5
165
+ @m.should_not be_valid
166
+ @m.value = 2
167
+ @m.should be_valid
168
+ @m.value = 3
169
+ @m.should_not be_valid
170
+ end
171
+
172
+ specify "should support validates_includes with a range" do
173
+ @c.set_validations{validates_includes(1..4, :value)}
174
+ @m.should_not be_valid
175
+ @m.value = 1
176
+ @m.should be_valid
177
+ @m.value = 1.5
178
+ @m.should be_valid
179
+ @m.value = 0
180
+ @m.should_not be_valid
181
+ @m.value = 5
182
+ @m.should_not be_valid
183
+ end
184
+
185
+ specify "should supports validates_integer" do
186
+ @c.set_validations{validates_integer(:value)}
187
+ @m.value = 'blah'
188
+ @m.should_not be_valid
189
+ @m.value = '123'
190
+ @m.should be_valid
191
+ @m.value = '123.1231'
192
+ @m.should_not be_valid
193
+ end
194
+
195
+ specify "should support validates_length_range" do
196
+ @c.set_validations{validates_length_range(2..5, :value)}
197
+ @m.should_not be_valid
198
+ @m.value = '12345'
199
+ @m.should be_valid
200
+ @m.value = '1'
201
+ @m.should_not be_valid
202
+ @m.value = '123456'
203
+ @m.should_not be_valid
204
+ end
205
+
206
+ specify "should support validates_max_length" do
207
+ @c.set_validations{validates_max_length(5, :value)}
208
+ @m.should_not be_valid
209
+ @m.value = '12345'
210
+ @m.should be_valid
211
+ @m.value = '123456'
212
+ @m.should_not be_valid
213
+ end
214
+
215
+ specify "should support validates_min_length" do
216
+ @c.set_validations{validates_min_length(5, :value)}
217
+ @m.should_not be_valid
218
+ @m.value = '12345'
219
+ @m.should be_valid
220
+ @m.value = '1234'
221
+ @m.should_not be_valid
222
+ end
223
+
224
+ specify "should support validates_not_string" do
225
+ @c.set_validations{validates_not_string(:value)}
226
+ @m.value = 123
227
+ @m.should be_valid
228
+ @m.value = '123'
229
+ @m.should_not be_valid
230
+ @m.errors.full_messages.should == ['value is a string']
231
+ @m.meta_def(:db_schema){{:value=>{:type=>:integer}}}
232
+ @m.should_not be_valid
233
+ @m.errors.full_messages.should == ['value is not a valid integer']
234
+ end
235
+
236
+ specify "should support validates_numeric" do
237
+ @c.set_validations{validates_numeric(:value)}
238
+ @m.value = 'blah'
239
+ @m.should_not be_valid
240
+ @m.value = '123'
241
+ @m.should be_valid
242
+ @m.value = '123.1231'
243
+ @m.should be_valid
244
+ @m.value = '+1'
245
+ @m.should be_valid
246
+ @m.value = '-1'
247
+ @m.should be_valid
248
+ @m.value = '+1.123'
249
+ @m.should be_valid
250
+ @m.value = '-0.123'
251
+ @m.should be_valid
252
+ @m.value = '-0.123E10'
253
+ @m.should be_valid
254
+ @m.value = '32.123e10'
255
+ @m.should be_valid
256
+ @m.value = '+32.123E10'
257
+ @m.should be_valid
258
+ @m.should be_valid
259
+ @m.value = '.0123'
260
+ end
261
+
262
+ specify "should support validates_type" do
263
+ @c.set_validations{validates_type(Integer, :value)}
264
+ @m.value = 123
265
+ @m.should be_valid
266
+ @m.value = '123'
267
+ @m.should_not be_valid
268
+ @m.errors.full_messages.should == ['value is not a Integer']
269
+
270
+ @c.set_validations{validates_type(:String, :value)}
271
+ @m.value = '123'
272
+ @m.should be_valid
273
+ @m.value = 123
274
+ @m.should_not be_valid
275
+ @m.errors.full_messages.should == ['value is not a String']
276
+
277
+ @c.set_validations{validates_type('Integer', :value)}
278
+ @m.value = 123
279
+ @m.should be_valid
280
+ @m.value = 123.05
281
+ @m.should_not be_valid
282
+ @m.errors.full_messages.should == ['value is not a Integer']
283
+ end
284
+
285
+ specify "should support validates_presence" do
286
+ @c.set_validations{validates_presence(:value)}
287
+ @m.should_not be_valid
288
+ @m.value = ''
289
+ @m.should_not be_valid
290
+ @m.value = 1234
291
+ @m.should be_valid
292
+ @m.value = nil
293
+ @m.should_not be_valid
294
+ @m.value = true
295
+ @m.should be_valid
296
+ @m.value = false
297
+ @m.should be_valid
298
+ @m.value = Time.now
299
+ @m.should be_valid
300
+ end
301
+
302
+ it "should support validates_unique with a single attribute" do
303
+ @c.columns(:id, :username, :password)
304
+ @c.set_dataset MODEL_DB[:items]
305
+ @c.set_validations{validates_unique(:username)}
306
+ @c.dataset.extend(Module.new {
307
+ def fetch_rows(sql)
308
+ @db << sql
309
+
310
+ case sql
311
+ when /COUNT.*username = '0records'/
312
+ yield({:v => 0})
313
+ when /COUNT.*username = '1record'/
314
+ yield({:v => 1})
315
+ end
316
+ end
317
+ })
318
+
319
+ @user = @c.new(:username => "0records", :password => "anothertest")
320
+ @user.should be_valid
321
+ @user = @c.load(:id=>3, :username => "0records", :password => "anothertest")
322
+ @user.should be_valid
323
+
324
+ @user = @c.new(:username => "1record", :password => "anothertest")
325
+ @user.should_not be_valid
326
+ @user.errors.full_messages.should == ['username is already taken']
327
+ @user = @c.load(:id=>4, :username => "1record", :password => "anothertest")
328
+ @user.should_not be_valid
329
+ @user.errors.full_messages.should == ['username is already taken']
330
+
331
+ ds1 = @c.dataset.filter([[:username, '0records']])
332
+ ds2 = ds1.exclude(:id=>1)
333
+ @c.dataset.should_receive(:filter).with([[:username, '0records']]).twice.and_return(ds1)
334
+ ds1.should_receive(:exclude).with(:id=>1).once.and_return(ds2)
335
+
336
+ @user = @c.load(:id=>1, :username => "0records", :password => "anothertest")
337
+ @user.should be_valid
338
+ MODEL_DB.sqls.last.should == "SELECT COUNT(*) AS count FROM items WHERE ((username = '0records') AND (id != 1)) LIMIT 1"
339
+ @user = @c.new(:username => "0records", :password => "anothertest")
340
+ @user.should be_valid
341
+ MODEL_DB.sqls.last.should == "SELECT COUNT(*) AS count FROM items WHERE (username = '0records') LIMIT 1"
342
+ end
343
+
344
+ it "should support validates_unique with multiple attributes" do
345
+ @c.columns(:id, :username, :password)
346
+ @c.set_dataset MODEL_DB[:items]
347
+ @c.set_validations{validates_unique([:username, :password])}
348
+ @c.dataset.extend(Module.new {
349
+ def fetch_rows(sql)
350
+ @db << sql
351
+
352
+ case sql
353
+ when /COUNT.*username = '0records'/
354
+ yield({:v => 0})
355
+ when /COUNT.*username = '1record'/
356
+ yield({:v => 1})
357
+ end
358
+ end
359
+ })
360
+
361
+ @user = @c.new(:username => "0records", :password => "anothertest")
362
+ @user.should be_valid
363
+ @user = @c.load(:id=>3, :username => "0records", :password => "anothertest")
364
+ @user.should be_valid
365
+
366
+ @user = @c.new(:username => "1record", :password => "anothertest")
367
+ @user.should_not be_valid
368
+ @user.errors.full_messages.should == ['username and password is already taken']
369
+ @user = @c.load(:id=>4, :username => "1record", :password => "anothertest")
370
+ @user.should_not be_valid
371
+ @user.errors.full_messages.should == ['username and password is already taken']
372
+
373
+ ds1 = @c.dataset.filter([[:username, '0records'], [:password, 'anothertest']])
374
+ ds2 = ds1.exclude(:id=>1)
375
+ @c.dataset.should_receive(:filter).with([[:username, '0records'], [:password, 'anothertest']]).twice.and_return(ds1)
376
+ ds1.should_receive(:exclude).with(:id=>1).once.and_return(ds2)
377
+
378
+ @user = @c.load(:id=>1, :username => "0records", :password => "anothertest")
379
+ @user.should be_valid
380
+ MODEL_DB.sqls.last.should == "SELECT COUNT(*) AS count FROM items WHERE ((username = '0records') AND (password = 'anothertest') AND (id != 1)) LIMIT 1"
381
+ @user = @c.new(:username => "0records", :password => "anothertest")
382
+ @user.should be_valid
383
+ MODEL_DB.sqls.last.should == "SELECT COUNT(*) AS count FROM items WHERE ((username = '0records') AND (password = 'anothertest')) LIMIT 1"
384
+ end
385
+
386
+ it "should support validates_unique with a block" do
387
+ @c.columns(:id, :username, :password)
388
+ @c.set_dataset MODEL_DB[:items]
389
+ @c.set_validations{validates_unique(:username){|ds| ds.filter(:active)}}
390
+ @c.dataset.extend(Module.new {
391
+ def fetch_rows (sql)
392
+ @db << sql
393
+ yield({:v => 0})
394
+ end
395
+ })
396
+
397
+ MODEL_DB.reset
398
+ @c.new(:username => "0records", :password => "anothertest").should be_valid
399
+ @c.load(:id=>3, :username => "0records", :password => "anothertest").should be_valid
400
+ MODEL_DB.sqls.should == ["SELECT COUNT(*) AS count FROM items WHERE ((username = '0records') AND active) LIMIT 1",
401
+ "SELECT COUNT(*) AS count FROM items WHERE ((username = '0records') AND active AND (id != 3)) LIMIT 1"]
402
+ end
403
+
404
+ it "should support :only_if_modified option for validates_unique, and not check uniqueness for existing records if values haven't changed" do
405
+ @c.columns(:id, :username, :password)
406
+ @c.set_dataset MODEL_DB[:items]
407
+ @c.set_validations{validates_unique([:username, :password], :only_if_modified=>true)}
408
+
409
+ @c.dataset.extend(Module.new {
410
+ def fetch_rows (sql)
411
+ @db << sql
412
+ yield({:v => 0})
413
+ end
414
+ })
415
+
416
+ MODEL_DB.reset
417
+ @c.new(:username => "0records", :password => "anothertest").should be_valid
418
+ MODEL_DB.sqls.should == ["SELECT COUNT(*) AS count FROM items WHERE ((username = '0records') AND (password = 'anothertest')) LIMIT 1"]
419
+ MODEL_DB.reset
420
+ m = @c.load(:id=>3, :username => "0records", :password => "anothertest")
421
+ m.should be_valid
422
+ MODEL_DB.sqls.should == []
423
+
424
+ m.username = '1'
425
+ m.should be_valid
426
+ MODEL_DB.sqls.should == ["SELECT COUNT(*) AS count FROM items WHERE ((username = '1') AND (password = 'anothertest') AND (id != 3)) LIMIT 1"]
427
+
428
+ m = @c.load(:id=>3, :username => "0records", :password => "anothertest")
429
+ MODEL_DB.reset
430
+ m.password = '1'
431
+ m.should be_valid
432
+ MODEL_DB.sqls.should == ["SELECT COUNT(*) AS count FROM items WHERE ((username = '0records') AND (password = '1') AND (id != 3)) LIMIT 1"]
433
+ MODEL_DB.reset
434
+ m.username = '2'
435
+ m.should be_valid
436
+ MODEL_DB.sqls.should == ["SELECT COUNT(*) AS count FROM items WHERE ((username = '2') AND (password = '1') AND (id != 3)) LIMIT 1"]
437
+ end
438
+ end
@@ -0,0 +1,281 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper.rb')
2
+
3
+ shared_examples_for "regular and composite key associations" do
4
+ specify "should return no objects if none are associated" do
5
+ @album.artist.should == nil
6
+ @artist.albums.should == []
7
+ @album.tags.should == []
8
+ @tag.albums.should == []
9
+ end
10
+
11
+ specify "should have add and set methods work any associated objects" do
12
+ @album.update(:artist => @artist)
13
+ @album.add_tag(@tag)
14
+
15
+ @album.reload
16
+ @artist.reload
17
+ @tag.reload
18
+
19
+ @album.artist.should == @artist
20
+ @artist.albums.should == [@album]
21
+ @album.tags.should == [@tag]
22
+ @tag.albums.should == [@album]
23
+ end
24
+
25
+ specify "should have remove methods work" do
26
+ @album.update(:artist => @artist)
27
+ @album.add_tag(@tag)
28
+
29
+ @album.update(:artist => nil)
30
+ @album.remove_tag(@tag)
31
+
32
+ @album.reload
33
+ @artist.reload
34
+ @tag.reload
35
+
36
+ @album.artist.should == nil
37
+ @artist.albums.should == []
38
+ @album.tags.should == []
39
+ @tag.albums.should == []
40
+ end
41
+
42
+ specify "should have remove_all methods work" do
43
+ @artist.add_album(@album)
44
+ @album.add_tag(@tag)
45
+
46
+ @artist.remove_all_albums
47
+ @album.remove_all_tags
48
+
49
+ @album.reload
50
+ @artist.reload
51
+ @tag.reload
52
+
53
+ @album.artist.should == nil
54
+ @artist.albums.should == []
55
+ @album.tags.should == []
56
+ @tag.albums.should == []
57
+ end
58
+
59
+ specify "should eager load via eager correctly" do
60
+ @album.update(:artist => @artist)
61
+ @album.add_tag(@tag)
62
+
63
+ a = Artist.eager(:albums=>:tags).all
64
+ a.should == [@artist]
65
+ a.first.albums.should == [@album]
66
+ a.first.albums.first.tags.should == [@tag]
67
+
68
+ a = Tag.eager(:albums=>:artist).all
69
+ a.should == [@tag]
70
+ a.first.albums.should == [@album]
71
+ a.first.albums.first.artist.should == @artist
72
+ end
73
+
74
+ specify "should eager load via eager_graph correctly" do
75
+ @album.update(:artist => @artist)
76
+ @album.add_tag(@tag)
77
+
78
+ a = Artist.eager_graph(:albums=>:tags).all
79
+ a.should == [@artist]
80
+ a.first.albums.should == [@album]
81
+ a.first.albums.first.tags.should == [@tag]
82
+
83
+ a = Tag.eager_graph(:albums=>:artist).all
84
+ a.should == [@tag]
85
+ a.first.albums.should == [@album]
86
+ a.first.albums.first.artist.should == @artist
87
+ end
88
+
89
+ specify "should work with a many_through_many association" do
90
+ @album.update(:artist => @artist)
91
+ @album.add_tag(@tag)
92
+
93
+ @album.reload
94
+ @artist.reload
95
+ @tag.reload
96
+
97
+ @album.tags.should == [@tag]
98
+
99
+ a = Artist.eager(:tags).all
100
+ a.should == [@artist]
101
+ a.first.tags.should == [@tag]
102
+
103
+ a = Artist.eager_graph(:tags).all
104
+ a.should == [@artist]
105
+ a.first.tags.should == [@tag]
106
+
107
+ a = Album.eager(:artist=>:tags).all
108
+ a.should == [@album]
109
+ a.first.artist.should == @artist
110
+ a.first.artist.tags.should == [@tag]
111
+
112
+ a = Album.eager_graph(:artist=>:tags).all
113
+ a.should == [@album]
114
+ a.first.artist.should == @artist
115
+ a.first.artist.tags.should == [@tag]
116
+ end
117
+ end
118
+
119
+ describe "Sequel::Model Simple Associations" do
120
+ before do
121
+ @db = INTEGRATION_DB
122
+ @db.create_table!(:artists) do
123
+ primary_key :id
124
+ String :name
125
+ end
126
+ @db.create_table!(:albums) do
127
+ primary_key :id
128
+ String :name
129
+ foreign_key :artist_id, :artists
130
+ end
131
+ @db.create_table!(:tags) do
132
+ primary_key :id
133
+ String :name
134
+ end
135
+ @db.create_table!(:albums_tags) do
136
+ foreign_key :album_id, :albums
137
+ foreign_key :tag_id, :tags
138
+ end
139
+ class ::Artist < Sequel::Model(@db)
140
+ one_to_many :albums
141
+ plugin :many_through_many
142
+ Artist.many_through_many :tags, [[:albums, :artist_id, :id], [:albums_tags, :album_id, :tag_id]]
143
+ end
144
+ class ::Album < Sequel::Model(@db)
145
+ many_to_one :artist
146
+ many_to_many :tags
147
+ end
148
+ class ::Tag < Sequel::Model(@db)
149
+ many_to_many :albums
150
+ end
151
+ @album = Album.create(:name=>'Al')
152
+ @artist = Artist.create(:name=>'Ar')
153
+ @tag = Tag.create(:name=>'T')
154
+ end
155
+ after do
156
+ @db.drop_table(:albums_tags, :tags, :albums, :artists)
157
+ [:Tag, :Album, :Artist].each{|x| Object.send(:remove_const, x)}
158
+ end
159
+
160
+ it_should_behave_like "regular and composite key associations"
161
+
162
+ specify "should have add method accept hashes and create new records" do
163
+ @artist.remove_all_albums
164
+ Album.delete
165
+ @album = @artist.add_album(:name=>'Al2')
166
+ Album.first[:name].should == 'Al2'
167
+ @artist.albums_dataset.first[:name].should == 'Al2'
168
+
169
+ @album.remove_all_tags
170
+ Tag.delete
171
+ @album.add_tag(:name=>'T2')
172
+ Tag.first[:name].should == 'T2'
173
+ @album.tags_dataset.first[:name].should == 'T2'
174
+ end
175
+
176
+ specify "should have remove method accept primary key and remove related album" do
177
+ @artist.add_album(@album)
178
+ @artist.reload.remove_album(@album.id)
179
+ @artist.reload.albums.should == []
180
+
181
+ @album.add_tag(@tag)
182
+ @album.reload.remove_tag(@tag.id)
183
+ @tag.reload.albums.should == []
184
+ end
185
+
186
+ specify "should have remove method raise an error for one_to_many records if the object isn't already associated" do
187
+ proc{@artist.remove_album(@album.id)}.should raise_error(Sequel::Error)
188
+ proc{@artist.remove_album(@album)}.should raise_error(Sequel::Error)
189
+ end
190
+ end
191
+
192
+ describe "Sequel::Model Composite Key Associations" do
193
+ before do
194
+ @db = INTEGRATION_DB
195
+ @db.create_table!(:artists) do
196
+ Integer :id1
197
+ Integer :id2
198
+ String :name
199
+ primary_key [:id1, :id2]
200
+ end
201
+ @db.create_table!(:albums) do
202
+ Integer :id1
203
+ Integer :id2
204
+ String :name
205
+ Integer :artist_id1
206
+ Integer :artist_id2
207
+ foreign_key [:artist_id1, :artist_id2], :artists
208
+ primary_key [:id1, :id2]
209
+ end
210
+ @db.create_table!(:tags) do
211
+ Integer :id1
212
+ Integer :id2
213
+ String :name
214
+ primary_key [:id1, :id2]
215
+ end
216
+ @db.create_table!(:albums_tags) do
217
+ Integer :album_id1
218
+ Integer :album_id2
219
+ Integer :tag_id1
220
+ Integer :tag_id2
221
+ foreign_key [:album_id1, :album_id2], :albums
222
+ foreign_key [:tag_id1, :tag_id2], :tags
223
+ end
224
+ class ::Artist < Sequel::Model(@db)
225
+ set_primary_key :id1, :id2
226
+ unrestrict_primary_key
227
+ one_to_many :albums, :key=>[:artist_id1, :artist_id2]
228
+ plugin :many_through_many
229
+ Artist.many_through_many :tags, [[:albums, [:artist_id1, :artist_id2], [:id1, :id2]], [:albums_tags, [:album_id1, :album_id2], [:tag_id1, :tag_id2]]]
230
+ end
231
+ class ::Album < Sequel::Model(@db)
232
+ set_primary_key :id1, :id2
233
+ unrestrict_primary_key
234
+ many_to_one :artist, :key=>[:artist_id1, :artist_id2]
235
+ many_to_many :tags, :left_key=>[:album_id1, :album_id2], :right_key=>[:tag_id1, :tag_id2]
236
+ end
237
+ class ::Tag < Sequel::Model(@db)
238
+ set_primary_key :id1, :id2
239
+ unrestrict_primary_key
240
+ many_to_many :albums, :right_key=>[:album_id1, :album_id2], :left_key=>[:tag_id1, :tag_id2]
241
+ end
242
+ @album = Album.create(:name=>'Al', :id1=>1, :id2=>2)
243
+ @artist = Artist.create(:name=>'Ar', :id1=>3, :id2=>4)
244
+ @tag = Tag.create(:name=>'T', :id1=>5, :id2=>6)
245
+ end
246
+ after do
247
+ @db.drop_table(:albums_tags, :tags, :albums, :artists)
248
+ [:Tag, :Album, :Artist].each{|x| Object.send(:remove_const, x)}
249
+ end
250
+
251
+ it_should_behave_like "regular and composite key associations"
252
+
253
+ specify "should have add method accept hashes and create new records" do
254
+ @artist.remove_all_albums
255
+ Album.delete
256
+ @artist.add_album(:id1=>1, :id2=>2, :name=>'Al2')
257
+ Album.first[:name].should == 'Al2'
258
+ @artist.albums_dataset.first[:name].should == 'Al2'
259
+
260
+ @album.remove_all_tags
261
+ Tag.delete
262
+ @album.add_tag(:id1=>1, :id2=>2, :name=>'T2')
263
+ Tag.first[:name].should == 'T2'
264
+ @album.tags_dataset.first[:name].should == 'T2'
265
+ end
266
+
267
+ specify "should have remove method accept primary key and remove related album" do
268
+ @artist.add_album(@album)
269
+ @artist.reload.remove_album([@album.id1, @album.id2])
270
+ @artist.reload.albums.should == []
271
+
272
+ @album.add_tag(@tag)
273
+ @album.reload.remove_tag([@tag.id1, @tag.id2])
274
+ @tag.reload.albums.should == []
275
+ end
276
+
277
+ specify "should have remove method raise an error for one_to_many records if the object isn't already associated" do
278
+ proc{@artist.remove_album([@album.id1, @album.id2])}.should raise_error(Sequel::Error)
279
+ proc{@artist.remove_album(@album)}.should raise_error(Sequel::Error)
280
+ end
281
+ end