m4dbi 0.6.2 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/spec/hash.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'spec/helper'
1
+ require_relative 'helper'
2
2
 
3
3
  describe 'Hash' do
4
4
  it 'is convertible to an SQL subclause and matching value Array' do
@@ -11,12 +11,12 @@ describe 'Hash' do
11
11
  }
12
12
  clause, values = h.to_clause( " AND " )
13
13
  where_clause, where_values = h.to_where_clause
14
-
14
+
15
15
  str = "a = ? AND b = ? AND the_nil = ? AND abc = ? AND xyz = ?"
16
16
  where_str = "a = ? AND b = ? AND the_nil IS NULL AND abc = ? AND xyz = ?"
17
17
  clause.length.should.equal str.length
18
18
  where_clause.length.should.equal where_str.length
19
-
19
+
20
20
  h.each_key do |key|
21
21
  clause.should.match /#{key} = ?/
22
22
  if h[ key ].nil?
@@ -25,11 +25,11 @@ describe 'Hash' do
25
25
  where_clause.should.match /#{key} = ?/
26
26
  end
27
27
  end
28
-
28
+
29
29
  values.should.equal h.values
30
30
  where_values.should.equal h.values.compact
31
31
  end
32
-
32
+
33
33
  it 'offers a means to get subhashes via #slice' do
34
34
  h = { :a => 1, :b => 2, :c => 3, :d => 4, :e => 5, :f => 6 }
