m4dbi 0.6.0 → 0.6.1

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.
data/lib/m4dbi.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  require 'rubygems'
2
2
 
3
- M4DBI_VERSION = '0.6.0'
3
+ M4DBI_VERSION = '0.6.1'
4
4
 
5
5
  __DIR__ = File.expand_path( File.dirname( __FILE__ ) )
6
6
 
data/lib/m4dbi/hash.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  class Hash
2
2
  COMPACT_NILS = true
3
3
  DONT_COMPACT_NILS = false
4
-
4
+
5
5
  # Takes an optional block to provide a single "field = ?" type subclause
6
6
  # for each key-value pair.
7
7
  def to_clause( join_string, compact_nils = DONT_COMPACT_NILS )
@@ -21,7 +21,7 @@ class Hash
21
21
  end
22
22
  [ clause, values_ ]
23
23
  end
24
-
24
+
25
25
  def to_where_clause
26
26
  to_clause( " AND ", COMPACT_NILS ) { |field|
27
27
  if self[ field ].nil?
@@ -31,19 +31,21 @@ class Hash
31
31
  end
32
32
  }
33
33
  end
34
-
34
+
35
35
  def to_set_clause
36
36
  to_clause( ", " )
37
37
  end
38
-
38
+
39
39
  if method_defined? :slice
40
40
  warn "Hash#slice already defined; redefining."
41
41
  end
42
42
  def slice( *desired_keys )
43
43
  Hash[
44
- select { |key,value|
45
- desired_keys.include? key
46
- }
44
+ *(
45
+ select { |key,value|
46
+ desired_keys.include? key
47
+ }.flatten
48
+ )
47
49
  ]
48
50
  end
49
51
  end
data/lib/m4dbi/model.rb CHANGED
@@ -6,11 +6,11 @@ module DBI
6
6
  #attr_reader :row
7
7
  ancestral_trait_reader :dbh, :table
8
8
  ancestral_trait_class_reader :dbh, :table, :pk, :columns
9
-
9
+
10
10
  M4DBI_UNASSIGNED = '__m4dbi_unassigned__'
11
-
11
+
12
12
  extend Enumerable
13
-
13
+
14
14
  def self.[]( first_arg, *args )
15
15
  if args.size == 0
16
16
  case first_arg
@@ -27,27 +27,27 @@ module DBI
27
27
  clause = pk_clause
28
28
  values = [ first_arg ] + args
29
29
  end
30
-
30
+
31
31
  row = dbh.select_one(
32
32
  "SELECT * FROM #{table} WHERE #{clause}",
33
33
  *values
34
34
  )
35
-
35
+
36
36
  if row
37
37
  self.new( row )
38
38
  end
39
39
  end
40
-
40
+
41
41
  def self.pk_clause
42
42
  pk.map { |col|
43
43
  "#{col} = ?"
44
44
  }.join( ' AND ' )
45
45
  end
46
-
46
+
47
47
  def self.from_rows( rows )
48
48
  rows.map { |r| self.new( r ) }
49
49
  end
50
-
50
+
51
51
  def self.where( conditions, *args )
52
52
  case conditions
53
53
  when String
@@ -57,12 +57,12 @@ module DBI
57
57
  cond, params = conditions.to_where_clause
58
58
  sql = "SELECT * FROM #{table} WHERE #{cond}"
59
59
  end
60
-
60
+
61
61
  self.from_rows(
62
62
  dbh.select_all( sql, *params )
63
63
  )
64
64
  end
65
-
65
+
66
66
  def self.one_where( conditions, *args )
67
67
  case conditions
68
68
  when String
@@ -72,35 +72,35 @@ module DBI
72
72
  cond, params = conditions.to_where_clause
73
73
  sql = "SELECT * FROM #{table} WHERE #{cond} LIMIT 1"
74
74
  end
75
-
75
+
76
76
  row = dbh.select_one( sql, *params )
77
77
  if row
78
78
  self.new( row )
79
79
  end
80
80
  end
81
-
81
+
82
82
  def self.all
83
83
  self.from_rows(
84
84
  dbh.select_all( "SELECT * FROM #{table}" )
85
85
  )
86
86
  end
87
-
87
+
88
88
  # TODO: Perhaps we'll use cursors for Model#each.
89
89
  def self.each( &block )
90
90
  self.all.each( &block )
91
91
  end
92
-
92
+
93
93
  def self.one
94
94
  row = dbh.select_one( "SELECT * FROM #{table} LIMIT 1" )
95
95
  if row
96
96
  self.new( row )
97
97
  end
98
98
  end
99
-
99
+
100
100
  def self.count
101
101
  dbh.select_column( "SELECT COUNT(*) FROM #{table}" ).to_i
102
102
  end
103
-
103
+
104
104
  def self.create( hash = {} )
105
105
  if block_given?
