sequel 3.21.0 → 3.28.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 (158) hide show
  1. data/CHANGELOG +294 -0
  2. data/README.rdoc +20 -6
  3. data/Rakefile +20 -15
  4. data/doc/association_basics.rdoc +210 -43
  5. data/doc/dataset_basics.rdoc +4 -4
  6. data/doc/mass_assignment.rdoc +54 -0
  7. data/doc/migration.rdoc +15 -538
  8. data/doc/model_hooks.rdoc +64 -27
  9. data/doc/opening_databases.rdoc +37 -10
  10. data/doc/prepared_statements.rdoc +16 -10
  11. data/doc/reflection.rdoc +8 -2
  12. data/doc/release_notes/3.22.0.txt +39 -0
  13. data/doc/release_notes/3.23.0.txt +172 -0
  14. data/doc/release_notes/3.24.0.txt +420 -0
  15. data/doc/release_notes/3.25.0.txt +88 -0
  16. data/doc/release_notes/3.26.0.txt +88 -0
  17. data/doc/release_notes/3.27.0.txt +82 -0
  18. data/doc/release_notes/3.28.0.txt +304 -0
  19. data/doc/schema_modification.rdoc +547 -0
  20. data/doc/testing.rdoc +106 -0
  21. data/doc/transactions.rdoc +97 -0
  22. data/doc/virtual_rows.rdoc +2 -2
  23. data/lib/sequel/adapters/ado.rb +12 -1
  24. data/lib/sequel/adapters/amalgalite.rb +4 -0
  25. data/lib/sequel/adapters/db2.rb +95 -58
  26. data/lib/sequel/adapters/do.rb +12 -0
  27. data/lib/sequel/adapters/firebird.rb +25 -203
  28. data/lib/sequel/adapters/ibmdb.rb +440 -0
  29. data/lib/sequel/adapters/informix.rb +4 -19
  30. data/lib/sequel/adapters/jdbc/as400.rb +0 -7
  31. data/lib/sequel/adapters/jdbc/db2.rb +49 -0
  32. data/lib/sequel/adapters/jdbc/firebird.rb +34 -0
  33. data/lib/sequel/adapters/jdbc/h2.rb +16 -5
  34. data/lib/sequel/adapters/jdbc/informix.rb +31 -0
  35. data/lib/sequel/adapters/jdbc/jtds.rb +34 -0
  36. data/lib/sequel/adapters/jdbc/mssql.rb +0 -32
  37. data/lib/sequel/adapters/jdbc/mysql.rb +9 -0
  38. data/lib/sequel/adapters/jdbc/oracle.rb +2 -27
  39. data/lib/sequel/adapters/jdbc/postgresql.rb +6 -0
  40. data/lib/sequel/adapters/jdbc/sqlserver.rb +46 -0
  41. data/lib/sequel/adapters/jdbc/transactions.rb +34 -0
  42. data/lib/sequel/adapters/jdbc.rb +62 -29
  43. data/lib/sequel/adapters/mysql.rb +22 -139
  44. data/lib/sequel/adapters/mysql2.rb +9 -14
  45. data/lib/sequel/adapters/odbc/db2.rb +21 -0
  46. data/lib/sequel/adapters/odbc.rb +15 -3
  47. data/lib/sequel/adapters/oracle.rb +17 -1
  48. data/lib/sequel/adapters/postgres.rb +111 -16
  49. data/lib/sequel/adapters/shared/access.rb +21 -0
  50. data/lib/sequel/adapters/shared/db2.rb +290 -0
  51. data/lib/sequel/adapters/shared/firebird.rb +214 -0
  52. data/lib/sequel/adapters/shared/informix.rb +45 -0
  53. data/lib/sequel/adapters/shared/mssql.rb +85 -47
  54. data/lib/sequel/adapters/shared/mysql.rb +50 -7
  55. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +143 -0
  56. data/lib/sequel/adapters/shared/oracle.rb +0 -4
  57. data/lib/sequel/adapters/shared/postgres.rb +75 -43
  58. data/lib/sequel/adapters/shared/sqlite.rb +56 -8
  59. data/lib/sequel/adapters/sqlite.rb +12 -11
  60. data/lib/sequel/adapters/swift/mysql.rb +9 -0
  61. data/lib/sequel/adapters/tinytds.rb +139 -7
  62. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +55 -0
  63. data/lib/sequel/ast_transformer.rb +190 -0
  64. data/lib/sequel/connection_pool/threaded.rb +3 -2
  65. data/lib/sequel/connection_pool.rb +1 -1
  66. data/lib/sequel/core.rb +6 -5
  67. data/lib/sequel/database/connecting.rb +5 -5
  68. data/lib/sequel/database/dataset.rb +1 -1
  69. data/lib/sequel/database/dataset_defaults.rb +1 -1
  70. data/lib/sequel/database/logging.rb +1 -1
  71. data/lib/sequel/database/misc.rb +38 -17
  72. data/lib/sequel/database/query.rb +50 -19
  73. data/lib/sequel/database/schema_generator.rb +8 -5
  74. data/lib/sequel/database/schema_methods.rb +52 -27
  75. data/lib/sequel/dataset/actions.rb +167 -48
  76. data/lib/sequel/dataset/features.rb +57 -8
  77. data/lib/sequel/dataset/graph.rb +1 -1
  78. data/lib/sequel/dataset/misc.rb +39 -20
  79. data/lib/sequel/dataset/mutation.rb +3 -3
  80. data/lib/sequel/dataset/prepared_statements.rb +29 -14
  81. data/lib/sequel/dataset/query.rb +182 -32
  82. data/lib/sequel/dataset/sql.rb +31 -58
  83. data/lib/sequel/dataset.rb +8 -0
  84. data/lib/sequel/exceptions.rb +4 -0
  85. data/lib/sequel/extensions/columns_introspection.rb +61 -0
  86. data/lib/sequel/extensions/migration.rb +6 -4
  87. data/lib/sequel/extensions/to_dot.rb +95 -83
  88. data/lib/sequel/model/associations.rb +893 -309
  89. data/lib/sequel/model/base.rb +302 -105
  90. data/lib/sequel/model/errors.rb +1 -1
  91. data/lib/sequel/model/exceptions.rb +5 -1
  92. data/lib/sequel/model.rb +13 -7
  93. data/lib/sequel/plugins/association_pks.rb +22 -4
  94. data/lib/sequel/plugins/defaults_setter.rb +58 -0
  95. data/lib/sequel/plugins/identity_map.rb +113 -6
  96. data/lib/sequel/plugins/many_through_many.rb +67 -5
  97. data/lib/sequel/plugins/prepared_statements.rb +140 -0
  98. data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
  99. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  100. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  101. data/lib/sequel/plugins/serialization_modification_detection.rb +51 -0
  102. data/lib/sequel/plugins/sharding.rb +12 -20
  103. data/lib/sequel/plugins/single_table_inheritance.rb +2 -0
  104. data/lib/sequel/plugins/update_primary_key.rb +1 -1
  105. data/lib/sequel/plugins/xml_serializer.rb +3 -3
  106. data/lib/sequel/sql.rb +107 -51
  107. data/lib/sequel/timezones.rb +12 -3
  108. data/lib/sequel/version.rb +1 -1
  109. data/spec/adapters/db2_spec.rb +146 -0
  110. data/spec/adapters/mssql_spec.rb +36 -0
  111. data/spec/adapters/mysql_spec.rb +36 -19
  112. data/spec/adapters/postgres_spec.rb +115 -28
  113. data/spec/adapters/spec_helper.rb +6 -0
  114. data/spec/adapters/sqlite_spec.rb +11 -0
  115. data/spec/core/connection_pool_spec.rb +62 -77
  116. data/spec/core/database_spec.rb +244 -287
  117. data/spec/core/dataset_spec.rb +383 -34
  118. data/spec/core/expression_filters_spec.rb +159 -41
  119. data/spec/core/schema_spec.rb +326 -3
  120. data/spec/core/spec_helper.rb +45 -0
  121. data/spec/extensions/association_pks_spec.rb +38 -0
  122. data/spec/extensions/columns_introspection_spec.rb +91 -0
  123. data/spec/extensions/defaults_setter_spec.rb +64 -0
  124. data/spec/extensions/identity_map_spec.rb +162 -0
  125. data/spec/extensions/many_through_many_spec.rb +195 -20
  126. data/spec/extensions/migration_spec.rb +17 -17
  127. data/spec/extensions/nested_attributes_spec.rb +1 -0
  128. data/spec/extensions/prepared_statements_associations_spec.rb +126 -0
  129. data/spec/extensions/prepared_statements_safe_spec.rb +79 -0
  130. data/spec/extensions/prepared_statements_spec.rb +72 -0
  131. data/spec/extensions/prepared_statements_with_pk_spec.rb +38 -0
  132. data/spec/extensions/schema_dumper_spec.rb +2 -2
  133. data/spec/extensions/schema_spec.rb +12 -20
  134. data/spec/extensions/serialization_modification_detection_spec.rb +36 -0
  135. data/spec/extensions/single_table_inheritance_spec.rb +11 -0
  136. data/spec/extensions/spec_helper.rb +3 -1
  137. data/spec/extensions/to_dot_spec.rb +3 -5
  138. data/spec/extensions/xml_serializer_spec.rb +16 -4
  139. data/spec/integration/associations_test.rb +405 -15
  140. data/spec/integration/database_test.rb +4 -2
  141. data/spec/integration/dataset_test.rb +240 -20
  142. data/spec/integration/plugin_test.rb +142 -5
  143. data/spec/integration/prepared_statement_test.rb +174 -95
  144. data/spec/integration/schema_test.rb +128 -16
  145. data/spec/integration/spec_helper.rb +15 -0
  146. data/spec/integration/transaction_test.rb +40 -0
  147. data/spec/integration/type_test.rb +16 -2
  148. data/spec/model/association_reflection_spec.rb +91 -0
  149. data/spec/model/associations_spec.rb +476 -5
  150. data/spec/model/base_spec.rb +91 -1
  151. data/spec/model/eager_loading_spec.rb +519 -31
  152. data/spec/model/hooks_spec.rb +161 -0
  153. data/spec/model/model_spec.rb +89 -2
  154. data/spec/model/plugins_spec.rb +17 -0
  155. data/spec/model/record_spec.rb +184 -12
  156. data/spec/model/spec_helper.rb +5 -0
  157. data/spec/model/validations_spec.rb +11 -0
  158. metadata +85 -34