35
35
  h.slice( :b, :c ).should.equal(
data/spec/helper.rb CHANGED
@@ -12,21 +12,33 @@ $LOAD_PATH.unshift(
12
12
 
13
13
  require 'm4dbi'
14
14
 
15
- puts "DBI version: #{DBI::VERSION}"
16
15
  puts "M4DBI version: #{M4DBI_VERSION}"
17
16
 
18
17
  # See test-schema*.sql and test-data.sql
19
18
  def connect_to_spec_database( database = ( ENV[ 'M4DBI_DATABASE' ] || 'm4dbi' ) )
20
- driver = ENV[ 'M4DBI_DRIVER' ] || "DBI:Pg"
21
- puts "Using DBI driver: '#{driver}'"
22
- DBI.connect( "#{driver}:#{database}", "m4dbi", "m4dbi" )
19
+ driver = ENV[ 'M4DBI_DRIVER' ] || "PostgreSQL"
20
+ # puts "\nUsing RDBI driver: '#{driver}'"
21
+ case driver.downcase
22
+ when 'postgresql', 'sqlite3', 'mysql'
23
+ require "rdbi/driver/#{driver.downcase}"
24
+ else
25
+ raise "Unrecognized RDBI driver: #{driver}"
26
+ end
27
+
28
+ M4DBI.connect(
29
+ driver,
30
+ :database => database,
31
+ :username => 'm4dbi',
32
+ :hostname => 'localhost',
33
+ :password => 'm4dbi'
34
+ )
23
35
  end
24
36
 
25
37
  def reset_data( dbh = $dbh, datafile = "test-data.sql" )
26
38
  dir = File.dirname( __FILE__ )
27
39
  File.read( "#{dir}/#{datafile}" ).split( /;/ ).each do |command|
28
- if not command.strip.empty?
29
- dbh.do command
40
+ if ! command.strip.empty?
41
+ dbh.execute command
30
42
  end
31
43
  end
32
44
  end
data/spec/model.rb CHANGED
@@ -1,13 +1,18 @@
1
- require 'spec/helper'
1
+ require_relative 'helper'
2
2
 
3
- describe 'DBI::Model' do
3
+ describe 'M4DBI::Model' do
4
4
  it 'raises an exception when trying to define a model before connecting to a database' do
5
- dbh = DBI::DatabaseHandle.last_handle
6
- if dbh and dbh.respond_to? :disconnect
5
+ dbh = M4DBI.last_dbh
6
+ if dbh && dbh.respond_to?( :disconnect )
7
7
  dbh.disconnect
8
+ dbh.should.not.be.connected
8
9
  end
9
- should.raise do
10
- @m_author = Class.new( DBI::Model( :authors ) )
10
+ dbh = M4DBI.last_dbh
11
+ if dbh
12
+ dbh.should.not.be.connected
13
+ end
14
+ should.raise( M4DBI::Error ) do
15
+ @m_author = Class.new( M4DBI::Model( :authors ) )
11
16
  end
12
17
  end
13
18
  end
@@ -15,7 +20,7 @@ end
15
20
  $dbh = connect_to_spec_database
16
21
  reset_data
17
22
 
18
- class ManyCol < DBI::Model( :many_col_table )
23
+ class ManyCol < M4DBI::Model( :many_col_table )
19
24
  def inc
20
25
  self.c1 = c1 + 10
21
26
  end
@@ -25,18 +30,18 @@ class ManyCol < DBI::Model( :many_col_table )
25
30
  end
26
31
  end
27
32
 
28
- describe 'A DBI::Model subclass' do
33
+ describe 'A M4DBI::Model subclass' do
29
34
  before do
30
- # Here we subclass DBI::Model.
35
+ # Here we subclass M4DBI::Model.
31
36
  # This is nearly equivalent to the typical "ChildClassName < ParentClassName"
32
37
  # syntax, but allows us to refer to the class in our specs.
33
- @m_author = Class.new( DBI::Model( :authors ) )
34
- @m_post = Class.new( DBI::Model( :posts ) )
35
- @m_empty = Class.new( DBI::Model( :empty_table ) )
36
- @m_mc = Class.new( DBI::Model( :many_col_table ) )
37
- @m_nipk = Class.new( DBI::Model( :non_id_pk, :pk => [ :str ] ) )
38
- @m_mcpk = Class.new( DBI::Model( :mcpk, :pk => [ :kc1, :kc2 ] ) )
39
- class Author < DBI::Model( :authors ); end
38
+ @m_author = Class.new( M4DBI::Model( :authors ) )
39
+ @m_post = Class.new( M4DBI::Model( :posts ) )
40
+ @m_empty = Class.new( M4DBI::Model( :empty_table ) )
41
+ @m_mc = Class.new( M4DBI::Model( :many_col_table ) )
42
+ @m_nipk = Class.new( M4DBI::Model( :non_id_pk, :pk => [ :str ] ) )
43
+ @m_mcpk = Class.new( M4DBI::Model( :mcpk, :pk => [ :kc1, :kc2 ] ) )
44
+ class Author < M4DBI::Model( :authors ); end
40
45
  end
41
46
 
42
47
  it 'can be defined' do
@@ -46,16 +51,16 @@ describe 'A DBI::Model subclass' do
46
51
 
47
52
  it 'maintains identity across different inheritances' do
48
53
  should.not.raise do
49
- class Author < DBI::Model( :authors ); end
50
- class Author < DBI::Model( :authors ); end
54
+ class Author < M4DBI::Model( :authors ); end
55
+ class Author < M4DBI::Model( :authors ); end
51
56
  end
52
57
  end
53
58
 
54
59
  it 'maintains member methods across redefinitions' do
55
- class Author < DBI::Model( :authors )
60
+ class Author < M4DBI::Model( :authors )
56
61
  def method1; 1; end
57
62
  end
58
- class Author < DBI::Model( :authors )
63
+ class Author < M4DBI::Model( :authors )
59
64
  def method2; 2; end
60
65
  end
61
66
  a = Author[ 3 ]
@@ -67,16 +72,29 @@ describe 'A DBI::Model subclass' do
67
72
  # If you try to subclass a class a second time with a different parent class,
68
73
  # Ruby raises an exception.
69
74
  should.not.raise do
70
- original_handle = DBI::DatabaseHandle.last_handle
75
+ original_handle = M4DBI.last_dbh
71
76
 
72
- class Author < DBI::Model( :authors ); end
77
+ class Author < M4DBI::Model( :authors ); end
73
78
 
74
79
  dbh = connect_to_spec_database
75
- new_handle = DBI::DatabaseHandle.last_handle
80
+ new_handle = M4DBI.last_dbh
76
81
  new_handle.should.equal dbh
77
82
  new_handle.should.not.equal original_handle
78
83
 
79
- class Author < DBI::Model( :authors ); end
84
+ class Author < M4DBI::Model( :authors ); end
85
+ end
86
+ end
87
+
88
+ it 'provides the database handle it is using' do
89
+ begin
90
+ @m_author.dbh.should.equal $dbh
91
+
92
+ dbh = connect_to_spec_database( ENV[ 'M4DBI_DATABASE2' ] || 'm4dbi2' )
93
+ @m_author2 = Class.new( M4DBI::Model( :authors ) )
94
+ @m_author2.dbh.should.equal dbh
95
+ ensure
96
+ # Clean up handles for later specs
97
+ connect_to_spec_database
80
98
  end
81
99
  end
82
100
 
@@ -89,8 +107,8 @@ describe 'A DBI::Model subclass' do
89
107
  dbh = connect_to_spec_database( ENV[ 'M4DBI_DATABASE2' ] || 'm4dbi2' )
90
108
  reset_data( dbh, "test-data2.sql" )
91
109
 
92
- @m_author2 = Class.new( DBI::Model( :authors ) )
93
- @m_author2.dbh.should.equal dbh
110
+ @m_author2 = Class.new( M4DBI::Model( :authors ) )
111
+ @m_author2.dbh.should.not.equal @m_author.dbh
94
112
 
95
113
  @m_author2[ 1 ].should.be.nil
96
114
  a11 = @m_author2[ 11 ]
@@ -111,15 +129,15 @@ describe 'A DBI::Model subclass' do
111
129
  it 'can use a specific database handle' do
112
130
  begin
113
131
  dbh1 = connect_to_spec_database
114
- dbh1.should.equal DBI::DatabaseHandle.last_handle
132
+ dbh1.should.equal M4DBI.last_dbh
115
133
  dbh2 = connect_to_spec_database( ENV[ 'M4DBI_DATABASE2' ] || 'm4dbi2' )
116
- dbh2.should.equal DBI::DatabaseHandle.last_handle
134
+ dbh2.should.equal M4DBI.last_dbh
117
135
  reset_data( dbh2, "test-data2.sql" )
118
136
 
119
137
  dbh1.should.not.equal dbh2
120
138
 
121
- class Author1 < DBI::Model( :authors, :dbh => dbh1 ); end
122
- class Author2 < DBI::Model( :authors, :dbh => dbh2 ); end
139
+ class Author1 < M4DBI::Model( :authors, :dbh => dbh1 ); end
140
+ class Author2 < M4DBI::Model( :authors, :dbh => dbh2 ); end
123
141
 
124
142
  a1 = Author1[ 1 ]
125
143
  a1.should.not.be.nil
@@ -135,13 +153,13 @@ describe 'A DBI::Model subclass' do
135
153
  end
136
154
 
137
155
  it 'raises an exception when creating with invalid arguments' do
138
- should.raise( DBI::Error ) do
156
+ should.raise( M4DBI::Error ) do
139
157
  @m_author.new nil
140
158
  end
141
- should.raise( DBI::Error ) do
159
+ should.raise( M4DBI::Error ) do
142
160
  @m_author.new 2
143
161
  end
144
- should.raise( DBI::Error ) do
162
+ should.raise( M4DBI::Error ) do
145
163
  @m_author.new Object.new
146
164
  end
147
165
  end
@@ -184,7 +202,7 @@ describe 'A DBI::Model subclass' do
184
202
  o.class.should.equal @m_mcpk
185
203
  o.val.should.equal 'five six'
186
204
 
187
- should.not.raise( DBI::Error ) do
205
+ should.not.raise( RDBI::Error ) do
188
206
  o = @m_author[ nil ]
189
207
  o.should.be.nil
190
208
  end
@@ -194,7 +212,7 @@ describe 'A DBI::Model subclass' do
194
212
  o = @m_author[ :name => 'author1' ]
195
213
  o.should.not.be.nil
196
214
  o.class.should.equal @m_author
197
- o.id.should.equal 1
215
+ o[ 'id' ].should.equal 1
198
216
 
199
217
  o = @m_post[ :author_id => 1 ]
200
218
  o.should.not.be.nil
@@ -228,7 +246,7 @@ describe 'A DBI::Model subclass' do
228
246
  posts[ 0 ].class.should.equal @m_post
229
247
 
230
248
  sorted_posts = posts.sort { |p1,p2|
231
- p1._id <=> p2._id
249
+ p1[ 'id' ] <=> p2[ 'id' ]
232
250
  }
233
251
  p = sorted_posts.first
234
252
  p.text.should.equal 'First post.'
@@ -260,7 +278,7 @@ describe 'A DBI::Model subclass' do
260
278
  posts[ 0 ].class.should.equal @m_post
261
279
 
262
280
  sorted_posts = posts.sort { |p1,p2|
263
- p2._id <=> p1._id
281
+ p2[ 'id' ] <=> p1[ 'id' ]
264
282
  }
265
283
  p = sorted_posts.first
266
284
  p.text.should.equal 'Second post.'
@@ -274,7 +292,7 @@ describe 'A DBI::Model subclass' do
274
292
  posts[ 0 ].class.should.equal @m_post
275
293
 
276
294
  sorted_posts = posts.sort { |p1,p2|
277
- p2._id <=> p1._id
295
+ p2[ 'id' ] <=> p1[ 'id' ]
278
296
  }
279
297
  p = sorted_posts.first
280
298
  p.text.should.equal 'Second post.'
@@ -305,14 +323,14 @@ describe 'A DBI::Model subclass' do
305
323
  post = @m_post.one_where( "text LIKE '%Third%'" )
306
324
  post.should.not.be.nil
307
325
  post.class.should.equal @m_post
308
- post.id.should.equal 3
326
+ post[ 'id' ].should.equal 3
309
327
  end
310
328
 
311
329
  it 'provides single-record access via #one_where( String, param, param... )' do
312
330
  post = @m_post.one_where( "text LIKE ?", '%Third%' )
313
331
  post.should.not.be.nil
314
332
  post.class.should.equal @m_post
315
- post.id.should.equal 3
333
+ post[ 'id' ].should.equal 3
316
334
  end
317
335
 
318
336
  it 'returns nil from #one_where when no record is found' do
@@ -329,10 +347,10 @@ describe 'A DBI::Model subclass' do
329
347
  rows.should.not.be.empty
330
348
  rows.size.should.equal 3
331
349
 
332
- rows[ 0 ].id.should.equal 1
350
+ rows[ 0 ][ 'id' ].should.equal 1
333
351
  rows[ 0 ].class.should.equal @m_author
334
352
  rows[ 0 ].name.should.equal 'author1'
335
- rows[ 1 ].id.should.equal 2
353
+ rows[ 1 ][ 'id' ].should.equal 2
336
354
  rows[ 1 ].class.should.equal @m_author
337
355
  rows[ 1 ].name.should.equal 'author2'
338
356
  end
@@ -360,34 +378,48 @@ describe 'A DBI::Model subclass' do
360
378
  end
361
379
 
362
380
  it 'provides a means to create new records via #create( Hash )' do
381
+ num_authors = @m_author.count
382
+
363
383
  a = @m_author.create(
364
- :id => 9,
365
- :name => 'author9'
384
+ :id => 99,
385
+ :name => 'author99'
366
386
  )
367
387
  a.should.not.be.nil
368
388
  a.class.should.equal @m_author
369
- a.id.should.equal 9
389
+ a[ 'id' ].should.equal 99
370
390
  a.should.respond_to :name
371
391
  a.should.not.respond_to :no_column_by_this_name
372
- a.name.should.equal 'author9'
392
+ a.name.should.equal 'author99'
373
393
 
374
- a_ = @m_author[ 9 ]
394
+ a_ = @m_author[ 99 ]
375
395
  a_.should.not.be.nil
376
396
  a_.should.equal a
377
- a_.name.should.equal 'author9'
378
-
379
- # No value given for auto-incrementing primary key
380
- a = @m_author.create(
381
- :name => 'author10'
382
- )
397
+ a_.name.should.equal 'author99'
398
+
399
+ # Insert without auto-incrementing primary key specified
400
+ # Try at least as many times as there were records in the DB,
401
+ # because the sequence used for the IDs is independent of
402
+ # the actual ID values in the DB for some RDBMSes.
403
+ num_authors.times do
404
+ begin
405
+ a = @m_author.create(
406
+ :name => 'author10'
407
+ )
408
+ break # Stop on success
409
+ rescue Exception => e
410
+ if e.message !~ /duplicate/
411
+ raise e
412
+ end
413
+ end
414
+ end
383
415
  a.should.not.be.nil
384
416
  a.class.should.equal @m_author
385
- a.id.should.not.equal 9
417
+ a[ 'id' ].should.not.be.nil
386
418
  a.should.respond_to :name
387
419
  a.should.not.respond_to :no_column_by_this_name
388
420
  a.name.should.equal 'author10'
389
421
 
390
- a_ = @m_author[ a.id ]
422
+ a_ = @m_author[ a[ 'id' ] ]
391
423
  a_.should.not.be.nil
392
424
  a_.should.equal a
393
425
  a_.name.should.equal 'author10'
@@ -403,12 +435,12 @@ describe 'A DBI::Model subclass' do
403
435
  end
404
436
 
405
437
  a = @m_author.create { |rec|
406
- rec.id = 9
438
+ rec[ 'id' ] = 9
407
439
  rec.name = 'author9'
408
440
  }
409
441
  a.should.not.be.nil
410
442
  a.class.should.equal @m_author
411
- a.id.should.equal 9
443
+ a[ 'id' ].should.equal 9
412
444
  a.name.should.equal 'author9'
413
445
 
414
446
  a_ = @m_author[ 9 ]
@@ -418,13 +450,13 @@ describe 'A DBI::Model subclass' do
418
450
  m = nil
419
451
  should.not.raise do
420
452
  m = @m_mc.create { |rec|
421
- rec.id = 1
453
+ rec[ 'id' ] = 1
422
454
  rec.c2 = 7
423
455
  rec.c3 = 8
424
456
  }
425
457
  end
426
458
  m_ = @m_mc[ 1 ]
427
- m_.id.should.equal 1
459
+ m_[ 'id' ].should.equal 1
428
460
  m_.c1.should.be.nil
429
461
  m_.c2.should.equal 7
430
462
  m_.c3.should.equal 8
@@ -442,7 +474,7 @@ describe 'A DBI::Model subclass' do
442
474
  )
443
475
  a.should.not.be.nil
444
476
  a.class.should.equal @m_author
445
- a.id.should.equal 1
477
+ a[ 'id' ].should.equal 1
446
478
  a.should.respond_to :name
447
479
  a.should.not.respond_to :no_column_by_this_name
448
480
  a.name.should.equal 'author1'
@@ -465,7 +497,7 @@ describe 'A DBI::Model subclass' do
465
497
  )
