sequel 3.21.0 → 3.29.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 (200) hide show
  1. data/CHANGELOG +413 -3
  2. data/README.rdoc +20 -6
  3. data/Rakefile +23 -16
  4. data/bin/sequel +1 -5
  5. data/doc/association_basics.rdoc +210 -43
  6. data/doc/dataset_basics.rdoc +4 -4
  7. data/doc/mass_assignment.rdoc +54 -0
  8. data/doc/migration.rdoc +15 -538
  9. data/doc/model_hooks.rdoc +72 -27
  10. data/doc/opening_databases.rdoc +86 -50
  11. data/doc/prepared_statements.rdoc +40 -13
  12. data/doc/reflection.rdoc +8 -2
  13. data/doc/release_notes/3.22.0.txt +39 -0
  14. data/doc/release_notes/3.23.0.txt +172 -0
  15. data/doc/release_notes/3.24.0.txt +420 -0
  16. data/doc/release_notes/3.25.0.txt +88 -0
  17. data/doc/release_notes/3.26.0.txt +88 -0
  18. data/doc/release_notes/3.27.0.txt +82 -0
  19. data/doc/release_notes/3.28.0.txt +304 -0
  20. data/doc/release_notes/3.29.0.txt +459 -0
  21. data/doc/schema_modification.rdoc +547 -0
  22. data/doc/sharding.rdoc +7 -1
  23. data/doc/testing.rdoc +115 -0
  24. data/doc/transactions.rdoc +137 -0
  25. data/doc/virtual_rows.rdoc +2 -2
  26. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  27. data/lib/sequel/adapters/ado.rb +40 -18
  28. data/lib/sequel/adapters/amalgalite.rb +15 -7
  29. data/lib/sequel/adapters/db2.rb +175 -86
  30. data/lib/sequel/adapters/dbi.rb +15 -15
  31. data/lib/sequel/adapters/do/mysql.rb +0 -5
  32. data/lib/sequel/adapters/do/postgres.rb +0 -5
  33. data/lib/sequel/adapters/do/sqlite.rb +0 -5
  34. data/lib/sequel/adapters/do.rb +17 -36
  35. data/lib/sequel/adapters/firebird.rb +27 -208
  36. data/lib/sequel/adapters/ibmdb.rb +448 -0
  37. data/lib/sequel/adapters/informix.rb +6 -23
  38. data/lib/sequel/adapters/jdbc/as400.rb +5 -31
  39. data/lib/sequel/adapters/jdbc/db2.rb +44 -0
  40. data/lib/sequel/adapters/jdbc/derby.rb +217 -0
  41. data/lib/sequel/adapters/jdbc/firebird.rb +29 -0
  42. data/lib/sequel/adapters/jdbc/h2.rb +26 -17
  43. data/lib/sequel/adapters/jdbc/hsqldb.rb +166 -0
  44. data/lib/sequel/adapters/jdbc/informix.rb +26 -0
  45. data/lib/sequel/adapters/jdbc/jtds.rb +29 -0
  46. data/lib/sequel/adapters/jdbc/mssql.rb +0 -32
  47. data/lib/sequel/adapters/jdbc/mysql.rb +9 -10
  48. data/lib/sequel/adapters/jdbc/oracle.rb +67 -25
  49. data/lib/sequel/adapters/jdbc/postgresql.rb +6 -11
  50. data/lib/sequel/adapters/jdbc/sqlite.rb +0 -5
  51. data/lib/sequel/adapters/jdbc/sqlserver.rb +41 -0
  52. data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
  53. data/lib/sequel/adapters/jdbc.rb +107 -38
  54. data/lib/sequel/adapters/mock.rb +315 -0
  55. data/lib/sequel/adapters/mysql.rb +78 -182
  56. data/lib/sequel/adapters/mysql2.rb +24 -23
  57. data/lib/sequel/adapters/odbc/db2.rb +17 -0
  58. data/lib/sequel/adapters/odbc/mssql.rb +0 -5
  59. data/lib/sequel/adapters/odbc.rb +28 -9
  60. data/lib/sequel/adapters/openbase.rb +2 -4
  61. data/lib/sequel/adapters/oracle.rb +349 -51
  62. data/lib/sequel/adapters/postgres.rb +169 -21
  63. data/lib/sequel/adapters/shared/access.rb +21 -6
  64. data/lib/sequel/adapters/shared/db2.rb +288 -0
  65. data/lib/sequel/adapters/shared/firebird.rb +214 -0
  66. data/lib/sequel/adapters/shared/informix.rb +45 -0
  67. data/lib/sequel/adapters/shared/mssql.rb +108 -65
  68. data/lib/sequel/adapters/shared/mysql.rb +56 -13
  69. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +149 -0
  70. data/lib/sequel/adapters/shared/oracle.rb +185 -34
  71. data/lib/sequel/adapters/shared/postgres.rb +107 -58
  72. data/lib/sequel/adapters/shared/progress.rb +0 -6
  73. data/lib/sequel/adapters/shared/sqlite.rb +168 -41
  74. data/lib/sequel/adapters/sqlite.rb +27 -18
  75. data/lib/sequel/adapters/swift/mysql.rb +9 -5
  76. data/lib/sequel/adapters/swift/postgres.rb +0 -5
  77. data/lib/sequel/adapters/swift/sqlite.rb +6 -4
  78. data/lib/sequel/adapters/swift.rb +5 -5
  79. data/lib/sequel/adapters/tinytds.rb +152 -17
  80. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +63 -0
  81. data/lib/sequel/ast_transformer.rb +190 -0
  82. data/lib/sequel/connection_pool/threaded.rb +3 -2
  83. data/lib/sequel/connection_pool.rb +1 -1
  84. data/lib/sequel/core.rb +46 -5
  85. data/lib/sequel/database/connecting.rb +5 -6
  86. data/lib/sequel/database/dataset.rb +4 -4
  87. data/lib/sequel/database/dataset_defaults.rb +59 -1
  88. data/lib/sequel/database/logging.rb +1 -1
  89. data/lib/sequel/database/misc.rb +100 -19
  90. data/lib/sequel/database/query.rb +153 -58
  91. data/lib/sequel/database/schema_generator.rb +8 -5
  92. data/lib/sequel/database/schema_methods.rb +59 -29
  93. data/lib/sequel/dataset/actions.rb +194 -57
  94. data/lib/sequel/dataset/features.rb +81 -8
  95. data/lib/sequel/dataset/graph.rb +8 -7
  96. data/lib/sequel/dataset/misc.rb +50 -23
  97. data/lib/sequel/dataset/mutation.rb +5 -6
  98. data/lib/sequel/dataset/prepared_statements.rb +32 -15
  99. data/lib/sequel/dataset/query.rb +223 -42
  100. data/lib/sequel/dataset/sql.rb +58 -61
  101. data/lib/sequel/dataset.rb +8 -0
  102. data/lib/sequel/exceptions.rb +4 -0
  103. data/lib/sequel/extensions/columns_introspection.rb +61 -0
  104. data/lib/sequel/extensions/migration.rb +6 -4
  105. data/lib/sequel/extensions/named_timezones.rb +5 -0
  106. data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
  107. data/lib/sequel/extensions/to_dot.rb +95 -83
  108. data/lib/sequel/model/associations.rb +997 -331
  109. data/lib/sequel/model/base.rb +386 -129
  110. data/lib/sequel/model/errors.rb +1 -1
  111. data/lib/sequel/model/exceptions.rb +5 -1
  112. data/lib/sequel/model.rb +15 -8
  113. data/lib/sequel/plugins/association_pks.rb +22 -4
  114. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  115. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  116. data/lib/sequel/plugins/defaults_setter.rb +58 -0
  117. data/lib/sequel/plugins/force_encoding.rb +6 -6
  118. data/lib/sequel/plugins/identity_map.rb +114 -7
  119. data/lib/sequel/plugins/many_through_many.rb +65 -7
  120. data/lib/sequel/plugins/prepared_statements.rb +151 -0
  121. data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
  122. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  123. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  124. data/lib/sequel/plugins/rcte_tree.rb +29 -15
  125. data/lib/sequel/plugins/serialization.rb +6 -1
  126. data/lib/sequel/plugins/serialization_modification_detection.rb +51 -0
  127. data/lib/sequel/plugins/sharding.rb +12 -25
  128. data/lib/sequel/plugins/single_table_inheritance.rb +3 -1
  129. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  130. data/lib/sequel/plugins/update_primary_key.rb +2 -2
  131. data/lib/sequel/plugins/xml_serializer.rb +3 -3
  132. data/lib/sequel/sql.rb +107 -51
  133. data/lib/sequel/timezones.rb +44 -35
  134. data/lib/sequel/version.rb +1 -1
  135. data/spec/adapters/db2_spec.rb +146 -0
  136. data/spec/adapters/mssql_spec.rb +65 -29
  137. data/spec/adapters/mysql_spec.rb +122 -123
  138. data/spec/adapters/oracle_spec.rb +48 -76
  139. data/spec/adapters/postgres_spec.rb +213 -61
  140. data/spec/adapters/spec_helper.rb +6 -5
  141. data/spec/adapters/sqlite_spec.rb +35 -21
  142. data/spec/core/connection_pool_spec.rb +71 -92
  143. data/spec/core/core_sql_spec.rb +20 -31
  144. data/spec/core/database_spec.rb +729 -508
  145. data/spec/core/dataset_spec.rb +980 -1044
  146. data/spec/core/expression_filters_spec.rb +159 -42
  147. data/spec/core/mock_adapter_spec.rb +378 -0
  148. data/spec/core/object_graph_spec.rb +48 -114
  149. data/spec/core/schema_generator_spec.rb +3 -3
  150. data/spec/core/schema_spec.rb +298 -38
  151. data/spec/core/spec_helper.rb +6 -48
  152. data/spec/extensions/association_pks_spec.rb +38 -0
  153. data/spec/extensions/class_table_inheritance_spec.rb +1 -1
  154. data/spec/extensions/columns_introspection_spec.rb +91 -0
  155. data/spec/extensions/dataset_associations_spec.rb +199 -0
  156. data/spec/extensions/defaults_setter_spec.rb +64 -0
  157. data/spec/extensions/identity_map_spec.rb +162 -0
  158. data/spec/extensions/instance_hooks_spec.rb +71 -0
  159. data/spec/extensions/many_through_many_spec.rb +195 -20
  160. data/spec/extensions/migration_spec.rb +17 -17
  161. data/spec/extensions/named_timezones_spec.rb +22 -2
  162. data/spec/extensions/nested_attributes_spec.rb +4 -0
  163. data/spec/extensions/prepared_statements_associations_spec.rb +126 -0
  164. data/spec/extensions/prepared_statements_safe_spec.rb +79 -0
  165. data/spec/extensions/prepared_statements_spec.rb +72 -0
  166. data/spec/extensions/prepared_statements_with_pk_spec.rb +38 -0
  167. data/spec/extensions/schema_dumper_spec.rb +2 -2
  168. data/spec/extensions/schema_spec.rb +13 -21
  169. data/spec/extensions/serialization_modification_detection_spec.rb +37 -0
  170. data/spec/extensions/serialization_spec.rb +5 -8
  171. data/spec/extensions/single_table_inheritance_spec.rb +11 -0
  172. data/spec/extensions/spec_helper.rb +7 -1
  173. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  174. data/spec/extensions/to_dot_spec.rb +3 -5
  175. data/spec/extensions/typecast_on_load_spec.rb +1 -6
  176. data/spec/extensions/xml_serializer_spec.rb +16 -4
  177. data/spec/integration/associations_test.rb +522 -21
  178. data/spec/integration/database_test.rb +4 -2
  179. data/spec/integration/dataset_test.rb +375 -62
  180. data/spec/integration/eager_loader_test.rb +19 -21
  181. data/spec/integration/model_test.rb +80 -1
  182. data/spec/integration/plugin_test.rb +304 -116
  183. data/spec/integration/prepared_statement_test.rb +200 -120
  184. data/spec/integration/schema_test.rb +161 -30
  185. data/spec/integration/spec_helper.rb +39 -30
  186. data/spec/integration/timezone_test.rb +38 -12
  187. data/spec/integration/transaction_test.rb +172 -5
  188. data/spec/integration/type_test.rb +17 -3
  189. data/spec/model/association_reflection_spec.rb +174 -7
  190. data/spec/model/associations_spec.rb +849 -661
  191. data/spec/model/base_spec.rb +255 -95
  192. data/spec/model/dataset_methods_spec.rb +7 -27
  193. data/spec/model/eager_loading_spec.rb +640 -676
  194. data/spec/model/hooks_spec.rb +309 -67
  195. data/spec/model/model_spec.rb +207 -167
  196. data/spec/model/plugins_spec.rb +24 -13
  197. data/spec/model/record_spec.rb +321 -218
  198. data/spec/model/spec_helper.rb +13 -71
  199. data/spec/model/validations_spec.rb +11 -0
  200. metadata +95 -38
