sequel_core 2.2.0 → 3.8.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.
- metadata +30 -101
- data/CHANGELOG +0 -1519
- data/COPYING +0 -19
- data/README +0 -313
- data/Rakefile +0 -158
- data/bin/sequel +0 -117
- data/doc/cheat_sheet.rdoc +0 -225
- data/doc/dataset_filtering.rdoc +0 -182
- data/lib/sequel_core.rb +0 -136
- data/lib/sequel_core/adapters/adapter_skeleton.rb +0 -68
- data/lib/sequel_core/adapters/ado.rb +0 -90
- data/lib/sequel_core/adapters/db2.rb +0 -160
- data/lib/sequel_core/adapters/dbi.rb +0 -127
- data/lib/sequel_core/adapters/informix.rb +0 -89
- data/lib/sequel_core/adapters/jdbc.rb +0 -110
- data/lib/sequel_core/adapters/mysql.rb +0 -486
- data/lib/sequel_core/adapters/odbc.rb +0 -167
- data/lib/sequel_core/adapters/odbc_mssql.rb +0 -106
- data/lib/sequel_core/adapters/openbase.rb +0 -76
- data/lib/sequel_core/adapters/oracle.rb +0 -182
- data/lib/sequel_core/adapters/postgres.rb +0 -560
- data/lib/sequel_core/adapters/sqlite.rb +0 -270
- data/lib/sequel_core/connection_pool.rb +0 -194
- data/lib/sequel_core/core_ext.rb +0 -197
- data/lib/sequel_core/core_sql.rb +0 -184
- data/lib/sequel_core/database.rb +0 -462
- data/lib/sequel_core/database/schema.rb +0 -156
- data/lib/sequel_core/dataset.rb +0 -457
- data/lib/sequel_core/dataset/callback.rb +0 -13
- data/lib/sequel_core/dataset/convenience.rb +0 -245
- data/lib/sequel_core/dataset/pagination.rb +0 -96
- data/lib/sequel_core/dataset/query.rb +0 -41
- data/lib/sequel_core/dataset/schema.rb +0 -15
- data/lib/sequel_core/dataset/sql.rb +0 -889
- data/lib/sequel_core/deprecated.rb +0 -26
- data/lib/sequel_core/exceptions.rb +0 -42
- data/lib/sequel_core/migration.rb +0 -187
- data/lib/sequel_core/object_graph.rb +0 -216
- data/lib/sequel_core/pretty_table.rb +0 -71
- data/lib/sequel_core/schema.rb +0 -2
- data/lib/sequel_core/schema/generator.rb +0 -239
- data/lib/sequel_core/schema/sql.rb +0 -326
- data/lib/sequel_core/sql.rb +0 -812
- data/lib/sequel_core/worker.rb +0 -68
- data/spec/adapters/informix_spec.rb +0 -96
- data/spec/adapters/mysql_spec.rb +0 -765
- data/spec/adapters/oracle_spec.rb +0 -222
- data/spec/adapters/postgres_spec.rb +0 -441
- data/spec/adapters/sqlite_spec.rb +0 -413
- data/spec/connection_pool_spec.rb +0 -363
- data/spec/core_ext_spec.rb +0 -156
- data/spec/core_sql_spec.rb +0 -427
- data/spec/database_spec.rb +0 -963
- data/spec/dataset_spec.rb +0 -2933
- data/spec/expression_filters_spec.rb +0 -316
- data/spec/migration_spec.rb +0 -261
- data/spec/object_graph_spec.rb +0 -230
- data/spec/pretty_table_spec.rb +0 -58
- data/spec/rcov.opts +0 -6
- data/spec/schema_generator_spec.rb +0 -122
- data/spec/schema_spec.rb +0 -422
- data/spec/spec.opts +0 -0
- data/spec/spec_config.rb +0 -7
- data/spec/spec_config.rb.example +0 -8
- data/spec/spec_helper.rb +0 -55
- data/spec/worker_spec.rb +0 -96
@@ -1,413 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), '../spec_helper.rb')
|
2
|
-
|
3
|
-
unless defined?(SQLITE_DB)
|
4
|
-
SQLITE_DB = Sequel.connect('sqlite:/')
|
5
|
-
end
|
6
|
-
|
7
|
-
SQLITE_DB.create_table :items do
|
8
|
-
integer :id, :primary_key => true, :auto_increment => true
|
9
|
-
text :name
|
10
|
-
float :value
|
11
|
-
end
|
12
|
-
SQLITE_DB.create_table :test2 do
|
13
|
-
text :name
|
14
|
-
integer :value
|
15
|
-
end
|
16
|
-
SQLITE_DB.create_table(:time) {timestamp :t}
|
17
|
-
|
18
|
-
context "An SQLite database" do
|
19
|
-
before do
|
20
|
-
@db = Sequel.connect('sqlite:/')
|
21
|
-
end
|
22
|
-
after do
|
23
|
-
@db.disconnect
|
24
|
-
end
|
25
|
-
|
26
|
-
specify "should provide a list of existing tables" do
|
27
|
-
@db.tables.should == []
|
28
|
-
|
29
|
-
@db.create_table :testing do
|
30
|
-
text :name
|
31
|
-
end
|
32
|
-
@db.tables.should include(:testing)
|
33
|
-
end
|
34
|
-
|
35
|
-
specify "should support getting pragma values" do
|
36
|
-
@db.pragma_get(:auto_vacuum).should == '0'
|
37
|
-
end
|
38
|
-
|
39
|
-
specify "should support setting pragma values" do
|
40
|
-
@db.pragma_set(:auto_vacuum, '1')
|
41
|
-
@db.pragma_get(:auto_vacuum).should == '1'
|
42
|
-
@db.pragma_set(:auto_vacuum, '2')
|
43
|
-
@db.pragma_get(:auto_vacuum).should == '2'
|
44
|
-
end
|
45
|
-
|
46
|
-
specify "should support getting and setting the auto_vacuum pragma" do
|
47
|
-
@db.auto_vacuum = :full
|
48
|
-
@db.auto_vacuum.should == :full
|
49
|
-
@db.auto_vacuum = :incremental
|
50
|
-
@db.auto_vacuum.should == :incremental
|
51
|
-
|
52
|
-
proc {@db.auto_vacuum = :invalid}.should raise_error(Sequel::Error)
|
53
|
-
end
|
54
|
-
|
55
|
-
specify "should support getting and setting the synchronous pragma" do
|
56
|
-
@db.synchronous = :off
|
57
|
-
@db.synchronous.should == :off
|
58
|
-
@db.synchronous = :normal
|
59
|
-
@db.synchronous.should == :normal
|
60
|
-
@db.synchronous = :full
|
61
|
-
@db.synchronous.should == :full
|
62
|
-
|
63
|
-
proc {@db.synchronous = :invalid}.should raise_error(Sequel::Error)
|
64
|
-
end
|
65
|
-
|
66
|
-
specify "should support getting and setting the temp_store pragma" do
|
67
|
-
@db.temp_store = :default
|
68
|
-
@db.temp_store.should == :default
|
69
|
-
@db.temp_store = :file
|
70
|
-
@db.temp_store.should == :file
|
71
|
-
@db.temp_store = :memory
|
72
|
-
@db.temp_store.should == :memory
|
73
|
-
|
74
|
-
proc {@db.temp_store = :invalid}.should raise_error(Sequel::Error)
|
75
|
-
end
|
76
|
-
|
77
|
-
specify "should be able to execute multiple statements at once" do
|
78
|
-
@db.create_table :t do
|
79
|
-
text :name
|
80
|
-
end
|
81
|
-
|
82
|
-
@db << "insert into t (name) values ('abc');insert into t (name) values ('def')"
|
83
|
-
|
84
|
-
@db[:t].count.should == 2
|
85
|
-
|
86
|
-
@db[:t].order(:name).map(:name).should == ['abc', 'def']
|
87
|
-
end
|
88
|
-
|
89
|
-
specify "should be able to execute transactions" do
|
90
|
-
@db.transaction do
|
91
|
-
@db.create_table(:t) {text :name}
|
92
|
-
end
|
93
|
-
|
94
|
-
@db.tables.should == [:t]
|
95
|
-
|
96
|
-
proc {@db.transaction do
|
97
|
-
@db.create_table(:u) {text :name}
|
98
|
-
raise ArgumentError
|
99
|
-
end}.should raise_error(ArgumentError)
|
100
|
-
# no commit
|
101
|
-
@db.tables.should == [:t]
|
102
|
-
|
103
|
-
proc {@db.transaction do
|
104
|
-
@db.create_table(:v) {text :name}
|
105
|
-
raise Sequel::Error::Rollback
|
106
|
-
end}.should_not raise_error
|
107
|
-
# no commit
|
108
|
-
@db.tables.should == [:t]
|
109
|
-
end
|
110
|
-
|
111
|
-
specify "should support nested transactions" do
|
112
|
-
@db.transaction do
|
113
|
-
@db.transaction do
|
114
|
-
@db.create_table(:t) {text :name}
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
@db.tables.should == [:t]
|
119
|
-
|
120
|
-
proc {@db.transaction do
|
121
|
-
@db.create_table(:v) {text :name}
|
122
|
-
@db.transaction do
|
123
|
-
raise Sequel::Error::Rollback # should roll back the top-level transaction
|
124
|
-
end
|
125
|
-
end}.should_not raise_error
|
126
|
-
# no commit
|
127
|
-
@db.tables.should == [:t]
|
128
|
-
end
|
129
|
-
|
130
|
-
specify "should handle returning inside of transaction by committing" do
|
131
|
-
@db.create_table(:items){text :name}
|
132
|
-
def @db.ret_commit
|
133
|
-
transaction do
|
134
|
-
self[:items] << {:name => 'abc'}
|
135
|
-
return
|
136
|
-
self[:items] << {:name => 'd'}
|
137
|
-
end
|
138
|
-
end
|
139
|
-
@db[:items].count.should == 0
|
140
|
-
@db.ret_commit
|
141
|
-
@db[:items].count.should == 1
|
142
|
-
@db.ret_commit
|
143
|
-
@db[:items].count.should == 2
|
144
|
-
proc do
|
145
|
-
@db.transaction do
|
146
|
-
raise Interrupt, 'asdf'
|
147
|
-
end
|
148
|
-
end.should raise_error(Interrupt)
|
149
|
-
|
150
|
-
@db[:items].count.should == 2
|
151
|
-
end
|
152
|
-
|
153
|
-
specify "should provide disconnect functionality" do
|
154
|
-
@db.tables
|
155
|
-
@db.pool.size.should == 1
|
156
|
-
@db.disconnect
|
157
|
-
@db.pool.size.should == 0
|
158
|
-
end
|
159
|
-
|
160
|
-
specify "should support timestamps" do
|
161
|
-
t1 = Time.at(Time.now.to_i) #normalize time
|
162
|
-
|
163
|
-
SQLITE_DB[:time] << {:t => t1}
|
164
|
-
SQLITE_DB[:time].first[:t].should == t1
|
165
|
-
end
|
166
|
-
|
167
|
-
specify "should support sequential primary keys" do
|
168
|
-
@db.create_table!(:with_pk) {primary_key :id; text :name}
|
169
|
-
@db[:with_pk] << {:name => 'abc'}
|
170
|
-
@db[:with_pk] << {:name => 'def'}
|
171
|
-
@db[:with_pk] << {:name => 'ghi'}
|
172
|
-
@db[:with_pk].order(:name).all.should == [
|
173
|
-
{:id => 1, :name => 'abc'},
|
174
|
-
{:id => 2, :name => 'def'},
|
175
|
-
{:id => 3, :name => 'ghi'}
|
176
|
-
]
|
177
|
-
end
|
178
|
-
|
179
|
-
specify "should catch invalid SQL errors and raise them as Error::InvalidStatement" do
|
180
|
-
proc {@db.execute 'blah blah'}.should raise_error(
|
181
|
-
Sequel::Error::InvalidStatement, "blah blah\r\nnear \"blah\": syntax error")
|
182
|
-
|
183
|
-
proc {@db.execute_insert 'blah blah'}.should raise_error(
|
184
|
-
Sequel::Error::InvalidStatement, "blah blah\r\nnear \"blah\": syntax error")
|
185
|
-
|
186
|
-
proc {@db.execute_select 'blah blah'}.should raise_error(
|
187
|
-
Sequel::Error::InvalidStatement, "blah blah\r\nnear \"blah\": syntax error")
|
188
|
-
|
189
|
-
proc {@db.single_value 'blah blah'}.should raise_error(
|
190
|
-
Sequel::Error::InvalidStatement, "blah blah\r\nnear \"blah\": syntax error")
|
191
|
-
end
|
192
|
-
|
193
|
-
specify "should not swallow non-SQLite based exceptions" do
|
194
|
-
proc {@db.pool.hold{raise Interrupt, "test"}}.should raise_error(Interrupt)
|
195
|
-
end
|
196
|
-
|
197
|
-
specify "should correctly parse the schema" do
|
198
|
-
@db.create_table(:time) {timestamp :t}
|
199
|
-
@db.schema(:time, :reload=>true).should == [[:t, {:type=>:datetime, :allow_null=>true, :max_chars=>nil, :default=>nil, :db_type=>"timestamp", :numeric_precision=>nil, :primary_key=>false}]]
|
200
|
-
end
|
201
|
-
|
202
|
-
specify "should get the schema all database tables if no table name is used" do
|
203
|
-
@db.create_table(:time) {timestamp :t}
|
204
|
-
@db.schema(:time, :reload=>true).should == @db.schema(nil, :reload=>true)[:time]
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
context "An SQLite dataset" do
|
209
|
-
setup do
|
210
|
-
@d = SQLITE_DB[:items]
|
211
|
-
@d.delete # remove all records
|
212
|
-
end
|
213
|
-
|
214
|
-
specify "should return the correct records" do
|
215
|
-
@d.to_a.should == []
|
216
|
-
@d << {:name => 'abc', :value => 1.23}
|
217
|
-
@d << {:name => 'abc', :value => 4.56}
|
218
|
-
@d << {:name => 'def', :value => 7.89}
|
219
|
-
@d.select(:name, :value).to_a.sort_by {|h| h[:value]}.should == [
|
220
|
-
{:name => 'abc', :value => 1.23},
|
221
|
-
{:name => 'abc', :value => 4.56},
|
222
|
-
{:name => 'def', :value => 7.89}
|
223
|
-
]
|
224
|
-
end
|
225
|
-
|
226
|
-
specify "should return the correct record count" do
|
227
|
-
@d.count.should == 0
|
228
|
-
@d << {:name => 'abc', :value => 1.23}
|
229
|
-
@d << {:name => 'abc', :value => 4.56}
|
230
|
-
@d << {:name => 'def', :value => 7.89}
|
231
|
-
@d.count.should == 3
|
232
|
-
end
|
233
|
-
|
234
|
-
specify "should return the last inserted id when inserting records" do
|
235
|
-
id = @d << {:name => 'abc', :value => 1.23}
|
236
|
-
id.should == @d.first[:id]
|
237
|
-
end
|
238
|
-
|
239
|
-
specify "should update records correctly" do
|
240
|
-
@d << {:name => 'abc', :value => 1.23}
|
241
|
-
@d << {:name => 'abc', :value => 4.56}
|
242
|
-
@d << {:name => 'def', :value => 7.89}
|
243
|
-
@d.filter(:name => 'abc').update(:value => 5.3)
|
244
|
-
|
245
|
-
# the third record should stay the same
|
246
|
-
@d[:name => 'def'][:value].should == 7.89
|
247
|
-
@d.filter(:value => 5.3).count.should == 2
|
248
|
-
end
|
249
|
-
|
250
|
-
specify "should delete records correctly" do
|
251
|
-
@d << {:name => 'abc', :value => 1.23}
|
252
|
-
@d << {:name => 'abc', :value => 4.56}
|
253
|
-
@d << {:name => 'def', :value => 7.89}
|
254
|
-
@d.filter(:name => 'abc').delete
|
255
|
-
|
256
|
-
@d.count.should == 1
|
257
|
-
@d.first[:name].should == 'def'
|
258
|
-
end
|
259
|
-
|
260
|
-
specify "should handle string pattern matches correctly" do
|
261
|
-
@d.literal(:x.like('a')).should == "(x LIKE 'a')"
|
262
|
-
@d.literal(~:x.like('a')).should == "NOT (x LIKE 'a')"
|
263
|
-
@d.literal(:x.ilike('a')).should == "(x LIKE 'a')"
|
264
|
-
@d.literal(~:x.ilike('a')).should == "NOT (x LIKE 'a')"
|
265
|
-
end
|
266
|
-
|
267
|
-
specify "should raise errors if given a regexp pattern match" do
|
268
|
-
proc{@d.literal(:x.like(/a/))}.should raise_error(Sequel::Error)
|
269
|
-
proc{@d.literal(~:x.like(/a/))}.should raise_error(Sequel::Error)
|
270
|
-
proc{@d.literal(:x.like(/a/i))}.should raise_error(Sequel::Error)
|
271
|
-
proc{@d.literal(~:x.like(/a/i))}.should raise_error(Sequel::Error)
|
272
|
-
end
|
273
|
-
end
|
274
|
-
|
275
|
-
context "An SQLite dataset" do
|
276
|
-
setup do
|
277
|
-
@d = SQLITE_DB[:items]
|
278
|
-
@d.delete # remove all records
|
279
|
-
@d << {:name => 'abc', :value => 1.23}
|
280
|
-
@d << {:name => 'def', :value => 4.56}
|
281
|
-
@d << {:name => 'ghi', :value => 7.89}
|
282
|
-
end
|
283
|
-
|
284
|
-
specify "should correctly return avg" do
|
285
|
-
@d.avg(:value).should == ((1.23 + 4.56 + 7.89) / 3).to_s
|
286
|
-
end
|
287
|
-
|
288
|
-
specify "should correctly return sum" do
|
289
|
-
@d.sum(:value).should == (1.23 + 4.56 + 7.89).to_s
|
290
|
-
end
|
291
|
-
|
292
|
-
specify "should correctly return max" do
|
293
|
-
@d.max(:value).should == 7.89.to_s
|
294
|
-
end
|
295
|
-
|
296
|
-
specify "should correctly return min" do
|
297
|
-
@d.min(:value).should == 1.23.to_s
|
298
|
-
end
|
299
|
-
end
|
300
|
-
|
301
|
-
context "SQLite::Dataset#delete" do
|
302
|
-
setup do
|
303
|
-
@d = SQLITE_DB[:items]
|
304
|
-
@d.delete # remove all records
|
305
|
-
@d << {:name => 'abc', :value => 1.23}
|
306
|
-
@d << {:name => 'def', :value => 4.56}
|
307
|
-
@d << {:name => 'ghi', :value => 7.89}
|
308
|
-
end
|
309
|
-
|
310
|
-
specify "should return the number of records affected when filtered" do
|
311
|
-
@d.count.should == 3
|
312
|
-
@d.filter {:value < 3}.delete.should == 1
|
313
|
-
@d.count.should == 2
|
314
|
-
|
315
|
-
@d.filter {:value < 3}.delete.should == 0
|
316
|
-
@d.count.should == 2
|
317
|
-
end
|
318
|
-
|
319
|
-
specify "should return the number of records affected when unfiltered" do
|
320
|
-
@d.count.should == 3
|
321
|
-
@d.delete.should == 3
|
322
|
-
@d.count.should == 0
|
323
|
-
|
324
|
-
@d.delete.should == 0
|
325
|
-
end
|
326
|
-
end
|
327
|
-
|
328
|
-
context "SQLite::Dataset#update" do
|
329
|
-
setup do
|
330
|
-
@d = SQLITE_DB[:items]
|
331
|
-
@d.delete # remove all records
|
332
|
-
@d << {:name => 'abc', :value => 1.23}
|
333
|
-
@d << {:name => 'def', :value => 4.56}
|
334
|
-
@d << {:name => 'ghi', :value => 7.89}
|
335
|
-
end
|
336
|
-
|
337
|
-
specify "should return the number of records affected" do
|
338
|
-
@d.filter(:name => 'abc').update(:value => 2).should == 1
|
339
|
-
|
340
|
-
@d.update(:value => 10).should == 3
|
341
|
-
|
342
|
-
@d.filter(:name => 'xxx').update(:value => 23).should == 0
|
343
|
-
end
|
344
|
-
end
|
345
|
-
|
346
|
-
context "SQLite dataset" do
|
347
|
-
setup do
|
348
|
-
SQLITE_DB.create_table :test do
|
349
|
-
integer :id, :primary_key => true, :auto_increment => true
|
350
|
-
text :name
|
351
|
-
float :value
|
352
|
-
end
|
353
|
-
|
354
|
-
@d = SQLITE_DB[:items]
|
355
|
-
@d.delete # remove all records
|
356
|
-
@d << {:name => 'abc', :value => 1.23}
|
357
|
-
@d << {:name => 'def', :value => 4.56}
|
358
|
-
@d << {:name => 'ghi', :value => 7.89}
|
359
|
-
end
|
360
|
-
|
361
|
-
teardown do
|
362
|
-
SQLITE_DB.drop_table :test
|
363
|
-
end
|
364
|
-
|
365
|
-
specify "should be able to insert from a subquery" do
|
366
|
-
SQLITE_DB[:test] << @d
|
367
|
-
SQLITE_DB[:test].count.should == 3
|
368
|
-
SQLITE_DB[:test].select(:name, :value).order(:value).to_a.should == \
|
369
|
-
@d.select(:name, :value).order(:value).to_a
|
370
|
-
end
|
371
|
-
end
|
372
|
-
|
373
|
-
context "A SQLite database" do
|
374
|
-
setup do
|
375
|
-
@db = SQLITE_DB
|
376
|
-
@db.create_table! :test2 do
|
377
|
-
text :name
|
378
|
-
integer :value
|
379
|
-
end
|
380
|
-
end
|
381
|
-
|
382
|
-
specify "should support add_column operations" do
|
383
|
-
@db.add_column :test2, :xyz, :text
|
384
|
-
|
385
|
-
@db[:test2].columns.should == [:name, :value, :xyz]
|
386
|
-
@db[:test2] << {:name => 'mmm', :value => 111, :xyz=>'000'}
|
387
|
-
@db[:test2].first.should == {:name => 'mmm', :value => 111, :xyz=>'000'}
|
388
|
-
end
|
389
|
-
|
390
|
-
specify "should support drop_column operations" do
|
391
|
-
@db.drop_column :test2, :value
|
392
|
-
@db[:test2].columns.should == [:name]
|
393
|
-
@db[:test2] << {:name => 'mmm'}
|
394
|
-
@db[:test2].first.should == {:name => 'mmm'}
|
395
|
-
end
|
396
|
-
|
397
|
-
specify "should not support rename_column operations" do
|
398
|
-
proc {@db.rename_column :test2, :value, :zyx}.should raise_error(Sequel::Error)
|
399
|
-
end
|
400
|
-
|
401
|
-
specify "should not support set_column_type operations" do
|
402
|
-
proc {@db.set_column_type :test2, :value, :integer}.should raise_error(Sequel::Error)
|
403
|
-
end
|
404
|
-
|
405
|
-
specify "should support add_index" do
|
406
|
-
@db.add_index :test2, :value, :unique => true
|
407
|
-
@db.add_index :test2, [:name, :value]
|
408
|
-
end
|
409
|
-
|
410
|
-
specify "should not support drop_index" do
|
411
|
-
proc {@db.drop_index :test2, :value}.should raise_error(Sequel::Error)
|
412
|
-
end
|
413
|
-
end
|
@@ -1,363 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
-
CONNECTION_POOL_DEFAULTS = {:pool_timeout=>5, :pool_sleep_time=>0.001,
|
3
|
-
:pool_reuse_connections=>:allow, :pool_convert_exceptions=>true, :max_connections=>4}
|
4
|
-
|
5
|
-
context "An empty ConnectionPool" do
|
6
|
-
setup do
|
7
|
-
@cpool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS)
|
8
|
-
end
|
9
|
-
|
10
|
-
specify "should have no available connections" do
|
11
|
-
@cpool.available_connections.should == []
|
12
|
-
end
|
13
|
-
|
14
|
-
specify "should have no allocated connections" do
|
15
|
-
@cpool.allocated.should == {}
|
16
|
-
end
|
17
|
-
|
18
|
-
specify "should have a created_count of zero" do
|
19
|
-
@cpool.created_count.should == 0
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
context "A connection pool handling connections" do
|
24
|
-
setup do
|
25
|
-
@max_size = 2
|
26
|
-
@cpool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>@max_size)) {:got_connection}
|
27
|
-
end
|
28
|
-
|
29
|
-
specify "#hold should increment #created_count" do
|
30
|
-
@cpool.hold do
|
31
|
-
@cpool.created_count.should == 1
|
32
|
-
@cpool.hold {@cpool.hold {@cpool.created_count.should == 1}}
|
33
|
-
Thread.new{@cpool.hold {@cpool.created_count.should == 2}}.join
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
specify "#hold should add the connection to the #allocated array" do
|
38
|
-
@cpool.hold do
|
39
|
-
@cpool.allocated.size.should == 1
|
40
|
-
|
41
|
-
@cpool.allocated.should == {Thread.current=>:got_connection}
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
specify "#hold should yield a new connection" do
|
46
|
-
@cpool.hold {|conn| conn.should == :got_connection}
|
47
|
-
end
|
48
|
-
|
49
|
-
specify "a connection should be de-allocated after it has been used in #hold" do
|
50
|
-
@cpool.hold {}
|
51
|
-
@cpool.allocated.size.should == 0
|
52
|
-
end
|
53
|
-
|
54
|
-
specify "#hold should return the value of its block" do
|
55
|
-
@cpool.hold {:block_return}.should == :block_return
|
56
|
-
end
|
57
|
-
|
58
|
-
specify "#make_new should not make more than max_size connections" do
|
59
|
-
@cpool.send(:make_new).should == :got_connection
|
60
|
-
@cpool.send(:make_new).should == :got_connection
|
61
|
-
@cpool.send(:make_new).should == nil
|
62
|
-
@cpool.created_count.should == 2
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
class DummyConnection
|
67
|
-
@@value = 0
|
68
|
-
def initialize
|
69
|
-
@@value += 1
|
70
|
-
end
|
71
|
-
|
72
|
-
def value
|
73
|
-
@@value
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
context "ConnectionPool#hold" do
|
78
|
-
setup do
|
79
|
-
@pool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS) {DummyConnection.new}
|
80
|
-
end
|
81
|
-
|
82
|
-
specify "should pass the result of the connection maker proc to the supplied block" do
|
83
|
-
res = nil
|
84
|
-
@pool.hold {|c| res = c}
|
85
|
-
res.should be_a_kind_of(DummyConnection)
|
86
|
-
res.value.should == 1
|
87
|
-
@pool.hold {|c| res = c}
|
88
|
-
res.should be_a_kind_of(DummyConnection)
|
89
|
-
res.value.should == 1 # the connection maker is invoked only once
|
90
|
-
end
|
91
|
-
|
92
|
-
specify "should be re-entrant by the same thread" do
|
93
|
-
cc = nil
|
94
|
-
@pool.hold {|c| @pool.hold {|c| @pool.hold {|c| cc = c}}}
|
95
|
-
cc.should be_a_kind_of(DummyConnection)
|
96
|
-
end
|
97
|
-
|
98
|
-
specify "should catch exceptions and reraise them" do
|
99
|
-
proc {@pool.hold {|c| c.foobar}}.should raise_error(NoMethodError)
|
100
|
-
end
|
101
|
-
|
102
|
-
specify "should handle Exception errors (normally not caught by rescue)" do
|
103
|
-
err = nil
|
104
|
-
begin
|
105
|
-
@pool.hold {raise Exception}
|
106
|
-
rescue => e
|
107
|
-
err = e
|
108
|
-
end
|
109
|
-
err.should be_a_kind_of(RuntimeError)
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
context "ConnectionPool#connection_proc" do
|
114
|
-
setup do
|
115
|
-
@pool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS)
|
116
|
-
end
|
117
|
-
|
118
|
-
specify "should be nil if no block is supplied to the pool" do
|
119
|
-
@pool.connection_proc.should be_nil
|
120
|
-
proc {@pool.hold {}}.should raise_error
|
121
|
-
end
|
122
|
-
|
123
|
-
specify "should be mutable" do
|
124
|
-
@pool.connection_proc = proc {'herro'}
|
125
|
-
res = nil
|
126
|
-
proc {@pool.hold {|c| res = c}}.should_not raise_error
|
127
|
-
res.should == 'herro'
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
context "A connection pool with a max size of 1" do
|
132
|
-
setup do
|
133
|
-
@invoked_count = 0
|
134
|
-
@pool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>1)) {@invoked_count += 1; 'herro'}
|
135
|
-
end
|
136
|
-
|
137
|
-
specify "should let only one thread access the connection at any time" do
|
138
|
-
cc,c1, c2 = nil
|
139
|
-
|
140
|
-
t1 = Thread.new {@pool.hold {|c| cc = c; c1 = c.dup; while c == 'herro';sleep 0.1;end}}
|
141
|
-
sleep 0.2
|
142
|
-
cc.should == 'herro'
|
143
|
-
c1.should == 'herro'
|
144
|
-
|
145
|
-
t2 = Thread.new {@pool.hold {|c| c2 = c.dup; while c == 'hello';sleep 0.1;end}}
|
146
|
-
sleep 0.2
|
147
|
-
|
148
|
-
# connection held by t1
|
149
|
-
t1.should be_alive
|
150
|
-
t2.should be_alive
|
151
|
-
|
152
|
-
cc.should == 'herro'
|
153
|
-
c1.should == 'herro'
|
154
|
-
c2.should be_nil
|
155
|
-
|
156
|
-
@pool.available_connections.should be_empty
|
157
|
-
@pool.allocated.should == {t1=>cc}
|
158
|
-
|
159
|
-
cc.gsub!('rr', 'll')
|
160
|
-
sleep 0.5
|
161
|
-
|
162
|
-
# connection held by t2
|
163
|
-
t1.should_not be_alive
|
164
|
-
t2.should be_alive
|
165
|
-
|
166
|
-
c2.should == 'hello'
|
167
|
-
|
168
|
-
@pool.available_connections.should be_empty
|
169
|
-
@pool.allocated.should == {t2=>cc}
|
170
|
-
|
171
|
-
cc.gsub!('ll', 'rr')
|
172
|
-
sleep 0.5
|
173
|
-
|
174
|
-
#connection released
|
175
|
-
t2.should_not be_alive
|
176
|
-
|
177
|
-
cc.should == 'herro'
|
178
|
-
|
179
|
-
@invoked_count.should == 1
|
180
|
-
@pool.size.should == 1
|
181
|
-
@pool.available_connections.should == [cc]
|
182
|
-
@pool.allocated.should be_empty
|
183
|
-
end
|
184
|
-
|
185
|
-
specify "should let the same thread reenter #hold" do
|
186
|
-
c1, c2, c3 = nil
|
187
|
-
@pool.hold do |c|
|
188
|
-
c1 = c
|
189
|
-
@pool.hold do |c|
|
190
|
-
c2 = c
|
191
|
-
@pool.hold do |c|
|
192
|
-
c3 = c
|
193
|
-
end
|
194
|
-
end
|
195
|
-
end
|
196
|
-
c1.should == 'herro'
|
197
|
-
c2.should == 'herro'
|
198
|
-
c3.should == 'herro'
|
199
|
-
|
200
|
-
@invoked_count.should == 1
|
201
|
-
@pool.size.should == 1
|
202
|
-
@pool.available_connections.size.should == 1
|
203
|
-
@pool.allocated.should be_empty
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
context "A connection pool with a max size of 5" do
|
208
|
-
setup do
|
209
|
-
@invoked_count = 0
|
210
|
-
@pool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>5)) {@invoked_count += 1}
|
211
|
-
end
|
212
|
-
|
213
|
-
specify "should let five threads simultaneously access separate connections" do
|
214
|
-
cc = {}
|
215
|
-
threads = []
|
216
|
-
stop = nil
|
217
|
-
|
218
|
-
5.times {|i| threads << Thread.new {@pool.hold {|c| cc[i] = c; while !stop;sleep 0.1;end}}; sleep 0.1}
|
219
|
-
sleep 0.2
|
220
|
-
threads.each {|t| t.should be_alive}
|
221
|
-
cc.size.should == 5
|
222
|
-
@invoked_count.should == 5
|
223
|
-
@pool.size.should == 5
|
224
|
-
@pool.available_connections.should be_empty
|
225
|
-
i = 0
|
226
|
-
h = {}
|
227
|
-
threads.each{|t| h[t] = (i+=1)}
|
228
|
-
@pool.allocated.should == h
|
229
|
-
|
230
|
-
threads[0].raise "your'e dead"
|
231
|
-
sleep 0.1
|
232
|
-
threads[3].raise "your'e dead too"
|
233
|
-
|
234
|
-
sleep 0.1
|
235
|
-
|
236
|
-
@pool.available_connections.should == [1, 4]
|
237
|
-
@pool.allocated.should == {threads[1]=>2, threads[2]=>3, threads[4]=>5}
|
238
|
-
|
239
|
-
stop = true
|
240
|
-
sleep 0.2
|
241
|
-
|
242
|
-
@pool.available_connections.size.should == 5
|
243
|
-
@pool.allocated.should be_empty
|
244
|
-
end
|
245
|
-
|
246
|
-
specify "should block threads until a connection becomes available" do
|
247
|
-
cc = {}
|
248
|
-
threads = []
|
249
|
-
stop = nil
|
250
|
-
|
251
|
-
5.times {|i| threads << Thread.new {@pool.hold {|c| cc[i] = c; while !stop;sleep 0.1;end}}; sleep 0.1}
|
252
|
-
sleep 0.2
|
253
|
-
threads.each {|t| t.should be_alive}
|
254
|
-
@pool.available_connections.should be_empty
|
255
|
-
|
256
|
-
3.times {|i| threads << Thread.new {@pool.hold {|c| cc[i + 5] = c}}}
|
257
|
-
|
258
|
-
sleep 0.2
|
259
|
-
threads[5].should be_alive
|
260
|
-
threads[6].should be_alive
|
261
|
-
threads[7].should be_alive
|
262
|
-
cc.size.should == 5
|
263
|
-
cc[5].should be_nil
|
264
|
-
cc[6].should be_nil
|
265
|
-
cc[7].should be_nil
|
266
|
-
|
267
|
-
stop = true
|
268
|
-
sleep 0.3
|
269
|
-
|
270
|
-
threads.each {|t| t.should_not be_alive}
|
271
|
-
|
272
|
-
@pool.size.should == 5
|
273
|
-
@invoked_count.should == 5
|
274
|
-
@pool.available_connections.size.should == 5
|
275
|
-
@pool.allocated.should be_empty
|
276
|
-
end
|
277
|
-
end
|
278
|
-
|
279
|
-
context "ConnectionPool#disconnect" do
|
280
|
-
setup do
|
281
|
-
@count = 0
|
282
|
-
@pool = Sequel::ConnectionPool.new(CONNECTION_POOL_DEFAULTS.merge(:max_connections=>5)) {{:id => @count += 1}}
|
283
|
-
end
|
284
|
-
|
285
|
-
specify "should invoke the given block for each available connection" do
|
286
|
-
threads = []
|
287
|
-
stop = nil
|
288
|
-
5.times {|i| threads << Thread.new {@pool.hold {|c| while !stop;sleep 0.1;end}}; sleep 0.1}
|
289
|
-
while @pool.size < 5
|
290
|
-
sleep 0.2
|
291
|
-
end
|
292
|
-
stop = true
|
293
|
-
sleep 1
|
294
|
-
threads.each {|t| t.join}
|
295
|
-
|
296
|
-
@pool.size.should == 5
|
297
|
-
@pool.available_connections.size.should == 5
|
298
|
-
@pool.available_connections.each {|c| c[:id].should_not be_nil}
|
299
|
-
conns = []
|
300
|
-
@pool.disconnect {|c| conns << c}
|
301
|
-
conns.size.should == 5
|
302
|
-
end
|
303
|
-
|
304
|
-
specify "should remove all available connections" do
|
305
|
-
threads = []
|
306
|
-
stop = nil
|
307
|
-
5.times {|i| threads << Thread.new {@pool.hold {|c| while !stop;sleep 0.1;end}}; sleep 0.1}
|
308
|
-
while @pool.size < 5
|
309
|
-
sleep 0.2
|
310
|
-
end
|
311
|
-
stop = true
|
312
|
-
sleep 1
|
313
|
-
threads.each {|t| t.join}
|
314
|
-
|
315
|
-
@pool.size.should == 5
|
316
|
-
@pool.disconnect
|
317
|
-
@pool.size.should == 0
|
318
|
-
end
|
319
|
-
|
320
|
-
specify "should not touch connections in use" do
|
321
|
-
threads = []
|
322
|
-
stop = nil
|
323
|
-
5.times {|i| threads << Thread.new {@pool.hold {|c| while !stop;sleep 0.1;end}}; sleep 0.1}
|
324
|
-
while @pool.size < 5
|
325
|
-
sleep 0.2
|
326
|
-
end
|
327
|
-
stop = true
|
328
|
-
sleep 1
|
329
|
-
threads.each {|t| t.join}
|
330
|
-
|
331
|
-
@pool.size.should == 5
|
332
|
-
|
333
|
-
@pool.hold do |conn|
|
334
|
-
@pool.available_connections.size.should == 4
|
335
|
-
@pool.available_connections.each {|c| c.should_not be(conn)}
|
336
|
-
conns = []
|
337
|
-
@pool.disconnect {|c| conns << c}
|
338
|
-
conns.size.should == 4
|
339
|
-
end
|
340
|
-
@pool.size.should == 1
|
341
|
-
end
|
342
|
-
end
|
343
|
-
|
344
|
-
context "SingleThreadedPool" do
|
345
|
-
setup do
|
346
|
-
@pool = Sequel::SingleThreadedPool.new(CONNECTION_POOL_DEFAULTS){1234}
|
347
|
-
end
|
348
|
-
|
349
|
-
specify "should provide a #hold method" do
|
350
|
-
conn = nil
|
351
|
-
@pool.hold {|c| conn = c}
|
352
|
-
conn.should == 1234
|
353
|
-
end
|
354
|
-
|
355
|
-
specify "should provide a #disconnect method" do
|
356
|
-
@pool.hold {|c|}
|
357
|
-
@pool.conn.should == 1234
|
358
|
-
conn = nil
|
359
|
-
@pool.disconnect {|c| conn = c}
|
360
|
-
conn.should == 1234
|
361
|
-
@pool.conn.should be_nil
|
362
|
-
end
|
363
|
-
end
|