466
498
  a.should.not.be.nil
467
499
  a.class.should.equal @m_author
468
- a.id.should.equal 9
500
+ a[ 'id' ].should.equal 9
469
501
  a.should.respond_to :name
470
502
  a.should.not.respond_to :no_column_by_this_name
471
503
  a.name.should.equal 'author9'
@@ -497,10 +529,10 @@ describe 'A DBI::Model subclass' do
497
529
  posts.should.not.be.empty
498
530
  posts.size.should.equal 2
499
531
 
500
- posts[ 0 ].id.should.equal 1
532
+ posts[ 0 ][ 'id' ].should.equal 1
501
533
  posts[ 0 ].text.should.equal 'First post.'
502
534
  posts[ 0 ].class.should.equal @m_post
503
- posts[ 1 ].id.should.equal 3
535
+ posts[ 1 ][ 'id' ].should.equal 3
504
536
  posts[ 1 ].text.should.equal 'Third post.'
505
537
  posts[ 1 ].class.should.equal @m_post
506
538
 
@@ -529,7 +561,7 @@ describe 'A DBI::Model subclass' do
529
561
  post.should.not.be.nil
530
562
  post.class.should.equal @m_post
531
563
 
532
- post.id.should.equal 3
564
+ post[ 'id' ].should.equal 3
533
565
  post.author_id.should.equal 1
