m4dbi 0.6.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
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