106
106
  row = DBI::Row.new(
@@ -115,13 +115,13 @@ module DBI
115
115
  end
116
116
  end
117
117
  end
118
-
118
+
119
119
  keys = hash.keys
120
120
  cols = keys.join( ',' )
121
121
  values = keys.map { |key| hash[ key ] }
122
122
  value_placeholders = values.map { |v| '?' }.join( ',' )
123
123
  rec = nil
124
-
124
+
125
125
  dbh.one_transaction do |dbh_|
126
126
  num_inserted = dbh_.do(
127
127
  "INSERT INTO #{table} ( #{cols} ) VALUES ( #{value_placeholders} )",
@@ -148,10 +148,10 @@ module DBI
148
148
  end
149
149
  end
150
150
  end
151
-
151
+
152
152
  rec
153
153
  end
154
-
154
+
155
155
  def self.find_or_create( hash = nil )
156
156
  item = nil
157
157
  error = nil
@@ -170,37 +170,37 @@ module DBI
170
170
  raise error
171
171
  end
172
172
  end
173
-
173
+
174
174
  def self.select_all( *args )
175
175
  self.from_rows(
176
176
  dbh.select_all( *args )
177
177
  )
178
178
  end
179
-
179
+
180
180
  def self.select_one( *args )
181
181
  row = dbh.select_one( *args )
182
182
  if row
183
183
  self.new( row )
184
184
  end
185
185
  end
186
-
186
+
187
187
  class << self
188
188
  alias s select_all
189
189
  alias s1 select_one
190
190
  end
191
-
191
+
192
192
  def self.update( where_hash_or_clause, set_hash )
193
193
  where_clause = nil
194
194
  set_clause = nil
195
195
  where_params = nil
196
-
196
+
197
197
  if where_hash_or_clause.respond_to? :keys
198
198
  where_clause, where_params = where_hash_or_clause.to_where_clause
199
199
  else
200
200
  where_clause = where_hash_or_clause
201
201
  where_params = []
202
202
  end
203
-
203
+
204
204
  set_clause, set_params = set_hash.to_set_clause
205
205
  params = set_params + where_params
206
206
  dbh.do(
@@ -208,7 +208,7 @@ module DBI
208
208
  *params
209
209
  )
210
210
  end
211
-
211
+
212
212
  def self.update_one( *args )
213
213
  set_clause, set_params = args[ -1 ].to_set_clause
214
214
  pk_values = args[ 0..-2 ]
@@ -218,9 +218,9 @@ module DBI
218
218
  *params
219
219
  )
220
220
  end
221
-
221
+
222
222
  # Example:
223
- # DBI::Model.one_to_many( Author, :posts, Post, :author, :author_id )
223
+ # DBI::Model.one_to_many( Author, Post, :posts, :author, :author_id )
224
224
  # her_posts = some_author.posts
225
225
  # the_author = some_post.author
226
226
  def self.one_to_many( the_one, the_many, many_as, one_as, the_one_fk )
@@ -234,7 +234,7 @@ module DBI
234
234
  send( "#{the_one_fk}=".to_sym, new_one.pk )
235
235
  end
236
236
  end
237
-
237
+
238
238
  # Example:
239
239
  # DBI::Model.many_to_many(
240
240
  # @m_author, @m_fan, :authors_liked, :fans, :authors_fans, :author_id, :fan_id
@@ -258,7 +258,7 @@ module DBI
258
258
  pk
259
259
  )
260
260
  end
261
-
261
+
262
262
  model2.class_def( m1_as.to_sym ) do
263
263
  model1.select_all(
264
264
  %{
@@ -276,9 +276,9 @@ module DBI
276
276
  )
277
277
  end
278
278
  end
279
-
279
+
280
280
  # ------------------- :nodoc:
281
-
281
+
282
282
  def initialize( row )
283
283
  if not row.respond_to?( "[]".to_sym ) or not row.respond_to?( "[]=".to_sym )
284
284
  raise DBI::Error.new( "Attempted to instantiate DBI::Model with an invalid argument (#{row.inspect}). (Expecting DBI::Row.)" )
@@ -288,7 +288,7 @@ module DBI
288
288
  end
289
289
  @row = row
290
290
  end
291
-
291
+
292
292
  def method_missing( method, *args )
293
293
  begin
294
294
  @row.send( method, *args )
@@ -300,7 +300,7 @@ module DBI
300
300
  )
301
301
  end
302
302
  end
303
-
303
+
304
304
  # Returns a single value for single-column primary keys,
305
305
  # returns an Array for multi-column primary keys.
306
306
  def pk
@@ -310,36 +310,36 @@ module DBI
310
310
  pk_values
311
311
  end
312
312
  end
313
-
313
+
314
314
  # Always returns an Array of values, even for single-column primary keys.
315
315
  def pk_values
316
316
  pk_columns.map { |col|
317
317
  @row[ col ]
318
318
  }
319
319
  end
320
-
320
+
321
321
  def pk_columns
322
322
  self.class.pk
323
323
  end
324
-
324
+
325
325
  def pk_clause
326
326
  pk_columns.map { |col|
327
327
  "#{col} = ?"
328
328
  }.join( ' AND ' )
329
329
  end
330
-
330
+
331
331
  def ==( other )
332
332
  other and ( pk == other.pk )
333
333
  end
334
-
334
+
335
335
  def hash
336
336
  "#{self.class.hash}#{pk}".to_i
337
337
  end
338
-
338
+
339
339
  def eql?( other )
340
340
  hash == other.hash
341
341
  end
342
-
342
+
343
343
  def set( hash )
344
344
  set_clause, set_params = hash.to_set_clause
345
345
  set_params << pk
@@ -354,7 +354,7 @@ module DBI
354
354
  end
355
355
  num_updated
356
356
  end
357
-
357
+
358
358
  # Returns true iff the record and only the record was successfully deleted.
359
359
  def delete
360
360
  num_deleted = dbh.do(
@@ -363,13 +363,13 @@ module DBI
363
363
  )
364
364
  num_deleted == 1
365
365
  end
366
-
366
+
367
367
  # save does nothing. It exists to provide compatibility with other ORMs.
368
368
  def save
369
369
  nil
370
370
  end
371
371
  end
372
-
372
+
373
373
  # Define a new DBI::Model like this:
374
374
  # class Post < DBI::Model( :posts ); end
375
375
  # You can specify the primary key column(s) using an array, like so:
@@ -382,7 +382,7 @@ module DBI
382
382
  if not pk_.respond_to? :each
383
383
  raise DBI::Error.new( "Primary key must be enumerable (was given #{pk_.inspect})" )
384
384
  end
385
-
385
+
386
386
  model_key =
387
387
  # DBD-dependent. Not all DBDs have dbname implemented by M4DBI.
388
388
  if h.respond_to? :dbname
@@ -390,7 +390,7 @@ module DBI
390
390
  else
391
391
  table
392
392
  end
393
-
393
+
394
394
  @models ||= Hash.new
395
395
  @models[ model_key ] ||= Class.new( DBI::Model ) do |klass|
396
396
  klass.trait( {
@@ -399,31 +399,31 @@ module DBI
399
399
  :pk => pk_,
400
400
  :columns => h.columns( table.to_s ),
401
401
  } )
402
-
402
+
403
403
  if defined?( DBI::DBD::Pg::Database ) and DBI::DBD::Pg::Database === h.handle
404
404
  # TODO: This is broken for non-SERIAL or multi-column primary keys
