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,36 +1,26 @@
1
1
  require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper.rb')
2
- require "timeout"
3
2
 
4
3
  unless defined?(ORACLE_DB)
5
4
  ORACLE_DB = Sequel.connect('oracle://hr:hr@localhost/XE')
6
5
  end
7
6
  INTEGRATION_DB = ORACLE_DB unless defined?(INTEGRATION_DB)
8
7
 
9
- if ORACLE_DB.table_exists?(:items)
10
- ORACLE_DB.drop_table :items
11
- end
12
- ORACLE_DB.create_table :items do
13
- varchar2 :name, :size => 50
14
- number :value, :size => 38
15
- date :date_created
8
+ ORACLE_DB.create_table!(:items) do
9
+ String :name, :size => 50
10
+ Integer :value
11
+ Date :date_created
16
12
  index :value
17
13
  end
18
14
 
19
- if ORACLE_DB.table_exists?(:books)
20
- ORACLE_DB.drop_table :books
21
- end
22
- ORACLE_DB.create_table :books do
23
- number :id, :size => 38
24
- varchar2 :title, :size => 50
25
- number :category_id, :size => 38
15
+ ORACLE_DB.create_table!(:books) do
16
+ Integer :id
17
+ String :title, :size => 50
18
+ Integer :category_id
26
19
  end
27
20
 
28
- if ORACLE_DB.table_exists?(:categories)
29
- ORACLE_DB.drop_table :categories
30
- end
31
- ORACLE_DB.create_table :categories do
32
- number :id, :size => 38
33
- varchar2 :cat_name, :size => 50
21
+ ORACLE_DB.create_table!(:categories) do
22
+ Integer :id
23
+ String :cat_name, :size => 50
34
24
  end
35
25
 
36
26
  describe "An Oracle database" do
@@ -40,38 +30,39 @@ describe "An Oracle database" do
40
30
  ORACLE_DB.disconnect
41
31
  ORACLE_DB.pool.size.should == 0
42
32
  end
33
+
34
+ specify "should be able to get current sequence value with SQL" do
35
+ begin
36
+ ORACLE_DB.create_table!(:foo){primary_key :id}
37
+ ORACLE_DB.fetch('SELECT seq_foo_id.nextval FROM DUAL').single_value.should == 1
38
+ ensure
39
+ ORACLE_DB.drop_table(:foo)
40
+ end
41
+ end
43
42
 
44
43
  specify "should provide schema information" do
45
- books_schema = [
46
- [:id, {:char_size=>0, :type=>:number, :allow_null=>true, :type_string=>"NUMBER(38)", :data_size=>22, :precision=>38, :char_used=>false, :scale=>0, :charset_form=>nil, :fsprecision=>38, :lfprecision=>0, :db_type=>"NUMBER(38)"}],
47
- [:title, {:char_size=>50, :type=>:varchar2, :allow_null=>true, :type_string=>"VARCHAR2(50)", :data_size=>50, :precision=>0, :char_used=>false, :scale=>0, :charset_form=>:implicit, :fsprecision=>0, :lfprecision=>0, :db_type=>"VARCHAR2(50)"}],
48
- [:category_id, {:char_size=>0, :type=>:number, :allow_null=>true, :type_string=>"NUMBER(38)", :data_size=>22, :precision=>38, :char_used=>false, :scale=>0, :charset_form=>nil, :fsprecision=>38, :lfprecision=>0, :db_type=>"NUMBER(38)"}]]
49
- categories_schema = [
50
- [:id, {:char_size=>0, :type=>:number, :allow_null=>true, :type_string=>"NUMBER(38)", :data_size=>22, :precision=>38, :char_used=>false, :scale=>0, :charset_form=>nil, :fsprecision=>38, :lfprecision=>0, :db_type=>"NUMBER(38)"}],
51
- [:cat_name, {:char_size=>50, :type=>:varchar2, :allow_null=>true, :type_string=>"VARCHAR2(50)", :data_size=>50, :precision=>0, :char_used=>false, :scale=>0, :charset_form=>:implicit, :fsprecision=>0, :lfprecision=>0, :db_type=>"VARCHAR2(50)"}]]
52
- items_schema = [
53
- [:name, {:char_size=>50, :type=>:varchar2, :allow_null=>true, :type_string=>"VARCHAR2(50)", :data_size=>50, :precision=>0, :char_used=>false, :scale=>0, :charset_form=>:implicit, :fsprecision=>0, :lfprecision=>0, :db_type=>"VARCHAR2(50)"}],
54
- [:value, {:char_size=>0, :type=>:number, :allow_null=>true, :type_string=>"NUMBER(38)", :data_size=>22, :precision=>38, :char_used=>false, :scale=>0, :charset_form=>nil, :fsprecision=>38, :lfprecision=>0, :db_type=>"NUMBER(38)"}],
55
- [:date_created, {:charset_form=>nil, :type=>:date, :type_string=>"DATE", :fsprecision=>0, :data_size=>7, :lfprecision=>0, :precision=>0, :db_type=>"DATE", :char_used=>false, :char_size=>0, :scale=>0, :allow_null=>true}]]
44
+ books_schema = [[:id, [:integer, false, true, nil]],
45
+ [:title, [:string, false, true, nil]],
46
+ [:category_id, [:integer, false, true, nil]]]
47
+ categories_schema = [[:id, [:integer, false, true, nil]],
48
+ [:cat_name, [:string, false, true, nil]]]
49
+ items_schema = [[:name, [:string, false, true, nil]],
50
+ [:value, [:integer, false, true, nil]],
51
+ [:date_created, [:datetime, false, true, nil]]]
56
52
 
