sequel 3.21.0 → 3.32.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 (234) hide show
  1. data/CHANGELOG +539 -3
  2. data/MIT-LICENSE +1 -1
  3. data/README.rdoc +20 -6
  4. data/Rakefile +37 -19
  5. data/bin/sequel +1 -5
  6. data/doc/advanced_associations.rdoc +17 -0
  7. data/doc/association_basics.rdoc +293 -43
  8. data/doc/dataset_basics.rdoc +4 -4
  9. data/doc/dataset_filtering.rdoc +8 -0
  10. data/doc/mass_assignment.rdoc +54 -0
  11. data/doc/migration.rdoc +15 -538
  12. data/doc/model_hooks.rdoc +72 -27
  13. data/doc/opening_databases.rdoc +89 -50
  14. data/doc/prepared_statements.rdoc +40 -13
  15. data/doc/reflection.rdoc +8 -2
  16. data/doc/release_notes/3.22.0.txt +39 -0
  17. data/doc/release_notes/3.23.0.txt +172 -0
  18. data/doc/release_notes/3.24.0.txt +420 -0
  19. data/doc/release_notes/3.25.0.txt +88 -0
  20. data/doc/release_notes/3.26.0.txt +88 -0
  21. data/doc/release_notes/3.27.0.txt +82 -0
  22. data/doc/release_notes/3.28.0.txt +304 -0
  23. data/doc/release_notes/3.29.0.txt +459 -0
  24. data/doc/release_notes/3.30.0.txt +135 -0
  25. data/doc/release_notes/3.31.0.txt +146 -0
  26. data/doc/release_notes/3.32.0.txt +202 -0
  27. data/doc/schema_modification.rdoc +547 -0
  28. data/doc/sharding.rdoc +7 -1
  29. data/doc/testing.rdoc +129 -0
  30. data/doc/transactions.rdoc +137 -0
  31. data/doc/virtual_rows.rdoc +2 -2
  32. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  33. data/lib/sequel/adapters/ado.rb +40 -18
  34. data/lib/sequel/adapters/amalgalite.rb +17 -9
  35. data/lib/sequel/adapters/db2.rb +175 -86
  36. data/lib/sequel/adapters/dbi.rb +15 -15
  37. data/lib/sequel/adapters/do/mysql.rb +5 -7
  38. data/lib/sequel/adapters/do/postgres.rb +0 -5
  39. data/lib/sequel/adapters/do/sqlite.rb +0 -5
  40. data/lib/sequel/adapters/do.rb +17 -36
  41. data/lib/sequel/adapters/firebird.rb +27 -208
  42. data/lib/sequel/adapters/ibmdb.rb +448 -0
  43. data/lib/sequel/adapters/informix.rb +6 -23
  44. data/lib/sequel/adapters/jdbc/as400.rb +16 -34
  45. data/lib/sequel/adapters/jdbc/db2.rb +52 -0
  46. data/lib/sequel/adapters/jdbc/derby.rb +260 -0
  47. data/lib/sequel/adapters/jdbc/firebird.rb +29 -0
  48. data/lib/sequel/adapters/jdbc/h2.rb +66 -30
  49. data/lib/sequel/adapters/jdbc/hsqldb.rb +177 -0
  50. data/lib/sequel/adapters/jdbc/informix.rb +26 -0
  51. data/lib/sequel/adapters/jdbc/jtds.rb +34 -0
  52. data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
  53. data/lib/sequel/adapters/jdbc/mysql.rb +11 -11
  54. data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
  55. data/lib/sequel/adapters/jdbc/postgresql.rb +9 -13
  56. data/lib/sequel/adapters/jdbc/sqlite.rb +2 -6
  57. data/lib/sequel/adapters/jdbc/sqlserver.rb +71 -0
  58. data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
  59. data/lib/sequel/adapters/jdbc.rb +231 -78
  60. data/lib/sequel/adapters/mock.rb +339 -0
  61. data/lib/sequel/adapters/mysql.rb +85 -184
  62. data/lib/sequel/adapters/mysql2.rb +26 -25
  63. data/lib/sequel/adapters/odbc/db2.rb +17 -0
  64. data/lib/sequel/adapters/odbc/mssql.rb +1 -6
  65. data/lib/sequel/adapters/odbc.rb +28 -9
  66. data/lib/sequel/adapters/openbase.rb +3 -5
  67. data/lib/sequel/adapters/oracle.rb +355 -53
  68. data/lib/sequel/adapters/postgres.rb +194 -33
  69. data/lib/sequel/adapters/shared/access.rb +32 -9
  70. data/lib/sequel/adapters/shared/db2.rb +328 -0
  71. data/lib/sequel/adapters/shared/firebird.rb +221 -0
  72. data/lib/sequel/adapters/shared/informix.rb +53 -0
  73. data/lib/sequel/adapters/shared/mssql.rb +278 -107
  74. data/lib/sequel/adapters/shared/mysql.rb +203 -65
  75. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +149 -0
  76. data/lib/sequel/adapters/shared/oracle.rb +237 -46
  77. data/lib/sequel/adapters/shared/postgres.rb +214 -82
  78. data/lib/sequel/adapters/shared/progress.rb +5 -8
  79. data/lib/sequel/adapters/shared/sqlite.rb +200 -50
  80. data/lib/sequel/adapters/sqlite.rb +29 -21
  81. data/lib/sequel/adapters/swift/mysql.rb +12 -7
  82. data/lib/sequel/adapters/swift/postgres.rb +0 -5
  83. data/lib/sequel/adapters/swift/sqlite.rb +8 -6
  84. data/lib/sequel/adapters/swift.rb +5 -5
  85. data/lib/sequel/adapters/tinytds.rb +160 -19
  86. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +66 -0
  87. data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
  88. data/lib/sequel/ast_transformer.rb +190 -0
  89. data/lib/sequel/connection_pool/threaded.rb +3 -2
  90. data/lib/sequel/connection_pool.rb +1 -1
  91. data/lib/sequel/core.rb +68 -5
  92. data/lib/sequel/database/connecting.rb +5 -6
  93. data/lib/sequel/database/dataset.rb +4 -4
  94. data/lib/sequel/database/dataset_defaults.rb +59 -1
  95. data/lib/sequel/database/logging.rb +1 -1
  96. data/lib/sequel/database/misc.rb +104 -19
  97. data/lib/sequel/database/query.rb +163 -59
  98. data/lib/sequel/database/schema_generator.rb +17 -7
  99. data/lib/sequel/database/schema_methods.rb +59 -29
  100. data/lib/sequel/dataset/actions.rb +240 -76
  101. data/lib/sequel/dataset/features.rb +91 -8
  102. data/lib/sequel/dataset/graph.rb +38 -11
  103. data/lib/sequel/dataset/misc.rb +50 -23
  104. data/lib/sequel/dataset/mutation.rb +12 -7
  105. data/lib/sequel/dataset/prepared_statements.rb +59 -27
  106. data/lib/sequel/dataset/query.rb +236 -43
  107. data/lib/sequel/dataset/sql.rb +676 -267
  108. data/lib/sequel/dataset.rb +8 -0
  109. data/lib/sequel/exceptions.rb +4 -0
  110. data/lib/sequel/extensions/columns_introspection.rb +61 -0
  111. data/lib/sequel/extensions/migration.rb +6 -4
  112. data/lib/sequel/extensions/named_timezones.rb +5 -0
  113. data/lib/sequel/extensions/query.rb +1 -1
  114. data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
  115. data/lib/sequel/extensions/to_dot.rb +95 -83
  116. data/lib/sequel/model/associations.rb +1081 -344
  117. data/lib/sequel/model/base.rb +420 -133
  118. data/lib/sequel/model/errors.rb +1 -1
  119. data/lib/sequel/model/exceptions.rb +5 -1
  120. data/lib/sequel/model.rb +20 -10
  121. data/lib/sequel/plugins/active_model.rb +13 -1
  122. data/lib/sequel/plugins/association_pks.rb +22 -4
  123. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  124. data/lib/sequel/plugins/composition.rb +43 -10
  125. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  126. data/lib/sequel/plugins/defaults_setter.rb +58 -0
  127. data/lib/sequel/plugins/force_encoding.rb +6 -6
  128. data/lib/sequel/plugins/identity_map.rb +114 -7
  129. data/lib/sequel/plugins/many_through_many.rb +68 -7
  130. data/lib/sequel/plugins/nested_attributes.rb +65 -10
  131. data/lib/sequel/plugins/prepared_statements.rb +151 -0
  132. data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
  133. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  134. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  135. data/lib/sequel/plugins/rcte_tree.rb +29 -15
  136. data/lib/sequel/plugins/serialization.rb +98 -49
  137. data/lib/sequel/plugins/serialization_modification_detection.rb +63 -0
  138. data/lib/sequel/plugins/sharding.rb +21 -54
  139. data/lib/sequel/plugins/single_table_inheritance.rb +3 -1
  140. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  141. data/lib/sequel/plugins/update_primary_key.rb +2 -2
  142. data/lib/sequel/plugins/xml_serializer.rb +3 -3
  143. data/lib/sequel/sql.rb +109 -52
  144. data/lib/sequel/timezones.rb +57 -38
  145. data/lib/sequel/version.rb +1 -1
  146. data/spec/adapters/db2_spec.rb +146 -0
  147. data/spec/adapters/mssql_spec.rb +135 -30
  148. data/spec/adapters/mysql_spec.rb +244 -212
  149. data/spec/adapters/oracle_spec.rb +67 -77
  150. data/spec/adapters/postgres_spec.rb +267 -78
  151. data/spec/adapters/spec_helper.rb +6 -5
  152. data/spec/adapters/sqlite_spec.rb +35 -21
  153. data/spec/core/connection_pool_spec.rb +71 -92
  154. data/spec/core/core_sql_spec.rb +21 -30
  155. data/spec/core/database_spec.rb +789 -512
  156. data/spec/core/dataset_spec.rb +1176 -1061
  157. data/spec/core/expression_filters_spec.rb +159 -42
  158. data/spec/core/mock_adapter_spec.rb +419 -0
  159. data/spec/core/object_graph_spec.rb +86 -114
  160. data/spec/core/schema_generator_spec.rb +3 -3
  161. data/spec/core/schema_spec.rb +298 -38
  162. data/spec/core/spec_helper.rb +6 -48
  163. data/spec/extensions/active_model_spec.rb +13 -0
  164. data/spec/extensions/association_autoreloading_spec.rb +1 -10
  165. data/spec/extensions/association_dependencies_spec.rb +2 -12
  166. data/spec/extensions/association_pks_spec.rb +66 -32
  167. data/spec/extensions/caching_spec.rb +23 -50
  168. data/spec/extensions/class_table_inheritance_spec.rb +31 -83
  169. data/spec/extensions/columns_introspection_spec.rb +91 -0
  170. data/spec/extensions/composition_spec.rb +18 -13
  171. data/spec/extensions/dataset_associations_spec.rb +199 -0
  172. data/spec/extensions/defaults_setter_spec.rb +64 -0
  173. data/spec/extensions/hook_class_methods_spec.rb +65 -91
  174. data/spec/extensions/identity_map_spec.rb +114 -22
  175. data/spec/extensions/instance_filters_spec.rb +11 -21
  176. data/spec/extensions/instance_hooks_spec.rb +53 -0
  177. data/spec/extensions/json_serializer_spec.rb +4 -5
  178. data/spec/extensions/lazy_attributes_spec.rb +16 -20
  179. data/spec/extensions/list_spec.rb +17 -39
  180. data/spec/extensions/many_through_many_spec.rb +283 -250
  181. data/spec/extensions/migration_spec.rb +35 -32
  182. data/spec/extensions/named_timezones_spec.rb +23 -3
  183. data/spec/extensions/nested_attributes_spec.rb +97 -88
  184. data/spec/extensions/optimistic_locking_spec.rb +9 -20
  185. data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
  186. data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
  187. data/spec/extensions/prepared_statements_spec.rb +53 -0
  188. data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
  189. data/spec/extensions/pretty_table_spec.rb +1 -6
  190. data/spec/extensions/query_spec.rb +6 -0
  191. data/spec/extensions/rcte_tree_spec.rb +41 -43
  192. data/spec/extensions/schema_dumper_spec.rb +5 -8
  193. data/spec/extensions/schema_spec.rb +13 -21
  194. data/spec/extensions/serialization_modification_detection_spec.rb +72 -0
  195. data/spec/extensions/serialization_spec.rb +81 -43
  196. data/spec/extensions/sharding_spec.rb +66 -140
  197. data/spec/extensions/single_table_inheritance_spec.rb +18 -29
  198. data/spec/extensions/spec_helper.rb +13 -61
  199. data/spec/extensions/sql_expr_spec.rb +20 -60
  200. data/spec/extensions/tactical_eager_loading_spec.rb +9 -19
  201. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  202. data/spec/extensions/timestamps_spec.rb +6 -6
  203. data/spec/extensions/to_dot_spec.rb +4 -7
  204. data/spec/extensions/touch_spec.rb +13 -14
  205. data/spec/extensions/tree_spec.rb +11 -26
  206. data/spec/extensions/typecast_on_load_spec.rb +1 -6
  207. data/spec/extensions/update_primary_key_spec.rb +30 -24
  208. data/spec/extensions/validation_class_methods_spec.rb +30 -51
  209. data/spec/extensions/validation_helpers_spec.rb +16 -35
  210. data/spec/extensions/xml_serializer_spec.rb +16 -4
  211. data/spec/integration/associations_test.rb +661 -21
  212. data/spec/integration/database_test.rb +4 -2
  213. data/spec/integration/dataset_test.rb +500 -67
  214. data/spec/integration/eager_loader_test.rb +19 -21
  215. data/spec/integration/model_test.rb +80 -1
  216. data/spec/integration/plugin_test.rb +367 -119
  217. data/spec/integration/prepared_statement_test.rb +222 -125
  218. data/spec/integration/schema_test.rb +217 -39
  219. data/spec/integration/spec_helper.rb +39 -30
  220. data/spec/integration/timezone_test.rb +38 -12
  221. data/spec/integration/transaction_test.rb +182 -5
  222. data/spec/integration/type_test.rb +17 -3
  223. data/spec/model/association_reflection_spec.rb +201 -7
  224. data/spec/model/associations_spec.rb +955 -662
  225. data/spec/model/base_spec.rb +275 -95
  226. data/spec/model/dataset_methods_spec.rb +7 -27
  227. data/spec/model/eager_loading_spec.rb +677 -676
  228. data/spec/model/hooks_spec.rb +349 -67
  229. data/spec/model/model_spec.rb +222 -168
  230. data/spec/model/plugins_spec.rb +24 -13
  231. data/spec/model/record_spec.rb +381 -218
  232. data/spec/model/spec_helper.rb +13 -71
  233. data/spec/model/validations_spec.rb +11 -0
  234. metadata +117 -73