534
566
  post.text.should.equal 'Third post.'
535
567
 
@@ -619,11 +651,12 @@ describe 'A DBI::Model subclass' do
619
651
  end
620
652
  end
621
653
 
622
- describe 'A created DBI::Model subclass instance' do
654
+ describe 'A created M4DBI::Model subclass instance' do
623
655
  before do
624
- @m_mc = Class.new( DBI::Model( :many_col_table ) )
625
- @m_author = Class.new( DBI::Model( :authors ) )
626
- @m_post = Class.new( DBI::Model( :posts ) )
656
+ @m_mc = Class.new( M4DBI::Model( :many_col_table ) )
657
+ @m_author = Class.new( M4DBI::Model( :authors ) )
658
+ @m_post = Class.new( M4DBI::Model( :posts ) )
659
+ @m_conflict = Class.new( M4DBI::Model( :conflicting_cols ) )
627
660
  end
628
661
 
629
662
  it 'provides read access to fields via identically-named readers' do
@@ -633,12 +666,12 @@ describe 'A created DBI::Model subclass instance' do
633
666
  )
634
667
  mc.should.not.be.nil
635
668
  should.not.raise do
636
- mc.id
669
+ mc[ 'id' ]
637
670
  mc.c1
638
671
  mc.c2
639
672
  mc.c5
