sequel 2.2.0 → 2.3.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 (98) hide show
  1. data/CHANGELOG +1551 -4
  2. data/README +306 -19
  3. data/Rakefile +84 -56
  4. data/bin/sequel +106 -0
  5. data/doc/cheat_sheet.rdoc +225 -0
  6. data/doc/dataset_filtering.rdoc +182 -0
  7. data/lib/sequel_core.rb +136 -0
  8. data/lib/sequel_core/adapters/adapter_skeleton.rb +54 -0
  9. data/lib/sequel_core/adapters/ado.rb +80 -0
  10. data/lib/sequel_core/adapters/db2.rb +148 -0
  11. data/lib/sequel_core/adapters/dbi.rb +117 -0
  12. data/lib/sequel_core/adapters/informix.rb +78 -0
  13. data/lib/sequel_core/adapters/jdbc.rb +186 -0
  14. data/lib/sequel_core/adapters/jdbc/mysql.rb +55 -0
  15. data/lib/sequel_core/adapters/jdbc/postgresql.rb +66 -0
  16. data/lib/sequel_core/adapters/jdbc/sqlite.rb +47 -0
  17. data/lib/sequel_core/adapters/mysql.rb +231 -0
  18. data/lib/sequel_core/adapters/odbc.rb +155 -0
  19. data/lib/sequel_core/adapters/odbc_mssql.rb +106 -0
  20. data/lib/sequel_core/adapters/openbase.rb +64 -0
  21. data/lib/sequel_core/adapters/oracle.rb +170 -0
  22. data/lib/sequel_core/adapters/postgres.rb +199 -0
  23. data/lib/sequel_core/adapters/shared/mysql.rb +275 -0
  24. data/lib/sequel_core/adapters/shared/postgres.rb +351 -0
  25. data/lib/sequel_core/adapters/shared/sqlite.rb +146 -0
  26. data/lib/sequel_core/adapters/sqlite.rb +138 -0
  27. data/lib/sequel_core/connection_pool.rb +194 -0
  28. data/lib/sequel_core/core_ext.rb +203 -0
  29. data/lib/sequel_core/core_sql.rb +184 -0
  30. data/lib/sequel_core/database.rb +471 -0
  31. data/lib/sequel_core/database/schema.rb +156 -0
  32. data/lib/sequel_core/dataset.rb +457 -0
  33. data/lib/sequel_core/dataset/callback.rb +13 -0
  34. data/lib/sequel_core/dataset/convenience.rb +245 -0
  35. data/lib/sequel_core/dataset/pagination.rb +96 -0
  36. data/lib/sequel_core/dataset/query.rb +41 -0
  37. data/lib/sequel_core/dataset/schema.rb +15 -0
  38. data/lib/sequel_core/dataset/sql.rb +889 -0
  39. data/lib/sequel_core/deprecated.rb +26 -0
  40. data/lib/sequel_core/exceptions.rb +42 -0
  41. data/lib/sequel_core/migration.rb +187 -0
  42. data/lib/sequel_core/object_graph.rb +216 -0
  43. data/lib/sequel_core/pretty_table.rb +71 -0
  44. data/lib/sequel_core/schema.rb +2 -0
  45. data/lib/sequel_core/schema/generator.rb +239 -0
  46. data/lib/sequel_core/schema/sql.rb +325 -0
  47. data/lib/sequel_core/sql.rb +812 -0
  48. data/lib/sequel_model.rb +5 -1
  49. data/lib/sequel_model/association_reflection.rb +3 -8
  50. data/lib/sequel_model/base.rb +15 -10
  51. data/lib/sequel_model/inflector.rb +3 -5
  52. data/lib/sequel_model/plugins.rb +1 -1
  53. data/lib/sequel_model/record.rb +11 -3
  54. data/lib/sequel_model/schema.rb +4 -4
  55. data/lib/sequel_model/validations.rb +6 -1
  56. data/spec/adapters/ado_spec.rb +17 -0
  57. data/spec/adapters/informix_spec.rb +96 -0
  58. data/spec/adapters/mysql_spec.rb +764 -0
  59. data/spec/adapters/oracle_spec.rb +222 -0
  60. data/spec/adapters/postgres_spec.rb +441 -0
  61. data/spec/adapters/spec_helper.rb +7 -0
  62. data/spec/adapters/sqlite_spec.rb +400 -0
  63. data/spec/integration/dataset_test.rb +51 -0
  64. data/spec/integration/eager_loader_test.rb +702 -0
  65. data/spec/integration/schema_test.rb +102 -0
  66. data/spec/integration/spec_helper.rb +44 -0
  67. data/spec/integration/type_test.rb +43 -0
  68. data/spec/rcov.opts +2 -0
  69. data/spec/sequel_core/connection_pool_spec.rb +363 -0
  70. data/spec/sequel_core/core_ext_spec.rb +156 -0
  71. data/spec/sequel_core/core_sql_spec.rb +427 -0
  72. data/spec/sequel_core/database_spec.rb +964 -0
  73. data/spec/sequel_core/dataset_spec.rb +2977 -0
  74. data/spec/sequel_core/expression_filters_spec.rb +346 -0
  75. data/spec/sequel_core/migration_spec.rb +261 -0
  76. data/spec/sequel_core/object_graph_spec.rb +234 -0
  77. data/spec/sequel_core/pretty_table_spec.rb +58 -0
  78. data/spec/sequel_core/schema_generator_spec.rb +122 -0
  79. data/spec/sequel_core/schema_spec.rb +497 -0
  80. data/spec/sequel_core/spec_helper.rb +51 -0
  81. data/spec/{association_reflection_spec.rb → sequel_model/association_reflection_spec.rb} +6 -6
  82. data/spec/{associations_spec.rb → sequel_model/associations_spec.rb} +47 -18
  83. data/spec/{base_spec.rb → sequel_model/base_spec.rb} +2 -1
  84. data/spec/{caching_spec.rb → sequel_model/caching_spec.rb} +0 -0
  85. data/spec/{dataset_methods_spec.rb → sequel_model/dataset_methods_spec.rb} +13 -1
  86. data/spec/{eager_loading_spec.rb → sequel_model/eager_loading_spec.rb} +75 -14
  87. data/spec/{hooks_spec.rb → sequel_model/hooks_spec.rb} +4 -4
  88. data/spec/sequel_model/inflector_spec.rb +119 -0
  89. data/spec/{model_spec.rb → sequel_model/model_spec.rb} +30 -11
  90. data/spec/{plugins_spec.rb → sequel_model/plugins_spec.rb} +0 -0
  91. data/spec/{record_spec.rb → sequel_model/record_spec.rb} +47 -6
  92. data/spec/{schema_spec.rb → sequel_model/schema_spec.rb} +18 -4
  93. data/spec/{spec_helper.rb → sequel_model/spec_helper.rb} +3 -2
  94. data/spec/{validations_spec.rb → sequel_model/validations_spec.rb} +37 -17
  95. data/spec/spec_config.rb +9 -0
  96. data/spec/spec_config.rb.example +10 -0
  97. metadata +110 -37
  98. data/spec/inflector_spec.rb +0 -34