@@ -1,14 +1,16 @@
1
1
  require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper.rb')
2
2
 
3
3
  describe "Database transactions" do
4
- before do
4
+ before(:all) do
5
5
  @db = INTEGRATION_DB
6
6
  @db.drop_table(:items) if @db.table_exists?(:items)
7
7
  @db.create_table(:items, :engine=>'InnoDB'){String :name; Integer :value}
8
8
  @d = @db[:items]
9
- clear_sqls
10
9
  end
11
- after do
10
+ before do
11
+ @d.delete
12
+ end
13
+ after(:all) do
12
14
  @db.drop_table(:items) if @db.table_exists?(:items)
13
15
  end
14
16
 
@@ -21,6 +23,13 @@ describe "Database transactions" do
21
23
  @db.transaction{|conn| conn.should_not == nil}
22
24
  end
23
25
 
26
+ specify "should have #in_transaction? work correctly" do
27
+ @db.in_transaction?.should be_false
28
+ c = nil
29
+ @db.transaction{c = @db.in_transaction?}
30
+ c.should be_true
31
+ end
32
+
24
33
  specify "should correctly rollback transactions" do
25
34
  proc do
26
35
  @db.transaction do
@@ -29,12 +38,22 @@ describe "Database transactions" do
29
38
  end
30
39
  end.should raise_error(Interrupt)