@@ -6,18 +6,21 @@ describe "Database schema parser" do
6
6
  @iom = INTEGRATION_DB.identifier_output_method
7
7
  @iim = INTEGRATION_DB.identifier_input_method
8
8
  @defsch = INTEGRATION_DB.default_schema
9
+ @qi = INTEGRATION_DB.quote_identifiers?
9
10
  clear_sqls
10
11
  end
11
12
  after do
12
13
  INTEGRATION_DB.identifier_output_method = @iom
13
14
  INTEGRATION_DB.identifier_input_method = @iim
14
15
  INTEGRATION_DB.default_schema = @defsch
16
+ INTEGRATION_DB.quote_identifiers = @qi
15
17
  INTEGRATION_DB.drop_table(:items) if INTEGRATION_DB.table_exists?(:items)
16
18
  end
17
19
 
18
20
  specify "should handle a database with a identifier_output_method" do
19
21
  INTEGRATION_DB.identifier_output_method = :reverse
20
22
  INTEGRATION_DB.identifier_input_method = :reverse
23
+ INTEGRATION_DB.quote_identifiers = true
21
24
  INTEGRATION_DB.default_schema = nil if INTEGRATION_DB.default_schema
22
25
  INTEGRATION_DB.create_table!(:items){Integer :number}
