sequel 3.28.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 (148) hide show
  1. data/CHANGELOG +119 -3
  2. data/Rakefile +5 -3
  3. data/bin/sequel +1 -5
  4. data/doc/model_hooks.rdoc +9 -1
  5. data/doc/opening_databases.rdoc +49 -40
  6. data/doc/prepared_statements.rdoc +27 -6
  7. data/doc/release_notes/3.28.0.txt +2 -2
  8. data/doc/release_notes/3.29.0.txt +459 -0
  9. data/doc/sharding.rdoc +7 -1
  10. data/doc/testing.rdoc +18 -9
  11. data/doc/transactions.rdoc +41 -1
  12. data/lib/sequel/adapters/ado.rb +28 -17
  13. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  14. data/lib/sequel/adapters/amalgalite.rb +11 -7
  15. data/lib/sequel/adapters/db2.rb +122 -70
  16. data/lib/sequel/adapters/dbi.rb +15 -15
  17. data/lib/sequel/adapters/do.rb +5 -36
  18. data/lib/sequel/adapters/do/mysql.rb +0 -5
  19. data/lib/sequel/adapters/do/postgres.rb +0 -5
  20. data/lib/sequel/adapters/do/sqlite.rb +0 -5
  21. data/lib/sequel/adapters/firebird.rb +3 -6
  22. data/lib/sequel/adapters/ibmdb.rb +24 -16
  23. data/lib/sequel/adapters/informix.rb +2 -4
  24. data/lib/sequel/adapters/jdbc.rb +47 -11
  25. data/lib/sequel/adapters/jdbc/as400.rb +5 -24
  26. data/lib/sequel/adapters/jdbc/db2.rb +0 -5
  27. data/lib/sequel/adapters/jdbc/derby.rb +217 -0
  28. data/lib/sequel/adapters/jdbc/firebird.rb +0 -5
  29. data/lib/sequel/adapters/jdbc/h2.rb +10 -12
  30. data/lib/sequel/adapters/jdbc/hsqldb.rb +166 -0
  31. data/lib/sequel/adapters/jdbc/informix.rb +0 -5
  32. data/lib/sequel/adapters/jdbc/jtds.rb +0 -5
  33. data/lib/sequel/adapters/jdbc/mysql.rb +0 -10
  34. data/lib/sequel/adapters/jdbc/oracle.rb +70 -3
  35. data/lib/sequel/adapters/jdbc/postgresql.rb +0 -11
  36. data/lib/sequel/adapters/jdbc/sqlite.rb +0 -5
  37. data/lib/sequel/adapters/jdbc/sqlserver.rb +0 -5
  38. data/lib/sequel/adapters/jdbc/transactions.rb +56 -7
  39. data/lib/sequel/adapters/mock.rb +315 -0
  40. data/lib/sequel/adapters/mysql.rb +64 -51
  41. data/lib/sequel/adapters/mysql2.rb +15 -9
  42. data/lib/sequel/adapters/odbc.rb +13 -6
  43. data/lib/sequel/adapters/odbc/db2.rb +0 -4
  44. data/lib/sequel/adapters/odbc/mssql.rb +0 -5
  45. data/lib/sequel/adapters/openbase.rb +2 -4
  46. data/lib/sequel/adapters/oracle.rb +333 -51
  47. data/lib/sequel/adapters/postgres.rb +80 -27
  48. data/lib/sequel/adapters/shared/access.rb +0 -6
  49. data/lib/sequel/adapters/shared/db2.rb +13 -15
  50. data/lib/sequel/adapters/shared/firebird.rb +6 -6
  51. data/lib/sequel/adapters/shared/mssql.rb +23 -18
  52. data/lib/sequel/adapters/shared/mysql.rb +6 -6
  53. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +6 -0
  54. data/lib/sequel/adapters/shared/oracle.rb +185 -30
  55. data/lib/sequel/adapters/shared/postgres.rb +35 -18
  56. data/lib/sequel/adapters/shared/progress.rb +0 -6
  57. data/lib/sequel/adapters/shared/sqlite.rb +116 -37
  58. data/lib/sequel/adapters/sqlite.rb +16 -8
  59. data/lib/sequel/adapters/swift.rb +5 -5
  60. data/lib/sequel/adapters/swift/mysql.rb +0 -5
  61. data/lib/sequel/adapters/swift/postgres.rb +0 -5
  62. data/lib/sequel/adapters/swift/sqlite.rb +6 -4
  63. data/lib/sequel/adapters/tinytds.rb +13 -10
  64. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +8 -0
  65. data/lib/sequel/core.rb +40 -0
  66. data/lib/sequel/database/connecting.rb +1 -2
  67. data/lib/sequel/database/dataset.rb +3 -3
  68. data/lib/sequel/database/dataset_defaults.rb +58 -0
  69. data/lib/sequel/database/misc.rb +62 -2
  70. data/lib/sequel/database/query.rb +113 -49
  71. data/lib/sequel/database/schema_methods.rb +7 -2
  72. data/lib/sequel/dataset/actions.rb +37 -19
  73. data/lib/sequel/dataset/features.rb +24 -0
  74. data/lib/sequel/dataset/graph.rb +7 -6
  75. data/lib/sequel/dataset/misc.rb +11 -3
  76. data/lib/sequel/dataset/mutation.rb +2 -3
  77. data/lib/sequel/dataset/prepared_statements.rb +6 -4
  78. data/lib/sequel/dataset/query.rb +46 -15
  79. data/lib/sequel/dataset/sql.rb +28 -4
  80. data/lib/sequel/extensions/named_timezones.rb +5 -0
  81. data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
  82. data/lib/sequel/model.rb +2 -1
  83. data/lib/sequel/model/associations.rb +115 -33
  84. data/lib/sequel/model/base.rb +91 -31
  85. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  86. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  87. data/lib/sequel/plugins/force_encoding.rb +6 -6
  88. data/lib/sequel/plugins/identity_map.rb +1 -1
  89. data/lib/sequel/plugins/many_through_many.rb +6 -10
  90. data/lib/sequel/plugins/prepared_statements.rb +12 -1
  91. data/lib/sequel/plugins/prepared_statements_associations.rb +1 -1
  92. data/lib/sequel/plugins/rcte_tree.rb +29 -15
  93. data/lib/sequel/plugins/serialization.rb +6 -1
  94. data/lib/sequel/plugins/sharding.rb +0 -5
  95. data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
  96. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  97. data/lib/sequel/plugins/update_primary_key.rb +1 -1
  98. data/lib/sequel/timezones.rb +42 -42
  99. data/lib/sequel/version.rb +1 -1
  100. data/spec/adapters/mssql_spec.rb +29 -29
  101. data/spec/adapters/mysql_spec.rb +86 -104
  102. data/spec/adapters/oracle_spec.rb +48 -76
  103. data/spec/adapters/postgres_spec.rb +98 -33
  104. data/spec/adapters/spec_helper.rb +0 -5
  105. data/spec/adapters/sqlite_spec.rb +24 -21
  106. data/spec/core/connection_pool_spec.rb +9 -15
  107. data/spec/core/core_sql_spec.rb +20 -31
  108. data/spec/core/database_spec.rb +491 -227
  109. data/spec/core/dataset_spec.rb +638 -1051
  110. data/spec/core/expression_filters_spec.rb +0 -1
  111. data/spec/core/mock_adapter_spec.rb +378 -0
  112. data/spec/core/object_graph_spec.rb +48 -114
  113. data/spec/core/schema_generator_spec.rb +3 -3
  114. data/spec/core/schema_spec.rb +51 -114
  115. data/spec/core/spec_helper.rb +3 -90
  116. data/spec/extensions/class_table_inheritance_spec.rb +1 -1
  117. data/spec/extensions/dataset_associations_spec.rb +199 -0
  118. data/spec/extensions/instance_hooks_spec.rb +71 -0
  119. data/spec/extensions/named_timezones_spec.rb +22 -2
  120. data/spec/extensions/nested_attributes_spec.rb +3 -0
  121. data/spec/extensions/schema_spec.rb +1 -1
  122. data/spec/extensions/serialization_modification_detection_spec.rb +1 -0
  123. data/spec/extensions/serialization_spec.rb +5 -8
  124. data/spec/extensions/spec_helper.rb +4 -0
  125. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  126. data/spec/extensions/typecast_on_load_spec.rb +1 -6
  127. data/spec/integration/associations_test.rb +123 -12
  128. data/spec/integration/dataset_test.rb +140 -47
  129. data/spec/integration/eager_loader_test.rb +19 -21
  130. data/spec/integration/model_test.rb +80 -1
  131. data/spec/integration/plugin_test.rb +179 -128
  132. data/spec/integration/prepared_statement_test.rb +92 -91
  133. data/spec/integration/schema_test.rb +42 -23
  134. data/spec/integration/spec_helper.rb +25 -31
  135. data/spec/integration/timezone_test.rb +38 -12
  136. data/spec/integration/transaction_test.rb +161 -34
  137. data/spec/integration/type_test.rb +3 -3
  138. data/spec/model/association_reflection_spec.rb +83 -7
  139. data/spec/model/associations_spec.rb +393 -676
  140. data/spec/model/base_spec.rb +186 -116
  141. data/spec/model/dataset_methods_spec.rb +7 -27
  142. data/spec/model/eager_loading_spec.rb +343 -867
  143. data/spec/model/hooks_spec.rb +160 -79
  144. data/spec/model/model_spec.rb +118 -165
  145. data/spec/model/plugins_spec.rb +7 -13
  146. data/spec/model/record_spec.rb +138 -207
  147. data/spec/model/spec_helper.rb +10 -73
  148. metadata +14 -8
@@ -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,20 +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'
518
+ @db.sqls.last.should == 'INSERT INTO "test5" ("value") VALUES (10) RETURNING "xid"'
515
519
  end
516
520
 
517
521
  specify "should have insert_select return nil if server_version < 80200" do
@@ -1093,4 +1097,65 @@ if POSTGRES_DB.adapter_scheme == :postgres && SEQUEL_POSTGRES_USES_PG && POSTGRE
1093
1097
  @db[:test_copy].select_order_map(:x).should == [1, 3]
1094
1098
  end
1095
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
1096
1161
  end
@@ -3,7 +3,6 @@ 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')
@@ -31,10 +30,6 @@ end
31
30
  end
32
31
  end
33
32
 
34
- def self.log_specify(message, &block)
35
- specify(message){log{instance_eval(&block)}}
36
- end
37
-
38
33
  def self.cspecify(message, *checked, &block)
39
34
  return specify(message, &block) if ENV['SEQUEL_NO_PENDING']
40
35
  pending = false