@@ -0,0 +1,102 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper.rb')
2
+
3
+ describe "Database schema parser" do
4
+ before do
5
+ INTEGRATION_DB.create_table!(:items){integer :number}
6
+ clear_sqls
7
+ end
8
+ after do
9
+ INTEGRATION_DB.drop_table(:items) if INTEGRATION_DB.table_exists?(:items)
10
+ end
11
+
12
+ specify "should be a hash with table_names as symbols" do
13
+ schema = INTEGRATION_DB.schema(nil, :reload=>true)
14
+ schema.should be_a_kind_of(Hash)
15
+ schema.should include(:items)
16
+ end
17
+
18
+ specify "should not issue an sql query if the schema has been loaded unless :reload is true" do
19
+ INTEGRATION_DB.schema(nil, :reload=>true)
20
+ clear_sqls
21
+ INTEGRATION_DB.schema
22
+ sqls_should_be
23
+ end
24
+
25
+ specify "should give the same result for a single table regardless of whether schema was called for a single table" do
26
+ INTEGRATION_DB.schema(:items, :reload=>true).should == INTEGRATION_DB.schema(nil, :reload=>true)[:items]
27
+ end
28
+
29
+ specify "should return the schema correctly" do
30
+ INTEGRATION_DB.create_table!(:items){integer :number}
31
+ schema = INTEGRATION_DB.schema(:items, :reload=>true)
32
+ schema.should be_a_kind_of(Array)
33
+ schema.length.should == 1
34
+ col = schema.first
35
+ col.should be_a_kind_of(Array)
36
+ col.length.should == 2
37
+ col.first.should == :number
38
+ col_info = col.last
39
+ col_info.should be_a_kind_of(Hash)
40
+ col_info[:type].should == :integer
41
+ clear_sqls
42
+ INTEGRATION_DB.schema(:items)
43
+ sqls_should_be
44
+ end
45
+ end
46
+
47
+ describe "Database schema modifiers" do
48
+ before do
49
+ INTEGRATION_DB.create_table!(:items){integer :number}
50
+ @ds = INTEGRATION_DB[:items]
51
+ @ds.insert([10])
52
+ clear_sqls
53
+ end
54
+ after do
55
+ INTEGRATION_DB.drop_table(:items) if INTEGRATION_DB.table_exists?(:items)
56
+ end
57
+
58
+ specify "should create tables correctly" do
59
+ INTEGRATION_DB.table_exists?(:items).should == true
60
+ INTEGRATION_DB.schema(:items, :reload=>true).map{|x| x.first}.should == [:number]
61
+ @ds.columns!.should == [:number]
62
+ end
63
+
64
+ specify "should add columns to tables correctly" do
65
+ INTEGRATION_DB.schema(:items, :reload=>true).map{|x| x.first}.should == [:number]
66
+ @ds.columns!.should == [:number]
67
+ INTEGRATION_DB.alter_table(:items){add_column :name, :text}
68
+ INTEGRATION_DB.schema(:items, :reload=>true).map{|x| x.first}.should == [:number, :name]
69
+ @ds.columns!.should == [:number, :name]
70
+ unless INTEGRATION_DB.url =~ /sqlite/
71
+ INTEGRATION_DB.alter_table(:items){add_primary_key :id}
72
+ INTEGRATION_DB.schema(:items, :reload=>true).map{|x| x.first}.should == [:number, :name, :id]
73
+ @ds.columns!.should == [:number, :name, :id]
74
+ unless INTEGRATION_DB.url =~ /mysql/
75
+ INTEGRATION_DB.alter_table(:items){add_foreign_key :item_id, :items}
76
+ INTEGRATION_DB.schema(:items, :reload=>true).map{|x| x.first}.should == [:number, :name, :id, :item_id]
77
+ @ds.columns!.should == [:number, :name, :id, :item_id]
78
+ end
79
+ end
80
+ end
81
+
82
+ specify "should remove columns from tables correctly" do
83
+ INTEGRATION_DB.create_table!(:items) do
84
+ primary_key :id
85
+ text :name
86
+ integer :number
87
+ foreign_key :item_id, :items
88
+ end
89
+ @ds.insert(:number=>10)
90
+ INTEGRATION_DB.schema(:items, :reload=>true).map{|x| x.first}.should == [:id, :name, :number, :item_id]
91
+ @ds.columns!.should == [:id, :name, :number, :item_id]
92
+ INTEGRATION_DB.drop_column(:items, :number)
93
+ INTEGRATION_DB.schema(:items, :reload=>true).map{|x| x.first}.should == [:id, :name, :item_id]
94
+ @ds.columns!.should == [:id, :name, :item_id]
95
+ INTEGRATION_DB.drop_column(:items, :name)
96
+ INTEGRATION_DB.schema(:items, :reload=>true).map{|x| x.first}.should == [:id, :item_id]
97
+ @ds.columns!.should == [:id, :item_id]
98
+ INTEGRATION_DB.drop_column(:items, :item_id)
99
+ INTEGRATION_DB.schema(:items, :reload=>true).map{|x| x.first}.should == [:id]
100
+ @ds.columns!.should == [:id]
101
+ end
102
+ end
@@ -0,0 +1,44 @@
1
+ require 'rubygems'
2
+ unless Object.const_defined?('Sequel')
3
+ $:.unshift(File.join(File.dirname(__FILE__), "../../lib/"))
4
+ require 'sequel'
5
+ end
6
+ require File.join(File.dirname(__FILE__), '../spec_config.rb')
7
+
8
+ $sqls = []
9
+ def clear_sqls
10
+ $sqls.clear
11
+ end
12
+
13
+ if defined?(INTEGRATION_DB) || defined?(INTEGRATION_URL) || ENV['SEQUEL_INTEGRATION_URL']
14
+ unless defined?(INTEGRATION_DB)
15
+ url = defined?(INTEGRATION_URL) ? INTEGRATION_URL : ENV['SEQUEL_INTEGRATION_URL']
16
+ INTEGRATION_DB = Sequel.connect(url)
17
+ end
18
+ class Spec::Example::ExampleGroup
19
+ def sqls_should_be(*args)
20
+ end
21
+ end
22
+ else
23
+ sql_logger = Object.new
24
+ def sql_logger.info(str)
25
+ $sqls << str
26
+ end
27
+ INTEGRATION_DB = Sequel.sqlite('', :loggers=>[sql_logger], :quote_identifiers=>false)
28
+ class Spec::Example::ExampleGroup
29
+ def sqls_should_be(*sqls)
30
+ sqls.zip($sqls).each do |should_be, is|
31
+ case should_be
32
+ when String
33
+ is.should == should_be
34
+ when Regexp
35
+ is.should =~ should_be
36
+ else
37
+ raise ArgumentError, "need String or RegExp"
38
+ end
39
+ end
40
+ $sqls.length.should == sqls.length
41
+ clear_sqls
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,43 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper.rb')
2
+
3
+ describe "Supported types" do
4
+ def create_items_table_with_column(name, type)
5
+ INTEGRATION_DB.create_table!(:items){column name, type}
6
+ INTEGRATION_DB[:items]
7
+ end
8
+
9
+ specify "should support NULL correctly" do
10
+ ds = create_items_table_with_column(:number, :integer)
11
+ ds.insert(:number => nil)
12
+ ds.all.should == [{:number=>nil}]
13
+ end
14
+
15
+ specify "should support integer type" do
16
+ ds = create_items_table_with_column(:number, :integer)
17
+ ds.insert(:number => 2)
18
+ ds.all.should == [{:number=>2}]
19
+ end
20
+
21
+ specify "should support varchar type" do
22
+ ds = create_items_table_with_column(:name, 'varchar(255)'.lit)
23
+ ds.insert(:name => 'Test User')
24
+ ds.all.should == [{:name=>'Test User'}]
25
+ end
26
+
27
+ specify "should support date type" do
28
+ ds = create_items_table_with_column(:dat, :date)
29
+ d = Date.today
30
+ ds.insert(:dat => d)
31
+ x = ds.first[:dat]
32
+ x = x.iso8601.to_date if Time === x
33
+ x.to_s.should == d.to_s
34
+ end
35
+
36
+ specify "should support time type" do
37
+ ds = create_items_table_with_column(:tim, :time)
38
+ t = Time.now
39
+ ds.insert(:tim => t)
40
+ x = ds.first[:tim]
41
+ [t.strftime('%H:%M:%S'), t.iso8601].should include(x.respond_to?(:strftime) ? x.strftime('%H:%M:%S') : x.to_s)
42
+ end
43
+ end
@@ -2,3 +2,5 @@
2
2
  gems
3
3
  --exclude
4
4
  spec
5
+ --exclude
6
+ 00*
@@ -0,0 +1,363 @@
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