23
26
  INTEGRATION_DB.schema(:items, :reload=>true).should be_a_kind_of(Array)
@@ -85,7 +88,7 @@ describe "Database schema parser" do
85
88
  INTEGRATION_DB.schema(:items).first.last[:ruby_default].should == 'blah'
86
89
  end
87
90
 
88
- specify "should parse types from the schema properly" do
91
+ cspecify "should parse types from the schema properly", [:jdbc, :db2] do
89
92
  INTEGRATION_DB.create_table!(:items){Integer :number}
90
93
  INTEGRATION_DB.schema(:items).first.last[:type].should == :integer
91
94
  INTEGRATION_DB.create_table!(:items){Fixnum :number}
@@ -174,6 +177,24 @@ describe "Database schema modifiers" do
174
177
  @db.create_table!(:items, :temp=>true){Integer :number}
175
178
  end
176
179
 
180
+ specify "should have create_table? only create the table if it doesn't already exist" do
181
+ @db.create_table!(:items){String :a}
182
+ @db.create_table?(:items){String :b}
183
+ @db[:items].columns.should == [:a]
184
+ @db.drop_table(:items) rescue nil
185
+ @db.create_table?(:items){String :b}
186
+ @db[:items].columns.should == [:b]
187
+ end
188
+
189
+ specify "should have create_table? work correctly with indexes" do
190
+ @db.create_table!(:items){String :a, :index=>true}
191
+ @db.create_table?(:items){String :b, :index=>true}
192
+ @db[:items].columns.should == [:a]
193
+ @db.drop_table(:items) rescue nil
194
+ @db.create_table?(:items){String :b, :index=>true}
195
+ @db[:items].columns.should == [:b]
196
+ end
197
+
177
198
  specify "should rename tables correctly" do