@@ -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
@@ -175,7 +189,7 @@ end
175
189
 
176
190
  describe Sequel::Model::Associations::AssociationReflection, "#remove_before_destroy?" do
177
191
  before do
178
- @c = Class.new(Sequel::Model)
192
+ @c = Class.new(Sequel::Model(:foo))
179
193
  end
180
194
 
181
195
  it "should be true for many_to_one and many_to_many associations" do
@@ -184,6 +198,7 @@ describe Sequel::Model::Associations::AssociationReflection, "#remove_before_des
184
198
  @c.many_to_many :cs, :class=>@c
185
199
  @c.association_reflection(:cs).remove_before_destroy?.should be_true
186
200
  end
201
+
187
202
  it "should be false for one_to_one and one_to_many associations" do
188
203
  @c.one_to_one :c, :class=>@c
189
204
  @c.association_reflection(:c).remove_before_destroy?.should be_false
@@ -192,3 +207,155 @@ describe Sequel::Model::Associations::AssociationReflection, "#remove_before_des
192
207
  end
193
208
  end
194
209
 
210
+ describe Sequel::Model::Associations::AssociationReflection, "#eager_limit_strategy" do
211
+ before do
212
+ @c = Class.new(Sequel::Model(:a))
213
+ end
214
+ after do
215
+ Sequel::Model.default_eager_limit_strategy = nil
216
+ end
217
+
218
+ it "should be nil by default for *_one associations" do
219
+ @c.many_to_one :c, :class=>@c
220
+ @c.association_reflection(:c).eager_limit_strategy.should be_nil
221
+ @c.one_to_one :c, :class=>@c
222
+ @c.association_reflection(:c).eager_limit_strategy.should be_nil
223
+ end
224
+
225
+ it "should be :ruby by default for *_many associations" do
226
+ @c.one_to_many :cs, :class=>@c, :limit=>1
227
+ @c.association_reflection(:cs).eager_limit_strategy.should == :ruby
228
+ @c.many_to_many :cs, :class=>@c, :limit=>1
229
+ @c.association_reflection(:cs).eager_limit_strategy.should == :ruby
230
+ end
231
+
232
+ it "should be nil for many_to_one associations" do
233
+ @c.many_to_one :c, :class=>@c, :eager_limit_strategy=>true
234
+ @c.association_reflection(:c).eager_limit_strategy.should be_nil
235
+ @c.many_to_one :c, :class=>@c, :eager_limit_strategy=>:distinct_on
236
+ @c.association_reflection(:c).eager_limit_strategy.should be_nil
237
+ end
238
+
239
+ it "should be a symbol for other associations if given a symbol" do
240
+ @c.one_to_one :c, :class=>@c, :eager_limit_strategy=>:distinct_on
241
+ @c.association_reflection(:c).eager_limit_strategy.should == :distinct_on
242
+ @c.one_to_many :cs, :class=>@c, :eager_limit_strategy=>:window_function, :limit=>1
243
+ @c.association_reflection(:cs).eager_limit_strategy.should == :window_function
244
+ end
245
+
246
+ it "should use :distinct_on for one_to_one associations if picking and the association dataset supports ordered distinct on" do
247
+ @c.dataset.meta_def(:supports_ordered_distinct_on?){true}
248
+ @c.one_to_one :c, :class=>@c, :eager_limit_strategy=>true
249
+ @c.association_reflection(:c).eager_limit_strategy.should == :distinct_on
250
+ end
251
+
252
+ it "should use :window_function for associations if picking and the association dataset supports window functions" do
253
+ @c.dataset.meta_def(:supports_window_functions?){true}
254
+ @c.one_to_one :c, :class=>@c, :eager_limit_strategy=>true
255
+ @c.association_reflection(:c).eager_limit_strategy.should == :window_function
256
+ @c.one_to_many :cs, :class=>@c, :eager_limit_strategy=>true, :limit=>1
257
+ @c.association_reflection(:cs).eager_limit_strategy.should == :window_function
258
+ @c.many_to_many :cs, :class=>@c, :eager_limit_strategy=>true, :limit=>1
259
+ @c.association_reflection(:cs).eager_limit_strategy.should == :window_function
260
+ end
261
+
262
+ it "should use :ruby for *_many associations if picking and the association dataset doesn't window functions" do
263
+ @c.one_to_many :cs, :class=>@c, :eager_limit_strategy=>true, :limit=>1
264
+ @c.association_reflection(:cs).eager_limit_strategy.should == :ruby
265
+ @c.many_to_many :cs, :class=>@c, :eager_limit_strategy=>true, :limit=>1
266
+ @c.association_reflection(:cs).eager_limit_strategy.should == :ruby
267
+ end
268
+
269
+ it "should respect Model.default_eager_limit_strategy to *_many associations" do
270
+ Sequel::Model.default_eager_limit_strategy = :window_function
271
+ Sequel::Model.default_eager_limit_strategy.should == :window_function
272
+ c = Class.new(Sequel::Model)
273
+ c.dataset = :a
274
+ c.default_eager_limit_strategy.should == :window_function
275
+ c.one_to_many :cs, :class=>c, :limit=>1
276
+ c.association_reflection(:cs).eager_limit_strategy.should == :window_function
277
+ c.many_to_many :cs, :class=>c, :limit=>1
278
+ c.association_reflection(:cs).eager_limit_strategy.should == :window_function
279
+
280
+ Sequel::Model.default_eager_limit_strategy = true
281
+ c = Class.new(Sequel::Model)
282
+ c.dataset = :a
283
+ c.one_to_many :cs, :class=>c, :limit=>1
284
+ c.association_reflection(:cs).eager_limit_strategy.should == :ruby
285
+ c.dataset.meta_def(:supports_window_functions?){true}
286
+ c.many_to_many :cs, :class=>c, :limit=>1
287
+ c.association_reflection(:cs).eager_limit_strategy.should == :window_function
288
+
289
+ c.default_eager_limit_strategy = :correlated_subquery
290
+ c.many_to_many :cs, :class=>c, :limit=>1
291
+ c.association_reflection(:cs).eager_limit_strategy.should == :correlated_subquery
292
+ end
293
+
294
+ it "should ignore Model.default_eager_limit_strategy for one_to_one associations" do
295
+ @c.default_eager_limit_strategy = :correlated_subquery
296
+ @c.one_to_one :c, :class=>@c
297
+ @c.association_reflection(:c).eager_limit_strategy.should be_nil
298
+ end
299
+ end
300
+
301
+ describe Sequel::Model, " association reflection methods" do
302
+ before do
303
+ @c1 = Class.new(Sequel::Model(:nodes)) do
304
+ def self.name; 'Node'; end
305
+ def self.to_s; 'Node'; end
306
+ end
307
+ MODEL_DB.reset
308
+ end
309
+
310
+ it "#all_association_reflections should include all association reflection hashes" do
311
+ @c1.all_association_reflections.should == []
312
+
313
+ @c1.associate :many_to_one, :parent, :class => @c1
314
+ @c1.all_association_reflections.collect{|v| v[:name]}.should == [:parent]
315
+ @c1.all_association_reflections.collect{|v| v[:type]}.should == [:many_to_one]
316
+ @c1.all_association_reflections.collect{|v| v[:class]}.should == [@c1]
317
+
318
+ @c1.associate :one_to_many, :children, :class => @c1
319
+ @c1.all_association_reflections.sort_by{|x|x[:name].to_s}
320
+ @c1.all_association_reflections.sort_by{|x|x[:name].to_s}.collect{|v| v[:name]}.should == [:children, :parent]
321
+ @c1.all_association_reflections.sort_by{|x|x[:name].to_s}.collect{|v| v[:type]}.should == [:one_to_many, :many_to_one]
322
+ @c1.all_association_reflections.sort_by{|x|x[:name].to_s}.collect{|v| v[:class]}.should == [@c1, @c1]
323
+ end
324
+
325
+ it "#association_reflection should return nil for nonexistent association" do
326
+ @c1.association_reflection(:blah).should == nil
327
+ end
328
+
329
+ it "#association_reflection should return association reflection hash if association exists" do
330
+ @c1.associate :many_to_one, :parent, :class => @c1
331
+ @c1.association_reflection(:parent).should be_a_kind_of(Sequel::Model::Associations::AssociationReflection)
332
+ @c1.association_reflection(:parent)[:name].should == :parent
333
+ @c1.association_reflection(:parent)[:type].should == :many_to_one
334
+ @c1.association_reflection(:parent)[:class].should == @c1
335
+
336
+ @c1.associate :one_to_many, :children, :class => @c1
337
+ @c1.association_reflection(:children).should be_a_kind_of(Sequel::Model::Associations::AssociationReflection)
338
+ @c1.association_reflection(:children)[:name].should == :children
339
+ @c1.association_reflection(:children)[:type].should == :one_to_many
340
+ @c1.association_reflection(:children)[:class].should == @c1
341
+ end
342
+
343
+ it "#associations should include all association names" do
344
+ @c1.associations.should == []
345
+ @c1.associate :many_to_one, :parent, :class => @c1
346
+ @c1.associations.should == [:parent]
347
+ @c1.associate :one_to_many, :children, :class => @c1
348
+ @c1.associations.sort_by{|x|x.to_s}.should == [:children, :parent]
349
+ end
350
+
351
+ it "association reflections should be copied upon subclasing" do
352
+ @c1.associate :many_to_one, :parent, :class => @c1
353
+ c = Class.new(@c1)
354
+ @c1.associations.should == [:parent]
355
+ c.associations.should == [:parent]
356
+ c.associate :many_to_one, :parent2, :class => @c1
357
+ @c1.associations.should == [:parent]
358
+ c.associations.sort_by{|x| x.to_s}.should == [:parent, :parent2]
359
+ c.instance_methods.map{|x| x.to_s}.should include('parent')
360
+ end
361
+ end