405
405
  meta_def( "last_record".to_sym ) do |dbh_|
406
- self.s1 "SELECT * FROM #{table} WHERE #{pk} = currval( '#{table}_#{pk}_seq' );"
406
+ self.s1 "SELECT * FROM #{table} WHERE #{pk} = currval( '#{table}_#{pk}_seq' );"
407
407
  end
408
408
  elsif defined?( DBI::DBD::Mysql::Database ) and DBI::DBD::Mysql::Database === h.handle
409
409
  meta_def( "last_record".to_sym ) do |dbh_|
410
- self.s1 "SELECT * FROM #{table} WHERE #{pk} = LAST_INSERT_ID();"
410
+ self.s1 "SELECT * FROM #{table} WHERE #{pk} = LAST_INSERT_ID();"
411
411
  end
412
412
  elsif defined?( DBI::DBD::SQLite3::Database ) and DBI::DBD::SQLite3::Database === h.handle
413
413
  meta_def( "last_record".to_sym ) do |dbh_|
414
- self.s1 "SELECT * FROM #{table} WHERE #{pk} = last_insert_rowid();"
414
+ self.s1 "SELECT * FROM #{table} WHERE #{pk} = last_insert_rowid();"
415
415
  end
416
416
  # TODO: more DBDs
417
417
  end
418
-
418
+
419
419
  klass.trait[ :columns ].each do |col|
420
420
  colname = col[ 'name' ]
421
-
421
+
422
422
  # Column readers
423
423
  class_def( colname.to_sym ) do
424
424
  @row[ colname ]
425
425
  end
426
-
426
+
427
427
  # Column writers
428
428
  class_def( "#{colname}=".to_sym ) do |new_value|