178
199
  @db.drop_table(:items) rescue nil
179
200
  @db.create_table!(:items2){Integer :number}
@@ -215,7 +236,7 @@ describe "Database schema modifiers" do
215
236
  specify "should add columns to tables correctly" do
216
237
  @db.create_table!(:items){Integer :number}
217
238
  @ds.insert(:number=>10)
218
- @db.alter_table(:items){add_column :name, :text}
239
+ @db.alter_table(:items){add_column :name, String}
219
240
  @db.schema(:items, :reload=>true).map{|x| x.first}.should == [:number, :name]
220
241
  @ds.columns!.should == [:number, :name]
221
242
  @ds.all.should == [{:number=>10, :name=>nil}]
@@ -228,6 +249,15 @@ describe "Database schema modifiers" do
228
249
  @db.schema(:items, :reload=>true).map{|x| x.first}.should == [:number, :id]
229
250
  @ds.columns!.should == [:number, :id]
230
251
  @ds.map(:number).should == [10]
252
+ proc{@ds.insert(:id=>@ds.map(:id).first)}.should raise_error
253
+ end
254
+
255
+ cspecify "should drop primary key constraints from tables correctly", :sqlite do
256
+ @db.create_table!(:items){Integer :number; primary_key [:number], :name=>:items_pk}
257
+ @ds.insert(:number=>10)
258
+ @db.alter_table(:items){drop_constraint :items_pk, :type=>:primary_key}
259
+ @ds.map(:number).should == [10]
260
+ proc{@ds.insert(10)}.should_not raise_error
231
261
  end
232
262
 
233
263
  specify "should add foreign key columns to tables correctly" do
@@ -269,7 +299,7 @@ describe "Database schema modifiers" do
269
299
  proc{@ds.insert(:n=>nil)}.should raise_error(Sequel::DatabaseError)
270
300
  end
271
301
 
272
- specify "should set column NULL/NOT NULL correctly" do
302
+ cspecify "should set column NULL/NOT NULL correctly", [:jdbc, :db2] do
273
303
  @db.create_table!(:items, :engine=>:InnoDB){Integer :id}
274
304
  @ds.insert(:id=>10)
275
305
  @db.alter_table(:items){set_column_allow_null :id, false}
@@ -291,7 +321,7 @@ describe "Database schema modifiers" do
291
321
  @ds.all.should == [{:id=>10}, {:id=>20}]
292
322
  end
293
323
 
294
- specify "should set column types correctly" do
324
+ cspecify "should set column types correctly", [:jdbc, :db2] do
295
325
  @db.create_table!(:items){Integer :id}
296
326
  @ds.insert(:id=>10)
297
327
  @db.alter_table(:items){set_column_type :id, String}
@@ -301,17 +331,50 @@ describe "Database schema modifiers" do
301
331
  @ds.all.should == [{:id=>"10"}, {:id=>"20"}]
302
332
  end