640
673
  end
641
- mc.id.should.not.be.nil
674
+ mc[ 'id' ].should.not.be.nil
642
675
  mc.c3.should.equal 3
643
676
  mc.c4.should.equal 4
644
677
  end
@@ -655,26 +688,86 @@ describe 'A created DBI::Model subclass instance' do
655
688
  mc.c2.should.equal 20
656
689
  mc.c3.should.equal 30
657
690
  mc.c4.should.equal 40
658
- id_ = mc.id
691
+ id_ = mc[ 'id' ]
659
692
  id_.should.not.be.nil
660
693
 
661
694
  mc_ = @m_mc[ id_ ]
662
- mc_.id.should.equal id_
695
+ mc_[ 'id' ].should.equal id_
663
696
  mc_.c1.should.equal 10
664
697
  mc_.c2.should.equal 20
665
698
  mc_.c3.should.equal 30
666
699
  mc_.c4.should.equal 40
667
700
  end
668
701
 
702
+ it 'provides read access to fields via Hash-like syntax' do
703
+ mc = @m_mc.create(
704
+ :c3 => 3,
705
+ :c4 => 4
706
+ )
707
+ mc.should.not.be.nil
708
+ mc[ 'id' ].should.not.be.nil
709
+ mc[ 'c3' ].should.equal 3
710
+ mc[ 'c4' ].should.equal 4
711
+ mc[ :id ].should.not.be.nil
712
+ mc[ :c3 ].should.equal 3
713
+ mc[ :c4 ].should.equal 4
714
+ end
715
+
716
+ it 'provides write access to fields via Hash-like syntax' do
717
+ mc = @m_mc.create(
718
+ :c3 => 30,
719
+ :c4 => 40
720
+ )
721
+ mc.should.not.be.nil
722
+ mc[ 'c1' ] = 10
723
+ mc[ 'c2' ] = 20
724
+ mc[ 'c1' ].should.equal 10
725
+ mc[ 'c2' ].should.equal 20
726
+ mc[ 'c3' ].should.equal 30
727
+ mc[ 'c4' ].should.equal 40
728
+ id_ = mc[ 'id' ]
729
+ id_.should.not.be.nil
730
+
731
+ mc_ = @m_mc[ id_ ]
732
+ mc_[ 'id' ].should.equal id_
733
+ mc_[ 'c1' ].should.equal 10
734
+ mc_[ 'c2' ].should.equal 20
735
+ mc_[ 'c3' ].should.equal 30
736
+ mc_[ 'c4' ].should.equal 40
737
+ end
738
+
739
+ it 'provides alternative accessors for columns that collide with Object methods' do
740
+ mc = @m_conflict.create(
741
+ :c1 => 123,
742
+ :class => 'Mammalia',
743
+ :dup => false
744
+ )
745
+ mc.should.not.be.nil
746
+ should.not.raise do
747
+ mc[ 'id' ]
748
+ mc.class
749
+ mc.class_
750
+ mc.dup
751
+ mc.dup_
752
+ end
753
+ mc[ 'id' ].should.not.be.nil
754
+ mc.c1.should.equal 123
755
+ mc.class.should.equal @m_conflict
756
+ mc.class_.should.equal 'Mammalia'
757
+ mc.dup.should.equal mc
758
+ end
759
+
669
760
  it 'maintains Hash key equality across different fetches' do