429
429
  num_changed = dbh.do(
@@ -438,5 +438,5 @@ module DBI
438
438
  end
439
439
  end
440
440
  end
441
-
441
+
442
442
  end
data/spec/model.rb CHANGED
@@ -19,7 +19,7 @@ class ManyCol < DBI::Model( :many_col_table )
19
19
  def inc
20
20
  self.c1 = c1 + 10
21
21
  end
22
-
22
+
23
23
  def dec
24
24
  self.c1 = c1 - 10
25
25
  end
@@ -34,22 +34,23 @@ describe 'A DBI::Model subclass' do
34
34
  @m_post = Class.new( DBI::Model( :posts ) )
35
35
  @m_empty = Class.new( DBI::Model( :empty_table ) )
36
36
  @m_mc = Class.new( DBI::Model( :many_col_table ) )
37
+ @m_nipk = Class.new( DBI::Model( :non_id_pk, [ :str ] ) )
37
38
  @m_mcpk = Class.new( DBI::Model( :mcpk, [ :kc1, :kc2 ] ) )
38
39
  class Author < DBI::Model( :authors ); end
39
40
  end
40
-
41
+
41
42
  it 'can be defined' do
42
43
  @m_author.should.not.be.nil
43
44
  @m_post.should.not.be.nil
44
45
  end
45
-
46
+
46
47
  it 'maintains identity across different inheritances' do
47
48
  should.not.raise do
48
49
  class Author < DBI::Model( :authors ); end
49
50
  class Author < DBI::Model( :authors ); end
50
51
  end
51
52
  end
52
-
53
+
53
54
  it 'maintains member methods across redefinitions' do
54
55
  class Author < DBI::Model( :authors )
55
56
  def method1; 1; end
@@ -61,40 +62,40 @@ describe 'A DBI::Model subclass' do
61
62
  a.method1.should.equal 1
62
63
  a.method2.should.equal 2
63
64
  end
64
-
65
+
65
66
  it 'maintains identity across different database handles of the same database' do
66
67
  # If you try to subclass a class a second time with a different parent class,
67
68
  # Ruby raises an exception.
68
69
  should.not.raise do
69
70
  original_handle = DBI::DatabaseHandle.last_handle
70
-
71
+
71
72
  class Author < DBI::Model( :authors ); end
72
-
73
+
73
74
  dbh = connect_to_spec_database
74
75
  new_handle = DBI::DatabaseHandle.last_handle
75
76
  new_handle.should.equal dbh
76
77
  new_handle.should.not.equal original_handle
77
-
78
+
78
79
  class Author < DBI::Model( :authors ); end
79
80
  end
80
81
  end
81
-
82
+
82
83
  it 'maintains distinction from models of the same name in different databases' do
83
84
  begin
84
85
  a1 = @m_author[ 1 ]
85
86
  a1.should.not.be.nil
86
87
  a1.name.should.equal 'author1'
87
-
88
- dbh = connect_to_spec_database( 'm4dbi2' )
88
+
89
+ dbh = connect_to_spec_database( ENV[ 'M4DBI_DATABASE2' ] || 'm4dbi2' )
89
90
  reset_data( dbh, "test-data2.sql" )
90
-
91
+
91
92
  @m_author2 = Class.new( DBI::Model( :authors ) )
92
-
93
+
93
94
  @m_author2[ 1 ].should.be.nil
94
95
  a11 = @m_author2[ 11 ]
95
96
  a11.should.not.be.nil
96
97
  a11.name.should.equal 'author11'
97
-
98
+
98
99
  a2 = @m_author[ 2 ]
99
100
  a2.should.not.be.nil
100
101
  a2.name.should.equal 'author2'
@@ -104,7 +105,7 @@ describe 'A DBI::Model subclass' do
104
105
  connect_to_spec_database
105
106
  end
106
107
  end
107
-
108
+
108
109
  it 'raises an exception when creating with invalid arguments' do
109
110
  should.raise( DBI::Error ) do
110
111
  @m_author.new nil
@@ -116,82 +117,94 @@ describe 'A DBI::Model subclass' do
116
117
  @m_author.new Object.new
117
118
  end
118
119
  end
119
-
120
+
120
121
  it 'provides hash-like single-record access via #[ primary_key_value ]' do
121
122
  o = @m_author[ 1 ]
122
123
  o.should.not.be.nil
123
124
  o.class.should.equal @m_author
124
125
  o.name.should.equal 'author1'
125
-
126
+
126
127
  o = @m_author[ 2 ]
127
128
  o.should.not.be.nil
128
129
  o.class.should.equal @m_author
129
130
  o.name.should.equal 'author2'
130
-
131
+
132
+ o = @m_nipk[ 'one' ]
133
+ o.should.not.be.nil
134
+ o.class.should.equal @m_nipk
135
+ o.c1.should.equal 1
136
+ o.c2.should.equal 2
137
+
138
+ o = @m_nipk[ 'two' ]
139
+ o.should.not.be.nil
140
+ o.class.should.equal @m_nipk
141
+ o.c1.should.equal 2
142
+ o.c2.should.equal 4
143
+
131
144
  o = @m_mcpk[ [ 2, 2 ] ]
132
145
  o.should.not.be.nil
133
146
  o.class.should.equal @m_mcpk
134
147
  o.val.should.equal 'two two'
135
-
148
+
136
149
  o = @m_mcpk[ 1, 1 ]
137
150
  o.should.not.be.nil
138
151
  o.class.should.equal @m_mcpk
139
152
  o.val.should.equal 'one one'
140
-
153
+
141
154
  o = @m_mcpk[ { :kc1 => 5, :kc2 => 6 } ]
142
155
  o.should.not.be.nil
143
156
  o.class.should.equal @m_mcpk
144
157
  o.val.should.equal 'five six'
145
-
158
+
146
159
  should.not.raise( DBI::Error ) do
147
160
  o = @m_author[ nil ]
148
161
  o.should.be.nil
149
162
  end
150
163
  end
151
-
164
+
152
165
  it 'provides hash-like single-record access via #[ field_hash ]' do
153
166
  o = @m_author[ :name => 'author1' ]
154
167
  o.should.not.be.nil
155
168
  o.class.should.equal @m_author
156
169
  o.id.should.equal 1
157
-
170
+
158
171
  o = @m_post[ :author_id => 1 ]
159
172
  o.should.not.be.nil
160
173
  o.class.should.equal @m_post
161
174
  o.text.should.equal 'First post.'
162
-
175
+
163
176
  o = @m_mc[ :c1 => 100, :c2 => 50 ]
164
177
  o.should.not.be.nil
165
178
  o.class.should.equal @m_mc
166
179
  o.c3.should.equal 20
167
-
180
+
168
181
  o = @m_mc[ :c1 => 100, :c2 => nil ]
169
182
  o.should.not.be.nil
170
183
  o.class.should.equal @m_mc
171
184
  o.c3.should.equal 40
172
185
  end
173
-
186
+
174
187
  it 'returns nil from #[] when no record is found' do
175
188
  o = @m_author[ 999 ]
176
189
  o.should.be.nil
177
-
190
+
178
191
  o = @m_author[ :name => 'foobar' ]
179
192
  o.should.be.nil
180
193
  end
181
-
194
+
182
195
  it 'provides multi-record access via #where( Hash )' do
183
196
  posts = @m_post.where( :author_id => 1 )
184
197
  posts.should.not.be.nil
185
198
  posts.should.not.be.empty
186
199
  posts.size.should.equal 2
187
200
  posts[ 0 ].class.should.equal @m_post
188
-
201
+
189
202
  sorted_posts = posts.sort { |p1,p2|
190
203
  p1._id <=> p2._id
191
204
  }
192
205
  p = sorted_posts.first
193
206
  p.text.should.equal 'First post.'
194
-
207
+
195
208
  rows = @m_mc.where( :c1 => 100, :c2 => 50 )
196
209
  rows.should.not.be.nil
197
210
  rows.should.not.be.empty
@@ -200,7 +213,7 @@ describe 'A DBI::Model subclass' do
200
213
  row.class.should.equal @m_mc
201
214
  row.c1.should.equal 100
202
215
  row.c3.should.equal 20
203
-
216
+
204
217
  rows = @m_mc.where( :c1 => 100, :c2 => nil )
205
218
  rows.should.not.be.nil
206
219
  rows.should.not.be.empty
@@ -209,85 +222,85 @@ describe 'A DBI::Model subclass' do
209
222
  row.class.should.equal @m_mc
210
223
  row.c1.should.equal 100
211
224
  row.c3.should.equal 40
212
- end
213
-
225
+ end
226
+
214
227
  it 'provides multi-record access via #where( String )' do
215
228
  posts = @m_post.where( "id < 3" )
216
229
  posts.should.not.be.nil
217
230
  posts.should.not.be.empty
218
231
  posts.size.should.equal 2
219
232
  posts[ 0 ].class.should.equal @m_post
220
-
233
+
221
234
  sorted_posts = posts.sort { |p1,p2|
222
235
  p2._id <=> p1._id
223
236
  }
224
237
  p = sorted_posts.first
225
238
  p.text.should.equal 'Second post.'
226
239
  end
227
-
240
+
228
241
  it 'provides multi-record access via #where( String, param, param... )' do
229
242
  posts = @m_post.where( "id < ?", 3 )
230
243
  posts.should.not.be.nil
231
244
  posts.should.not.be.empty
232
245
  posts.size.should.equal 2
233
246
  posts[ 0 ].class.should.equal @m_post
234
-
247
+
235
248
  sorted_posts = posts.sort { |p1,p2|
236
249
  p2._id <=> p1._id
237
250
  }
238
251
  p = sorted_posts.first
239
252
  p.text.should.equal 'Second post.'
240
253
  end
241
-
254
+
242
255
  it 'returns an empty array from #where when no records are found' do
243
256
  a = @m_author.where( :id => 999 )
244
257
  a.should.be.empty
245
-
258
+
246
259
  p = @m_post.where( "text = 'aoeu'" )
247
260
  p.should.be.empty
248
261
  end
249
-
262
+
250
263
  it 'provides single-record access via #one_where( Hash )' do
251
264
  post = @m_post.one_where( :author_id => 2 )
252
265
  post.should.not.be.nil
253
266
  post.class.should.equal @m_post
254
267
  post.text.should.equal 'Second post.'
255
-
268
+
256
269
  row = @m_mc.one_where( :c1 => 100, :c2 => nil )
257
270
  row.should.not.be.nil
258
271
  row.class.should.equal @m_mc
259
272
  row.c1.should.equal 100
260
273
  row.c3.should.equal 40
261
274
  end
262
-
275
+
263
276
  it 'provides single-record access via #one_where( String )' do
264
277
  post = @m_post.one_where( "text LIKE '%Third%'" )
265
278
  post.should.not.be.nil
266
279
  post.class.should.equal @m_post
267
280
  post.id.should.equal 3
268
281
  end
269
-
282
+
270
283
  it 'provides single-record access via #one_where( String, param, param... )' do
271
284
  post = @m_post.one_where( "text LIKE ?", '%Third%' )
272
285
  post.should.not.be.nil
273
286
  post.class.should.equal @m_post
274
287
  post.id.should.equal 3
275
288
  end
276
-
289
+
277
290
  it 'returns nil from #one_where when no record is found' do
278
291
  a = @m_author.one_where( :id => 999 )
279
292
  a.should.be.nil
280
-
293
+
281
294
  p = @m_post.one_where( "text = 'aoeu'" )
282
295
  p.should.be.nil
283
296
  end
284
-
297
+
285
298
  it 'returns all table records via #all' do
286
299
  rows = @m_author.all
287
300
  rows.should.not.be.nil
288
301
  rows.should.not.be.empty
289
302
  rows.size.should.equal 3
290
-
303
+
291
304
  rows[ 0 ].id.should.equal 1
292
305
  rows[ 0 ].class.should.equal @m_author
293
306
  rows[ 0 ].name.should.equal 'author1'
@@ -295,29 +308,29 @@ describe 'A DBI::Model subclass' do
295
308
  rows[ 1 ].class.should.equal @m_author
296
309
  rows[ 1 ].name.should.equal 'author2'
297
310
  end
298
-
311
+
299
312
  it 'returns an empty array when #all is called on an empty table' do
300
313
  rows = @m_empty.all
301
314
  rows.should.not.be.nil
302
315
  rows.should.be.empty
303
316
  end
304
-
317
+
305
318
  it 'returns a random single record from #one' do
306
319
  one = @m_author.one
307
320
  one.should.not.be.nil
308
321
  one.class.should.equal @m_author
309
322
  end
310
-
323
+
311
324
  it 'returns nil from #one on an empty table' do
312
325
  one = @m_empty.one
313
326
  one.should.be.nil
314
327
  end
315
-
328
+
316
329
  it 'returns the record count via #count' do
317
330
  n = @m_author.count
318
331
  n.should.equal 3
319
332
  end
320
-
333
+
321
334
  it 'provides a means to create new records via #create( Hash )' do
322
335
  a = @m_author.create(
323
336
  :id => 9,
@@ -329,22 +342,22 @@ describe 'A DBI::Model subclass' do
329
342
  a.should.respond_to :name
330
343
  a.should.not.respond_to :no_column_by_this_name
331
344
  a.name.should.equal 'author9'
332
-
345
+
333
346
  a_ = @m_author[ 9 ]
334
347
  a_.should.not.be.nil
335
348
  a_.should.equal a
336
349
  a_.name.should.equal 'author9'
337
-
350
+
338
351
  reset_data
339
352
  end
340
-
353
+
341
354
  it 'provides a means to create new records via #create { |r| }' do
342
355
  should.raise( NoMethodError ) do
343
356
  @m_author.create { |rec|
344
357
  rec.no_such_column = 'foobar'
345
358
  }
346
359
  end
347
-
360
+
348
361
  a = @m_author.create { |rec|
349
362
  rec.id = 9
350
363
  rec.name = 'author9'
@@ -353,11 +366,11 @@ describe 'A DBI::Model subclass' do
353
366
  a.class.should.equal @m_author
354
367
  a.id.should.equal 9
355
368
  a.name.should.equal 'author9'
356
-
369
+
357
370
  a_ = @m_author[ 9 ]
358
371
  a_.should.equal a
359
372
  a_.name.should.equal 'author9'
360
-
373
+
361
374
  m = nil
362
375
  should.not.raise do
363
376
  m = @m_mc.create { |rec|
@@ -373,10 +386,10 @@ describe 'A DBI::Model subclass' do
373
386
  m_.c3.should.equal 8
374
387
  m_.c4.should.be.nil
375
388
  m_.c5.should.be.nil
376
-
389
+
377
390
  reset_data
378
391
  end
379
-
392
+
380
393
  it 'returns a record via #find_or_create( Hash )' do
381
394
  n = @m_author.count
382
395
  a = @m_author.find_or_create(
@@ -390,7 +403,7 @@ describe 'A DBI::Model subclass' do
390
403
  a.should.not.respond_to :no_column_by_this_name
391
404
  a.name.should.equal 'author1'
392
405
  @m_author.count.should.equal n
393
-
406
+
394
407
  n = @m_mc.count
395
408
  row = @m_mc.find_or_create( :c1 => 100, :c2 => nil )
396
409
  row.should.not.be.nil
@@ -399,7 +412,7 @@ describe 'A DBI::Model subclass' do
399
412
  row.c3.should.equal 40
400
413
  @m_mc.count.should.equal n
401
414
  end
402
-
415
+
403
416
  it 'creates a record via #find_or_create( Hash )' do
404
417
  n = @m_author.count
405
418
  a = @m_author.find_or_create(
@@ -413,15 +426,15 @@ describe 'A DBI::Model subclass' do
413
426
  a.should.not.respond_to :no_column_by_this_name
414
427
  a.name.should.equal 'author9'
415
428
  @m_author.count.should.equal n+1
416
-
429
+
417
430
  a_ = @m_author[ 9 ]
418
431
  a_.should.not.be.nil
419
432
  a_.should.equal a
420
433
  a_.name.should.equal 'author9'
421
-
434
+
422
435
  reset_data
423
436
  end
424
-
437
+
425
438
  it 'provides a means to use generic raw SQL to select model instances' do
426
439
  posts = @m_post.s(
427
440
  %{
@@ -439,19 +452,19 @@ describe 'A DBI::Model subclass' do
439
452
  posts.should.not.be.nil
440
453
  posts.should.not.be.empty
441
454
  posts.size.should.equal 2
442
-
455
+
443
456
  posts[ 0 ].id.should.equal 1
444
457
  posts[ 0 ].text.should.equal 'First post.'
445
458
  posts[ 0 ].class.should.equal @m_post
446
459
  posts[ 1 ].id.should.equal 3
447
460
  posts[ 1 ].text.should.equal 'Third post.'
448
461
  posts[ 1 ].class.should.equal @m_post
449
-
462
+
450
463
  no_posts = @m_post.s( "SELECT * FROM posts WHERE 1+1 = 3" )
451
464
  no_posts.should.not.be.nil
452
465
  no_posts.should.be.empty
453
466
  end
454
-
467
+
455
468
  it 'provides a means to use generic raw SQL to select one model instance' do
456
469
  post = @m_post.s1(
457
470
  %{
@@ -468,18 +481,18 @@ describe 'A DBI::Model subclass' do
468
481
  },
469
482
  'author1'
470
483
  )
471
-
484
+
472
485
  post.should.not.be.nil
473
486
  post.class.should.equal @m_post
474
-
487
+
475
488
  post.id.should.equal 3
476
489
  post.author_id.should.equal 1
477
490
  post.text.should.equal 'Third post.'
478
-
491
+
479
492
  no_post = @m_post.s1( "SELECT * FROM posts WHERE 1+1 = 3" )
480
493
  no_post.should.be.nil
481
494
  end
482
-
495
+
483
496
  it 'is Enumerable' do
484
497
  should.not.raise do
485
498
  @m_author.each { |a| }
@@ -498,66 +511,66 @@ describe 'A DBI::Model subclass' do
498
511
  authors.find { |a| a.name == 'author3' }.should.not.be.nil
499
512
  authors.find { |a| a.name == 'author99' }.should.be.nil
500
513
  end
501
-
514
+
502
515
  it 'provides a means to update records referred to by primary key value' do
503
516
  new_text = 'Some new text.'
504
-
517
+
505
518
  p2 = @m_post[ 2 ]
506
519
  p2.text.should.not.equal new_text
507
520
  @m_post.update_one( 2, { :text => new_text } )
508
521
  p2_ = @m_post[ 2 ]
509
522
  p2_.text.should.equal new_text
510
-
523
+
511
524
  row = @m_mcpk[ 1, 1 ]
512
525
  row.val.should.not.equal new_text
513
526
  @m_mcpk.update_one( 1, 1, { :val => new_text } )
514
527
  row = @m_mcpk[ 1, 1 ]
515
528
  row.val.should.equal new_text
516
-
529
+
517
530
  row = @m_mcpk[ 3, 4 ]
518
531
  row.val.should.not.equal new_text
519
532
  @m_mcpk.update_one( 3, 4, { :val => new_text } )
520
533
  row = @m_mcpk[ 3, 4 ]
521
534
  row.val.should.equal new_text
522
-
535
+
523
536
  reset_data
524
537
  end
525
-
538
+
526
539
  it 'provides a means to update records referred to by a value hash' do
527
540
  new_text = 'This is some new text.'
528
-
541
+
529
542
  posts = @m_post.where( :author_id => 1 )
530
543
  posts.size.should.equal 2
531
544
  posts.find_all { |p| p.text == new_text }.should.be.empty
532
-
545
+
533
546
  @m_post.update(
534
547
  { :author_id => 1 },
535
548
  { :text => new_text }
536
549
  )
537
-
550
+
538
551
  posts_ = @m_post.where( :author_id => 1 )
539
552
  posts_.size.should.equal 2
540
553
  posts_.find_all { |p| p.text == new_text }.should.equal posts_
541
-
554
+
542
555
  reset_data
543
556
  end
544
-
557
+
545
558
  it 'provides a means to update records specified by a raw WHERE clause' do
546
559
  new_text = 'This is some new text.'
547
-
560
+
548
561
  posts = @m_post.where( :author_id => 1 )
549
562
  posts.size.should.equal 2
550
563
  posts.find_all { |p| p.text == new_text }.should.be.empty
551
-
564
+
552
565
  @m_post.update(
553
566
  "author_id < 2",
554
567
  { :text => new_text }
555
568
  )
556
-
569
+
557
570
  posts_ = @m_post.where( :author_id => 1 )
558
571
  posts_.size.should.equal 2
559
572
  posts_.find_all { |p| p.text == new_text }.should.equal posts_
560
-
573
+
561
574
  reset_data
562
575
  end
563
576
  end
@@ -568,7 +581,7 @@ describe 'A created DBI::Model subclass instance' do
568
581
  @m_author = Class.new( DBI::Model( :authors ) )
569
582
  @m_post = Class.new( DBI::Model( :posts ) )
570
583
  end
571
-
584
+
572
585
  it 'provides read access to fields via identically-named readers' do
573
586
  mc = @m_mc.create(
574
587
  :c3 => 3,
@@ -585,7 +598,7 @@ describe 'A created DBI::Model subclass instance' do
585
598
  mc.c3.should.equal 3
586
599
  mc.c4.should.equal 4
587
600
  end
588
-
601
+
589
602
  it 'provides write access to fields via identically-named writers' do
590
603
  mc = @m_mc.create(
591
604
  :c3 => 30,
@@ -600,7 +613,7 @@ describe 'A created DBI::Model subclass instance' do
600
613
  mc.c4.should.equal 40
601
614
  id_ = mc.id
602
615
  id_.should.not.be.nil
603
-
616
+
604
617
  mc_ = @m_mc[ id_ ]
605
618
  mc_.id.should.equal id_
606
619
  mc_.c1.should.equal 10
@@ -608,25 +621,25 @@ describe 'A created DBI::Model subclass instance' do
608
621
  mc_.c3.should.equal 30
609
622
  mc_.c4.should.equal 40
610
623
  end
611
-
624
+
612
625
  it 'maintains Hash key equality across different fetches' do
613
626
  h = Hash.new
614
627
  a = @m_author[ 1 ]
615
628
  h[ a ] = 123
616
629
  a_ = @m_author[ 1 ]
617
630
  h[ a_].should.equal 123
618
-
631
+
619
632
  a2 = @m_author[ 2 ]
620
633
  h[ a2 ].should.be.nil
621
-
634
+
622
635
  h[ a2 ] = 456
623
636
  h[ a ].should.equal 123
624
637
  h[ a_ ].should.equal 123
625
-
638
+
626
639
  a2_ = @m_author[ 2 ]
627
640
  h[ a2_ ].should.equal 456
628
641
  end
629
-
642
+
630
643
  it 'maintains Hash key distinction for different Model subclasses' do
631
644
  h = Hash.new
632
645
  a = @m_author[ 1 ]
@@ -634,7 +647,7 @@ describe 'A created DBI::Model subclass instance' do
634
647
  p = @m_post[ 1 ]
635
648
  h[ p ] = 456
636
649
  h[ p ].should.equal 456
637
-
650
+
638
651
  a_ = @m_author[ 1 ]
639
652
  h[ a_ ].should.equal 123
640
653
  end
@@ -645,57 +658,58 @@ describe 'A found DBI::Model subclass instance' do
645
658
  @m_author = Class.new( DBI::Model( :authors ) )
646
659
  @m_post = Class.new( DBI::Model( :posts ) )
647
660
  @m_mc = Class.new( DBI::Model( :many_col_table ) )
661
+ @m_nipk = Class.new( DBI::Model( :non_id_pk, [ :str ] ) )
648
662
  @m_mcpk = Class.new( DBI::Model( :mcpk, [ :kc1, :kc2 ] ) )
649
663
  end
650
-
664
+
651
665
  it 'provides access to primary key value' do
652
666
  a = @m_author[ 1 ]
653
667
  a.pk.should.equal 1
654
-
668
+
655
669
  p = @m_post[ 3 ]
656
670
  p.pk.should.equal 3
657
-
671
+
658
672
  r = @m_mcpk[ 1, 1 ]
659
673
  r.pk.should.equal [ 1, 1 ]
660
-
674
+
661
675
  r = @m_mcpk[ { :kc1 => 3, :kc2 => 4 } ]
662
676
  r.pk.should.equal [ 3, 4 ]
663
677
  end
664
-
678
+
665
679
  it 'provides read access to fields via identically-named readers' do
666
680
  p = @m_post[ 2 ]
667
-
681
+
668
682
  should.not.raise( NoMethodError ) do
669
683
  p.id
670
684
  p.author_id
671
685
  p.text
672
686
  end
673
-
687
+
674
688
  should.raise( NoMethodError ) do
675
689
  p.foobar
676
690
  end
677
-
691
+
678
692
  p.id.should.equal 2
679
693
  p.author_id.should.equal 2
680
694
  p.text.should.equal 'Second post.'
681
695
  end
682
-
696
+
683
697
  it 'provides write access to fields via identically-named writers' do
684
698
  the_new_text = 'Here is some new text.'
685
-
699
+
686
700
  p2 = @m_post[ 2 ]
687
-
701
+
688
702
  p3 = @m_post[ 3 ]
689
703
  p3.text = the_new_text
690
704
  p3.text.should.equal the_new_text
691
-
705
+
692
706
  p3_ = @m_post[ 3 ]
693
707
  p3_.text.should.equal the_new_text
694
-
708
+
695
709
  # Shouldn't change other rows
696
710
  p2_ = @m_post[ 2 ]
697
711
  p2_.text.should.equal p2.text
698
-
712
+
699
713
  mc1 = @m_mc.create(
700
714
  :id => 1,
701
715
  :c1 => 2
@@ -705,17 +719,17 @@ describe 'A found DBI::Model subclass instance' do
705
719
  mc1.c1.should.be.nil
706
720
  mc1_ = @m_mc[ 1 ]
707
721
  mc1_.c1.should.be.nil
708
-
722
+
709
723
  reset_data
710
724
  end
711
-
725
+
712
726
  it 'maintains identity across multiple DB hits' do
713
727
  px = @m_post[ 1 ]
714
728
  py = @m_post[ 1 ]
715
-
729
+
716
730
  px.should.equal py
717
731
  end
718
-
732
+
719
733
  it 'provides multi-column writability via Model#set' do
720
734
  p = @m_post[ 1 ]
721
735
  the_new_text = 'The 3rd post.'
@@ -725,11 +739,11 @@ describe 'A found DBI::Model subclass instance' do
725
739
  )
726
740
  p.author_id.should.equal 2
727
741
  p.text.should.equal the_new_text
728
-
742
+
729
743
  p_ = @m_post[ 1 ]
730
744
  p_.author_id.should.equal 2
731
745
  p_.text.should.equal the_new_text
732
-
746
+
733
747
  mc1 = @m_mc.create(
734
748
  :id => 1,
735
749
  :c1 => 2,
@@ -744,17 +758,23 @@ describe 'A found DBI::Model subclass instance' do
744
758
  mc1_ = @m_mc[ 1 ]
745
759
  mc1_.c1.should.be.nil
746
760
  mc1_.c2.should.equal 4
747
-
761
+
748
762
  reset_data
749
763
  end
750
-
764
+
751
765
  it 'is deleted by #delete' do
752
766
  p = @m_post[ 3 ]
753
767
  p.should.not.be.nil
754
768
  successfully_deleted = p.delete
755
769
  successfully_deleted.should.be.true
756
770
  @m_post[ 3 ].should.be.nil
757
-
771
+
772
+ o = @m_nipk[ 'one' ]
773
+ o.should.not.be.nil
774
+ successfully_deleted = o.delete
775
+ successfully_deleted.should.be.true
776
+ @m_nipk[ 'one' ].should.be.nil
777
+
758
778
  reset_data
759
779
  end
760
780
 
@@ -764,7 +784,7 @@ describe 'A found DBI::Model subclass instance' do
764
784
  p.save
765
785
  end
766
786
  end
767
-
787
+
768
788
  end
769
789
 
770
790
  describe 'DBI::Model (relationships)' do
@@ -773,7 +793,7 @@ describe 'DBI::Model (relationships)' do
773
793
  @m_post = Class.new( DBI::Model( :posts ) )
774
794
  @m_fan = Class.new( DBI::Model( :fans ) )
775
795
  end
776
-
796
+
777
797
  it 'facilitates relating one to many, providing read access' do
778
798
  DBI::Model.one_to_many( @m_author, @m_post, :posts, :author, :author_id )
779
799
  a = @m_author[ 1 ]
@@ -782,7 +802,7 @@ describe 'DBI::Model (relationships)' do
782
802
  p.author.should.not.be.nil
783
803
  p.author.id.should.equal 1
784
804
  end
785
-
805
+
786
806
  it 'facilitates relating one to many, allowing one of the many to set its one' do
787
807
  DBI::Model.one_to_many(
788
808
  @m_author, @m_post, :posts, :author, :author_id
@@ -793,10 +813,10 @@ describe 'DBI::Model (relationships)' do
793
813
  p.author = @m_author.create( :id => 4, :name => 'author4' )
794
814
  p_ = @m_post[ 3 ]
795
815
  p_.author.id.should.equal 4
796
-
816
+
797
817
  reset_data
798
818
  end
799
-
819
+
800
820
  it 'facilitates relating many to many, providing read access' do
801
821
  DBI::Model.many_to_many(
802
822
  @m_author, @m_fan, :authors_liked, :fans, :authors_fans, :author_id, :fan_id
@@ -805,7 +825,7 @@ describe 'DBI::Model (relationships)' do
805
825
  a2 = @m_author[ 2 ]
806
826
  f2 = @m_fan[ 2 ]
807
827
  f3 = @m_fan[ 3 ]
808
-
828
+
809
829
  a1f = a1.fans
810
830
  a1f.should.not.be.nil
811
831
  a1f.should.not.be.empty
@@ -814,7 +834,7 @@ describe 'DBI::Model (relationships)' do
814
834
  a1f.find { |f| f.name == 'fan1' }.should.be.nil
815
835
  a1f.find { |f| f.name == 'fan2' }.should.not.be.nil
816
836
  a1f.find { |f| f.name == 'fan3' }.should.not.be.nil
817
-
837
+
818
838
  a2f = a2.fans
819
839
  a2f.should.not.be.nil
820
840
  a2f.should.not.be.empty
@@ -823,14 +843,14 @@ describe 'DBI::Model (relationships)' do
823
843
  a2f.find { |f| f.name == 'fan1' }.should.be.nil
824
844
  a2f.find { |f| f.name == 'fan3' }.should.not.be.nil
825
845
  a2f.find { |f| f.name == 'fan4' }.should.not.be.nil
826
-
846
+
827
847
  f2a = f2.authors_liked
828
848
  f2a.should.not.be.nil
829
849
  f2a.should.not.be.empty
830
850
  f2a.size.should.equal 1
831
851
  f2a[ 0 ].class.should.equal @m_author
832
852
  f2a[ 0 ].name.should.equal 'author1'
833
-
853
+
834
854
  f3a = f3.authors_liked
835
855
  f3a.should.not.be.nil
836
856
  f3a.should.not.be.empty
@@ -838,7 +858,7 @@ describe 'DBI::Model (relationships)' do
838
858
  f3a.find { |a| a.name == 'author1' }.should.not.be.nil
839
859
  f3a.find { |a| a.name == 'author2' }.should.not.be.nil
840
860
  f3a.find { |a| a.name == 'author3' }.should.be.nil
841
-
861
+
842
862
  @m_author[ 3 ].fans.should.be.empty
843
863
  @m_fan[ 5 ].authors_liked.should.be.empty
844
864
  end
@@ -848,12 +868,12 @@ describe 'DBI::Collection' do
848
868
  before do
849
869
  @m_author = Class.new( DBI::Model( :authors ) )
850
870
  @m_post = Class.new( DBI::Model( :posts ) )
851
-
871
+
852
872
  DBI::Model.one_to_many(
853
873
  @m_author, @m_post, :posts, :author, :author_id
854
874
  )
855
875
  end
856
-
876
+
857
877
  it 'accepts additions' do
858
878
  a = @m_author[ 1 ]
859
879
  the_text = 'A new post.'
@@ -861,26 +881,26 @@ describe 'DBI::Collection' do
861
881
  p = a.posts.find { |p| p.text == the_text }
862
882
  p.should.not.be.nil
863
883
  p.author.should.equal a
864
-
884
+
865
885
  a_ = @m_author[ 1 ]
866
886
  a_.posts.find { |p| p.text == the_text }.should.not.be.nil
867
-
887
+
868
888
  reset_data
869
889
  end
870
-
890
+
871
891
  it 'facilitates single record deletions' do
872
892
  a = @m_author[ 1 ]
873
893
  posts = a.posts
874
894
  n = posts.size
875
895
  p = posts[ 0 ]
876
-
896
+
877
897
  posts.delete( p ).should.be.true
878
898
  a.posts.size.should.equal( n - 1 )
879
899
  posts.find { |p_| p_ == p }.should.be.nil
880
-
900
+
881
901
  reset_data
882
902
  end
883
-
903
+
884
904
  it 'facilitates multi-record deletions' do
885
905
  a = @m_author[ 1 ]
886
906
  posts = a.posts
@@ -889,16 +909,16 @@ describe 'DBI::Collection' do
889
909
  a.posts.size.should.equal( n - 1 )
890
910
  posts.find { |p| p.text == 'Third post.' }.should.be.nil
891
911
  posts.find { |p| p.text == 'First post.' }.should.not.be.nil
892
-
912
+
893
913
  reset_data
894
914
  end
895
-
915
+
896
916
  it 'facilitates table-wide deletion' do
897
917
  a = @m_author[ 1 ]
898
918
  a.posts.should.not.be.empty
899
919
  a.posts.clear.should.be > 0
900
920
  a.posts.should.be.empty
901
-
921
+
902
922
  reset_data
903
923
  end
904
924
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: m4dbi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pistos
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-11-10 00:00:00 -05:00
12
+ date: 2009-02-08 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -83,7 +83,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
83
83
  requirements:
84
84
  - bacon (optional)
85
85
  rubyforge_project: m4dbi
86
- rubygems_version: 1.2.0
86
+ rubygems_version: 1.3.1
87
87
  signing_key:
88
88
  specification_version: 2
89
89
  summary: Models (and More) for DBI