57
53
  {:books => books_schema, :categories => categories_schema, :items => items_schema}.each_pair do |table, expected_schema|
58
54
  schema = ORACLE_DB.schema(table)
59
55
  schema.should_not be_nil
60
- expected_schema.should == schema
56
+ schema.map{|c, s| [c, s.values_at(:type, :primary_key, :allow_null, :ruby_default)]}.should == expected_schema
61
57
  end
62
58
  end
63
59
 
64
60
  specify "should create a temporary table" do
65
- ORACLE_DB.create_table :test_tmp, :temporary => true do
61
+ ORACLE_DB.create_table! :test_tmp, :temp => true do
62
+ varchar2 :name, :size => 50
66
63
  primary_key :id, :integer, :null => false
67
- column :name, :text
68
64
  index :name, :unique => true
69
65
  end
70
-
71
- ORACLE_DB.sqls.should == [
72
- 'CREATE GLOBAL TEMPORARY TABLE test_tmp (id integer NOT NULL PRIMARY KEY AUTOINCREMENT, name text)',
73
- 'CREATE UNIQUE INDEX test_tmp_name_index ON test_tmp (name)'
74
- ]
75
66
  end
76
67
  end
77
68
 
@@ -148,27 +139,27 @@ describe "An Oracle dataset" do
148
139
 
149
140
  @d.max(:value).to_i.should == 789
150
141
 
