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.
@@ -94,6 +94,8 @@ module RDBI::Type
94
94
  true
95
95
  when /^(f(alse)?|0)$/i
96
96
  false
97
+ else
98
+ nil
97
99
  end
98
100
  }
99
101
  end
@@ -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.rdoc"
17
+ "README.txt"
18
18
  ]
19
19
  s.files = [
20
- ".document",
21
20
  "LICENSE",
22
- "README.rdoc",
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",
@@ -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')
@@ -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.new("should call rollback")) do
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.new("should call rollback")) do
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
- @dbh.execute("some statement") do |res|
220
- assert(res)
221
- assert_kind_of(RDBI::Result, res)
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 teardown
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
@@ -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.new("too many handles in this pool (max: 5)")) do
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
- assert(10, count)
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
@@ -16,7 +16,7 @@ class TestRDBI < Test::Unit::TestCase
16
16
 
17
17
  assert_raise(ArgumentError) { RDBI.connect(1, :user => :blah) }
18
18
 
19
- assert_nothing_raised { dbh = RDBI.connect(:Mock) }
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
@@ -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(@dbh.prepare("foo"), [1], generate_data, RDBI::Schema.new((0..2).to_a.map { |x| RDBI::Column.new(names[x], :integer, :default) }), { :default => RDBI::Type.filterlist() })
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(@dbh.prepare("foo"), [1], RDBI::Driver::Mock::Cursor.new([]), RDBI::Schema.new((0..2).to_a.map { |x| RDBI::Column.new(names[x], :integer, :default) }), { :default => RDBI::Type.filterlist() })
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(get_guts(res)[:data])[:index]
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[index schema binds sth data].collect(&:to_sym).each do |sym|
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
- raw_fetch
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