303
333
 
304
- cspecify "should add unique constraints and foreign key table constraints correctly", :sqlite do
305
- @db.create_table!(:items){Integer :id; Integer :item_id}
334
+ cspecify "should add unnamed unique constraints and foreign key table constraints correctly", :sqlite do
335
+ @db.create_table!(:items, :engine=>:InnoDB){Integer :id; Integer :item_id}
306
336
  @db.alter_table(:items) do
307
337
  add_unique_constraint [:item_id, :id]
308
338
  add_foreign_key [:id, :item_id], :items, :key=>[:item_id, :id]
309
339
  end
310
340
  @db.schema(:items, :reload=>true).map{|x| x.first}.should == [:id, :item_id]
311
341
  @ds.columns!.should == [:id, :item_id]
342
+ proc{@ds.insert(1, 1)}.should_not raise_error
343
+ proc{@ds.insert(1, 1)}.should raise_error
344
+ proc{@ds.insert(1, 2)}.should raise_error
345
+ end
346
+
347
+ cspecify "should add named unique constraints and foreign key table constraints correctly", :sqlite do
348
+ @db.create_table!(:items, :engine=>:InnoDB){Integer :id, :null=>false; Integer :item_id, :null=>false}
349
+ @db.alter_table(:items) do
350
+ add_unique_constraint [:item_id, :id], :name=>:unique_iii
351
+ add_foreign_key [:id, :item_id], :items, :key=>[:item_id, :id], :name=>:fk_iii
352
+ end
353
+ @db.schema(:items, :reload=>true).map{|x| x.first}.should == [:id, :item_id]
354
+ @ds.columns!.should == [:id, :item_id]
355
+ proc{@ds.insert(1, 1)}.should_not raise_error
356
+ proc{@ds.insert(1, 1)}.should raise_error
357
+ proc{@ds.insert(1, 2)}.should raise_error
358
+ end
359
+
360
+ cspecify "should drop unique constraints and foreign key table constraints correctly", :sqlite do
361
+ @db.create_table!(:items) do
362
+ Integer :id
363
+ Integer :item_id
364
+ unique [:item_id, :id], :name=>:items_uk
365
+ foreign_key [:id, :item_id], :items, :key=>[:item_id, :id], :name=>:items_fk
366
+ end
367
+ @db.alter_table(:items) do
368
+ drop_constraint(:items_fk, :type=>:foreign_key)
369
+ drop_constraint(:items_uk, :type=>:unique)
370
+ end
371
+ @db.schema(:items, :reload=>true).map{|x| x.first}.should == [:id, :item_id]
372
+ @ds.columns!.should == [:id, :item_id]
373
+ proc{@ds.insert(1, 2)}.should_not raise_error
374
+ proc{@ds.insert(1, 2)}.should_not raise_error
312
375
  end
313
376
 
314
- cspecify "should remove columns from tables correctly", :h2, :mssql do
377
+ cspecify "should remove columns from tables correctly", :h2, :mssql, [:jdbc, :db2] do
315
378
  @db.create_table!(:items) do
316
379
  primary_key :id
317
380
  String :name
@@ -332,7 +395,7 @@ describe "Database schema modifiers" do
332
395
  @ds.columns!.should == [:id]
333
396
  end
334
397
 
335
- specify "should remove multiple columns in a single alter_table block" do
398
+ cspecify "should remove multiple columns in a single alter_table block", [:jdbc, :db2] do
336
399
  @db.create_table!(:items) do
337
400
  primary_key :id
338
401
  String :name
@@ -362,25 +425,74 @@ describe "Database#tables" do
362
425
  "xxxxx#{@@xxxxx += 1}"
363
426
  end
364
427
  end
365
- @iom = INTEGRATION_DB.identifier_output_method
366
- @iim = INTEGRATION_DB.identifier_input_method
428
+ @db = INTEGRATION_DB
429
+ @db.create_table(:sequel_test_table){Integer :a}
430
+ @db.create_view :sequel_test_view, @db[:sequel_test_table]
431
+ @iom = @db.identifier_output_method
432
+ @iim = @db.identifier_input_method
367
433
  clear_sqls
368
434
  end