31
40
 
41
+ @db.transaction do
42
+ @d << {:name => 'abc', :value => 1}
43
+ raise Sequel::Rollback
44
+ end.should be_nil
45
+
32
46
  proc do
33
- @db.transaction do
47
+ @db.transaction(:rollback=>:reraise) do
34
48
  @d << {:name => 'abc', :value => 1}
35
49
  raise Sequel::Rollback
36
50
  end
37
- end.should_not raise_error
51
+ end.should raise_error(Sequel::Rollback)
52
+
53
+ @db.transaction(:rollback=>:always) do
54
+ @d << {:name => 'abc', :value => 1}
55
+ 2
56
+ end.should be_nil
38
57
 
39
58
  @d.count.should == 0
40
59
  end
@@ -115,6 +134,16 @@ describe "Database transactions" do
115
134
  end
116
135
 
117
136
  if INTEGRATION_DB.supports_prepared_transactions?
137
+ specify "should allow saving and destroying of model objects" do
138
+ c = Class.new(Sequel::Model(@d))
139
+ c.set_primary_key :name
140
+ c.unrestrict_primary_key
141
+ c.use_after_commit_rollback = false
142
+ @db.transaction(:prepare=>'XYZ'){c.create(:name => '1'); c.create(:name => '2').destroy}
143
+ @db.commit_prepared_transaction('XYZ')
144
+ @d.select_order_map(:name).should == ['1']
145
+ end
146
+
118
147
  specify "should commit prepared transactions using commit_prepared_transaction" do