670
761
  h = Hash.new
671
762
  a = @m_author[ 1 ]
672
763
  h[ a ] = 123
673
764
  a_ = @m_author[ 1 ]
674
765
  h[ a_].should.equal 123
766
+ a.should.equal a_
675
767
 
676
768
  a2 = @m_author[ 2 ]
677
769
  h[ a2 ].should.be.nil
770
+ a2.should.not.equal a
678
771
 
679
772
  h[ a2 ] = 456
680
773
  h[ a ].should.equal 123
@@ -682,6 +775,7 @@ describe 'A created DBI::Model subclass instance' do
682
775
 
683
776
  a2_ = @m_author[ 2 ]
684
777
  h[ a2_ ].should.equal 456
778
+ a2.should.equal a2_
685
779
  end
686
780
 
687
781
  it 'maintains Hash key distinction for different Model subclasses' do
@@ -697,13 +791,13 @@ describe 'A created DBI::Model subclass instance' do
697
791
  end
698
792
  end
699
793
 
700
- describe 'A found DBI::Model subclass instance' do
794
+ describe 'A found M4DBI::Model subclass instance' do
701
795
  before do
702
- @m_author = Class.new( DBI::Model( :authors ) )
703
- @m_post = Class.new( DBI::Model( :posts ) )
704
- @m_mc = Class.new( DBI::Model( :many_col_table ) )
705
- @m_nipk = Class.new( DBI::Model( :non_id_pk, :pk => [ :str ] ) )
706
- @m_mcpk = Class.new( DBI::Model( :mcpk, :pk => [ :kc1, :kc2 ] ) )
796
+ @m_author = Class.new( M4DBI::Model( :authors ) )
797
+ @m_post = Class.new( M4DBI::Model( :posts ) )
798
+ @m_mc = Class.new( M4DBI::Model( :many_col_table ) )
799
+ @m_nipk = Class.new( M4DBI::Model( :non_id_pk, :pk => [ :str ] ) )
800
+ @m_mcpk = Class.new( M4DBI::Model( :mcpk, :pk => [ :kc1, :kc2 ] ) )
707
801
  end