151
- @d.select(:name, :AVG.sql_function(:value)).filter(:name => 'abc').group(:name).to_a.should == [
152
- {:name => 'abc', :"avg(value)" => (456+123)/2.0}
142
+ @d.select(:name, :AVG.sql_function(:value).as(:avg)).filter(:name => 'abc').group(:name).to_a.should == [
143
+ {:name => 'abc', :avg => (456+123)/2.0}
153
144
  ]
154
145
 
155
- @d.select(:AVG.sql_function(:value)).group(:name).order(:name).limit(1).to_a.should == [
156
- {:"avg(value)" => (456+123)/2.0}
146
+ @d.select(:AVG.sql_function(:value).as(:avg)).group(:name).order(:name).limit(1).to_a.should == [
147
+ {:avg => (456+123)/2.0}
157
148
  ]
158
149
 
159
- @d.select(:name, :AVG.sql_function(:value)).group(:name).order(:name).to_a.should == [
160
- {:name => 'abc', :"avg(value)" => (456+123)/2.0},
161
- {:name => 'def', :"avg(value)" => 789*1.0}
150
+ @d.select(:name, :AVG.sql_function(:value).as(:avg)).group(:name).order(:name).to_a.should == [
151
+ {:name => 'abc', :avg => (456+123)/2.0},
152
+ {:name => 'def', :avg => 789*1.0}
162
153
  ]
163
154
 
164
- @d.select(:name, :AVG.sql_function(:value)).group(:name).order(:name).to_a.should == [
165
- {:name => 'abc', :"avg(value)" => (456+123)/2.0},
166
- {:name => 'def', :"avg(value)" => 789*1.0}
155
+ @d.select(:name, :AVG.sql_function(:value).as(:avg)).group(:name).order(:name).to_a.should == [
156
+ {:name => 'abc', :avg => (456+123)/2.0},
157
+ {:name => 'def', :avg => 789*1.0}
167
158
  ]
168
159
 
169
- @d.select(:name, :AVG.sql_function(:value)).group(:name).having(:name => ['abc', 'def']).order(:name).to_a.should == [
170
- {:name => 'abc', :"avg(value)" => (456+123)/2.0},
171
- {:name => 'def', :"avg(value)" => 789*1.0}
160
+ @d.select(:name, :AVG.sql_function(:value).as(:avg)).group(:name).having(:name => ['abc', 'def']).order(:name).to_a.should == [
161
+ {:name => 'abc', :avg => (456+123)/2.0},
162
+ {:name => 'def', :avg => 789*1.0}
172
163
  ]
173
164
 
174
165
  @d.select(:name, :value).filter(:name => 'abc').union(@d.select(:name, :value).filter(:name => 'def')).order(:value).to_a.should == [
@@ -194,7 +185,7 @@ describe "An Oracle dataset" do
194
185
  specify "should translate values correctly" do
195
186
  @d << {:name => 'abc', :value => 456}
196
187
  @d << {:name => 'def', :value => 789}
197
- @d.filter(:value > 500).update(:date_created => "to_timestamp('2009-09-09', 'YYYY-MM-DD')".lit)
188
+ @d.filter('value > 500').update(:date_created => "to_timestamp('2009-09-09', 'YYYY-MM-DD')".lit)
198
189
 
199
190
  @d[:name => 'def'][:date_created].should == Time.parse('2009-09-09')
200
191
  end
@@ -289,34 +280,15 @@ end
289
280
  describe "Row locks in Oracle" do
290
281
  before do
291
282
  @d1 = ORACLE_DB[:books]
292
- @d1.delete # remove all records
283
+ @d1.delete
293
284
  @d1 << {:id => 1, :title => 'aaa'}
294
285
  end
295
286
 
296
287
  specify "#for_update should use FOR UPDATE" do
297
- @d1.for_update.sql.should == "SELECT * FROM BOOKS FOR UPDATE"
288
+ @d1.for_update.sql.should == 'SELECT * FROM "BOOKS" FOR UPDATE'
298
289
  end
299
290
 
300
291
  specify "#lock_style should accept symbols" do
301
- @d1.lock_style(:update).sql.should == "SELECT * FROM BOOKS FOR UPDATE"
302
- end
303
-
304
- specify "should not update during row lock" do
305
- ORACLE_DB.transaction do
306
- @d1.filter(:id => 1).for_update.to_a
307
- proc do
308
- t1 = Thread.start do
309
- # wait for unlock
310
- Timeout::timeout(0.02) do
311
- ORACLE_DB[:books].filter(:id => 1).update(:title => "bbb")
312
- end
313
- end
314
- t1.join
315
- end.should raise_error
316
- @d1.filter(:id => 1).first[:title].should == "aaa"
317
- end
318
- t2 = Thread.start { ORACLE_DB[:books].filter(:id => 1).update(:title => "bbb") }
319
- t2.join
320
- @d1.filter(:id => 1).first[:title].should == "bbb"
292
+ @d1.lock_style(:update).sql.should == 'SELECT * FROM "BOOKS" FOR UPDATE'
321
293
  end
322
294
  end
@@ -197,35 +197,39 @@ if POSTGRES_DB.pool.respond_to?(:max_size) and POSTGRES_DB.pool.max_size > 1
197
197
 
198
198
  specify "should handle FOR UPDATE" do
199
199
  @ds.insert(:number=>20)
200
- c = nil
201
- t = nil
200
+ c, t = nil, nil
201
+ q = Queue.new
202
202
  POSTGRES_DB.transaction do
203
203
  @ds.for_update.first(:id=>1)
204
204
  t = Thread.new do
205
205
  POSTGRES_DB.transaction do
206
+ q.push nil
206
207
  @ds.filter(:id=>1).update(:name=>'Jim')
207
208
  c = @ds.first(:id=>1)
209
+ q.push nil
208
210
  end
209
211
  end
210
- sleep 0.01
212
+ q.pop
211
213
  @ds.filter(:id=>1).update(:number=>30)
212
214
  end
215
+ q.pop
213
216
  t.join
214
217
  c.should == {:id=>1, :number=>30, :name=>'Jim'}
215
218
  end
216
219
 
217
220
  specify "should handle FOR SHARE" do
218
221
  @ds.insert(:number=>20)
219
- c = nil
220
- t = nil
222
+ c, t = nil
223
+ q = Queue.new
221
224
  POSTGRES_DB.transaction do
222
225
  @ds.for_share.first(:id=>1)
223
226
  t = Thread.new do
224
227
  POSTGRES_DB.transaction do
225
228
  c = @ds.for_share.filter(:id=>1).first
229
+ q.push nil
226
230
  end
227
231
  end
228
- sleep 0.1
232
+ q.pop
229
233
  @ds.filter(:id=>1).update(:name=>'Jim')
230
234
  c.should == {:id=>1, :number=>20, :name=>nil}
231
235
  end
@@ -351,17 +355,17 @@ describe "A PostgreSQL database" do
351
355
  specify "should support opclass specification" do
352
356
  @db.create_table(:posts){text :title; text :body; integer :user_id; index(:user_id, :opclass => :int4_ops, :type => :btree)}
353
357
  @db.sqls.should == [
354
- "CREATE TABLE posts (title text, body text, user_id integer)",
355
- "CREATE INDEX posts_user_id_index ON posts USING btree (user_id int4_ops)"
358
+ 'CREATE TABLE "posts" ("title" text, "body" text, "user_id" integer)',
359
+ 'CREATE INDEX "posts_user_id_index" ON "posts" USING btree ("user_id" int4_ops)'
356
360
  ]
357
361
  end
358
362
 
359
363
  specify "should support fulltext indexes and searching" do
360
364
  @db.create_table(:posts){text :title; text :body; full_text_index [:title, :body]; full_text_index :title, :language => 'french'}
361
365
  @db.sqls.should == [
362
- "CREATE TABLE posts (title text, body text)",
363
- "CREATE INDEX posts_title_body_index ON posts USING gin (to_tsvector('simple', (COALESCE(title, '') || ' ' || COALESCE(body, ''))))",
364
- "CREATE INDEX posts_title_index ON posts USING gin (to_tsvector('french', (COALESCE(title, ''))))"
366
+ %{CREATE TABLE "posts" ("title" text, "body" text)},
367
+ %{CREATE INDEX "posts_title_body_index" ON "posts" USING gin (to_tsvector('simple', (COALESCE("title", '') || ' ' || COALESCE("body", ''))))},
368
+ %{CREATE INDEX "posts_title_index" ON "posts" USING gin (to_tsvector('french', (COALESCE("title", ''))))}
365
369
  ]
366
370
 
367
371
  @db[:posts].insert(:title=>'ruby rails', :body=>'yowsa')
@@ -373,48 +377,48 @@ describe "A PostgreSQL database" do
373
377
  @db[:posts].full_text_search([:title, :body], ['yowsa', 'rails']).all.should == [:title=>'ruby rails', :body=>'yowsa']
374
378
  @db[:posts].full_text_search(:title, 'scooby', :language => 'french').all.should == [{:title=>'ruby scooby', :body=>'x'}]
375
379
  @db.sqls.should == [
376
- "SELECT * FROM posts WHERE (to_tsvector('simple', (COALESCE(title, ''))) @@ to_tsquery('simple', 'rails'))",
377
- "SELECT * FROM posts WHERE (to_tsvector('simple', (COALESCE(title, '') || ' ' || COALESCE(body, ''))) @@ to_tsquery('simple', 'yowsa | rails'))",
378
- "SELECT * FROM posts WHERE (to_tsvector('french', (COALESCE(title, ''))) @@ to_tsquery('french', 'scooby'))"]
380
+ %{SELECT * FROM "posts" WHERE (to_tsvector('simple', (COALESCE("title", ''))) @@ to_tsquery('simple', 'rails'))},
381
+ %{SELECT * FROM "posts" WHERE (to_tsvector('simple', (COALESCE("title", '') || ' ' || COALESCE("body", ''))) @@ to_tsquery('simple', 'yowsa | rails'))},
382
+ %{SELECT * FROM "posts" WHERE (to_tsvector('french', (COALESCE("title", ''))) @@ to_tsquery('french', 'scooby'))}]
379
383
  end
380
384
 
381
385
  specify "should support spatial indexes" do
382
386
  @db.create_table(:posts){box :geom; spatial_index [:geom]}
383
387
  @db.sqls.should == [
384
- "CREATE TABLE posts (geom box)",
385
- "CREATE INDEX posts_geom_index ON posts USING gist (geom)"
388
+ 'CREATE TABLE "posts" ("geom" box)',
389
+ 'CREATE INDEX "posts_geom_index" ON "posts" USING gist ("geom")'
386
390
  ]
387
391
  end
388
392
 
389
393
  specify "should support indexes with index type" do
390
394
  @db.create_table(:posts){varchar :title, :size => 5; index :title, :type => 'hash'}
391
395
  @db.sqls.should == [
392
- "CREATE TABLE posts (title varchar(5))",
393
- "CREATE INDEX posts_title_index ON posts USING hash (title)"
396
+ 'CREATE TABLE "posts" ("title" varchar(5))',
397
+ 'CREATE INDEX "posts_title_index" ON "posts" USING hash ("title")'
394
398
  ]
395
399
  end
396
400
 
397
401
  specify "should support unique indexes with index type" do
398
402
  @db.create_table(:posts){varchar :title, :size => 5; index :title, :type => 'btree', :unique => true}
399
403
  @db.sqls.should == [
400
- "CREATE TABLE posts (title varchar(5))",
401
- "CREATE UNIQUE INDEX posts_title_index ON posts USING btree (title)"
404
+ 'CREATE TABLE "posts" ("title" varchar(5))',
405
+ 'CREATE UNIQUE INDEX "posts_title_index" ON "posts" USING btree ("title")'
402
406
  ]
403
407
  end
404
408
 
405
409
  specify "should support partial indexes" do
406
410
  @db.create_table(:posts){varchar :title, :size => 5; index :title, :where => {:title => '5'}}
407
411
  @db.sqls.should == [
408
- "CREATE TABLE posts (title varchar(5))",
409
- "CREATE INDEX posts_title_index ON posts (title) WHERE (title = '5')"
412
+ 'CREATE TABLE "posts" ("title" varchar(5))',
413
+ 'CREATE INDEX "posts_title_index" ON "posts" ("title") WHERE ("title" = \'5\')'
410
414
  ]
411
415
  end
412
416
 
413
417
  specify "should support identifiers for table names in indicies" do
414
418
  @db.create_table(Sequel::SQL::Identifier.new(:posts)){varchar :title, :size => 5; index :title, :where => {:title => '5'}}
415
419
  @db.sqls.should == [
416
- "CREATE TABLE posts (title varchar(5))",
417
- "CREATE INDEX posts_title_index ON posts (title) WHERE (title = '5')"
420
+ 'CREATE TABLE "posts" ("title" varchar(5))',
421
+ 'CREATE INDEX "posts_title_index" ON "posts" ("title") WHERE ("title" = \'5\')'
418
422
  ]
419
423
  end
420
424
 
@@ -442,8 +446,8 @@ describe "Postgres::Dataset#import" do
442
446
 
443
447
  @db.sqls.should == [
444
448
  'BEGIN',
445
- 'INSERT INTO test (x, y) VALUES (1, 2)',
446
- 'INSERT INTO test (x, y) VALUES (3, 4)',
449
+ 'INSERT INTO "test" ("x", "y") VALUES (1, 2)',
450
+ 'INSERT INTO "test" ("x", "y") VALUES (3, 4)',
447
451
  'COMMIT'
448
452
  ]
449
453
  @ds.all.should == [{:x=>1, :y=>2}, {:x=>3, :y=>4}]
@@ -456,7 +460,7 @@ describe "Postgres::Dataset#import" do
456
460
 
457
461
  @db.sqls.should == [
458
462
  'BEGIN',
459
- 'INSERT INTO test (x, y) VALUES (1, 2), (3, 4)',
463
+ 'INSERT INTO "test" ("x", "y") VALUES (1, 2), (3, 4)',
460
464
  'COMMIT'
461
465
  ]
462
466
  @ds.all.should == [{:x=>1, :y=>2}, {:x=>3, :y=>4}]
@@ -487,10 +491,10 @@ describe "Postgres::Dataset#insert" do
487
491
  @ds.insert(:value=>13).should == 3
488
492
 
489
493
  @db.sqls.reject{|x| x =~ /pg_class/}.should == [
490
- 'INSERT INTO test5 (value) VALUES (10) RETURNING xid',
491
- 'INSERT INTO test5 (value) VALUES (20)',
494
+ 'INSERT INTO "test5" ("value") VALUES (10) RETURNING "xid"',
495
+ 'INSERT INTO "test5" ("value") VALUES (20)',
492
496
  "SELECT currval('\"public\".test5_xid_seq')",
493
- 'INSERT INTO test5 (value) VALUES (13)',
497
+ 'INSERT INTO "test5" ("value") VALUES (13)',
494
498
  "SELECT currval('\"public\".test5_xid_seq')"
495
499
  ]
496
500
  @ds.all.should == [{:xid=>1, :value=>10}, {:xid=>2, :value=>20}, {:xid=>3, :value=>13}]
@@ -498,25 +502,20 @@ describe "Postgres::Dataset#insert" do
498
502
 
499
503
  specify "should call execute_insert if server_version < 80200" do
500
504
  @ds.meta_def(:server_version){80100}
501
- @ds.should_receive(:execute_insert).once.with('INSERT INTO test5 (value) VALUES (10)', :table=>:test5, :values=>{:value=>10})
505
+ @ds.should_receive(:execute_insert).once.with('INSERT INTO "test5" ("value") VALUES (10)', :table=>:test5, :values=>{:value=>10})
502
506
  @ds.insert(:value=>10)
503
507
  end
504
508
 
505
509
  specify "should call execute_insert if disabling insert returning" do
506
510
  @ds.disable_insert_returning!
507
- @ds.should_receive(:execute_insert).once.with('INSERT INTO test5 (value) VALUES (10)', :table=>:test5, :values=>{:value=>10})
511
+ @ds.should_receive(:execute_insert).once.with('INSERT INTO "test5" ("value") VALUES (10)', :table=>:test5, :values=>{:value=>10})
508
512
  @ds.insert(:value=>10)
509
513
  end
510
514
 
511
515
  specify "should use INSERT RETURNING if server_version >= 80200" do
512
516
  @ds.meta_def(:server_version){80201}
513
517
  @ds.insert(:value=>10)
514
- @db.sqls.last.should == 'INSERT INTO test5 (value) VALUES (10) RETURNING xid'
515
- end
516
-
517
- specify "should have insert_returning_sql use the RETURNING keyword" do
518
- @ds.insert_returning_sql(:xid, :value=>10).should == "INSERT INTO test5 (value) VALUES (10) RETURNING xid"
519
- @ds.insert_returning_sql('*'.lit, :value=>10).should == "INSERT INTO test5 (value) VALUES (10) RETURNING *"
518
+ @db.sqls.last.should == 'INSERT INTO "test5" ("value") VALUES (10) RETURNING "xid"'
520
519
  end
521
520
 
522
521
  specify "should have insert_select return nil if server_version < 80200" do
@@ -606,12 +605,6 @@ describe "Postgres::Database schema qualified tables" do
606
605
  POSTGRES_DB.drop_table(:domains)
607
606
  end
608
607
 
609
- specify "#table_exists? should not include tables from the default non-public schemas" do
610
- POSTGRES_DB.create_table(:schema_test__schema_test){integer :i}
611
- POSTGRES_DB.table_exists?(:schema_test).should == true
612
- POSTGRES_DB.table_exists?(:domain_udt_usage).should == false
613
- end
614
-
615
608
  specify "#table_exists? should see if the table is in a given schema" do
616
609
  POSTGRES_DB.create_table(:schema_test__schema_test){integer :i}
617
610
  POSTGRES_DB.table_exists?(:schema_test__schema_test).should == true
@@ -909,7 +902,7 @@ describe "Postgres::Database functions, languages, and triggers" do
909
902
  after do
910
903
  @d.drop_function('tf', :if_exists=>true, :cascade=>true)
911
904
  @d.drop_function('tf', :if_exists=>true, :cascade=>true, :args=>%w'integer integer')
912
- @d.drop_language(:plpgsql, :if_exists=>true, :cascade=>true)
905
+ @d.drop_language(:plpgsql, :if_exists=>true, :cascade=>true) if @d.server_version < 90000
913
906
  @d.drop_table(:test) rescue nil
914
907
  end
915
908
 
@@ -940,19 +933,19 @@ describe "Postgres::Database functions, languages, and triggers" do
940
933
 
941
934
  specify "#create_language and #drop_language should create and drop languages" do
942
935
  @d.send(:create_language_sql, :plpgsql).should == 'CREATE LANGUAGE plpgsql'
943
- @d.create_language(:plpgsql, :replace=>true)
936
+ @d.create_language(:plpgsql, :replace=>true) if @d.server_version < 90000
944
937
  proc{@d.create_language(:plpgsql)}.should raise_error(Sequel::DatabaseError)
945
938
  @d.send(:drop_language_sql, :plpgsql).should == 'DROP LANGUAGE plpgsql'
946
- @d.drop_language(:plpgsql)
947
- proc{@d.drop_language(:plpgsql)}.should raise_error(Sequel::DatabaseError)
939
+ @d.drop_language(:plpgsql) if @d.server_version < 90000
940
+ proc{@d.drop_language(:plpgsql)}.should raise_error(Sequel::DatabaseError) if @d.server_version < 90000
948
941
  @d.send(:create_language_sql, :plpgsql, :replace=>true, :trusted=>true, :handler=>:a, :validator=>:b).should == (@d.server_version >= 90000 ? 'CREATE OR REPLACE TRUSTED LANGUAGE plpgsql HANDLER a VALIDATOR b' : 'CREATE TRUSTED LANGUAGE plpgsql HANDLER a VALIDATOR b')
949
942
  @d.send(:drop_language_sql, :plpgsql, :if_exists=>true, :cascade=>true).should == 'DROP LANGUAGE IF EXISTS plpgsql CASCADE'
950
943
  # Make sure if exists works
951
- @d.drop_language(:plpgsql, :if_exists=>true, :cascade=>true)
944
+ @d.drop_language(:plpgsql, :if_exists=>true, :cascade=>true) if @d.server_version < 90000
952
945
  end
953
946
 
954
947
  specify "#create_trigger and #drop_trigger should create and drop triggers" do
955
- @d.create_language(:plpgsql)
948
+ @d.create_language(:plpgsql) if @d.server_version < 90000
956
949
  @d.create_function(:tf, 'BEGIN IF NEW.value IS NULL THEN RAISE EXCEPTION \'Blah\'; END IF; RETURN NEW; END;', :language=>:plpgsql, :returns=>:trigger)
957
950
  @d.send(:create_trigger_sql, :test, :identity, :tf, :each_row=>true).should == 'CREATE TRIGGER identity BEFORE INSERT OR UPDATE OR DELETE ON test FOR EACH ROW EXECUTE PROCEDURE tf()'
958
951
  @d.create_table(:test){String :name; Integer :value}
@@ -973,17 +966,17 @@ describe "Postgres::Database functions, languages, and triggers" do
973
966
  end
974
967
 
975
968
  if POSTGRES_DB.adapter_scheme == :postgres
976
- describe "Postgres::Dataset #use_cursor" do
977
- before(:all) do
978
- @db = POSTGRES_DB
979
- @db.create_table!(:test_cursor){Integer :x}
980
- @db.sqls.clear
981
- @ds = @db[:test_cursor]
982
- @db.transaction{1001.times{|i| @ds.insert(i)}}
983
- end
984
- after(:all) do
985
- @db.drop_table(:test) rescue nil
986
- end
969
+ describe "Postgres::Dataset #use_cursor" do
970
+ before(:all) do
971
+ @db = POSTGRES_DB
972
+ @db.create_table!(:test_cursor){Integer :x}
973
+ @db.sqls.clear
974
+ @ds = @db[:test_cursor]
975
+ @db.transaction{1001.times{|i| @ds.insert(i)}}
976
+ end
977
+ after(:all) do
978
+ @db.drop_table(:test_cursor) rescue nil
979
+ end
987
980
 
988
981
  specify "should return the same results as the non-cursor use" do
989
982
  @ds.all.should == @ds.use_cursor.all
@@ -1005,5 +998,164 @@ describe "Postgres::Dataset #use_cursor" do
1005
998
  @ds.check_return
1006
999
  @ds.all.should == @ds.use_cursor.all
1007
1000
  end
1001
+ end
1002
+
1003
+ describe "Postgres::PG_NAMED_TYPES" do
1004
+ before do
1005
+ @db = POSTGRES_DB
1006
+ Sequel::Postgres::PG_NAMED_TYPES[:interval] = lambda{|v| v.reverse}
1007
+ @db.instance_eval do
1008
+ disconnect
1009
+ @conversion_procs = nil
1010
+ end
1011
+ end
1012
+ after do
1013
+ Sequel::Postgres::PG_NAMED_TYPES.delete(:interval)
1014
+ @db.instance_eval do
1015
+ disconnect
1016
+ @conversion_procs = nil
1017
+ end
1018
+ @db.drop_table(:foo)
1019
+ end
1020
+
1021
+ specify "should look up conversion procs by name" do
1022
+ @db.create_table!(:foo){interval :bar}
1023
+ @db[:foo].insert('21 days')
1024
+ @db[:foo].get(:bar).should == 'syad 12'
1025
+ end
1026
+ end
1008
1027
  end
1028
+
1029
+ if POSTGRES_DB.adapter_scheme == :postgres && SEQUEL_POSTGRES_USES_PG && POSTGRES_DB.server_version >= 90000
1030
+ describe "Postgres::Database#copy_table" do
1031
+ before(:all) do
1032
+ @db = POSTGRES_DB
1033
+ @db.create_table!(:test_copy){Integer :x; Integer :y}
1034
+ ds = @db[:test_copy]
1035
+ ds.insert(1, 2)
1036
+ ds.insert(3, 4)
1037
+ end
1038
+ after(:all) do
1039
+ @db.drop_table(:test_copy) rescue nil
1040
+ end
1041
+
1042
+ specify "without a block or options should return a text version of the table as a single string" do
1043
+ @db.copy_table(:test_copy).should == "1\t2\n3\t4\n"
1044
+ end
1045
+
1046
+ specify "without a block and with :format=>:csv should return a csv version of the table as a single string" do
1047
+ @db.copy_table(:test_copy, :format=>:csv).should == "1,2\n3,4\n"
1048
+ end
1049
+
1050
+ specify "should treat string as SQL code" do
1051
+ @db.copy_table('COPY "test_copy" TO STDOUT').should == "1\t2\n3\t4\n"
1052
+ end
1053
+
1054
+ specify "should respect given :options options" do
1055
+ @db.copy_table(:test_copy, :options=>"FORMAT csv, HEADER TRUE").should == "x,y\n1,2\n3,4\n"
1056
+ end
1057
+
1058
+ specify "should respect given :options options when :format is used" do
1059
+ @db.copy_table(:test_copy, :format=>:csv, :options=>"QUOTE '''', FORCE_QUOTE *").should == "'1','2'\n'3','4'\n"
1060
+ end
1061
+
1062
+ specify "should accept dataset as first argument" do
1063
+ @db.copy_table(@db[:test_copy].cross_join(:test_copy___tc).order(1, 2, 3, 4)).should == "1\t2\t1\t2\n1\t2\t3\t4\n3\t4\t1\t2\n3\t4\t3\t4\n"
1064
+ end
1065
+
1066
+ specify "with a block and no options should yield each row as a string in text format" do
1067
+ buf = []
1068
+ @db.copy_table(:test_copy){|b| buf << b}
1069
+ buf.should == ["1\t2\n", "3\t4\n"]
1070
+ end
1071
+
1072
+ specify "with a block and :format=>:csv should yield each row as a string in csv format" do
1073
+ buf = []
1074
+ @db.copy_table(:test_copy, :format=>:csv){|b| buf << b}
1075
+ buf.should == ["1,2\n", "3,4\n"]
1076
+ end
1077
+
1078
+ specify "should work fine when using a block that is terminated early with a following copy_table" do
1079
+ buf = []
1080
+ proc{@db.copy_table(:test_copy, :format=>:csv){|b| buf << b; break}}.should raise_error(Sequel::DatabaseDisconnectError)
1081
+ buf.should == ["1,2\n"]
1082
+ buf.clear
1083
+ proc{@db.copy_table(:test_copy, :format=>:csv){|b| buf << b; raise ArgumentError}}.should raise_error(Sequel::DatabaseDisconnectError)
1084
+ buf.should == ["1,2\n"]
1085
+ buf.clear
1086
+ @db.copy_table(:test_copy){|b| buf << b}
1087
+ buf.should == ["1\t2\n", "3\t4\n"]
1088
+ end
1089
+
1090
+ specify "should work fine when using a block that is terminated early with a following regular query" do
1091
+ buf = []
1092
+ proc{@db.copy_table(:test_copy, :format=>:csv){|b| buf << b; break}}.should raise_error(Sequel::DatabaseDisconnectError)
1093
+ buf.should == ["1,2\n"]
1094
+ buf.clear
1095
+ proc{@db.copy_table(:test_copy, :format=>:csv){|b| buf << b; raise ArgumentError}}.should raise_error(Sequel::DatabaseDisconnectError)
1096
+ buf.should == ["1,2\n"]
1097
+ @db[:test_copy].select_order_map(:x).should == [1, 3]
1098
+ end
1099
+ end
1100
+
1101
+ describe "Postgres::Database LISTEN/NOTIFY" do
1102
+ before(:all) do
1103
+ @db = POSTGRES_DB
1104
+ end
1105
+
1106
+ specify "should support listen and notify" do
1107
+ notify_pid = @db.synchronize{|conn| conn.backend_pid}
1108
+
1109
+ called = false
1110
+ @db.listen('foo', :after_listen=>proc{@db.notify('foo')}) do |ev, pid, payload|
1111
+ ev.should == 'foo'
1112
+ pid.should == notify_pid
1113
+ ['', nil].should include(payload)
1114
+ called = true
1115
+ end.should == 'foo'
1116
+ called.should be_true
1117
+
1118
+ called = false
1119
+ @db.listen('foo', :after_listen=>proc{@db.notify('foo', :payload=>'bar')}) do |ev, pid, payload|
1120
+ ev.should == 'foo'
1121
+ pid.should == notify_pid
1122
+ payload.should == 'bar'
1123
+ called = true
1124
+ end.should == 'foo'
1125
+ called.should be_true
1126
+
1127
+ @db.listen('foo', :after_listen=>proc{@db.notify('foo')}).should == 'foo'
1128
+
1129
+ called = false
1130
+ called2 = false
1131
+ i = 0
1132
+ @db.listen(['foo', 'bar'], :after_listen=>proc{@db.notify('foo', :payload=>'bar'); @db.notify('bar', :payload=>'foo')}, :loop=>proc{i+=1}) do |ev, pid, payload|
1133
+ if !called
1134
+ ev.should == 'foo'
1135
+ pid.should == notify_pid
1136
+ payload.should == 'bar'
1137
+ called = true
1138
+ else
1139
+ ev.should == 'bar'
1140
+ pid.should == notify_pid
1141
+ payload.should == 'foo'
1142
+ called2 = true
1143
+ break
1144
+ end
1145
+ end.should be_nil
1146
+ called.should be_true
1147
+ called2.should be_true
1148
+ i.should == 1
1149
+ end
1150
+
1151
+ specify "should accept a :timeout option in listen" do
1152
+ @db.listen('foo2', :timeout=>0.001).should == nil
1153
+ called = false
1154
+ @db.listen('foo2', :timeout=>0.001){|ev, pid, payload| called = true}.should == nil
1155
+ called.should be_false
1156
+ i = 0
1157
+ @db.listen('foo2', :timeout=>0.001, :loop=>proc{i+=1; throw :stop if i > 3}){|ev, pid, payload| called = true}.should == nil
1158
+ i.should == 4
1159
+ end
1160
+ end
1009
1161
  end
@@ -3,13 +3,17 @@ require 'logger'
3
3
  unless Object.const_defined?('Sequel')
4
4
  $:.unshift(File.join(File.dirname(File.expand_path(__FILE__)), "../../lib/"))
5
5
  require 'sequel'
6
- Sequel.quote_identifiers = false
7
6
  end
8
7
  begin
9
8
  require File.join(File.dirname(File.dirname(File.expand_path(__FILE__))), 'spec_config.rb')
10
9
  rescue LoadError
11
10
  end
12
11
 
12
+ if ENV['SEQUEL_COLUMNS_INTROSPECTION']
13
+ Sequel.extension :columns_introspection
14
+ Sequel::Dataset.introspect_all_columns
15
+ end
16
+
13
17
  class Sequel::Database
14
18
  def log_duration(duration, message)
15
19
  log_info(message)
@@ -26,11 +30,8 @@ end
26
30
  end
27
31
  end
28
32
 
29
- def self.log_specify(message, &block)
30
- specify(message){log{instance_eval(&block)}}
31
- end
32
-
33
33
  def self.cspecify(message, *checked, &block)
34
+ return specify(message, &block) if ENV['SEQUEL_NO_PENDING']
34
35
  pending = false
35
36
  checked.each do |c|
36
37
  case c