119
148
  @db.transaction(:prepare=>'XYZ'){@d << {:name => '1'}}
120
149
  @db.commit_prepared_transaction('XYZ')
@@ -126,6 +155,14 @@ describe "Database transactions" do
126
155
  @db.rollback_prepared_transaction('XYZ')
127
156
  @d.select_order_map(:name).should == []
128
157
  end
158
+
159
+ if INTEGRATION_DB.supports_savepoints?
160
+ specify "should support savepoints when using prepared transactions" do
161
+ @db.transaction(:prepare=>'XYZ'){@db.transaction(:savepoint=>true){@d << {:name => '1'}}}
162
+ @db.commit_prepared_transaction('XYZ')
163
+ @d.select_order_map(:name).should == ['1']
164
+ end
165
+ end
129
166
  end
130
167
 
131
168
  specify "should support all transaction isolation levels" do
@@ -134,4 +171,144 @@ describe "Database transactions" do
134
171
  @d.count.should == i + 1
135
172
  end
136
173
  end
174
+
175
+ specify "should support after_commit outside transactions" do
176
+ c = nil
177
+ @db.after_commit{c = 1}
178
+ c.should == 1
179
+ end
180
+
181
+ specify "should support after_rollback outside transactions" do
182
+ c = nil
183
+ @db.after_rollback{c = 1}
184
+ c.should be_nil
185
+ end
186
+
187
+ specify "should support after_commit inside transactions" do
188
+ c = nil
189
+ @db.transaction{@db.after_commit{c = 1}; c.should be_nil}
190
+ c.should == 1
191
+ end
192
+
193
+ specify "should support after_rollback inside transactions" do
194
+ c = nil
195
+ @db.transaction{@db.after_rollback{c = 1}; c.should be_nil}
196
+ c.should be_nil
197
+ end
198
+
199
+ specify "should not call after_commit if the transaction rolls back" do
200
+ c = nil
201
+ @db.transaction{@db.after_commit{c = 1}; c.should be_nil; raise Sequel::Rollback}
202
+ c.should be_nil
203
+ end
204
+
205
+ specify "should call after_rollback if the transaction rolls back" do
206
+ c = nil
207
+ @db.transaction{@db.after_rollback{c = 1}; c.should be_nil; raise Sequel::Rollback}
208
+ c.should == 1
209
+ end
210
+
211
+ specify "should support multiple after_commit blocks inside transactions" do
212
+ c = []
213
+ @db.transaction{@db.after_commit{c << 1}; @db.after_commit{c << 2}; c.should == []}
214
+ c.should == [1, 2]
215
+ end
216
+
217
+ specify "should support multiple after_rollback blocks inside transactions" do
218
+ c = []
219
+ @db.transaction{@db.after_rollback{c << 1}; @db.after_rollback{c << 2}; c.should == []; raise Sequel::Rollback}
220
+ c.should == [1, 2]
221
+ end
222
+
223
+ specify "should support after_commit inside nested transactions" do
224
+ c = nil
225
+ @db.transaction{@db.transaction{@db.after_commit{c = 1}}; c.should be_nil}
226
+ c.should == 1
227
+ end
228
+
229
+ specify "should support after_rollback inside nested transactions" do
230
+ c = nil
231
+ @db.transaction{@db.transaction{@db.after_rollback{c = 1}}; c.should be_nil; raise Sequel::Rollback}
232
+ c.should == 1
233
+ end
234
+
235
+ if INTEGRATION_DB.supports_savepoints?
236
+ specify "should support after_commit inside savepoints" do
237
+ c = nil
238
+ @db.transaction{@db.transaction(:savepoint=>true){@db.after_commit{c = 1}}; c.should be_nil}
239
+ c.should == 1
240
+ end
241
+
242
+ specify "should support after_rollback inside savepoints" do
243
+ c = nil
244
+ @db.transaction{@db.transaction(:savepoint=>true){@db.after_rollback{c = 1}}; c.should be_nil; raise Sequel::Rollback}
245
+ c.should == 1
246
+ end
247
+ end
248
+
249
+ if INTEGRATION_DB.supports_prepared_transactions?
250
+ specify "should raise an error if you attempt to use after_commit or after_rollback inside a prepared transaction" do
251
+ proc{@db.transaction(:prepare=>'XYZ'){@db.after_commit{}}}.should raise_error(Sequel::Error)
252
+ proc{@db.transaction(:prepare=>'XYZ'){@db.after_rollback{}}}.should raise_error(Sequel::Error)
253
+ end
254
+
255
+ if INTEGRATION_DB.supports_savepoints?
256
+ specify "should raise an error if you attempt to use after_commit or after rollback inside a savepoint in a prepared transaction" do
257
+ proc{@db.transaction(:prepare=>'XYZ'){@db.transaction(:savepoint=>true){@db.after_commit{}}}}.should raise_error(Sequel::Error)
258
+ proc{@db.transaction(:prepare=>'XYZ'){@db.transaction(:savepoint=>true){@db.after_rollback{}}}}.should raise_error(Sequel::Error)
259
+ end
260
+ end
261
+ end
262
+ end
263
+
264
+ if (! defined?(RUBY_ENGINE) or RUBY_ENGINE == 'ruby' or (RUBY_ENGINE == 'rbx' && !Sequel.guarded?([:do, :sqlite], [:tinytds, :mssql]))) and RUBY_VERSION < '1.9'
265
+ describe "Database transactions and Thread#kill" do
266
+ before do
267
+ @db = INTEGRATION_DB
268
+ @db.drop_table(:items) if @db.table_exists?(:items)
269
+ @db.create_table(:items, :engine=>'InnoDB'){String :name; Integer :value}
270
+ @d = @db[:items]
271
+ end
272
+ after do
273
+ @db.drop_table(:items) if @db.table_exists?(:items)
274
+ end
275
+
276
+ specify "should handle transactions inside threads" do
277
+ q = Queue.new
278
+ q1 = Queue.new
279
+ t = Thread.new do
280
+ @db.transaction do
281
+ @d << {:name => 'abc', :value => 1}
282
+ q1.push nil
283
+ q.pop
284
+ @d << {:name => 'def', :value => 2}
285
+ end
286
+ end
287
+ q1.pop
288
+ t.kill
289
+ @d.count.should == 0
290
+ end
291
+
292
+ if INTEGRATION_DB.supports_savepoints?
293
+ specify "should handle transactions with savepoints inside threads" do
294
+ q = Queue.new
295
+ q1 = Queue.new
296
+ t = Thread.new do
297
+ @db.transaction do
298
+ @d << {:name => 'abc', :value => 1}
299
+ @db.transaction(:savepoint=>true) do
300
+ @d << {:name => 'def', :value => 2}
301
+ q1.push nil
302
+ q.pop
303
+ @d << {:name => 'ghi', :value => 3}
304
+ end
305
+ @d << {:name => 'jkl', :value => 4}
306
+ end
307
+ end
308
+ q1.pop
309
+ t.kill
310
+ @d.count.should == 0
311
+ end
312
+ end
313
+ end
137
314
  end