369
435
  after do
370
- INTEGRATION_DB.identifier_output_method = @iom
371
- INTEGRATION_DB.identifier_input_method = @iim
436
+ @db.identifier_output_method = @iom
437
+ @db.identifier_input_method = @iim
438
+ @db.drop_view :sequel_test_view
439
+ @db.drop_table :sequel_test_table
440
+ end
441
+
442
+ specify "should return an array of symbols" do
443
+ ts = @db.tables
444
+ ts.should be_a_kind_of(Array)
445
+ ts.each{|t| t.should be_a_kind_of(Symbol)}
446
+ ts.should include(:sequel_test_table)
447
+ ts.should_not include(:sequel_test_view)
448
+ end
449
+
450
+ specify "should respect the database's identifier_output_method" do
451
+ @db.identifier_output_method = :xxxxx
452
+ @db.identifier_input_method = :xxxxx
453
+ @db.tables.each{|t| t.to_s.should =~ /\Ax{5}\d+\z/}
454
+ end
455
+ end
456
+ end
457
+
458
+ begin
459
+ INTEGRATION_DB.views
460
+ rescue Sequel::NotImplemented
461
+ rescue
462
+ describe "Database#views" do
463
+ before do
464
+ class ::String
465
+ @@xxxxx = 0
466
+ def xxxxx
467
+ "xxxxx#{@@xxxxx += 1}"
468
+ end
469
+ end
470
+ @db = INTEGRATION_DB
471
+ @db.create_table(:sequel_test_table){Integer :a}
472
+ @db.create_view :sequel_test_view, @db[:sequel_test_table]
473
+ @iom = @db.identifier_output_method
474
+ @iim = @db.identifier_input_method
475
+ clear_sqls
476
+ end
477
+ after do
478
+ @db.identifier_output_method = @iom
479
+ @db.identifier_input_method = @iim
480
+ @db.drop_view :sequel_test_view
481
+ @db.drop_table :sequel_test_table
372
482
  end
373
483
 
374
484
  specify "should return an array of symbols" do
375
- ts = INTEGRATION_DB.tables
485
+ ts = @db.views
376
486
  ts.should be_a_kind_of(Array)
377
487
  ts.each{|t| t.should be_a_kind_of(Symbol)}
488
+ ts.should_not include(:sequel_test_table)
489
+ ts.should include(:sequel_test_view)
378
490
  end
379
491
 
380
492
  specify "should respect the database's identifier_output_method" do
381
- INTEGRATION_DB.identifier_output_method = :xxxxx
382
- INTEGRATION_DB.identifier_input_method = :xxxxx
383
- INTEGRATION_DB.tables.each{|t| t.to_s.should =~ /\Ax{5}\d+\z/}
493
+ @db.identifier_output_method = :xxxxx
494
+ @db.identifier_input_method = :xxxxx
495
+ @db.views.each{|t| t.to_s.should =~ /\Ax{5}\d+\z/}
384
496
  end
385
497
  end
386
498
  end
@@ -9,6 +9,11 @@ begin
9
9
  rescue LoadError
10
10
  end
11
11
 
12
+ if ENV['SEQUEL_COLUMNS_INTROSPECTION']
13
+ Sequel.extension :columns_introspection
14
+ Sequel::Dataset.introspect_all_columns
15
+ end
16
+
12
17
  Sequel::Model.use_transactions = false
13
18
 
14
19
  $sqls = []
@@ -44,6 +49,7 @@ end
44
49
  end
45
50
 
46
51
  def self.cspecify(message, *checked, &block)
52
+ return specify(message, &block) if ENV['SEQUEL_NO_PENDING']
47
53
  pending = false
48
54
  checked.each do |c|
49
55
  case c
