sequel 3.21.0 → 3.31.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 (225) hide show
  1. data/CHANGELOG +485 -3
  2. data/README.rdoc +20 -6
  3. data/Rakefile +37 -19
  4. data/bin/sequel +1 -5
  5. data/doc/association_basics.rdoc +249 -43
  6. data/doc/dataset_basics.rdoc +4 -4
  7. data/doc/dataset_filtering.rdoc +8 -0
  8. data/doc/mass_assignment.rdoc +54 -0
  9. data/doc/migration.rdoc +15 -538
  10. data/doc/model_hooks.rdoc +72 -27
  11. data/doc/opening_databases.rdoc +89 -50
  12. data/doc/prepared_statements.rdoc +40 -13
  13. data/doc/reflection.rdoc +8 -2
  14. data/doc/release_notes/3.22.0.txt +39 -0
  15. data/doc/release_notes/3.23.0.txt +172 -0
  16. data/doc/release_notes/3.24.0.txt +420 -0
  17. data/doc/release_notes/3.25.0.txt +88 -0
  18. data/doc/release_notes/3.26.0.txt +88 -0
  19. data/doc/release_notes/3.27.0.txt +82 -0
  20. data/doc/release_notes/3.28.0.txt +304 -0
  21. data/doc/release_notes/3.29.0.txt +459 -0
  22. data/doc/release_notes/3.30.0.txt +135 -0
  23. data/doc/release_notes/3.31.0.txt +146 -0
  24. data/doc/schema_modification.rdoc +547 -0
  25. data/doc/sharding.rdoc +7 -1
  26. data/doc/testing.rdoc +129 -0
  27. data/doc/transactions.rdoc +137 -0
  28. data/doc/virtual_rows.rdoc +2 -2
  29. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  30. data/lib/sequel/adapters/ado.rb +40 -18
  31. data/lib/sequel/adapters/amalgalite.rb +17 -9
  32. data/lib/sequel/adapters/db2.rb +175 -86
  33. data/lib/sequel/adapters/dbi.rb +15 -15
  34. data/lib/sequel/adapters/do/mysql.rb +5 -7
  35. data/lib/sequel/adapters/do/postgres.rb +0 -5
  36. data/lib/sequel/adapters/do/sqlite.rb +0 -5
  37. data/lib/sequel/adapters/do.rb +17 -36
  38. data/lib/sequel/adapters/firebird.rb +27 -208
  39. data/lib/sequel/adapters/ibmdb.rb +448 -0
  40. data/lib/sequel/adapters/informix.rb +6 -23
  41. data/lib/sequel/adapters/jdbc/as400.rb +16 -34
  42. data/lib/sequel/adapters/jdbc/db2.rb +45 -0
  43. data/lib/sequel/adapters/jdbc/derby.rb +247 -0
  44. data/lib/sequel/adapters/jdbc/firebird.rb +29 -0
  45. data/lib/sequel/adapters/jdbc/h2.rb +56 -29
  46. data/lib/sequel/adapters/jdbc/hsqldb.rb +170 -0
  47. data/lib/sequel/adapters/jdbc/informix.rb +26 -0
  48. data/lib/sequel/adapters/jdbc/jtds.rb +34 -0
  49. data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
  50. data/lib/sequel/adapters/jdbc/mysql.rb +11 -11
  51. data/lib/sequel/adapters/jdbc/oracle.rb +81 -25
  52. data/lib/sequel/adapters/jdbc/postgresql.rb +9 -13
  53. data/lib/sequel/adapters/jdbc/sqlite.rb +2 -6
  54. data/lib/sequel/adapters/jdbc/sqlserver.rb +71 -0
  55. data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
  56. data/lib/sequel/adapters/jdbc.rb +231 -78
  57. data/lib/sequel/adapters/mock.rb +335 -0
  58. data/lib/sequel/adapters/mysql.rb +82 -184
  59. data/lib/sequel/adapters/mysql2.rb +26 -25
  60. data/lib/sequel/adapters/odbc/db2.rb +17 -0
  61. data/lib/sequel/adapters/odbc/mssql.rb +1 -6
  62. data/lib/sequel/adapters/odbc.rb +28 -9
  63. data/lib/sequel/adapters/openbase.rb +3 -5
  64. data/lib/sequel/adapters/oracle.rb +351 -53
  65. data/lib/sequel/adapters/postgres.rb +194 -33
  66. data/lib/sequel/adapters/shared/access.rb +32 -9
  67. data/lib/sequel/adapters/shared/db2.rb +321 -0
  68. data/lib/sequel/adapters/shared/firebird.rb +221 -0
  69. data/lib/sequel/adapters/shared/informix.rb +53 -0
  70. data/lib/sequel/adapters/shared/mssql.rb +231 -106
  71. data/lib/sequel/adapters/shared/mysql.rb +181 -63
  72. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +149 -0
  73. data/lib/sequel/adapters/shared/oracle.rb +231 -41
  74. data/lib/sequel/adapters/shared/postgres.rb +214 -82
  75. data/lib/sequel/adapters/shared/progress.rb +4 -7
  76. data/lib/sequel/adapters/shared/sqlite.rb +201 -57
  77. data/lib/sequel/adapters/sqlite.rb +29 -21
  78. data/lib/sequel/adapters/swift/mysql.rb +12 -7
  79. data/lib/sequel/adapters/swift/postgres.rb +0 -5
  80. data/lib/sequel/adapters/swift/sqlite.rb +8 -6
  81. data/lib/sequel/adapters/swift.rb +5 -5
  82. data/lib/sequel/adapters/tinytds.rb +160 -19
  83. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +66 -0
  84. data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
  85. data/lib/sequel/ast_transformer.rb +190 -0
  86. data/lib/sequel/connection_pool/threaded.rb +3 -2
  87. data/lib/sequel/connection_pool.rb +1 -1
  88. data/lib/sequel/core.rb +46 -5
  89. data/lib/sequel/database/connecting.rb +5 -6
  90. data/lib/sequel/database/dataset.rb +4 -4
  91. data/lib/sequel/database/dataset_defaults.rb +59 -1
  92. data/lib/sequel/database/logging.rb +1 -1
  93. data/lib/sequel/database/misc.rb +104 -19
  94. data/lib/sequel/database/query.rb +153 -58
  95. data/lib/sequel/database/schema_generator.rb +17 -7
  96. data/lib/sequel/database/schema_methods.rb +59 -29
  97. data/lib/sequel/dataset/actions.rb +231 -76
  98. data/lib/sequel/dataset/features.rb +91 -8
  99. data/lib/sequel/dataset/graph.rb +38 -11
  100. data/lib/sequel/dataset/misc.rb +50 -23
  101. data/lib/sequel/dataset/mutation.rb +5 -6
  102. data/lib/sequel/dataset/prepared_statements.rb +48 -27
  103. data/lib/sequel/dataset/query.rb +236 -43
  104. data/lib/sequel/dataset/sql.rb +665 -253
  105. data/lib/sequel/dataset.rb +8 -0
  106. data/lib/sequel/exceptions.rb +4 -0
  107. data/lib/sequel/extensions/columns_introspection.rb +61 -0
  108. data/lib/sequel/extensions/migration.rb +6 -4
  109. data/lib/sequel/extensions/named_timezones.rb +5 -0
  110. data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
  111. data/lib/sequel/extensions/to_dot.rb +95 -83
  112. data/lib/sequel/model/associations.rb +1020 -337
  113. data/lib/sequel/model/base.rb +414 -132
  114. data/lib/sequel/model/errors.rb +1 -1
  115. data/lib/sequel/model/exceptions.rb +5 -1
  116. data/lib/sequel/model.rb +15 -8
  117. data/lib/sequel/plugins/association_pks.rb +22 -4
  118. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  119. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  120. data/lib/sequel/plugins/defaults_setter.rb +58 -0
  121. data/lib/sequel/plugins/force_encoding.rb +6 -6
  122. data/lib/sequel/plugins/identity_map.rb +114 -7
  123. data/lib/sequel/plugins/many_through_many.rb +65 -7
  124. data/lib/sequel/plugins/prepared_statements.rb +151 -0
  125. data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
  126. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  127. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  128. data/lib/sequel/plugins/rcte_tree.rb +29 -15
  129. data/lib/sequel/plugins/serialization.rb +88 -44
  130. data/lib/sequel/plugins/serialization_modification_detection.rb +51 -0
  131. data/lib/sequel/plugins/sharding.rb +21 -54
  132. data/lib/sequel/plugins/single_table_inheritance.rb +3 -1
  133. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  134. data/lib/sequel/plugins/update_primary_key.rb +2 -2
  135. data/lib/sequel/plugins/xml_serializer.rb +3 -3
  136. data/lib/sequel/sql.rb +109 -52
  137. data/lib/sequel/timezones.rb +57 -38
  138. data/lib/sequel/version.rb +1 -1
  139. data/spec/adapters/db2_spec.rb +146 -0
  140. data/spec/adapters/mssql_spec.rb +111 -29
  141. data/spec/adapters/mysql_spec.rb +135 -123
  142. data/spec/adapters/oracle_spec.rb +49 -77
  143. data/spec/adapters/postgres_spec.rb +267 -78
  144. data/spec/adapters/spec_helper.rb +6 -5
  145. data/spec/adapters/sqlite_spec.rb +35 -21
  146. data/spec/core/connection_pool_spec.rb +71 -92
  147. data/spec/core/core_sql_spec.rb +21 -30
  148. data/spec/core/database_spec.rb +788 -512
  149. data/spec/core/dataset_spec.rb +1073 -1053
  150. data/spec/core/expression_filters_spec.rb +159 -42
  151. data/spec/core/mock_adapter_spec.rb +419 -0
  152. data/spec/core/object_graph_spec.rb +86 -114
  153. data/spec/core/schema_generator_spec.rb +3 -3
  154. data/spec/core/schema_spec.rb +298 -38
  155. data/spec/core/spec_helper.rb +6 -48
  156. data/spec/extensions/association_autoreloading_spec.rb +1 -10
  157. data/spec/extensions/association_dependencies_spec.rb +2 -12
  158. data/spec/extensions/association_pks_spec.rb +66 -32
  159. data/spec/extensions/caching_spec.rb +23 -50
  160. data/spec/extensions/class_table_inheritance_spec.rb +31 -83
  161. data/spec/extensions/columns_introspection_spec.rb +91 -0
  162. data/spec/extensions/composition_spec.rb +18 -13
  163. data/spec/extensions/dataset_associations_spec.rb +199 -0
  164. data/spec/extensions/defaults_setter_spec.rb +64 -0
  165. data/spec/extensions/hook_class_methods_spec.rb +65 -91
  166. data/spec/extensions/identity_map_spec.rb +114 -22
  167. data/spec/extensions/instance_filters_spec.rb +11 -21
  168. data/spec/extensions/instance_hooks_spec.rb +53 -0
  169. data/spec/extensions/json_serializer_spec.rb +4 -5
  170. data/spec/extensions/lazy_attributes_spec.rb +16 -20
  171. data/spec/extensions/list_spec.rb +17 -39
  172. data/spec/extensions/many_through_many_spec.rb +283 -250
  173. data/spec/extensions/migration_spec.rb +35 -32
  174. data/spec/extensions/named_timezones_spec.rb +23 -3
  175. data/spec/extensions/nested_attributes_spec.rb +97 -88
  176. data/spec/extensions/optimistic_locking_spec.rb +9 -20
  177. data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
  178. data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
  179. data/spec/extensions/prepared_statements_spec.rb +53 -0
  180. data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
  181. data/spec/extensions/pretty_table_spec.rb +1 -6
  182. data/spec/extensions/rcte_tree_spec.rb +41 -43
  183. data/spec/extensions/schema_dumper_spec.rb +5 -8
  184. data/spec/extensions/schema_spec.rb +13 -21
  185. data/spec/extensions/serialization_modification_detection_spec.rb +37 -0
  186. data/spec/extensions/serialization_spec.rb +72 -43
  187. data/spec/extensions/sharding_spec.rb +66 -140
  188. data/spec/extensions/single_table_inheritance_spec.rb +18 -29
  189. data/spec/extensions/spec_helper.rb +13 -61
  190. data/spec/extensions/sql_expr_spec.rb +20 -60
  191. data/spec/extensions/tactical_eager_loading_spec.rb +9 -19
  192. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  193. data/spec/extensions/timestamps_spec.rb +6 -6
  194. data/spec/extensions/to_dot_spec.rb +4 -7
  195. data/spec/extensions/touch_spec.rb +13 -14
  196. data/spec/extensions/tree_spec.rb +11 -26
  197. data/spec/extensions/typecast_on_load_spec.rb +1 -6
  198. data/spec/extensions/update_primary_key_spec.rb +30 -24
  199. data/spec/extensions/validation_class_methods_spec.rb +30 -51
  200. data/spec/extensions/validation_helpers_spec.rb +16 -35
  201. data/spec/extensions/xml_serializer_spec.rb +16 -4
  202. data/spec/integration/associations_test.rb +537 -21
  203. data/spec/integration/database_test.rb +4 -2
  204. data/spec/integration/dataset_test.rb +461 -65
  205. data/spec/integration/eager_loader_test.rb +19 -21
  206. data/spec/integration/model_test.rb +80 -1
  207. data/spec/integration/plugin_test.rb +304 -116
  208. data/spec/integration/prepared_statement_test.rb +212 -122
  209. data/spec/integration/schema_test.rb +161 -30
  210. data/spec/integration/spec_helper.rb +39 -30
  211. data/spec/integration/timezone_test.rb +38 -12
  212. data/spec/integration/transaction_test.rb +172 -5
  213. data/spec/integration/type_test.rb +17 -3
  214. data/spec/model/association_reflection_spec.rb +201 -7
  215. data/spec/model/associations_spec.rb +865 -662
  216. data/spec/model/base_spec.rb +275 -95
  217. data/spec/model/dataset_methods_spec.rb +7 -27
  218. data/spec/model/eager_loading_spec.rb +677 -676
  219. data/spec/model/hooks_spec.rb +309 -67
  220. data/spec/model/model_spec.rb +222 -168
  221. data/spec/model/plugins_spec.rb +24 -13
  222. data/spec/model/record_spec.rb +381 -218
  223. data/spec/model/spec_helper.rb +13 -71
  224. data/spec/model/validations_spec.rb +11 -0
  225. metadata +115 -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