@@ -6,7 +6,7 @@ describe "Supported types" do
6
6
  INTEGRATION_DB[:items]
7
7
  end
8
8
 
9
- cspecify "should support casting correctly", [:sqlite, :sqlite] do
9
+ specify "should support casting correctly" do
10
10
  ds = create_items_table_with_column(:number, Integer)
11
11
  ds.insert(:number => 1)
12
12
  ds.select(:number.cast_string.as(:n)).map(:n).should == %w'1'
@@ -60,7 +60,7 @@ describe "Supported types" do
60
60
  ds.all.should == [{:name=>'Test User'}]
61
61
  end
62
62
 
63
- cspecify "should support generic date type", [:do, :sqlite], [:jdbc, :sqlite], :mssql do
63
+ cspecify "should support generic date type", [:do, :sqlite], [:jdbc, :sqlite], :mssql, :oracle do
64
64
  ds = create_items_table_with_column(:dat, Date)
65
65
  d = Date.today
66
66
  ds.insert(:dat => d)
@@ -68,6 +68,20 @@ describe "Supported types" do
68
68
  ds.first[:dat].to_s.should == d.to_s
69
69
  end
70
70
 
71
+ cspecify "should support generic time type", [:do], [:swift], [:odbc], [:jdbc, :mssql], [:jdbc, :postgres], [:jdbc, :sqlite], [:mysql2], [:tinytds], :oracle do
72
+ ds = create_items_table_with_column(:tim, Time, :only_time=>true)
73
+ t = Sequel::SQLTime.now
74
+ ds.insert(:tim => t)
75
+ v = ds.first[:tim]
76
+ ds.literal(v).should == ds.literal(t)
77
+ v.should be_a_kind_of(Sequel::SQLTime)
78
+ ds.delete
79
+ ds.insert(:tim => v)
80
+ v2 = ds.first[:tim]
81
+ ds.literal(v2).should == ds.literal(t)
82
+ v2.should be_a_kind_of(Sequel::SQLTime)
83
+ end
84
+
71
85
  cspecify "should support generic datetime type", [:do, :sqlite], [:jdbc, :sqlite] do