708
802
 
709
803
  it 'provides access to primary key value' do
@@ -724,7 +818,7 @@ describe 'A found DBI::Model subclass instance' do
724
818
  p = @m_post[ 2 ]
725
819
 
726
820
  should.not.raise( NoMethodError ) do
727
- p.id
821
+ p[ 'id' ]
728
822
  p.author_id
729
823
  p.text
730
824
  end
@@ -733,7 +827,7 @@ describe 'A found DBI::Model subclass instance' do
733
827
  p.foobar
734
828
  end
735
829
 
736
- p.id.should.equal 2
830
+ p[ 'id' ].should.equal 2
737
831
  p.author_id.should.equal 2
738
832
  p.text.should.equal 'Second post.'
739
833
  end
@@ -831,38 +925,38 @@ describe 'A found DBI::Model subclass instance' do
831
925
 
832
926
  end
833
927
 
834
- describe 'DBI::Model (relationships)' do
928
+ describe 'M4DBI::Model (relationships)' do
835
929
  before do
836
- @m_author = Class.new( DBI::Model( :authors ) )
837
- @m_post = Class.new( DBI::Model( :posts ) )
838
- @m_fan = Class.new( DBI::Model( :fans ) )
930
+ @m_author = Class.new( M4DBI::Model( :authors ) )
931
+ @m_post = Class.new( M4DBI::Model( :posts ) )
932
+ @m_fan = Class.new( M4DBI::Model( :fans ) )
839
933
  end
