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,240 @@
1
+ require File.join(File.dirname(__FILE__), "spec_helper")
2
+
3
+ describe "Model#after_initialize" do
4
+ specify "should be called after initialization" do
5
+ $values1 = nil
6
+ $reached_after_initialized = false
7
+
8
+ a = Class.new(Sequel::Model)
9
+ a.class_eval do
10
+ columns :x, :y
11
+ def after_initialize
12
+ $values1 = @values.clone
13
+ $reached_after_initialized = true
14
+ end
15
+ end
16
+
17
+ a.new(:x => 1, :y => 2)
18
+ $values1.should == {:x => 1, :y => 2}
19
+ $reached_after_initialized.should == true
20
+ end
21
+ end
22
+
23
+ describe "Model#before_create && Model#after_create" do
24
+ before do
25
+ MODEL_DB.reset
26
+
27
+ @c = Class.new(Sequel::Model(:items))
28
+ @c.class_eval do
29
+ columns :x
30
+ no_primary_key
31
+
32
+ def after_create
33
+ MODEL_DB << "BLAH after"
34
+ end
35
+ end
36
+ end
37
+
38
+ specify "should be called around new record creation" do
39
+ @c.send(:define_method, :before_create){MODEL_DB << "BLAH before"}
40
+ @c.create(:x => 2)
41
+ MODEL_DB.sqls.should == [
42
+ 'BLAH before',
43
+ 'INSERT INTO items (x) VALUES (2)',
44
+ 'BLAH after'
45
+ ]
46
+ end
47
+
48
+ specify ".create should cancel the save and raise an error if before_create returns false and raise_on_save_failure is true" do
49
+ @c.send(:define_method, :before_create){false}
50
+ proc{@c.load(:id => 2233).save}.should_not raise_error(Sequel::ValidationFailed)
51
+ proc{@c.create(:x => 2)}.should raise_error(Sequel::BeforeHookFailed)
52
+ MODEL_DB.sqls.should == []
53
+ end
54
+
55
+ specify ".create should cancel the save and return nil if before_create returns false and raise_on_save_failure is false" do
56
+ @c.send(:define_method, :before_create){false}
57
+ @c.raise_on_save_failure = false
58
+ @c.create(:x => 2).should == nil
59
+ MODEL_DB.sqls.should == []
60
+ end
61
+ end
62
+
63
+ describe "Model#before_update && Model#after_update" do
64
+ before do
65
+ MODEL_DB.reset
66
+
67
+ @c = Class.new(Sequel::Model(:items))
68
+ @c.class_eval do
69
+ columns :id, :x
70
+ def after_update; MODEL_DB << "BLAH after" end
71
+ end
72
+ end
73
+
74
+ specify "should be called around record update" do
75
+ @c.send(:define_method, :before_update){MODEL_DB << "BLAH before"}
76
+ m = @c.load(:id => 2233, :x=>123)
77
+ m.save
78
+ MODEL_DB.sqls.should == [
79
+ 'BLAH before',
80
+ 'UPDATE items SET x = 123 WHERE (id = 2233)',
81
+ 'BLAH after'
82
+ ]
83
+ end
84
+
85
+ specify "#save should cancel the save and raise an error if before_update returns false and raise_on_save_failure is true" do
86
+ @c.send(:define_method, :before_update){false}
87
+ proc{@c.load(:id => 2233).save}.should_not raise_error(Sequel::ValidationFailed)
88
+ proc{@c.load(:id => 2233).save}.should raise_error(Sequel::BeforeHookFailed)
89
+ MODEL_DB.sqls.should == []
90
+ end
91
+
92
+ specify "#save should cancel the save and return nil if before_update returns false and raise_on_save_failure is false" do
93
+ @c.send(:define_method, :before_update){false}
94
+ @c.raise_on_save_failure = false
95
+ @c.load(:id => 2233).save.should == nil
96
+ MODEL_DB.sqls.should == []
97
+ end
98
+ end
99
+
100
+ describe "Model#before_save && Model#after_save" do
101
+ before do
102
+ MODEL_DB.reset
103
+
104
+ @c = Class.new(Sequel::Model(:items))
105
+ @c.class_eval do
106
+ columns :x
107
+ def after_save; MODEL_DB << "BLAH after" end
108
+ end
109
+ end
110
+
111
+ specify "should be called around record update" do
112
+ @c.send(:define_method, :before_save){MODEL_DB << "BLAH before"}
113
+ m = @c.load(:id => 2233, :x=>123)
114
+ m.save
115
+ MODEL_DB.sqls.should == [
116
+ 'BLAH before',
117
+ 'UPDATE items SET x = 123 WHERE (id = 2233)',
118
+ 'BLAH after'
119
+ ]
120
+ end
121
+
122
+ specify "should be called around record creation" do
123
+ @c.send(:define_method, :before_save){MODEL_DB << "BLAH before"}
124
+ @c.no_primary_key
125
+ @c.create(:x => 2)
126
+ MODEL_DB.sqls.should == [
127
+ 'BLAH before',
128
+ 'INSERT INTO items (x) VALUES (2)',
129
+ 'BLAH after'
130
+ ]
131
+ end
132
+
133
+ specify "#save should cancel the save and raise an error if before_save returns false and raise_on_save_failure is true" do
134
+ @c.send(:define_method, :before_save){false}
135
+ proc{@c.load(:id => 2233).save}.should_not raise_error(Sequel::ValidationFailed)
136
+ proc{@c.load(:id => 2233).save}.should raise_error(Sequel::BeforeHookFailed)
137
+ MODEL_DB.sqls.should == []
138
+ end
139
+
140
+ specify "#save should cancel the save and return nil if before_save returns false and raise_on_save_failure is false" do
141
+ @c.send(:define_method, :before_save){false}
142
+ @c.raise_on_save_failure = false
143
+ @c.load(:id => 2233).save.should == nil
144
+ MODEL_DB.sqls.should == []
145
+ end
146
+ end
147
+
148
+ describe "Model#before_destroy && Model#after_destroy" do
149
+ before do
150
+ MODEL_DB.reset
151
+
152
+ @c = Class.new(Sequel::Model(:items))
153
+ @c.class_eval do
154
+ def after_destroy; MODEL_DB << "BLAH after"; end
155
+
156
+ def delete
157
+ MODEL_DB << "DELETE BLAH"
158
+ end
159
+ end
160
+ end
161
+
162
+ specify "should be called around record destruction" do
163
+ @c.send(:define_method, :before_destroy){MODEL_DB << "BLAH before"}
164
+ m = @c.load(:id => 2233)
165
+ m.destroy
166
+ MODEL_DB.sqls.should == [
167
+ 'BLAH before',
168
+ 'DELETE BLAH',
169
+ 'BLAH after'
170
+ ]
171
+ end
172
+
173
+ specify "#destroy should cancel the destroy and raise an error if before_destroy returns false and raise_on_save_failure is true" do
174
+ @c.send(:define_method, :before_destroy){false}
175
+ proc{@c.load(:id => 2233).destroy}.should raise_error(Sequel::BeforeHookFailed)
176
+ MODEL_DB.sqls.should == []
177
+ end
178
+
179
+ specify "#destroy should cancel the destroy and return nil if before_destroy returns false and raise_on_save_failure is false" do
180
+ @c.send(:define_method, :before_destroy){false}
181
+ @c.raise_on_save_failure = false
182
+ @c.load(:id => 2233).destroy.should == nil
183
+ MODEL_DB.sqls.should == []
184
+ end
185
+ end
186
+
187
+ describe "Model#before_validation && Model#after_validation" do
188
+ before do
189
+ MODEL_DB.reset
190
+
191
+ @c = Class.new(Sequel::Model(:items))
192
+ @c.class_eval do
193
+ def after_validation; MODEL_DB << "BLAH after" end
194
+
195
+ def validate
196
+ errors.add(:id, 'not valid') unless id == 2233
197
+ end
198
+ columns :id
199
+ end
200
+ end
201
+
202
+ specify "should be called around validation" do
203
+ @c.send(:define_method, :before_validation){MODEL_DB << "BLAH before"}
204
+ m = @c.load(:id => 2233)
205
+ m.should be_valid
206
+ MODEL_DB.sqls.should == ['BLAH before', 'BLAH after']
207
+
208
+ MODEL_DB.sqls.clear
209
+ m = @c.load(:id => 22)
210
+ m.should_not be_valid
211
+ MODEL_DB.sqls.should == ['BLAH before', 'BLAH after']
212
+ end
213
+
214
+ specify "should be called when calling save" do
215
+ @c.send(:define_method, :before_validation){MODEL_DB << "BLAH before"}
216
+ m = @c.load(:id => 2233, :x=>123)
217
+ m.save.should == m
218
+ MODEL_DB.sqls.should == ['BLAH before', 'BLAH after', 'UPDATE items SET x = 123 WHERE (id = 2233)']
219
+
220
+ MODEL_DB.sqls.clear
221
+ m = @c.load(:id => 22)
222
+ m.raise_on_save_failure = false
223
+ m.save.should == nil
224
+ MODEL_DB.sqls.should == ['BLAH before', 'BLAH after']
225
+ end
226
+
227
+ specify "#save should cancel the save and raise an error if before_validation returns false and raise_on_save_failure is true" do
228
+ @c.send(:define_method, :before_validation){false}
229
+ proc{@c.load(:id => 2233).save}.should_not raise_error(Sequel::ValidationFailed)
230
+ proc{@c.load(:id => 2233).save}.should raise_error(Sequel::BeforeHookFailed)
231
+ MODEL_DB.sqls.should == []
232
+ end
233
+
234
+ specify "#save should cancel the save and return nil if before_validation returns false and raise_on_save_failure is false" do
235
+ @c.send(:define_method, :before_validation){false}
236
+ @c.raise_on_save_failure = false
237
+ @c.load(:id => 2233).save.should == nil
238
+ MODEL_DB.sqls.should == []
239
+ end
240
+ end
@@ -0,0 +1,26 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe Sequel::Inflections do
4
+ before do
5
+ @plurals, @singulars, @uncountables = Sequel.inflections.plurals.dup, Sequel.inflections.singulars.dup, Sequel.inflections.uncountables.dup
6
+ end
7
+ after do
8
+ Sequel.inflections.plurals.replace(@plurals)
9
+ Sequel.inflections.singulars.replace(@singulars)
10
+ Sequel.inflections.uncountables.replace(@uncountables)
11
+ end
12
+
13
+ it "should be possible to clear the list of singulars, plurals, and uncountables" do
14
+ Sequel.inflections.clear(:plurals)
15
+ Sequel.inflections.plurals.should == []
16
+ Sequel.inflections.plural('blah', 'blahs')
17
+ Sequel.inflections.clear
18
+ Sequel.inflections.plurals.should == []
19
+ Sequel.inflections.singulars.should == []
20
+ Sequel.inflections.uncountables.should == []
21
+ end
22
+
23
+ it "should be yielded and returned by Sequel.inflections" do
24
+ Sequel.inflections{|i| i.should == Sequel::Inflections}.should == Sequel::Inflections
25
+ end
26
+ end
@@ -0,0 +1,593 @@
1
+ require File.join(File.dirname(__FILE__), "spec_helper")
2
+
3
+ describe "Sequel::Model()" do
4
+ before do
5
+ @db = Sequel::Model.db
6
+ end
7
+
8
+ it "should return a model subclass with the given dataset if given a dataset" do
9
+ ds = @db[:blah]
10
+ c = Sequel::Model(ds)
11
+ c.superclass.should == Sequel::Model
12
+ c.dataset.should == ds
13
+ end
14
+
15
+ it "should return a model subclass with a dataset with the default database and given table name if given a symbol" do
16
+ c = Sequel::Model(:blah)
17
+ c.superclass.should == Sequel::Model
18
+ c.db.should == @db
19
+ c.table_name.should == :blah
20
+ end
21
+
22
+ it "should return a model subclass associated to the given database if given a database" do
23
+ db = Sequel::Database.new
24
+ c = Sequel::Model(db)
25
+ c.superclass.should == Sequel::Model
26
+ c.db.should == db
27
+ proc{c.dataset}.should raise_error(Sequel::Error)
28
+ class SmBlahTest < c
29
+ end
30
+ SmBlahTest.db.should == db
31
+ SmBlahTest.table_name.should == :sm_blah_tests
32
+ end
33
+ end
34
+
35
+ describe Sequel::Model do
36
+ it "should have class method aliased as model" do
37
+ Sequel::Model.instance_methods.collect{|x| x.to_s}.should include("model")
38
+
39
+ model_a = Class.new(Sequel::Model(:items))
40
+ model_a.new.model.should be(model_a)
41
+ end
42
+
43
+ it "should be associated with a dataset" do
44
+ model_a = Class.new(Sequel::Model) { set_dataset MODEL_DB[:as] }
45
+
46
+ model_a.dataset.should be_a_kind_of(MockDataset)
47
+ model_a.dataset.opts[:from].should == [:as]
48
+
49
+ model_b = Class.new(Sequel::Model) { set_dataset MODEL_DB[:bs] }
50
+
51
+ model_b.dataset.should be_a_kind_of(MockDataset)
52
+ model_b.dataset.opts[:from].should == [:bs]
53
+
54
+ model_a.dataset.opts[:from].should == [:as]
55
+ end
56
+
57
+ end
58
+
59
+ describe Sequel::Model, "dataset & schema" do
60
+ before do
61
+ @model = Class.new(Sequel::Model(:items))
62
+ end
63
+
64
+ it "creates dynamic model subclass with set table name" do
65
+ @model.table_name.should == :items
66
+ end
67
+
68
+ it "defaults to primary key of id" do
69
+ @model.primary_key.should == :id
70
+ end
71
+
72
+ it "allow primary key change" do
73
+ @model.set_primary_key :ssn
74
+ @model.primary_key.should == :ssn
75
+ end
76
+
77
+ it "allows dataset change" do
78
+ @model.set_dataset(MODEL_DB[:foo])
79
+ @model.table_name.should == :foo
80
+ end
81
+
82
+ it "set_dataset should take a symbol" do
83
+ @model.db = MODEL_DB
84
+ @model.set_dataset(:foo)
85
+ @model.table_name.should == :foo
86
+ end
87
+
88
+ it "table_name should respect table aliases" do
89
+ @model.set_dataset(:foo___x)
90
+ @model.table_name.should == :x
91
+ end
92
+
93
+ it "set_dataset should raise an error unless given a Symbol or Dataset" do
94
+ proc{@model.set_dataset(Object.new)}.should raise_error(Sequel::Error)
95
+ end
96
+
97
+ it "set_dataset should add the destroy method to the dataset" do
98
+ ds = MODEL_DB[:foo]
99
+ ds.should_not respond_to(:destroy)
100
+ @model.set_dataset(ds)
101
+ ds.should respond_to(:destroy)
102
+ end
103
+
104
+ it "should raise an error on set_dataset if there is an error connecting to the database" do
105
+ @model.meta_def(:columns){raise Sequel::DatabaseConnectionError}
106
+ proc{@model.set_dataset(MODEL_DB[:foo].join(:blah))}.should raise_error
107
+ end
108
+
109
+ it "should not raise an error if there is a problem getting the columns for a dataset" do
110
+ @model.meta_def(:columns){raise Sequel::Error}
111
+ proc{@model.set_dataset(MODEL_DB[:foo].join(:blah))}.should_not raise_error
112
+ end
113
+
114
+ it "doesn't raise an error on set_dataset if there is an error raised getting the schema" do
115
+ @model.meta_def(:get_db_schema){raise Sequel::Error}
116
+ proc{@model.set_dataset(MODEL_DB[:foo])}.should_not raise_error
117
+ end
118
+
119
+ it "doesn't raise an error on inherited if there is an error setting the dataset" do
120
+ @model.meta_def(:set_dataset){raise Sequel::Error}
121
+ proc{Class.new(@model)}.should_not raise_error
122
+ end
123
+ end
124
+
125
+ describe Sequel::Model, "constructor" do
126
+
127
+ before(:each) do
128
+ @m = Class.new(Sequel::Model)
129
+ @m.columns :a, :b
130
+ end
131
+
132
+ it "should accept a hash" do
133
+ m = @m.new(:a => 1, :b => 2)
134
+ m.values.should == {:a => 1, :b => 2}
135
+ m.should be_new
136
+ end
137
+
138
+ it "should accept a block and yield itself to the block" do
139
+ block_called = false
140
+ m = @m.new {|i| block_called = true; i.should be_a_kind_of(@m); i.values[:a] = 1}
141
+
142
+ block_called.should be_true
143
+ m.values[:a].should == 1
144
+ end
145
+
146
+ end
147
+
148
+ describe Sequel::Model, "new" do
149
+
150
+ before(:each) do
151
+ @m = Class.new(Sequel::Model) do
152
+ set_dataset MODEL_DB[:items]
153
+ columns :x, :id
154
+ end
155
+ end
156
+
157
+ it "should be marked as new?" do
158
+ o = @m.new
159
+ o.should be_new
160
+ end
161
+
162
+ it "should not be marked as new? once it is saved" do
163
+ o = @m.new(:x => 1)
164
+ o.should be_new
165
+ o.save
166
+ o.should_not be_new
167
+ end
168
+
169
+ it "should use the last inserted id as primary key if not in values" do
170
+ d = @m.dataset
171
+ def d.insert(*args)
172
+ super
173
+ 1234
174
+ end
175
+
176
+ def d.first
177
+ {:x => 1, :id => 1234}
178
+ end
179
+
180
+ o = @m.new(:x => 1)
181
+ o.save
182
+ o.id.should == 1234
183
+
184
+ o = @m.load(:x => 1, :id => 333)
185
+ o.save
186
+ o.id.should == 333
187
+ end
188
+
189
+ end
190
+
191
+ describe Sequel::Model, ".subset" do
192
+ before do
193
+ MODEL_DB.reset
194
+
195
+ @c = Class.new(Sequel::Model(:items))
196
+ end
197
+
198
+ specify "should create a filter on the underlying dataset" do
199
+ proc {@c.new_only}.should raise_error(NoMethodError)
200
+
201
+ @c.subset(:new_only) {:age.sql_number < 'new'}
202
+
203
+ @c.new_only.sql.should == "SELECT * FROM items WHERE (age < 'new')"
204
+ @c.dataset.new_only.sql.should == "SELECT * FROM items WHERE (age < 'new')"
205
+
206
+ @c.subset(:pricey) {:price.sql_number > 100}
207
+
208
+ @c.pricey.sql.should == "SELECT * FROM items WHERE (price > 100)"
209
+ @c.dataset.pricey.sql.should == "SELECT * FROM items WHERE (price > 100)"
210
+
211
+ @c.pricey.new_only.sql.should == "SELECT * FROM items WHERE ((price > 100) AND (age < 'new'))"
212
+ @c.new_only.pricey.sql.should == "SELECT * FROM items WHERE ((age < 'new') AND (price > 100))"
213
+ end
214
+
215
+ specify "should not override existing model methods" do
216
+ @c.meta_def(:active){true}
217
+ @c.subset(:active, :active)
218
+ @c.active.should == true
219
+ end
220
+ end
221
+
222
+ describe Sequel::Model, ".find" do
223
+
224
+ before(:each) do
225
+ MODEL_DB.reset
226
+
227
+ @c = Class.new(Sequel::Model(:items))
228
+
229
+ $cache_dataset_row = {:name => 'sharon', :id => 1}
230
+ @dataset = @c.dataset
231
+ $sqls = []
232
+ @dataset.extend(Module.new {
233
+ def fetch_rows(sql)
234
+ $sqls << sql
235
+ yield $cache_dataset_row
236
+ end
237
+ })
238
+ end
239
+
240
+ it "should return the first record matching the given filter" do
241
+ @c.find(:name => 'sharon').should be_a_kind_of(@c)
242
+ $sqls.last.should == "SELECT * FROM items WHERE (name = 'sharon') LIMIT 1"
243
+
244
+ @c.find(:name.like('abc%')).should be_a_kind_of(@c)
245
+ $sqls.last.should == "SELECT * FROM items WHERE (name LIKE 'abc%') LIMIT 1"
246
+ end
247
+
248
+ specify "should accept filter blocks" do
249
+ @c.find{:id.sql_number > 1}.should be_a_kind_of(@c)
250
+ $sqls.last.should == "SELECT * FROM items WHERE (id > 1) LIMIT 1"
251
+
252
+ @c.find {(:x.sql_number > 1) & (:y.sql_number < 2)}.should be_a_kind_of(@c)
253
+ $sqls.last.should == "SELECT * FROM items WHERE ((x > 1) AND (y < 2)) LIMIT 1"
254
+ end
255
+
256
+ end
257
+
258
+ describe Sequel::Model, ".fetch" do
259
+
260
+ before(:each) do
261
+ MODEL_DB.reset
262
+ @c = Class.new(Sequel::Model(:items))
263
+ end
264
+
265
+ it "should return instances of Model" do
266
+ @c.fetch("SELECT * FROM items").first.should be_a_kind_of(@c)
267
+ end
268
+
269
+ it "should return true for .empty? and not raise an error on empty selection" do
270
+ rows = @c.fetch("SELECT * FROM items WHERE FALSE")
271
+ @c.send(:define_method, :fetch_rows){|sql| yield({:count => 0})}
272
+ proc {rows.empty?}.should_not raise_error
273
+ end
274
+ end
275
+
276
+ describe Sequel::Model, ".find_or_create" do
277
+
278
+ before(:each) do
279
+ MODEL_DB.reset
280
+ @c = Class.new(Sequel::Model(:items)) do
281
+ no_primary_key
282
+ columns :x
283
+ end
284
+ end
285
+
286
+ it "should find the record" do
287
+ @c.find_or_create(:x => 1)
288
+ MODEL_DB.sqls.should == ["SELECT * FROM items WHERE (x = 1) LIMIT 1"]
289
+
290
+ MODEL_DB.reset
291
+ end
292
+
293
+ it "should create the record if not found" do
294
+ @c.meta_def(:find) do |*args|
295
+ dataset.filter(*args).first
296
+ nil
297
+ end
298
+
299
+ @c.find_or_create(:x => 1)
300
+ MODEL_DB.sqls.should == [
301
+ "SELECT * FROM items WHERE (x = 1) LIMIT 1",
302
+ "INSERT INTO items (x) VALUES (1)"
303
+ ]
304
+ end
305
+ end
306
+
307
+ describe Sequel::Model, ".all" do
308
+
309
+ before(:each) do
310
+ MODEL_DB.reset
311
+ @c = Class.new(Sequel::Model(:items)) do
312
+ no_primary_key
313
+ end
314
+
315
+ @c.dataset.meta_def(:all) {1234}
316
+ end
317
+
318
+ it "should return all records in the dataset" do
319
+ @c.all.should == 1234
320
+ end
321
+
322
+ end
323
+
324
+ class DummyModelBased < Sequel::Model(:blog)
325
+ end
326
+
327
+ describe Sequel::Model, "(:tablename)" do
328
+
329
+ it "should allow reopening of descendant classes" do
330
+ proc do
331
+ eval "class DummyModelBased < Sequel::Model(:blog); end"
332
+ end.should_not raise_error
333
+ end
334
+
335
+ end
336
+
337
+ describe Sequel::Model, "A model class without a primary key" do
338
+
339
+ before(:each) do
340
+ MODEL_DB.reset
341
+ @c = Class.new(Sequel::Model(:items)) do
342
+ columns :x
343
+ no_primary_key
344
+ end
345
+ end
346
+
347
+ it "should be able to insert records without selecting them back" do
348
+ i = nil
349
+ proc {i = @c.create(:x => 1)}.should_not raise_error
350
+ i.class.should be(@c)
351
+ i.values.to_hash.should == {:x => 1}
352
+
353
+ MODEL_DB.sqls.should == ['INSERT INTO items (x) VALUES (1)']
354
+ end
355
+
356
+ it "should raise when deleting" do
357
+ o = @c.new
358
+ proc {o.delete}.should raise_error
359
+ end
360
+
361
+ it "should insert a record when saving" do
362
+ o = @c.new(:x => 2)
363
+ o.should be_new
364
+ o.save
365
+ MODEL_DB.sqls.should == ['INSERT INTO items (x) VALUES (2)']
366
+ end
367
+
368
+ end
369
+
370
+ describe Sequel::Model, "attribute accessors" do
371
+ before do
372
+ MODEL_DB.reset
373
+ @dataset = Sequel::Dataset.new(MODEL_DB)
374
+ def @dataset.columns; [:x, :y]; end
375
+ @c = Class.new(Sequel::Model) do
376
+ def self.db_schema
377
+ set_columns(Array(@columns))
378
+ @db_schema = {:x=>{}, :y=>{}}
379
+ end
380
+ def self.set_dataset(ds, opts={})
381
+ @columns = ds.columns
382
+ db_schema
383
+ end
384
+ end
385
+ end
386
+
387
+ it "should be created on set_dataset" do
388
+ %w'x y x= y='.each do |x|
389
+ @c.instance_methods.collect{|y| y.to_s}.should_not include(x)
390
+ end
391
+ @c.set_dataset(@dataset)
392
+ %w'x y x= y='.each do |x|
393
+ @c.instance_methods.collect{|y| y.to_s}.should include(x)
394
+ end
395
+ o = @c.new
396
+ %w'x y x= y='.each do |x|
397
+ o.methods.collect{|y| y.to_s}.should include(x)
398
+ end
399
+
400
+ o.x.should be_nil
401
+ o.x = 34
402
+ o.x.should == 34
403
+ end
404
+
405
+ it "should be only accept one argument for the write accessor" do
406
+ @c.set_dataset(@dataset)
407
+ o = @c.new
408
+
409
+ o.x = 34
410
+ o.x.should == 34
411
+ proc{o.send(:x=)}.should raise_error
412
+ proc{o.send(:x=, 3, 4)}.should raise_error
413
+ end
414
+ end
415
+
416
+ describe Sequel::Model, ".[]" do
417
+
418
+ before(:each) do
419
+ MODEL_DB.reset
420
+
421
+ @c = Class.new(Sequel::Model(:items))
422
+
423
+ $cache_dataset_row = {:name => 'sharon', :id => 1}
424
+ @dataset = @c.dataset
425
+ $sqls = []
426
+ @dataset.extend(Module.new {
427
+ def fetch_rows(sql)
428
+ $sqls << sql
429
+ yield $cache_dataset_row
430
+ end
431
+ })
432
+ end
433
+
434
+ it "should return the first record for the given pk" do
435
+ @c[1].should be_a_kind_of(@c)
436
+ $sqls.last.should == "SELECT * FROM items WHERE (id = 1) LIMIT 1"
437
+ @c[9999].should be_a_kind_of(@c)
438
+ $sqls.last.should == "SELECT * FROM items WHERE (id = 9999) LIMIT 1"
439
+ end
440
+
441
+ it "should work correctly for custom primary key" do
442
+ @c.set_primary_key :name
443
+ @c['sharon'].should be_a_kind_of(@c)
444
+ $sqls.last.should == "SELECT * FROM items WHERE (name = 'sharon') LIMIT 1"
445
+ end
446
+
447
+ it "should work correctly for composite primary key specified as array" do
448
+ @c.set_primary_key [:node_id, :kind]
449
+ @c[3921, 201].should be_a_kind_of(@c)
450
+ $sqls.last.should =~ \
451
+ /^SELECT \* FROM items WHERE \((\(node_id = 3921\) AND \(kind = 201\))|(\(kind = 201\) AND \(node_id = 3921\))\) LIMIT 1$/
452
+ end
453
+
454
+ it "should work correctly for composite primary key specified as separate arguments" do
455
+ @c.set_primary_key :node_id, :kind
456
+ @c[3921, 201].should be_a_kind_of(@c)
457
+ $sqls.last.should =~ \
458
+ /^SELECT \* FROM items WHERE \((\(node_id = 3921\) AND \(kind = 201\))|(\(kind = 201\) AND \(node_id = 3921\))\) LIMIT 1$/
459
+ end
460
+ end
461
+
462
+ context "Model#inspect" do
463
+ before do
464
+ @o = Sequel::Model.load(:x => 333)
465
+ end
466
+
467
+ specify "should include the class name and the values" do
468
+ @o.inspect.should == '#<Sequel::Model @values={:x=>333}>'
469
+ end
470
+ end
471
+
472
+ context "Model.db_schema" do
473
+ before do
474
+ @c = Class.new(Sequel::Model(:items)) do
475
+ def self.columns; orig_columns; end
476
+ end
477
+ @dataset = Sequel::Dataset.new(nil).from(:items)
478
+ @dataset.meta_def(:db){@db ||= Sequel::Database.new}
479
+ def @dataset.naked; self; end
480
+ def @dataset.columns; []; end
481
+ def @dataset.def_mutation_method(*names); end
482
+ end
483
+
484
+ specify "should use the database's schema_for_table and set the columns and dataset columns" do
485
+ d = @dataset.db
486
+ def d.schema(table, opts = {})
487
+ [[:x, {:type=>:integer}], [:y, {:type=>:string}]]
488
+ end
489
+ @c.dataset = @dataset
490
+ @c.db_schema.should == {:x=>{:type=>:integer}, :y=>{:type=>:string}}
491
+ @c.columns.should == [:x, :y]
492
+ @c.dataset.instance_variable_get(:@columns).should == [:x, :y]
493
+ end
494
+
495
+ specify "should restrict the schema and columns for datasets with a :select option" do
496
+ ds = @dataset.select(:x, :y___z)
497
+ d = ds.db
498
+ def d.schema(table, opts = {})
499
+ [[:x, {:type=>:integer}], [:y, {:type=>:string}]]
500
+ end
501
+ def @c.columns; [:x, :z]; end
502
+ @c.dataset = ds
503
+ @c.db_schema.should == {:x=>{:type=>:integer}, :z=>{}}
504
+ end
505
+
506
+ specify "should not use schema if the dataset uses multiple tables or custom sql" do
507
+ ds = @dataset.join(:x, :id)
508
+ d = ds.db
509
+ e = false
510
+ d.meta_def(:schema){|table, *opts| e = true}
511
+ def @c.columns; [:x]; end
512
+ @c.dataset = ds
513
+ @c.db_schema.should == {:x=>{}}
514
+ e.should == false
515
+ end
516
+
517
+ specify "should fallback to fetching records if schema raises an error" do
518
+ ds = @dataset.join(:x, :id)
519
+ d = ds.db
520
+ def d.schema(table, opts={})
521
+ raise StandardError
522
+ end
523
+ def @c.columns; [:x]; end
524
+ @c.dataset = ds
525
+ @c.db_schema.should == {:x=>{}}
526
+ end
527
+
528
+ specify "should automatically set a singular primary key based on the schema" do
529
+ ds = @dataset
530
+ d = ds.db
531
+ d.meta_def(:schema){|table, *opts| [[:x, {:primary_key=>true}]]}
532
+ @c.primary_key.should == :id
533
+ @c.dataset = ds
534
+ @c.db_schema.should == {:x=>{:primary_key=>true}}
535
+ @c.primary_key.should == :x
536
+ end
537
+
538
+ specify "should automatically set the composite primary key based on the schema" do
539
+ ds = @dataset
540
+ d = ds.db
541
+ d.meta_def(:schema){|table, *opts| [[:x, {:primary_key=>true}], [:y, {:primary_key=>true}]]}
542
+ @c.primary_key.should == :id
543
+ @c.dataset = ds
544
+ @c.db_schema.should == {:x=>{:primary_key=>true}, :y=>{:primary_key=>true}}
545
+ @c.primary_key.should == [:x, :y]
546
+ end
547
+
548
+ specify "should automatically set no primary key based on the schema" do
549
+ ds = @dataset
550
+ d = ds.db
551
+ d.meta_def(:schema){|table, *opts| [[:x, {:primary_key=>false}], [:y, {:primary_key=>false}]]}
552
+ @c.primary_key.should == :id
553
+ @c.dataset = ds
554
+ @c.db_schema.should == {:x=>{:primary_key=>false}, :y=>{:primary_key=>false}}
555
+ @c.primary_key.should == nil
556
+ end
557
+
558
+ specify "should not modify the primary key unless all column schema hashes have a :primary_key entry" do
559
+ ds = @dataset
560
+ d = ds.db
561
+ d.meta_def(:schema){|table, *opts| [[:x, {:primary_key=>false}], [:y, {}]]}
562
+ @c.primary_key.should == :id
563
+ @c.dataset = ds
564
+ @c.db_schema.should == {:x=>{:primary_key=>false}, :y=>{}}
565
+ @c.primary_key.should == :id
566
+ end
567
+ end
568
+
569
+ context "Model#use_transactions" do
570
+ before do
571
+ @c = Class.new(Sequel::Model(:items))
572
+ end
573
+
574
+ specify "should return class value by default" do
575
+ @c.use_transactions = true
576
+ @c.new.use_transactions.should == true
577
+ @c.use_transactions = false
578
+ @c.new.use_transactions.should == false
579
+ end
580
+
581
+ specify "should return set value if manually set" do
582
+ instance = @c.new
583
+ instance.use_transactions = false
584
+ instance.use_transactions.should == false
585
+ @c.use_transactions = true
586
+ instance.use_transactions.should == false
587
+
588
+ instance.use_transactions = true
589
+ instance.use_transactions.should == true
590
+ @c.use_transactions = false
591
+ instance.use_transactions.should == true
592
+ end
593
+ end