72
86
  ds = create_items_table_with_column(:tim, DateTime)
73
87
  t = DateTime.now
@@ -86,7 +100,7 @@ describe "Supported types" do
86
100
  ds.first[:name].should be_a_kind_of(::Sequel::SQL::Blob)
87
101
  end
88
102
 
89
- cspecify "should support generic boolean type", [:do, :sqlite], [:jdbc, :sqlite], [:odbc, :mssql] do
103
+ cspecify "should support generic boolean type", [:do, :sqlite], [:jdbc, :sqlite], [:jdbc, :db2], [:odbc, :mssql], :oracle do
90
104
  ds = create_items_table_with_column(:number, TrueClass)
91
105
  ds.insert(:number => true)
92
106
  ds.all.should == [{:number=>true}]
@@ -2,15 +2,19 @@ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
3
  describe Sequel::Model::Associations::AssociationReflection, "#associated_class" do
4
4
  before do
5
- @c = Class.new(Sequel::Model)
5
+ @c = Class.new(Sequel::Model(:foo))
6
6
  class ::ParParent < Sequel::Model; end
7
7
  end
8
+ after do
9
+ Object.send(:remove_const, :ParParent)
10
+ end
8
11
 
9
12
  it "should use the :class value if present" do
10
13
  @c.many_to_one :c, :class=>ParParent
11
14
  @c.association_reflection(:c).keys.should include(:class)
12
15
  @c.association_reflection(:c).associated_class.should == ParParent
13
16
  end
17
+
14
18
  it "should figure out the class if the :class value is not present" do
15
19
  @c.many_to_one :c, :class=>'ParParent'
16
20
  @c.association_reflection(:c).keys.should_not include(:class)
@@ -20,15 +24,19 @@ end
20
24
 
21
25
  describe Sequel::Model::Associations::AssociationReflection, "#primary_key" do
22
26
  before do
23
- @c = Class.new(Sequel::Model)
27
+ @c = Class.new(Sequel::Model(:foo))
24
28
  class ::ParParent < Sequel::Model; end
25
29
  end
30
+ after do
31
+ Object.send(:remove_const, :ParParent)
32
+ end
26
33
 
27
34
  it "should use the :primary_key value if present" do
28
35
  @c.many_to_one :c, :class=>ParParent, :primary_key=>:blah__blah
29
36
  @c.association_reflection(:c).keys.should include(:primary_key)
30
37
  @c.association_reflection(:c).primary_key.should == :blah__blah
31
38
  end
39
+
32
40
  it "should use the associated table's primary key if :primary_key is not present" do
33
41
  @c.many_to_one :c, :class=>'ParParent'
34
42
  @c.association_reflection(:c).keys.should_not include(:primary_key)
@@ -49,8 +57,8 @@ describe Sequel::Model::Associations::AssociationReflection, "#reciprocal" do
49
57
  end
50
58
 
51
59
  it "should use the :reciprocal value if present" do
52
- @c = Class.new(Sequel::Model)
53
- @d = Class.new(Sequel::Model)
60
+ @c = Class.new(Sequel::Model(:foo))
61
+ @d = Class.new(Sequel::Model(:foo))
54
62
  @c.many_to_one :c, :class=>@d, :reciprocal=>:xx
55
63
  @c.association_reflection(:c).keys.should include(:reciprocal)
56
64
  @c.association_reflection(:c).reciprocal.should == :xx
@@ -111,9 +119,12 @@ end
111
119
 
112
120
  describe Sequel::Model::Associations::AssociationReflection, "#select" do
113
121
  before do
114
- @c = Class.new(Sequel::Model)
122
+ @c = Class.new(Sequel::Model(:foo))
115
123
  class ::ParParent < Sequel::Model; end
116
124
  end
125
+ after do
126
+ Object.send(:remove_const, :ParParent)
127
+ end
117
128
 
118
129
  it "should use the :select value if present" do
119
130
  @c.many_to_one :c, :class=>ParParent, :select=>[:par_parents__id]
@@ -143,9 +154,12 @@ end
143
154
 
144
155
  describe Sequel::Model::Associations::AssociationReflection, "#associated_object_keys" do
145
156
  before do
146
- @c = Class.new(Sequel::Model)
157
+ @c = Class.new(Sequel::Model(:foo))
147
158
  class ::ParParent < Sequel::Model; end
148
159
  end
160
+ after do
161
+ Object.send(:remove_const, :ParParent)
162
+ end
149
163
 
150
164
  it "should use the primary keys for a many_to_one association" do
151
165
  @c.many_to_one :c, :class=>ParParent
@@ -173,9 +187,36 @@ describe Sequel::Model::Associations::AssociationReflection, "#associated_object
173
187
  end
174
188
  end
175
189
 