@@ -126,6 +145,14 @@ describe "Database transactions" do
126
145
  @db.rollback_prepared_transaction('XYZ')
127
146
  @d.select_order_map(:name).should == []
128
147
  end
148
+
149
+ if INTEGRATION_DB.supports_savepoints?
150
+ specify "should support savepoints when using prepared transactions" do
151
+ @db.transaction(:prepare=>'XYZ'){@db.transaction(:savepoint=>true){@d << {:name => '1'}}}
152
+ @db.commit_prepared_transaction('XYZ')
153
+ @d.select_order_map(:name).should == ['1']
154
+ end
155
+ end
129
156
  end
130
157
 
131
158
  specify "should support all transaction isolation levels" do
@@ -134,4 +161,144 @@ describe "Database transactions" do
134
161
  @d.count.should == i + 1
135
162
  end
136
163
  end
164
+
165
+ specify "should support after_commit outside transactions" do
166
+ c = nil
167
+ @db.after_commit{c = 1}
168
+ c.should == 1
169
+ end
170
+
171
+ specify "should support after_rollback outside transactions" do
172
+ c = nil
173
+ @db.after_rollback{c = 1}
174
+ c.should be_nil
175
+ end
176
+
177
+ specify "should support after_commit inside transactions" do
178
+ c = nil
179
+ @db.transaction{@db.after_commit{c = 1}; c.should be_nil}
180
+ c.should == 1
181
+ end
182
+
183
+ specify "should support after_rollback inside transactions" do
184
+ c = nil
185
+ @db.transaction{@db.after_rollback{c = 1}; c.should be_nil}
186
+ c.should be_nil
187
+ end
188
+
189
+ specify "should not call after_commit if the transaction rolls back" do
190
+ c = nil
191
+ @db.transaction{@db.after_commit{c = 1}; c.should be_nil; raise Sequel::Rollback}
192
+ c.should be_nil
193
+ end
194
+
195
+ specify "should call after_rollback if the transaction rolls back" do
196
+ c = nil
197
+ @db.transaction{@db.after_rollback{c = 1}; c.should be_nil; raise Sequel::Rollback}
198
+ c.should == 1
199
+ end
200
+
201
+ specify "should support multiple after_commit blocks inside transactions" do
202
+ c = []
203
+ @db.transaction{@db.after_commit{c << 1}; @db.after_commit{c << 2}; c.should == []}
204
+ c.should == [1, 2]
205
+ end
206
+
207
+ specify "should support multiple after_rollback blocks inside transactions" do
208
+ c = []
209
+ @db.transaction{@db.after_rollback{c << 1}; @db.after_rollback{c << 2}; c.should == []; raise Sequel::Rollback}
210
+ c.should == [1, 2]
211
+ end
212
+
213
+ specify "should support after_commit inside nested transactions" do
214
+ c = nil
215
+ @db.transaction{@db.transaction{@db.after_commit{c = 1}}; c.should be_nil}
216
+ c.should == 1
217
+ end
218
+
219
+ specify "should support after_rollback inside nested transactions" do
220
+ c = nil
221
+ @db.transaction{@db.transaction{@db.after_rollback{c = 1}}; c.should be_nil; raise Sequel::Rollback}
222
+ c.should == 1
223
+ end
224
+
225
+ if INTEGRATION_DB.supports_savepoints?
226
+ specify "should support after_commit inside savepoints" do
227
+ c = nil
228
+ @db.transaction{@db.transaction(:savepoint=>true){@db.after_commit{c = 1}}; c.should be_nil}
229
+ c.should == 1
230
+ end
231
+
232
+ specify "should support after_rollback inside savepoints" do
233
+ c = nil
234
+ @db.transaction{@db.transaction(:savepoint=>true){@db.after_rollback{c = 1}}; c.should be_nil; raise Sequel::Rollback}
235
+ c.should == 1
236
+ end
237
+ end
238
+
239
+ if INTEGRATION_DB.supports_prepared_transactions?
240
+ specify "should raise an error if you attempt to use after_commit or after_rollback inside a prepared transaction" do
241
+ proc{@db.transaction(:prepare=>'XYZ'){@db.after_commit{}}}.should raise_error(Sequel::Error)
242
+ proc{@db.transaction(:prepare=>'XYZ'){@db.after_rollback{}}}.should raise_error(Sequel::Error)
243
+ end
244
+
245
+ if INTEGRATION_DB.supports_savepoints?
246
+ specify "should raise an error if you attempt to use after_commit or after rollback inside a savepoint in a prepared transaction" do
247
+ proc{@db.transaction(:prepare=>'XYZ'){@db.transaction(:savepoint=>true){@db.after_commit{}}}}.should raise_error(Sequel::Error)
248
+ proc{@db.transaction(:prepare=>'XYZ'){@db.transaction(:savepoint=>true){@db.after_rollback{}}}}.should raise_error(Sequel::Error)
249
+ end
250
+ end
251
+ end
252
+ end
253
+
254
+ if (! defined?(RUBY_ENGINE) or RUBY_ENGINE == 'ruby' or (RUBY_ENGINE == 'rbx' && !Sequel.guarded?([:do, :sqlite], [:tinytds, :mssql]))) and RUBY_VERSION < '1.9'
255
+ describe "Database transactions and Thread#kill" do
256
+ before do
257
+ @db = INTEGRATION_DB
258
+ @db.drop_table(:items) if @db.table_exists?(:items)
259
+ @db.create_table(:items, :engine=>'InnoDB'){String :name; Integer :value}
260
+ @d = @db[:items]
261
+ end
262
+ after do
263
+ @db.drop_table(:items) if @db.table_exists?(:items)
264
+ end
265
+
266
+ specify "should handle transactions inside threads" do
267
+ q = Queue.new
268
+ q1 = Queue.new
269
+ t = Thread.new do
270
+ @db.transaction do
271
+ @d << {:name => 'abc', :value => 1}
272
+ q1.push nil
273
+ q.pop
274
+ @d << {:name => 'def', :value => 2}
275
+ end
276
+ end
277
+ q1.pop
278
+ t.kill
279
+ @d.count.should == 0
280
+ end
281
+
282
+ if INTEGRATION_DB.supports_savepoints?
283
+ specify "should handle transactions with savepoints inside threads" do
284
+ q = Queue.new
285
+ q1 = Queue.new
286
+ t = Thread.new do
287
+ @db.transaction do
288
+ @d << {:name => 'abc', :value => 1}
289
+ @db.transaction(:savepoint=>true) do
290
+ @d << {:name => 'def', :value => 2}
291
+ q1.push nil
292
+ q.pop
293
+ @d << {:name => 'ghi', :value => 3}
294
+ end
295
+ @d << {:name => 'jkl', :value => 4}
296
+ end
297
+ end
298
+ q1.pop
299
+ t.kill
300
+ @d.count.should == 0
301
+ end
302
+ end
303
+ end
137
304
  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