@@ -84,3 +90,12 @@ if defined?(INTEGRATION_DB) || defined?(INTEGRATION_URL) || ENV['SEQUEL_INTEGRAT
84
90
  else
85
91
  INTEGRATION_DB = Sequel.sqlite('', :quote_identifiers=>false)
86
92
  end
93
+
94
+ if INTEGRATION_DB.adapter_scheme == :ibmdb
95
+ def INTEGRATION_DB.drop_table(*tables)
96
+ super
97
+ rescue Sequel::DatabaseError
98
+ disconnect
99
+ super
100
+ end
101
+ end
@@ -134,4 +134,44 @@ describe "Database transactions" do
134
134
  @d.count.should == i + 1
135
135
  end
136
136
  end
137
+
138
+ if (! defined?(RUBY_ENGINE) or RUBY_ENGINE == 'ruby' or (RUBY_ENGINE == 'rbx' && ![[:do, :sqlite], [:tinytds, :mssql]].include?([INTEGRATION_DB.adapter_scheme, INTEGRATION_DB.database_type]))) and RUBY_VERSION < '1.9'
139
+ specify "should handle Thread#kill for transactions inside threads" do
140
+ q = Queue.new
141
+ q1 = Queue.new
142
+ t = Thread.new do
143
+ @db.transaction do
144
+ @d << {:name => 'abc', :value => 1}
145
+ q1.push nil
146
+ q.pop
147
+ @d << {:name => 'def', :value => 2}
148
+ end
149
+ end
150
+ q1.pop
151
+ t.kill
152
+ @d.count.should == 0
153
+ end
154
+
155
+ if INTEGRATION_DB.supports_savepoints?
156
+ specify "should handle Thread#kill for transactions with savepoints inside threads" do
157
+ q = Queue.new
158
+ q1 = Queue.new
159
+ t = Thread.new do
160
+ @db.transaction do
161
+ @d << {:name => 'abc', :value => 1}
162
+ @db.transaction(:savepoint=>true) do
163
+ @d << {:name => 'def', :value => 2}
164
+ q1.push nil
165
+ q.pop
166
+ @d << {:name => 'ghi', :value => 3}
167
+ end
168
+ @d << {:name => 'jkl', :value => 4}
169
+ end
170
+ end
171
+ q1.pop
172
+ t.kill
173
+ @d.count.should == 0
174
+ end
175
+ end
176
+ end
137
177
  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'
@@ -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], [:mysql2], [:tinytds] 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] do
90
104
  ds = create_items_table_with_column(:number, TrueClass)
91
105
  ds.insert(:number => true)
92
106
  ds.all.should == [{:number=>true}]
@@ -184,6 +184,7 @@ describe Sequel::Model::Associations::AssociationReflection, "#remove_before_des
184
184
  @c.many_to_many :cs, :class=>@c
185
185
  @c.association_reflection(:cs).remove_before_destroy?.should be_true
186
186
  end
187
+
187
188
  it "should be false for one_to_one and one_to_many associations" do
188
189
  @c.one_to_one :c, :class=>@c
189
190
  @c.association_reflection(:c).remove_before_destroy?.should be_false
@@ -192,3 +193,93 @@ describe Sequel::Model::Associations::AssociationReflection, "#remove_before_des
192
193
  end
193
194
  end
194
195
 