190
+ describe Sequel::Model::Associations::AssociationReflection do
191
+ before do
192
+ @c = Class.new(Sequel::Model(:foo))
193
+ @c.meta_def(:name){"C"}
194
+ end
195
+
196
+ it "one_to_many #qualified_primary_key should be a qualified version of the primary key" do
197
+ @c.one_to_many :cs, :class=>@c
198
+ @c.dataset.literal(@c.association_reflection(:cs).qualified_primary_key).should == 'foo.id'
199
+ end
200
+
201
+ it "many_to_many #associated_key_column should be the left key" do
202
+ @c.many_to_many :cs, :class=>@c
203
+ @c.association_reflection(:cs).associated_key_column.should == :c_id
204
+ end
205
+
206
+ it "many_to_many #qualified_right_key should be a qualified version of the primary key" do
207
+ @c.many_to_many :cs, :class=>@c, :right_key=>:c2_id
208
+ @c.dataset.literal(@c.association_reflection(:cs).qualified_right_key).should == 'cs_cs.c2_id'
209
+ end
210
+
211
+ it "many_to_many #qualified_right_primary_key should be a qualified version of the primary key" do
212
+ @c.many_to_many :cs, :class=>@c
213
+ @c.dataset.literal(@c.association_reflection(:cs).qualified_right_primary_key).should == 'foo.id'
214
+ end
215
+ end
216
+
176
217
  describe Sequel::Model::Associations::AssociationReflection, "#remove_before_destroy?" do
177
218
  before do
178
- @c = Class.new(Sequel::Model)
219
+ @c = Class.new(Sequel::Model(:foo))
179
220
  end
180
221
 
181
222
  it "should be true for many_to_one and many_to_many associations" do
@@ -184,6 +225,7 @@ describe Sequel::Model::Associations::AssociationReflection, "#remove_before_des
184
225
  @c.many_to_many :cs, :class=>@c
185
226
  @c.association_reflection(:cs).remove_before_destroy?.should be_true
186
227
  end
228
+
187
229
  it "should be false for one_to_one and one_to_many associations" do
188
230
  @c.one_to_one :c, :class=>@c
189
231
  @c.association_reflection(:c).remove_before_destroy?.should be_false
@@ -192,3 +234,155 @@ describe Sequel::Model::Associations::AssociationReflection, "#remove_before_des
192
234
  end
193
235
  end
194
236
 