840
934
 
841
935
  it 'facilitates relating one to many, providing read access' do
842
- DBI::Model.one_to_many( @m_author, @m_post, :posts, :author, :author_id )
936
+ M4DBI::Model.one_to_many( @m_author, @m_post, :posts, :author, :author_id )
843
937
  a = @m_author[ 1 ]
844
938
  a.posts.should.not.be.empty
845
939
  p = @m_post[ 3 ]
846
940
  p.author.should.not.be.nil
847
- p.author.id.should.equal 1
941
+ p.author[ 'id' ].should.equal 1
848
942
  end
849
943
 
850
944
  it 'facilitates relating one to many, allowing one of the many to set its one' do
851
- DBI::Model.one_to_many(
945
+ M4DBI::Model.one_to_many(
852
946
  @m_author, @m_post, :posts, :author, :author_id
853
947
  )
854
948
  p = @m_post[ 3 ]
855
949
  p.author.should.not.be.nil
856
- p.author.id.should.equal 1
950
+ p.author[ 'id' ].should.equal 1
857
951
  p.author = @m_author.create( :id => 4, :name => 'author4' )
858
952
  p_ = @m_post[ 3 ]
859
- p_.author.id.should.equal 4
953
+ p_.author[ 'id' ].should.equal 4
860
954
 
861
955
  reset_data
862
956
  end
863
957
 
864
958
  it 'facilitates relating many to many, providing read access' do
865
- DBI::Model.many_to_many(
959
+ M4DBI::Model.many_to_many(
866
960
  @m_author, @m_fan, :authors_liked, :fans, :authors_fans, :author_id, :fan_id
867
961
  )
868
962
  a1 = @m_author[ 1 ]
@@ -908,20 +1002,41 @@ describe 'DBI::Model (relationships)' do
908
1002
  end
909
1003
  end
910
1004
 
911
- describe 'DBI::Collection' do
1005
+ describe 'M4DBI::Collection' do
912
1006
  before do
913
- @m_author = Class.new( DBI::Model( :authors ) )
914
- @m_post = Class.new( DBI::Model( :posts ) )
1007
+ @m_author = Class.new( M4DBI::Model( :authors ) )
1008
+ @m_post = Class.new( M4DBI::Model( :posts ) )
915
1009
 
916
- DBI::Model.one_to_many(
1010
+ M4DBI::Model.one_to_many(
917
1011
  @m_author, @m_post, :posts, :author, :author_id
918
1012
  )
919
1013
  end
920
1014
 
921
1015
  it 'accepts additions' do
1016
+ num_posts = @m_post.count
1017
+
922
1018
  a = @m_author[ 1 ]
923
1019
  the_text = 'A new post.'
924
- a.posts << { :text => the_text }
1020
+
1021
+ num_posts_of_author = a.posts.count
1022
+
1023
+ # Insert without auto-incrementing primary key specified
1024
+ # Try at least as many times as there were records in the DB,
1025
+ # because the sequence used for the IDs is independent of
1026
+ # the actual ID values in the DB for some RDBMSes.
1027
+ num_posts.times do
1028
+ begin
1029
+ a.posts << { :text => the_text }
1030
+ break # Stop on success
1031
+ rescue Exception => e
1032
+ if e.message !~ /duplicate/
1033
+ raise e
1034
+ end
1035
+ end
1036
+ end
1037
+
1038
+ a.posts.count.should.equal num_posts_of_author + 1
1039
+
925
1040
  p = a.posts.find { |p| p.text == the_text }
926
1041
  p.should.not.be.nil
927
1042
  p.author.should.equal a
@@ -965,4 +1080,4 @@ describe 'DBI::Collection' do
965
1080
 
966
1081
  reset_data
967
1082
  end
968
- end
1083
+ end