196
+ describe Sequel::Model::Associations::AssociationReflection, "#eager_limit_strategy" do
197
+ before do
198
+ @c = Class.new(Sequel::Model(:a))
199
+ end
200
+ after do
201
+ Sequel::Model.default_eager_limit_strategy = nil
202
+ end
203
+
204
+ it "should be nil by default for *_one associations" do
205
+ @c.many_to_one :c, :class=>@c
206
+ @c.association_reflection(:c).eager_limit_strategy.should be_nil
207
+ @c.one_to_one :c, :class=>@c
208
+ @c.association_reflection(:c).eager_limit_strategy.should be_nil
209
+ end
210
+
211
+ it "should be :ruby by default for *_many associations" do
212
+ @c.one_to_many :cs, :class=>@c, :limit=>1
213
+ @c.association_reflection(:cs).eager_limit_strategy.should == :ruby
214
+ @c.many_to_many :cs, :class=>@c, :limit=>1
215
+ @c.association_reflection(:cs).eager_limit_strategy.should == :ruby
216
+ end
217
+
218
+ it "should be nil for many_to_one associations" do
219
+ @c.many_to_one :c, :class=>@c, :eager_limit_strategy=>true
220
+ @c.association_reflection(:c).eager_limit_strategy.should be_nil
221
+ @c.many_to_one :c, :class=>@c, :eager_limit_strategy=>:distinct_on
222
+ @c.association_reflection(:c).eager_limit_strategy.should be_nil
223
+ end
224
+
225
+ it "should be a symbol for other associations if given a symbol" do
226
+ @c.one_to_one :c, :class=>@c, :eager_limit_strategy=>:distinct_on
227
+ @c.association_reflection(:c).eager_limit_strategy.should == :distinct_on
228
+ @c.one_to_many :cs, :class=>@c, :eager_limit_strategy=>:window_function, :limit=>1
229
+ @c.association_reflection(:cs).eager_limit_strategy.should == :window_function
230
+ end
231
+
232
+ it "should use :distinct_on for one_to_one associations if picking and the association dataset supports ordered distinct on" do
233
+ @c.dataset.meta_def(:supports_ordered_distinct_on?){true}
234
+ @c.one_to_one :c, :class=>@c, :eager_limit_strategy=>true
235
+ @c.association_reflection(:c).eager_limit_strategy.should == :distinct_on
236
+ end
237
+
238
+ it "should use :window_function for associations if picking and the association dataset supports window functions" do
239
+ @c.dataset.meta_def(:supports_window_functions?){true}
240
+ @c.one_to_one :c, :class=>@c, :eager_limit_strategy=>true
241
+ @c.association_reflection(:c).eager_limit_strategy.should == :window_function
242
+ @c.one_to_many :cs, :class=>@c, :eager_limit_strategy=>true, :limit=>1
243
+ @c.association_reflection(:cs).eager_limit_strategy.should == :window_function
244
+ @c.many_to_many :cs, :class=>@c, :eager_limit_strategy=>true, :limit=>1
245
+ @c.association_reflection(:cs).eager_limit_strategy.should == :window_function
246
+ end
247
+
248
+ it "should use :ruby for *_many associations if picking and the association dataset doesn't window functions" do
249
+ @c.one_to_many :cs, :class=>@c, :eager_limit_strategy=>true, :limit=>1
250
+ @c.association_reflection(:cs).eager_limit_strategy.should == :ruby
251
+ @c.many_to_many :cs, :class=>@c, :eager_limit_strategy=>true, :limit=>1
252
+ @c.association_reflection(:cs).eager_limit_strategy.should == :ruby
253
+ end
254
+
255
+ it "should respect Model.default_eager_limit_strategy to *_many associations" do
256
+ Sequel::Model.default_eager_limit_strategy = :window_function
257
+ Sequel::Model.default_eager_limit_strategy.should == :window_function
258
+ c = Class.new(Sequel::Model)
259
+ c.dataset = :a
260
+ c.default_eager_limit_strategy.should == :window_function
261
+ c.one_to_many :cs, :class=>c, :limit=>1
262
+ c.association_reflection(:cs).eager_limit_strategy.should == :window_function
263
+ c.many_to_many :cs, :class=>c, :limit=>1
264
+ c.association_reflection(:cs).eager_limit_strategy.should == :window_function
265
+
266
+ Sequel::Model.default_eager_limit_strategy = true
267
+ c = Class.new(Sequel::Model)
268
+ c.dataset = :a
269
+ c.one_to_many :cs, :class=>c, :limit=>1
270
+ c.association_reflection(:cs).eager_limit_strategy.should == :ruby
271
+ c.dataset.meta_def(:supports_window_functions?){true}
272
+ c.many_to_many :cs, :class=>c, :limit=>1
273
+ c.association_reflection(:cs).eager_limit_strategy.should == :window_function
274
+
275
+ c.default_eager_limit_strategy = :correlated_subquery
276
+ c.many_to_many :cs, :class=>c, :limit=>1
277
+ c.association_reflection(:cs).eager_limit_strategy.should == :correlated_subquery
278
+ end
279
+
280
+ it "should ignore Model.default_eager_limit_strategy for one_to_one associations" do
281
+ @c.default_eager_limit_strategy = :correlated_subquery
282
+ @c.one_to_one :c, :class=>@c
283
+ @c.association_reflection(:c).eager_limit_strategy.should be_nil
284
+ end
285
+ end