237
+ describe Sequel::Model::Associations::AssociationReflection, "#eager_limit_strategy" do
238
+ before do
239
+ @c = Class.new(Sequel::Model(:a))
240
+ end
241
+ after do
242
+ Sequel::Model.default_eager_limit_strategy = nil
243
+ end
244
+
245
+ it "should be nil by default for *_one associations" do
246
+ @c.many_to_one :c, :class=>@c
247
+ @c.association_reflection(:c).eager_limit_strategy.should be_nil
248
+ @c.one_to_one :c, :class=>@c
249
+ @c.association_reflection(:c).eager_limit_strategy.should be_nil
250
+ end
251
+
252
+ it "should be :ruby by default for *_many associations" do
253
+ @c.one_to_many :cs, :class=>@c, :limit=>1
254
+ @c.association_reflection(:cs).eager_limit_strategy.should == :ruby
255
+ @c.many_to_many :cs, :class=>@c, :limit=>1
256
+ @c.association_reflection(:cs).eager_limit_strategy.should == :ruby
257
+ end
258
+
259
+ it "should be nil for many_to_one associations" do
260
+ @c.many_to_one :c, :class=>@c, :eager_limit_strategy=>true
261
+ @c.association_reflection(:c).eager_limit_strategy.should be_nil
262
+ @c.many_to_one :c, :class=>@c, :eager_limit_strategy=>:distinct_on
263
+ @c.association_reflection(:c).eager_limit_strategy.should be_nil
264
+ end
265
+
266
+ it "should be a symbol for other associations if given a symbol" do
267
+ @c.one_to_one :c, :class=>@c, :eager_limit_strategy=>:distinct_on
268
+ @c.association_reflection(:c).eager_limit_strategy.should == :distinct_on
269
+ @c.one_to_many :cs, :class=>@c, :eager_limit_strategy=>:window_function, :limit=>1
270
+ @c.association_reflection(:cs).eager_limit_strategy.should == :window_function
271
+ end
272
+
273
+ it "should use :distinct_on for one_to_one associations if picking and the association dataset supports ordered distinct on" do
274
+ @c.dataset.meta_def(:supports_ordered_distinct_on?){true}
275
+ @c.one_to_one :c, :class=>@c, :eager_limit_strategy=>true
276
+ @c.association_reflection(:c).eager_limit_strategy.should == :distinct_on
277
+ end
278
+
279
+ it "should use :window_function for associations if picking and the association dataset supports window functions" do
280
+ @c.dataset.meta_def(:supports_window_functions?){true}
281
+ @c.one_to_one :c, :class=>@c, :eager_limit_strategy=>true
282
+ @c.association_reflection(:c).eager_limit_strategy.should == :window_function
283
+ @c.one_to_many :cs, :class=>@c, :eager_limit_strategy=>true, :limit=>1
284
+ @c.association_reflection(:cs).eager_limit_strategy.should == :window_function
285
+ @c.many_to_many :cs, :class=>@c, :eager_limit_strategy=>true, :limit=>1
286
+ @c.association_reflection(:cs).eager_limit_strategy.should == :window_function
287
+ end
288
+
289
+ it "should use :ruby for *_many associations if picking and the association dataset doesn't window functions" do
290
+ @c.one_to_many :cs, :class=>@c, :eager_limit_strategy=>true, :limit=>1
291
+ @c.association_reflection(:cs).eager_limit_strategy.should == :ruby
292
+ @c.many_to_many :cs, :class=>@c, :eager_limit_strategy=>true, :limit=>1
293
+ @c.association_reflection(:cs).eager_limit_strategy.should == :ruby
294
+ end
295
+
296
+ it "should respect Model.default_eager_limit_strategy to *_many associations" do
297
+ Sequel::Model.default_eager_limit_strategy = :window_function
298
+ Sequel::Model.default_eager_limit_strategy.should == :window_function
299
+ c = Class.new(Sequel::Model)
300
+ c.dataset = :a
301
+ c.default_eager_limit_strategy.should == :window_function
302
+ c.one_to_many :cs, :class=>c, :limit=>1
303
+ c.association_reflection(:cs).eager_limit_strategy.should == :window_function
304
+ c.many_to_many :cs, :class=>c, :limit=>1
305
+ c.association_reflection(:cs).eager_limit_strategy.should == :window_function
306
+
307
+ Sequel::Model.default_eager_limit_strategy = true
308
+ c = Class.new(Sequel::Model)
309
+ c.dataset = :a
310
+ c.one_to_many :cs, :class=>c, :limit=>1
311
+ c.association_reflection(:cs).eager_limit_strategy.should == :ruby
312
+ c.dataset.meta_def(:supports_window_functions?){true}
313
+ c.many_to_many :cs, :class=>c, :limit=>1
314
+ c.association_reflection(:cs).eager_limit_strategy.should == :window_function
315
+
316
+ c.default_eager_limit_strategy = :correlated_subquery
317
+ c.many_to_many :cs, :class=>c, :limit=>1
318
+ c.association_reflection(:cs).eager_limit_strategy.should == :correlated_subquery
319
+ end
320
+
321
+ it "should ignore Model.default_eager_limit_strategy for one_to_one associations" do
322
+ @c.default_eager_limit_strategy = :correlated_subquery
323
+ @c.one_to_one :c, :class=>@c
324
+ @c.association_reflection(:c).eager_limit_strategy.should be_nil
325
+ end
326
+ end
327
+
328
+ describe Sequel::Model, " association reflection methods" do
329
+ before do
330
+ @c1 = Class.new(Sequel::Model(:nodes)) do
331
+ def self.name; 'Node'; end
332
+ def self.to_s; 'Node'; end
333
+ end
334
+ MODEL_DB.reset
335
+ end
336
+
337
+ it "#all_association_reflections should include all association reflection hashes" do
338
+ @c1.all_association_reflections.should == []
339
+
340
+ @c1.associate :many_to_one, :parent, :class => @c1
341
+ @c1.all_association_reflections.collect{|v| v[:name]}.should == [:parent]
342
+ @c1.all_association_reflections.collect{|v| v[:type]}.should == [:many_to_one]
343
+ @c1.all_association_reflections.collect{|v| v[:class]}.should == [@c1]
344
+
345
+ @c1.associate :one_to_many, :children, :class => @c1
346
+ @c1.all_association_reflections.sort_by{|x|x[:name].to_s}
347
+ @c1.all_association_reflections.sort_by{|x|x[:name].to_s}.collect{|v| v[:name]}.should == [:children, :parent]
348
+ @c1.all_association_reflections.sort_by{|x|x[:name].to_s}.collect{|v| v[:type]}.should == [:one_to_many, :many_to_one]
349
+ @c1.all_association_reflections.sort_by{|x|x[:name].to_s}.collect{|v| v[:class]}.should == [@c1, @c1]
350
+ end
351
+
352
+ it "#association_reflection should return nil for nonexistent association" do
353
+ @c1.association_reflection(:blah).should == nil
354
+ end
355
+
356
+ it "#association_reflection should return association reflection hash if association exists" do
357
+ @c1.associate :many_to_one, :parent, :class => @c1
358
+ @c1.association_reflection(:parent).should be_a_kind_of(Sequel::Model::Associations::AssociationReflection)
359
+ @c1.association_reflection(:parent)[:name].should == :parent
360
+ @c1.association_reflection(:parent)[:type].should == :many_to_one
361
+ @c1.association_reflection(:parent)[:class].should == @c1
362
+
363
+ @c1.associate :one_to_many, :children, :class => @c1
364
+ @c1.association_reflection(:children).should be_a_kind_of(Sequel::Model::Associations::AssociationReflection)
365
+ @c1.association_reflection(:children)[:name].should == :children
366
+ @c1.association_reflection(:children)[:type].should == :one_to_many
367
+ @c1.association_reflection(:children)[:class].should == @c1
368
+ end
369
+
370
+ it "#associations should include all association names" do
371
+ @c1.associations.should == []
372
+ @c1.associate :many_to_one, :parent, :class => @c1
373
+ @c1.associations.should == [:parent]
374
+ @c1.associate :one_to_many, :children, :class => @c1
375
+ @c1.associations.sort_by{|x|x.to_s}.should == [:children, :parent]
376
+ end
377
+
378
+ it "association reflections should be copied upon subclasing" do
379
+ @c1.associate :many_to_one, :parent, :class => @c1
380
+ c = Class.new(@c1)
381
+ @c1.associations.should == [:parent]
382
+ c.associations.should == [:parent]
383
+ c.associate :many_to_one, :parent2, :class => @c1
384
+ @c1.associations.should == [:parent]
385
+ c.associations.sort_by{|x| x.to_s}.should == [:parent, :parent2]
386
+ c.instance_methods.map{|x| x.to_s}.should include('parent')
387
+ end
388
+ end