rdbi 0.9.1 → 1.1.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.
- checksums.yaml +7 -0
- data/.gemtest +0 -0
- data/History.txt +13 -0
- data/Manifest.txt +28 -0
- data/{README.rdoc → README.txt} +9 -9
- data/Rakefile +39 -133
- data/lib/rdbi.rb +44 -32
- data/lib/rdbi/database.rb +61 -20
- data/lib/rdbi/driver.rb +4 -1
- data/lib/rdbi/pool.rb +10 -0
- data/lib/rdbi/result.rb +94 -123
- data/lib/rdbi/schema.rb +8 -1
- data/lib/rdbi/statement.rb +22 -3
- data/lib/rdbi/types.rb +2 -0
- data/rdbi.gemspec +2 -4
- data/test/helper.rb +29 -1
- data/test/test_database.rb +95 -6
- data/test/test_pool.rb +11 -2
- data/test/test_rdbi.rb +54 -1
- data/test/test_result.rb +129 -7
- data/test/test_statement.rb +1 -1
- data/test/test_util.rb +2 -4
- metadata +201 -137
- data/.document +0 -5
- data/VERSION +0 -1
data/lib/rdbi/types.rb
CHANGED
data/rdbi.gemspec
CHANGED
@@ -14,14 +14,12 @@ Gem::Specification.new do |s|
|
|
14
14
|
s.email = %q{erik@hollensbe.org}
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"LICENSE",
|
17
|
-
"README.
|
17
|
+
"README.txt"
|
18
18
|
]
|
19
19
|
s.files = [
|
20
|
-
".document",
|
21
20
|
"LICENSE",
|
22
|
-
"README.
|
21
|
+
"README.txt",
|
23
22
|
"Rakefile",
|
24
|
-
"VERSION",
|
25
23
|
"docs/external-api.pdf",
|
26
24
|
"docs/external-api.texi",
|
27
25
|
"lib/rdbi.rb",
|
data/test/helper.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
gem 'rdbi-driver-mock'
|
3
|
-
gem 'test-unit'
|
4
3
|
require 'test/unit'
|
5
4
|
|
6
5
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
@@ -8,6 +7,35 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
8
7
|
require 'rdbi'
|
9
8
|
require 'rdbi/driver/mock'
|
10
9
|
|
10
|
+
# -- Fake an exceptional statement handle
|
11
|
+
module FaultyDB
|
12
|
+
class Error < Exception; end
|
13
|
+
end
|
14
|
+
|
15
|
+
module RDBI
|
16
|
+
class Driver
|
17
|
+
class MockFaulty < RDBI::Driver
|
18
|
+
def initialize(*args)
|
19
|
+
super(MockFaulty::Database, *args)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class MockFaulty::Database < Mock::DBH
|
24
|
+
def new_statement(query)
|
25
|
+
MockFaulty::Statement.new(query, self)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class MockFaulty::Statement < Mock::STH
|
30
|
+
def execute(*binds)
|
31
|
+
raise ::FaultyDB::Error.new('Deadlocked, de-synchronized, corrupted, invalid, etc.')
|
32
|
+
end
|
33
|
+
alias :execute_modification :execute
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
|
11
39
|
class Test::Unit::TestCase
|
12
40
|
def mock_connect
|
13
41
|
RDBI.connect(:Mock, :username => 'foo', :password => 'bar')
|
data/test/test_database.rb
CHANGED
@@ -5,6 +5,10 @@ class TestDatabase < Test::Unit::TestCase
|
|
5
5
|
@dbh = mock_connect
|
6
6
|
end
|
7
7
|
|
8
|
+
def teardown
|
9
|
+
@dbh.disconnect
|
10
|
+
end
|
11
|
+
|
8
12
|
def assert_transaction(count)
|
9
13
|
in_transaction = @dbh.instance_variable_get("@in_transaction") ||
|
10
14
|
@dbh.instance_variable_get(:@in_transaction)
|
@@ -38,7 +42,7 @@ class TestDatabase < Test::Unit::TestCase
|
|
38
42
|
raise StandardError, "should call rollback"
|
39
43
|
end
|
40
44
|
|
41
|
-
assert_raises(StandardError
|
45
|
+
assert_raises(StandardError) do
|
42
46
|
@dbh.transaction do |dbh|
|
43
47
|
assert_transaction(1)
|
44
48
|
true
|
@@ -52,7 +56,7 @@ class TestDatabase < Test::Unit::TestCase
|
|
52
56
|
|
53
57
|
@dbh.next_action = proc { |*args| true }
|
54
58
|
|
55
|
-
assert_raises(StandardError
|
59
|
+
assert_raises(StandardError) do
|
56
60
|
@dbh.transaction do |dbh|
|
57
61
|
assert_transaction(1)
|
58
62
|
|
@@ -206,20 +210,52 @@ class TestDatabase < Test::Unit::TestCase
|
|
206
210
|
my_sth = nil
|
207
211
|
my_res = nil
|
208
212
|
|
213
|
+
# ordinary execution
|
209
214
|
@dbh.prepare("some statement") do |sth|
|
210
215
|
assert(sth)
|
211
216
|
assert_respond_to(sth, :execute)
|
212
217
|
res = sth.execute
|
213
218
|
assert(res)
|
214
219
|
my_sth = sth
|
220
|
+
assert(! my_sth.finished?)
|
215
221
|
end
|
216
222
|
|
217
223
|
assert(my_sth.finished?)
|
218
224
|
|
219
|
-
|
220
|
-
|
221
|
-
|
225
|
+
# and exceptional
|
226
|
+
begin
|
227
|
+
@dbh.prepare("some statement") do |sth|
|
228
|
+
assert(sth)
|
229
|
+
assert_respond_to(sth, :execute)
|
230
|
+
res = sth.execute
|
231
|
+
assert(res)
|
232
|
+
my_sth = sth
|
233
|
+
assert(! my_sth.finished?)
|
234
|
+
raise "Blam!"
|
235
|
+
end
|
236
|
+
rescue
|
222
237
|
end
|
238
|
+
|
239
|
+
assert(my_sth.finished?)
|
240
|
+
|
241
|
+
# Database#execute &block
|
242
|
+
|
243
|
+
my_res = nil
|
244
|
+
block_ret = @dbh.execute("some statement") do |res|
|
245
|
+
my_res = res
|
246
|
+
assert(res)
|
247
|
+
assert_kind_of(RDBI::Result, res)
|
248
|
+
"BLOCK RETURN"
|
249
|
+
end
|
250
|
+
|
251
|
+
assert_kind_of(RDBI::Result, my_res)
|
252
|
+
# Result#finish implies Statement#finish, nil'ing
|
253
|
+
assert(my_res.sth.nil?,
|
254
|
+
'Database#execute &p did not finish its Result')
|
255
|
+
assert(!block_ret.kind_of?(RDBI::Result),
|
256
|
+
'Database#execute &block wrongly returned its Result')
|
257
|
+
assert_equal("BLOCK RETURN", block_ret,
|
258
|
+
"Database#execute &block didn't return the return value of &block")
|
223
259
|
end
|
224
260
|
|
225
261
|
def test_09_statement_allocation
|
@@ -239,9 +275,62 @@ class TestDatabase < Test::Unit::TestCase
|
|
239
275
|
@dbh.disconnect
|
240
276
|
end
|
241
277
|
|
242
|
-
def
|
278
|
+
def test_10_execute_finish
|
279
|
+
@dbh.execute("SELECT 1") do |res|
|
280
|
+
# noop
|
281
|
+
end
|
282
|
+
assert(@dbh.last_statement.finished?,
|
283
|
+
"#execute() block did not finish implicit sth")
|
284
|
+
|
285
|
+
res = @dbh.execute("SELECT 2")
|
286
|
+
assert(!@dbh.last_statement.finished?,
|
287
|
+
"#execute() unexpectedly finished implicit sth")
|
288
|
+
assert_nothing_raised do
|
289
|
+
res.finish
|
290
|
+
@dbh.disconnect
|
291
|
+
end
|
292
|
+
|
293
|
+
@dbh = RDBI.connect(:MockFaulty, :user => 'u', :pass => 'p')
|
294
|
+
assert_raises(FaultyDB::Error) do
|
295
|
+
@dbh.execute("ignored") do |not_reached|
|
296
|
+
assert(false, "A block not supposed to be reached was executed")
|
297
|
+
end
|
298
|
+
end
|
299
|
+
assert(@dbh.last_statement.finished?,
|
300
|
+
"Failed execute() &block did not finish statement")
|
301
|
+
|
302
|
+
assert_raises(FaultyDB::Error) do
|
303
|
+
res = @dbh.execute("ignored")
|
304
|
+
res.finish # Not reached
|
305
|
+
end
|
306
|
+
assert(@dbh.last_statement.finished?,
|
307
|
+
"Failed execute() did not finish statement")
|
308
|
+
end
|
309
|
+
|
310
|
+
def test_11_execute_mod_finish
|
311
|
+
@dbh.execute_modification("DROP SCHEMA INFORMATION_SCHEMA")
|
312
|
+
assert(@dbh.last_statement.finished?,
|
313
|
+
"#execute_modification() did not finish implicit sth")
|
314
|
+
|
315
|
+
a = nil
|
316
|
+
@dbh.execute_modification("IGNORED!") do |*blah|
|
317
|
+
a = "Not nil - but this block is not executed"
|
318
|
+
end
|
319
|
+
|
320
|
+
assert(a.nil?, "#execute_modification() invoked a block unexpectedly")
|
321
|
+
assert(@dbh.last_statement.finished?,
|
322
|
+
"#execute_modification() &ignored_block did not finish implicit sth")
|
323
|
+
|
243
324
|
@dbh.disconnect
|
325
|
+
|
326
|
+
@dbh = RDBI.connect(:MockFaulty, :user => 'u', :pass => 'p')
|
327
|
+
assert_raises(FaultyDB::Error) do
|
328
|
+
count = @dbh.execute_modification("ignored")
|
329
|
+
end
|
330
|
+
assert(@dbh.last_statement.finished?,
|
331
|
+
"Failed execute_modification() did not finish statement")
|
244
332
|
end
|
333
|
+
|
245
334
|
end
|
246
335
|
|
247
336
|
# vim: syntax=ruby ts=2 et sw=2 sts=2
|
data/test/test_pool.rb
CHANGED
@@ -20,7 +20,7 @@ class TestPool < Test::Unit::TestCase
|
|
20
20
|
|
21
21
|
def test_03_pooling!
|
22
22
|
pool = create_pool(:test_03)
|
23
|
-
assert_raise(ArgumentError
|
23
|
+
assert_raise(ArgumentError) do
|
24
24
|
6.times do
|
25
25
|
RDBI::Pool[:test_03].add_connection
|
26
26
|
end
|
@@ -160,7 +160,7 @@ class TestPool < Test::Unit::TestCase
|
|
160
160
|
assert_kind_of(RDBI::Pool, pool)
|
161
161
|
end
|
162
162
|
|
163
|
-
|
163
|
+
assert_equal(10, count)
|
164
164
|
assert_respond_to(RDBI::Pool, :map)
|
165
165
|
|
166
166
|
pool = create_pool(:test_08)
|
@@ -182,6 +182,15 @@ class TestPool < Test::Unit::TestCase
|
|
182
182
|
|
183
183
|
assert_respond_to(pool, :map)
|
184
184
|
end
|
185
|
+
|
186
|
+
def test_09_alternative_connect_syntax
|
187
|
+
pool = RDBI::Pool.new("connections!", { :driver => :Mock, :database => ":memory:", :username => "foo" })
|
188
|
+
dbh = pool.get_dbh
|
189
|
+
assert(dbh)
|
190
|
+
assert_kind_of(RDBI::Database, dbh)
|
191
|
+
|
192
|
+
assert_equal([:Mock, { :database => ":memory:", :username => "foo" }], pool.instance_variable_get(:@connect_args))
|
193
|
+
end
|
185
194
|
end
|
186
195
|
|
187
196
|
# vim: syntax=ruby ts=2 et sw=2 sts=2
|
data/test/test_rdbi.rb
CHANGED
@@ -16,7 +16,7 @@ class TestRDBI < Test::Unit::TestCase
|
|
16
16
|
|
17
17
|
assert_raise(ArgumentError) { RDBI.connect(1, :user => :blah) }
|
18
18
|
|
19
|
-
|
19
|
+
assert_raise(ArgumentError) { dbh = RDBI.connect(:Mock) }
|
20
20
|
end
|
21
21
|
|
22
22
|
def test_02_last_dbh
|
@@ -63,6 +63,59 @@ class TestRDBI < Test::Unit::TestCase
|
|
63
63
|
dbh = RDBI.connect_cached(:Mock, :username => :foo, :pool_name => :test_05)
|
64
64
|
assert_equal(RDBI.pool(:test_05).handles[0], dbh)
|
65
65
|
end
|
66
|
+
|
67
|
+
def test_06_connect_block
|
68
|
+
my_dbh = nil
|
69
|
+
|
70
|
+
# Ordinary operation
|
71
|
+
RDBI.connect(:Mock, :username => :foo, :password => :bar) do |dbh|
|
72
|
+
assert(dbh)
|
73
|
+
assert_kind_of(RDBI::Database, dbh)
|
74
|
+
my_dbh = dbh
|
75
|
+
assert(my_dbh.connected?)
|
76
|
+
end
|
77
|
+
assert(! my_dbh.connected?)
|
78
|
+
|
79
|
+
# and exceptional operation
|
80
|
+
begin
|
81
|
+
RDBI.connect(:Mock, :username => :foo, :password => :bar) do |dbh|
|
82
|
+
assert(dbh)
|
83
|
+
assert_kind_of(RDBI::Database, dbh)
|
84
|
+
my_dbh = dbh
|
85
|
+
assert(my_dbh.connected?)
|
86
|
+
raise "Blam!"
|
87
|
+
end
|
88
|
+
rescue
|
89
|
+
end
|
90
|
+
assert(! my_dbh.connected?)
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_07_connect_cached_block
|
94
|
+
conn_args = [:Mock, {:username => :foo, :password => :bar}]
|
95
|
+
my_dbh = nil
|
96
|
+
|
97
|
+
# Ordinary operation
|
98
|
+
RDBI.connect_cached(*conn_args) do |dbh|
|
99
|
+
assert(dbh)
|
100
|
+
assert_kind_of(RDBI::Database, dbh)
|
101
|
+
my_dbh = dbh
|
102
|
+
assert(my_dbh.connected?)
|
103
|
+
end
|
104
|
+
assert(my_dbh.connected?)
|
105
|
+
|
106
|
+
# and exceptional operation
|
107
|
+
begin
|
108
|
+
RDBI.connect_cached(*conn_args) do |dbh|
|
109
|
+
assert(dbh)
|
110
|
+
assert_kind_of(RDBI::Database, dbh)
|
111
|
+
my_dbh = dbh
|
112
|
+
assert(my_dbh.connected?)
|
113
|
+
raise "Blam!"
|
114
|
+
end
|
115
|
+
rescue
|
116
|
+
end
|
117
|
+
assert(my_dbh.connected?)
|
118
|
+
end
|
66
119
|
end
|
67
120
|
|
68
121
|
# vim: syntax=ruby ts=2 et sw=2 sts=2
|
data/test/test_result.rb
CHANGED
@@ -15,21 +15,34 @@ class TestResult < Test::Unit::TestCase
|
|
15
15
|
|
16
16
|
def mock_result
|
17
17
|
names = [:zero, :one, :two]
|
18
|
-
res = RDBI::Result.new(
|
18
|
+
res = RDBI::Result.new(
|
19
|
+
@dbh.prepare("foo"),
|
20
|
+
[1],
|
21
|
+
generate_data,
|
22
|
+
RDBI::Schema.new((0..2).to_a.map { |x| RDBI::Column.new(names[x], :integer, :default) }),
|
23
|
+
{ :default => RDBI::Type.filterlist() }
|
24
|
+
)
|
19
25
|
end
|
20
26
|
|
21
27
|
def mock_empty_result
|
22
28
|
names = [:zero, :one, :two]
|
23
|
-
res = RDBI::Result.new(
|
29
|
+
res = RDBI::Result.new(
|
30
|
+
@dbh.prepare("foo"),
|
31
|
+
[1],
|
32
|
+
RDBI::Driver::Mock::Cursor.new([]),
|
33
|
+
RDBI::Schema.new((0..2).to_a.map { |x| RDBI::Column.new(names[x], :integer, :default) }),
|
34
|
+
{ :default => RDBI::Type.filterlist() }
|
35
|
+
)
|
24
36
|
end
|
25
37
|
|
26
38
|
def get_index(res)
|
27
|
-
get_guts(
|
39
|
+
cursor = get_guts(res)[:data]
|
40
|
+
cursor.instance_variable_get("@index") || res.instance_variable_get(:@index)
|
28
41
|
end
|
29
42
|
|
30
43
|
def get_guts(res)
|
31
44
|
h = { }
|
32
|
-
%W[
|
45
|
+
%W[schema binds sth data].collect(&:to_sym).each do |sym|
|
33
46
|
h[sym] = res.instance_variable_get("@#{sym}") || res.instance_variable_get("@#{sym}".to_sym)
|
34
47
|
end
|
35
48
|
|
@@ -76,10 +89,9 @@ class TestResult < Test::Unit::TestCase
|
|
76
89
|
as
|
77
90
|
fetch
|
78
91
|
read
|
79
|
-
|
80
|
-
finish
|
92
|
+
finish
|
81
93
|
].collect(&:to_sym).each do |sym|
|
82
|
-
assert_respond_to(res, sym)
|
94
|
+
assert_respond_to(res, sym, "#{res.class} did not respond to :#{sym}")
|
83
95
|
end
|
84
96
|
|
85
97
|
res.sth.finish
|
@@ -299,6 +311,116 @@ class TestResult < Test::Unit::TestCase
|
|
299
311
|
assert_equal({:zero=>-1, :one=>0, :two=>1}, YAML.load(res.as(:YAML).first))
|
300
312
|
assert_equal({:zero=>8, :one=>9, :two=>10}, YAML.load(res.as(:YAML).last))
|
301
313
|
end
|
314
|
+
|
315
|
+
def test_13_enumerable_as
|
316
|
+
# 'master' dab6270 branch (0.9.1+) returned a Result::Driver for as()
|
317
|
+
|
318
|
+
res = mock_result
|
319
|
+
|
320
|
+
i = -1
|
321
|
+
# Mock result set is:
|
322
|
+
#
|
323
|
+
# ZERO ONE TWO
|
324
|
+
# ==== === ===
|
325
|
+
# -1 0 1
|
326
|
+
# 0 1 2
|
327
|
+
# 1 2 3
|
328
|
+
# ...
|
329
|
+
# 8 9 10
|
330
|
+
#
|
331
|
+
res.as(:Struct).each do |row|
|
332
|
+
assert_kind_of(::Struct, row)
|
333
|
+
assert_equal([i, i+1, i+2], [row.zero, row.one, row.two])
|
334
|
+
i += 1
|
335
|
+
end
|
336
|
+
res.sth.finish
|
337
|
+
end
|
338
|
+
|
339
|
+
def test_14_results_driven_struct
|
340
|
+
# 'master' dab6270 branch (0.9.1+) returned 'raw' rows for #each,
|
341
|
+
# #first and #last
|
342
|
+
|
343
|
+
res = mock_result
|
344
|
+
|
345
|
+
res.as(:Struct)
|
346
|
+
row = res.first # does not advance underlying index
|
347
|
+
assert_kind_of(::Struct, row)
|
348
|
+
assert_equal([-1, 0, 1], [row.zero, row.one, row.two])
|
349
|
+
|
350
|
+
res.each do |r|
|
351
|
+
assert_kind_of(::Struct, r)
|
352
|
+
assert_equal([-1, 0, 1], [r.zero, r.one, r.two])
|
353
|
+
break # Just one row, thank you
|
354
|
+
end
|
355
|
+
|
356
|
+
row = res.last
|
357
|
+
assert_kind_of(::Struct, row)
|
358
|
+
assert_equal([8, 9, 10], [row.zero, row.one, row.two])
|
359
|
+
|
360
|
+
res.sth.finish
|
361
|
+
end
|
362
|
+
|
363
|
+
def test_15_results_driven_csv
|
364
|
+
# 'master' 20917a3 branch (pilcrow/result-as) didn't handle
|
365
|
+
# eof properly for result drivers that didn't return sets of
|
366
|
+
# rows as an array of rows
|
367
|
+
|
368
|
+
res = mock_result
|
369
|
+
|
370
|
+
res.as(:CSV)
|
371
|
+
row = res.first # does not advance underlying index
|
372
|
+
assert_equal("-1,0,1\n", row)
|
373
|
+
|
374
|
+
res.each do |r|
|
375
|
+
assert_equal("-1,0,1\n", r)
|
376
|
+
break # Just one row, thank you
|
377
|
+
end
|
378
|
+
|
379
|
+
row = res.last
|
380
|
+
assert_equal("8,9,10\n", row)
|
381
|
+
|
382
|
+
res.sth.finish
|
383
|
+
end
|
384
|
+
|
385
|
+
def test_16_results_driven_yaml
|
386
|
+
# As for test_15, but with YAML
|
387
|
+
# 'master' 20917a3 branch (pilcrow/result-as) didn't handle
|
388
|
+
# eof properly for result drivers that didn't return sets of
|
389
|
+
# rows as an array of rows
|
390
|
+
|
391
|
+
res = mock_result
|
392
|
+
|
393
|
+
res.as(:YAML)
|
394
|
+
row = res.first # does not advance underlying index
|
395
|
+
assert_equal({:zero=>-1, :one=>0, :two=>1}, YAML.load(row))
|
396
|
+
|
397
|
+
res.each do |r|
|
398
|
+
assert_equal({:zero=>-1, :one=>0, :two=>1}, YAML.load(r))
|
399
|
+
break # Just one row, thank you
|
400
|
+
end
|
401
|
+
|
402
|
+
row = res.last
|
403
|
+
assert_equal({:zero=>8, :one=>9, :two=>10}, YAML.load(row))
|
404
|
+
|
405
|
+
res.sth.finish
|
406
|
+
end
|
407
|
+
|
408
|
+
def test_17_results_as_empty
|
409
|
+
[:Array, :Struct, :YAML, :CSV].each do |rd|
|
410
|
+
res = mock_empty_result
|
411
|
+
res.as(rd).each do |not_reached|
|
412
|
+
assert(false, "each block unexpectedly reached during :#{rd} test")
|
413
|
+
end
|
414
|
+
res.sth.finish
|
415
|
+
|
416
|
+
res = mock_empty_result
|
417
|
+
res.as(rd)
|
418
|
+
assert_nil(res.first, "#first was not nil on empty result set")
|
419
|
+
assert_nil(res.last, "#last was not nil on empty result set")
|
420
|
+
res.sth.finish
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
302
424
|
end
|
303
425
|
|
304
426
|
# vim: syntax=ruby ts=2 et sw=2 sts=2
|