sequel 3.13.0 → 3.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. data/CHANGELOG +36 -0
  2. data/doc/release_notes/3.14.0.txt +118 -0
  3. data/lib/sequel/adapters/oracle.rb +7 -2
  4. data/lib/sequel/adapters/shared/mssql.rb +9 -3
  5. data/lib/sequel/connection_pool/sharded_threaded.rb +1 -1
  6. data/lib/sequel/connection_pool/threaded.rb +3 -3
  7. data/lib/sequel/database/connecting.rb +47 -11
  8. data/lib/sequel/database/dataset.rb +17 -6
  9. data/lib/sequel/database/dataset_defaults.rb +15 -3
  10. data/lib/sequel/database/logging.rb +4 -3
  11. data/lib/sequel/database/misc.rb +33 -21
  12. data/lib/sequel/database/query.rb +61 -22
  13. data/lib/sequel/database/schema_generator.rb +108 -45
  14. data/lib/sequel/database/schema_methods.rb +8 -5
  15. data/lib/sequel/dataset/actions.rb +194 -45
  16. data/lib/sequel/dataset/features.rb +1 -1
  17. data/lib/sequel/dataset/graph.rb +51 -43
  18. data/lib/sequel/dataset/misc.rb +29 -5
  19. data/lib/sequel/dataset/mutation.rb +0 -1
  20. data/lib/sequel/dataset/prepared_statements.rb +14 -2
  21. data/lib/sequel/dataset/query.rb +268 -125
  22. data/lib/sequel/dataset/sql.rb +33 -44
  23. data/lib/sequel/extensions/migration.rb +3 -2
  24. data/lib/sequel/extensions/pagination.rb +1 -1
  25. data/lib/sequel/model/associations.rb +89 -87
  26. data/lib/sequel/model/base.rb +386 -109
  27. data/lib/sequel/model/errors.rb +15 -1
  28. data/lib/sequel/model/exceptions.rb +3 -3
  29. data/lib/sequel/model/inflections.rb +2 -2
  30. data/lib/sequel/model/plugins.rb +9 -5
  31. data/lib/sequel/plugins/rcte_tree.rb +43 -15
  32. data/lib/sequel/plugins/schema.rb +6 -5
  33. data/lib/sequel/plugins/serialization.rb +1 -1
  34. data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
  35. data/lib/sequel/plugins/tree.rb +33 -1
  36. data/lib/sequel/timezones.rb +16 -10
  37. data/lib/sequel/version.rb +1 -1
  38. data/spec/adapters/mssql_spec.rb +36 -2
  39. data/spec/adapters/mysql_spec.rb +4 -4
  40. data/spec/adapters/postgres_spec.rb +1 -1
  41. data/spec/adapters/spec_helper.rb +2 -2
  42. data/spec/core/database_spec.rb +8 -1
  43. data/spec/core/dataset_spec.rb +36 -1
  44. data/spec/extensions/pagination_spec.rb +1 -1
  45. data/spec/extensions/rcte_tree_spec.rb +40 -8
  46. data/spec/extensions/schema_spec.rb +5 -0
  47. data/spec/extensions/serialization_spec.rb +4 -4
  48. data/spec/extensions/single_table_inheritance_spec.rb +7 -0
  49. data/spec/extensions/tree_spec.rb +36 -0
  50. data/spec/integration/dataset_test.rb +19 -0
  51. data/spec/integration/prepared_statement_test.rb +2 -2
  52. data/spec/integration/schema_test.rb +1 -1
  53. data/spec/integration/spec_helper.rb +4 -4
  54. data/spec/integration/timezone_test.rb +27 -21
  55. data/spec/model/associations_spec.rb +5 -5
  56. data/spec/model/dataset_methods_spec.rb +13 -0
  57. data/spec/model/hooks_spec.rb +31 -0
  58. data/spec/model/record_spec.rb +24 -7
  59. data/spec/model/validations_spec.rb +9 -4
  60. metadata +6 -4
@@ -10,7 +10,7 @@ module Sequel
10
10
  # * All of the method names in Model::DATASET_METHODS have class methods created that call
11
11
  # the Model's dataset with the method of the same name with the given arguments.
12
12
  module ClassMethods
13
- # Which columns should be the only columns allowed in a call to set
13
+ # Which columns should be the only columns allowed in a call to a mass assignment method (e.g. set)
14
14
  # (default: not set, so all columns not otherwise restricted).
15
15
  attr_reader :allowed_columns
16
16
 
@@ -88,7 +88,13 @@ module Sequel
88
88
  # Returns the first record from the database matching the conditions.
89
89
  # If a hash is given, it is used as the conditions. If another
90
90
  # object is given, it finds the first record whose primary key(s) match
91
- # the given argument(s).
91
+ # the given argument(s). If no object is returned by the dataset, returns nil.
92
+ #
93
+ # Artist[1] # SELECT * FROM artists WHERE id = 1
94
+ # # => #<Artist {:id=>1, ...}>
95
+ #
96
+ # Artist[:name=>'Bob'] # SELECT * FROM artists WHERE (name = 'Bob') LIMIT 1
97
+ # # => #<Artist {:name=>'Bob', ...}>
92
98
  def [](*args)
93
99
  args = args.first if (args.size == 1)
94
100
  args.is_a?(Hash) ? dataset[args] : primary_key_lookup(args)
@@ -97,19 +103,32 @@ module Sequel
97
103
  # Returns the columns in the result set in their original order.
98
104
  # Generally, this will use the columns determined via the database
99
105
  # schema, but in certain cases (e.g. models that are based on a joined
100
- # dataset) it will use Dataset#columns to find the columns, which
101
- # may be empty if the Dataset has no records.
106
+ # dataset) it will use <tt>Dataset#columns</tt> to find the columns.
107
+ #
108
+ # Artist.columns
109
+ # # => [:id, :name]
102
110
  def columns
103
111
  @columns || set_columns(dataset.naked.columns)
104
112
  end
105
113
 
106
114
  # Creates instance using new with the given values and block, and saves it.
115
+ #
116
+ # Artist.create(:name=>'Bob')
117
+ # # INSERT INTO artists (name) VALUES ('Bob')
118
+ #
119
+ # Artist.create do |a|
120
+ # a.name = 'Jim'
121
+ # end # INSERT INTO artists (name) VALUES ('Jim')
107
122
  def create(values = {}, &block)
108
123
  new(values, &block).save
109
124
  end
110
125
 
111
126
  # Returns the dataset associated with the Model class. Raises
112
- # an error if there is no associated dataset for this class.
127
+ # an +Error+ if there is no associated dataset for this class.
128
+ # In most cases, you don't need to call this directly, as Model
129
+ # proxies many dataset methods to the underlying dataset.
130
+ #
131
+ # Artist.dataset.all # SELECT * FROM artists
113
132
  def dataset
114
133
  @dataset || raise(Error, "No dataset associated with #{self}")
115
134
  end
@@ -124,6 +143,11 @@ module Sequel
124
143
  # assumes the superclass's database, or the first object in
125
144
  # Sequel::DATABASES. If no Sequel::Database object has
126
145
  # been created, raises an error.
146
+ #
147
+ # Artist.db.transaction do # BEGIN
148
+ # Artist.create(:name=>'Bob')
149
+ # # INSERT INTO artists (name) VALUES ('Bob')
150
+ # end # COMMIT
127
151
  def db
128
152
  return @db if @db
129
153
  @db = self == Model ? DATABASES.first : superclass.db
@@ -134,25 +158,46 @@ module Sequel
134
158
  # Sets the database associated with the Model class. If the
135
159
  # model has an associated dataset, sets the model's dataset
136
160
  # to a dataset on the new database with the same options
137
- # used by the current dataset.
161
+ # used by the current dataset. This can be used directly on
162
+ # Sequel::Model to set the default database to be used
163
+ # by subclasses, or to override the database used for specific
164
+ # models:
165
+ #
166
+ # Sequel::Model.db = DB1
167
+ # Artist.db = DB2
138
168
  def db=(db)
139
169
  @db = db
140
170
  set_dataset(db.dataset(@dataset.opts)) if @dataset
141
171
  end
142
172
 
143
173
  # Returns the cached schema information if available or gets it
144
- # from the database.
174
+ # from the database. This is a hash where keys are column symbols
175
+ # and values are hashes of information related to the column. See
176
+ # <tt>Database#schema</tt>.
177
+ #
178
+ # Artist.db_schema
179
+ # # {:id=>{:type=>:integer, :primary_key=>true, ...},
180
+ # # :name=>{:type=>:string, :primary_key=>false, ...}}
145
181
  def db_schema
146
182
  @db_schema ||= get_db_schema
147
183
  end
148
184
 
149
- # If a block is given, define a method on the dataset (if the model has an associated dataset) with the given argument name using
150
- # the given block as well as a method on the model that calls the
185
+ # If a block is given, define a method on the dataset (if the model currently has an dataset) with the given argument name using
186
+ # the given block. Also define a class method on the model that calls the
151
187
  # dataset method. Stores the method name and block so that it can be reapplied if the model's
152
188
  # dataset changes.
153
189
  #
154
- # If a block is not given, define a method on the model for each argument
190
+ # If a block is not given, just define a class method on the model for each argument
155
191
  # that calls the dataset method of the same argument name.
192
+ #
193
+ # # Add new dataset method and class method that calls it
194
+ # Artist.def_dataset_method(:by_name){order(:name)}
195
+ # Artist.filter(:name.like('A%')).by_name
196
+ # Artist.by_name.filter(:name.like('A%'))
197
+ #
198
+ # # Just add a class method that calls an existing dataset method
199
+ # Artist.def_dataset_method(:server!)
200
+ # Artist.server!(:server1)
156
201
  def def_dataset_method(*args, &block)
157
202
  raise(Error, "No arguments given") if args.empty?
158
203
  if block_given?
@@ -164,17 +209,30 @@ module Sequel
164
209
  args.each{|arg| instance_eval("def #{arg}(*args, &block); dataset.#{arg}(*args, &block) end", __FILE__, __LINE__) unless respond_to?(arg)}
165
210
  end
166
211
 
167
- # Finds a single record according to the supplied filter, e.g.:
212
+ # Finds a single record according to the supplied filter.
213
+ # You are encouraged to use Model.[] or Model.first instead of this method.
168
214
  #
169
- # Ticket.find :author => 'Sharon' # => record
215
+ # Artist.find(:name=>'Bob')
216
+ # # SELECT * FROM artists WHERE (name = 'Bob') LIMIT 1
170
217
  #
171
- # You are encouraged to use Model.[] or Model.first instead of this method.
218
+ # Artist.find{name > 'M'}
219
+ # # SELECT * FROM artists WHERE (name > 'M') LIMIT 1
172
220
  def find(*args, &block)
173
221
  filter(*args, &block).first
174
222
  end
175
223
 
176
- # Like find but invokes create with given conditions when record does not
177
- # exist.
224
+ # Like +find+ but invokes create with given conditions when record does not
225
+ # exist. Unlike +find+ in that the block used in this method is not passed
226
+ # to +find+, but instead is passed to +create+ only if +find+ does not
227
+ # return an object.
228
+ #
229
+ # Artist.find_or_create(:name=>'Bob')
230
+ # # SELECT * FROM artists WHERE (name = 'Bob') LIMIT 1
231
+ # # INSERT INTO artists (name) VALUES ('Bob')
232
+ #
233
+ # Artist.find_or_create(:name=>'Jim'){|a| a.hometown = 'Sactown'}
234
+ # # SELECT * FROM artists WHERE (name = 'Bob') LIMIT 1
235
+ # # INSERT INTO artists (name, hometown) VALUES ('Bob', 'Sactown')
178
236
  def find_or_create(cond, &block)
179
237
  find(cond) || create(cond, &block)
180
238
  end
@@ -182,6 +240,12 @@ module Sequel
182
240
  # If possible, set the dataset for the model subclass as soon as it
183
241
  # is created. Also, make sure the inherited class instance variables
184
242
  # are copied into the subclass.
243
+ #
244
+ # Sequel queries the database to get schema information as soon as
245
+ # a model class is created:
246
+ #
247
+ # class Artist < Sequel::Model # Causes schema query
248
+ # end
185
249
  def inherited(subclass)
186
250
  super
187
251
  ivs = subclass.instance_variables.collect{|x| x.to_s}
@@ -206,14 +270,18 @@ module Sequel
206
270
  end
207
271
  end
208
272
 
209
- # Returns the implicit table name for the model class.
273
+ # Returns the implicit table name for the model class, which is the demodulized,
274
+ # underscored, pluralized name of the class.
275
+ #
276
+ # Artist.implicit_table_name # => :artists
277
+ # Foo::ArtistAlias.implicit_table_name # => :artist_aliases
210
278
  def implicit_table_name
211
279
  pluralize(underscore(demodulize(name))).to_sym
212
280
  end
213
281
 
214
282
  # Initializes a model instance as an existing record. This constructor is
215
283
  # used by Sequel to initialize model instances when fetching records.
216
- # load requires that values be a hash where all keys are symbols. It
284
+ # +load+ requires that values be a hash where all keys are symbols. It
217
285
  # probably should not be used by external code.
218
286
  def load(values)
219
287
  new(values, true)
@@ -221,6 +289,10 @@ module Sequel
221
289
 
222
290
  # Mark the model as not having a primary key. Not having a primary key
223
291
  # can cause issues, among which is that you won't be able to update records.
292
+ #
293
+ # Artist.primary_key # => :id
294
+ # Artist.no_primary_key
295
+ # Artist.primary_key # => nil
224
296
  def no_primary_key
225
297
  @simple_pk = @primary_key = nil
226
298
  end
@@ -229,7 +301,10 @@ module Sequel
229
301
  # value such be an array with values for each primary key in the correct
230
302
  # order. For a standard primary key, value should be an object with a
231
303
  # compatible type for the key. If the model does not have a primary key,
232
- # raises an Error.
304
+ # raises an +Error+.
305
+ #
306
+ # Artist.primary_key_hash(1) # => {:id=>1}
307
+ # Artist.primary_key_hash([1, 2]) # => {:id1=>1, :id2=>2}
233
308
  def primary_key_hash(value)
234
309
  raise(Error, "#{self} does not have a primary key") unless key = @primary_key
235
310
  case key
@@ -243,49 +318,61 @@ module Sequel
243
318
  end
244
319
 
245
320
  # Return a hash where the keys are qualified column references. Uses the given
246
- # qualifier if provided, or the table_name otherwise.
321
+ # qualifier if provided, or the table_name otherwise. This is useful if you
322
+ # plan to join other tables to this table and you want the column references
323
+ # to be qualified.
324
+ #
325
+ # Artist.filter(Artist.qualified_primary_key_hash(1))
326
+ # # SELECT * FROM artists WHERE (artists.id = 1)
247
327
  def qualified_primary_key_hash(value, qualifier=table_name)
248
328
  h = primary_key_hash(value)
249
329
  h.to_a.each{|k,v| h[SQL::QualifiedIdentifier.new(qualifier, k)] = h.delete(k)}
250
330
  h
251
331
  end
252
332
 
253
- # Restrict the setting of the primary key(s) inside new/set/update. Because
333
+ # Restrict the setting of the primary key(s) when using mass assignment (e.g. +set+). Because
254
334
  # this is the default, this only make sense to use in a subclass where the
255
- # parent class has used unrestrict_primary_key.
335
+ # parent class has used +unrestrict_primary_key+.
256
336
  def restrict_primary_key
257
337
  @restrict_primary_key = true
258
338
  end
259
339
 
260
- # Whether or not setting the primary key inside new/set/update is
340
+ # Whether or not setting the primary key(s) when using mass assignment (e.g. +set+) is
261
341
  # restricted, true by default.
262
342
  def restrict_primary_key?
263
343
  @restrict_primary_key
264
344
  end
265
345
 
266
- # Set the columns to allow in new/set/update. Using this means that
346
+ # Set the columns to allow when using mass assignment (e.g. +set+). Using this means that
267
347
  # any columns not listed here will not be modified. If you have any virtual
268
- # setter methods (methods that end in =) that you want to be used in
269
- # new/set/update, they need to be listed here as well (without the =).
348
+ # setter methods (methods that end in =) that you want to be used during
349
+ # mass assignment, they need to be listed here as well (without the =).
270
350
  #
271
- # It may be better to use (set|update)_only instead of this in places where
351
+ # It may be better to use a method such as +set_only+ instead of this in places where
272
352
  # only certain columns may be allowed.
353
+ #
354
+ # Artist.set_allowed_columns(:name, :hometown)
355
+ # Artist.set(:name=>'Bob', :hometown=>'Sactown') # No Error
356
+ # Artist.set(:name=>'Bob', :records_sold=>30000) # Error
273
357
  def set_allowed_columns(*cols)
274
358
  @allowed_columns = cols
275
359
  end
276
360
 
277
- # Sets the dataset associated with the Model class. ds can be a Symbol
278
- # (specifying a table name in the current database), or a Dataset.
279
- # If a dataset is used, the model's database is changed to the given
361
+ # Sets the dataset associated with the Model class. +ds+ can be a +Symbol+
362
+ # (specifying a table name in the current database), or a +Dataset+.
363
+ # If a dataset is used, the model's database is changed to the database of the given
280
364
  # dataset. If a symbol is used, a dataset is created from the current
281
- # database with the table name given. Other arguments raise an Error.
365
+ # database with the table name given. Other arguments raise an +Error+.
282
366
  # Returns self.
283
367
  #
284
- # This changes the row_proc of the given dataset to return
368
+ # This changes the row_proc of the dataset to return
285
369
  # model objects, extends the dataset with the dataset_method_modules,
286
370
  # and defines methods on the dataset using the dataset_methods.
287
371
  # It also attempts to determine the database schema for the model,
288
372
  # based on the given dataset.
373
+ #
374
+ # Artist.set_dataset(:tbl_artists)
375
+ # Artist.set_dataset(DB[:artists])
289
376
  def set_dataset(ds, opts={})
290
377
  inherited = opts[:inherited]
291
378
  @dataset = case ds
@@ -314,46 +401,50 @@ module Sequel
314
401
  end
315
402
 
316
403
  # Sets the primary key for this model. You can use either a regular
317
- # or a composite primary key.
318
- #
319
- # Example:
320
- # class Tagging < Sequel::Model
321
- # # composite key
322
- # set_primary_key [:taggable_id, :tag_id]
323
- # end
404
+ # or a composite primary key. To not use a primary key, set to nil
405
+ # or use +no_primary_key+.
324
406
  #
325
407
  # class Person < Sequel::Model
326
408
  # # regular key
327
409
  # set_primary_key :person_id
328
410
  # end
329
411
  #
330
- # You can set it to nil to not have a primary key, but that
331
- # cause certain things not to work, see no_primary_key.
412
+ # class Tagging < Sequel::Model
413
+ # # composite key
414
+ # set_primary_key [:taggable_id, :tag_id]
415
+ # end
332
416
  def set_primary_key(*key)
333
417
  key = key.flatten
334
418
  @simple_pk = key.length == 1 ? db.literal(key.first) : nil
335
419
  @primary_key = (key.length == 1) ? key[0] : key
336
420
  end
337
421
 
338
- # Set the columns to restrict in new/set/update. Using this means that
422
+ # Set the columns to restrict when using mass assignment (e.g. +set+). Using this means that
339
423
  # attempts to call setter methods for the columns listed here will cause an
340
- # exception or be silently skipped (based on the strict_param_setting setting.
341
- # If you have any virtual # setter methods (methods that end in =) that you
342
- # want not to be used in new/set/update, they need to be listed here as well (without the =).
424
+ # exception or be silently skipped (based on the +strict_param_setting+ setting.
425
+ # If you have any virtual setter methods (methods that end in =) that you
426
+ # want not to be used during mass assignment, they need to be listed here as well (without the =).
343
427
  #
344
- # It may be better to use (set|update)_except instead of this in places where
345
- # only certain columns may be allowed.
428
+ # It may be better to use a method such as +set_except+ instead of this in places where
429
+ # certain columns are restricted. In general, it's better to have a whitelist approach
430
+ # where you specify only what is allowed, as opposed to a blacklist approach that this
431
+ # method uses, where everything is allowed other than what you restrict.
432
+ #
433
+ # Artist.set_restricted_column(:records_sold)
434
+ # Artist.set(:name=>'Bob', :hometown=>'Sactown') # No Error
435
+ # Artist.set(:name=>'Bob', :records_sold=>30000) # Error
346
436
  def set_restricted_columns(*cols)
347
437
  @restricted_columns = cols
348
438
  end
349
439
 
350
- # Defines a method that returns a filtered dataset. Subsets
351
- # create dataset methods, so they can be chained for scoping.
440
+ # Shortcut for +def_dataset_method+ that is restricted to modifying the
441
+ # dataset's filter. Sometimes thought of as a scope, and like most dataset methods,
442
+ # they can be chained.
352
443
  # For example:
353
444
  #
354
445
  # Topic.subset(:joes, :username.like('%joe%'))
355
- # Topic.subset(:popular){|o| o.num_posts > 100}
356
- # Topic.subset(:recent){|o| o.created_on > Date.today - 7}
446
+ # Topic.subset(:popular){num_posts > 100}
447
+ # Topic.subset(:recent){created_on > Date.today - 7}
357
448
  #
358
449
  # Allows you to do:
359
450
  #
@@ -363,17 +454,26 @@ module Sequel
363
454
  # have more than 100 posts and were created less than
364
455
  # 7 days ago.
365
456
  #
366
- # Both the args given and the block are passed to Dataset#filter.
457
+ # Both the args given and the block are passed to <tt>Dataset#filter</tt>.
367
458
  def subset(name, *args, &block)
368
459
  def_dataset_method(name){filter(*args, &block)}
369
460
  end
370
461
 
371
- # Returns name of primary table for the dataset.
462
+ # Returns name of primary table for the dataset. If the table for the dataset
463
+ # is aliased, returns the aliased name.
464
+ #
465
+ # Artist.table_name # => :artists
466
+ # Sequel::Model(:foo).table_name # => :foo
467
+ # Sequel::Model(:foo___bar).table_name # => :bar
372
468
  def table_name
373
469
  dataset.first_source_alias
374
470
  end
375
471
 
376
- # Allow the setting of the primary key(s) inside new/set/update.
472
+ # Allow the setting of the primary key(s) when using the mass assignment methods.
473
+ #
474
+ # Artist.set(:id=>1) # Error
475
+ # Artist.unrestrict_primary_key
476
+ # Artist.set(:id=>1) # No Error
377
477
  def unrestrict_primary_key
378
478
  @restrict_primary_key = false
379
479
  end
@@ -472,14 +572,14 @@ module Sequel
472
572
  end
473
573
 
474
574
  # Module that the class includes that holds methods the class adds for column accessors and
475
- # associations so that the methods can be overridden with super
575
+ # associations so that the methods can be overridden with +super+.
476
576
  def overridable_methods_module
477
577
  include(@overridable_methods_module = Module.new) unless @overridable_methods_module
478
578
  @overridable_methods_module
479
579
  end
480
580
 
481
581
  # Find the row in the dataset that matches the primary key. Uses
482
- # an static SQL optimization if the table and primary key are simple.
582
+ # a static SQL optimization if the table and primary key are simple.
483
583
  def primary_key_lookup(pk)
484
584
  if t = simple_table and p = simple_pk
485
585
  with_sql("SELECT * FROM #{t} WHERE #{p} = #{dataset.literal(pk)}").first
@@ -499,27 +599,30 @@ module Sequel
499
599
  DATASET_METHODS.each{|arg| class_eval("def #{arg}(*args, &block); dataset.#{arg}(*args, &block) end", __FILE__, __LINE__)}
500
600
 
501
601
  # Returns a copy of the model's dataset with custom SQL
602
+ #
603
+ # Artist.fetch("SELECT * FROM artists WHERE name LIKE 'A%'")
604
+ # Artist.fetch("SELECT * FROM artists WHERE id = ?", 1)
502
605
  alias fetch with_sql
503
606
  end
504
607
 
505
608
  # Sequel::Model instance methods that implement basic model functionality.
506
609
  #
507
- # * All of the methods in HOOKS create instance methods that are called
610
+ # * All of the methods in +HOOKS+ create instance methods that are called
508
611
  # by Sequel when the appropriate action occurs. For example, when destroying
509
- # a model object, Sequel will call before_destroy, do the destroy,
510
- # and then call after_destroy.
612
+ # a model object, Sequel will call +before_destroy+, do the destroy,
613
+ # and then call +after_destroy+.
511
614
  # * The following instance_methods all call the class method of the same
512
615
  # name: columns, dataset, db, primary_key, db_schema.
513
- # * The following instance methods allow boolean flags to be set on a per-object
514
- # basis: raise_on_save_failure, raise_on_typecast_failure, require_modification, strict_param_setting,
515
- # typecast_empty_string_to_nil, typecast_on_assignment, use_transactions.
516
- # If they are not used, the object will default to whatever the model setting is.
616
+ # * All of the methods in +BOOLEAN_SETTINGS+ create attr_writers allowing you
617
+ # to set values for the attribute. It also creates instnace getters returning
618
+ # the value of the setting. If the value has not yet been set, it
619
+ # gets the default value from the class by calling the class method of the same name.
517
620
  module InstanceMethods
518
621
  HOOKS.each{|h| class_eval("def #{h}; end", __FILE__, __LINE__)}
519
622
 
520
623
  # Define instance method(s) that calls class method(s) of the
521
624
  # same name, caching the result in an instance variable. Define
522
- # standard attr_writer method for modifying that instance variable
625
+ # standard attr_writer method for modifying that instance variable.
523
626
  def self.class_attr_overridable(*meths) # :nodoc:
524
627
  meths.each{|meth| class_eval("def #{meth}; !defined?(@#{meth}) ? (@#{meth} = self.class.#{meth}) : @#{meth} end", __FILE__, __LINE__)}
525
628
  attr_writer(*meths)
@@ -540,6 +643,9 @@ module Sequel
540
643
 
541
644
  # The hash of attribute values. Keys are symbols with the names of the
542
645
  # underlying database columns.
646
+ #
647
+ # Artist.new(:name=>'Bob').values # => {:name=>'Bob'}
648
+ # Artist[1].values # => {:id=>1, :name=>'Jim', ...}
543
649
  attr_reader :values
544
650
 
545
651
  # Creates new instance and passes the given values to set.
@@ -549,9 +655,14 @@ module Sequel
549
655
  # it has optionally yielded itself to the block.
550
656
  #
551
657
  # Arguments:
552
- # * values - should be a hash to pass to set.
553
- # * from_db - should only be set by Model.load, forget it
554
- # exists.
658
+ # values :: should be a hash to pass to set.
659
+ # from_db :: should only be set by <tt>Model.load</tt>, forget it exists.
660
+ #
661
+ # Artist.new(:name=>'Bob')
662
+ #
663
+ # Artist.new do |a|
664
+ # a.name = 'Bob'
665
+ # end
555
666
  def initialize(values = {}, from_db = false)
556
667
  if from_db
557
668
  @new = false
@@ -568,6 +679,8 @@ module Sequel
568
679
  end
569
680
 
570
681
  # Returns value of the column's attribute.
682
+ #
683
+ # Artist[1][:id] #=> 1
571
684
  def [](column)
572
685
  @values[column]
573
686
  end
@@ -576,6 +689,10 @@ module Sequel
576
689
  # this object, typecast the value based on the column's type.
577
690
  # If this a a new record or the typecasted value isn't the same
578
691
  # as the current value for the column, mark the column as changed.
692
+ #
693
+ # a = Artist.new
694
+ # a[:name] = 'Bob'
695
+ # a.values #=> {:name=>'Bob'}
579
696
  def []=(column, value)
580
697
  # If it is new, it doesn't have a value yet, so we should
581
698
  # definitely set the new value.
@@ -595,6 +712,10 @@ module Sequel
595
712
 
596
713
  # If pk is not nil, true only if the objects have the same class and pk.
597
714
  # If pk is nil, false.
715
+ #
716
+ # Artist[1] === Artist[1] # true
717
+ # Artist.new === Artist.new # false
718
+ # Artist[1].set(:name=>'Bob') == Artist[1] # => true
598
719
  def ===(obj)
599
720
  pk.nil? ? false : (obj.class == model) && (obj.pk == pk)
600
721
  end
@@ -603,6 +724,8 @@ module Sequel
603
724
  # and since a lot of instance methods call class methods,
604
725
  # this alias makes it so you can use model instead of
605
726
  # self.class.
727
+ #
728
+ # Artist.new.model # => Artist
606
729
  alias_method :model, :class
607
730
 
608
731
  # The autoincrementing primary key for this model object. Should be
@@ -613,13 +736,21 @@ module Sequel
613
736
  end
614
737
 
615
738
  # The columns that have been updated. This isn't completely accurate,
616
- # see Model#[]=.
739
+ # as it could contain columns whose values have not changed.
740
+ #
741
+ # a = Artist[1]
742
+ # a.changed_columns # => []
743
+ # a.name = 'Bob'
744
+ # a.changed_columns # => [:name]
617
745
  def changed_columns
618
746
  @changed_columns ||= []
619
747
  end
620
748
 
621
- # Deletes and returns self. Does not run destroy hooks.
622
- # Look into using destroy instead.
749
+ # Deletes and returns +self+. Does not run destroy hooks.
750
+ # Look into using +destroy+ instead.
751
+ #
752
+ # Artist[1].delete # DELETE FROM artists WHERE (id = 1)
753
+ # # => #<Artist {:id=>1, ...}>
623
754
  def delete
624
755
  _delete
625
756
  self
@@ -631,24 +762,33 @@ module Sequel
631
762
  # the item from the database and returns self. Uses a transaction
632
763
  # if use_transactions is true or if the :transaction option is given and
633
764
  # true.
765
+ #
766
+ # Artist[1].destroy # BEGIN; DELETE FROM artists WHERE (id = 1); COMMIT;
767
+ # # => #<Artist {:id=>1, ...}>
634
768
  def destroy(opts = {})
635
- checked_save_failure{checked_transaction(opts){_destroy(opts)}}
769
+ checked_save_failure(opts){checked_transaction(opts){_destroy(opts)}}
636
770
  end
637
771
 
638
772
  # Iterates through all of the current values using each.
639
773
  #
640
- # Example:
641
- # Ticket.find(7).each { |k, v| puts "#{k} => #{v}" }
774
+ # Album[1].each{|k, v| puts "#{k} => #{v}"}
775
+ # # id => 1
776
+ # # name => 'Bob'
642
777
  def each(&block)
643
778
  @values.each(&block)
644
779
  end
645
780
 
646
781
  # Compares model instances by values.
782
+ #
783
+ # Artist[1] == Artist[1] # => true
784
+ # Artist.new == Artist.new # => true
785
+ # Artist[1].set(:name=>'Bob') == Artist[1] # => false
647
786
  def eql?(obj)
648
787
  (obj.class == model) && (obj.values == @values)
649
788
  end
650
789
 
651
790
  # Returns the validation errors associated with this object.
791
+ # See +Errors+.
652
792
  def errors
653
793
  @errors ||= Errors.new
654
794
  end
@@ -656,18 +796,28 @@ module Sequel
656
796
  # Returns true when current instance exists, false otherwise.
657
797
  # Generally an object that isn't new will exist unless it has
658
798
  # been deleted.
799
+ #
800
+ # Artist[1].exists? # SELECT 1 FROM artists WHERE (id = 1)
801
+ # # => true
659
802
  def exists?
660
- this.count > 0
803
+ !this.get(1).nil?
661
804
  end
662
805
 
663
806
  # Value that should be unique for objects with the same class and pk (if pk is not nil), or
664
807
  # the same class and values (if pk is nil).
808
+ #
809
+ # Artist[1].hash == Artist[1].hash # true
810
+ # Artist[1].set(:name=>'Bob').hash == Artist[1].hash # true
811
+ # Artist.new.hash == Artist.new.hash # true
812
+ # Artist.new(:name=>'Bob').hash == Artist.new.hash # false
665
813
  def hash
666
814
  [model, pk.nil? ? @values.sort_by{|k,v| k.to_s} : pk].hash
667
815
  end
668
816
 
669
817
  # Returns value for the :id attribute, even if the primary key is
670
- # not id. To get the primary key value, use #pk.
818
+ # not id. To get the primary key value, use +pk+.
819
+ #
820
+ # Artist[1].id # => 1
671
821
  def id
672
822
  @values[:id]
673
823
  end
@@ -678,24 +828,45 @@ module Sequel
678
828
  "#<#{model.name} @values=#{inspect_values}>"
679
829
  end
680
830
 
681
- # Returns the keys in values. May not include all column names.
831
+ # Returns the keys in +values+. May not include all column names.
832
+ #
833
+ # Artist.new.keys # => []
834
+ # Artist.new(:name=>'Bob').keys # => [:name]
835
+ # Artist[1].keys # => [:id, :name]
682
836
  def keys
683
837
  @values.keys
684
838
  end
685
839
 
686
- # Refresh this record using for_update unless this is a new record. Returns self.
840
+ # Refresh this record using +for_update+ unless this is a new record. Returns self.
841
+ # This can be used to make sure no other process is updating the record at the
842
+ # same time.
843
+ #
844
+ # a = Artist[1]
845
+ # Artist.db.transaction do
846
+ # a.lock!
847
+ # a.update(...)
848
+ # end
687
849
  def lock!
688
850
  new? ? self : _refresh(this.for_update)
689
851
  end
690
852
 
691
853
  # Remove elements of the model object that make marshalling fail. Returns self.
854
+ #
855
+ # a = Artist[1]
856
+ # a.marshallable!
857
+ # Marshal.dump(a)
692
858
  def marshallable!
693
859
  @this = nil
694
860
  self
695
861
  end
696
862
 
697
- # Explicitly mark the object as modified, so save_changes/update will
863
+ # Explicitly mark the object as modified, so +save_changes+/+update+ will
698
864
  # run callbacks even if no columns have changed.
865
+ #
866
+ # a = Artist[1]
867
+ # a.save_changes # No callbacks run, as no changes
868
+ # a.modified!
869
+ # a.save_changes # Callbacks run, even though no changes made
699
870
  def modified!
700
871
  @modified = true
701
872
  end
@@ -703,11 +874,19 @@ module Sequel
703
874
  # Whether this object has been modified since last saved, used by
704
875
  # save_changes to determine whether changes should be saved. New
705
876
  # values are always considered modified.
877
+ #
878
+ # a = Artist[1]
879
+ # a.modified? # => false
880
+ # a.set(:name=>'Jim')
881
+ # a.modified # => true
706
882
  def modified?
707
883
  @modified || !changed_columns.empty?
708
884
  end
709
885
 
710
886
  # Returns true if the current instance represents a new record.
887
+ #
888
+ # Artist.new.new? # => true
889
+ # Artist[1].new? # => false
711
890
  def new?
712
891
  @new
713
892
  end
@@ -715,21 +894,30 @@ module Sequel
715
894
  # Returns the primary key value identifying the model instance.
716
895
  # Raises an error if this model does not have a primary key.
717
896
  # If the model has a composite primary key, returns an array of values.
897
+ #
898
+ # Artist[1].pk # => 1
899
+ # Artist[[1, 2]].pk # => [1, 2]
718
900
  def pk
719
901
  raise(Error, "No primary key is associated with this model") unless key = primary_key
720
902
  key.is_a?(Array) ? key.map{|k| @values[k]} : @values[key]
721
903
  end
722
904
 
723
- # Returns a hash identifying the model instance. It should be true that:
905
+ # Returns a hash identifying mapping the receivers primary key column(s) to their values.
724
906
  #
725
- # Model[model_instance.pk_hash] === model_instance
907
+ # Artist[1].pk_hash # => {:id=>1}
908
+ # Artist[[1, 2]].pk_hash # => {:id1=>1, :id2=>2}
726
909
  def pk_hash
727
910
  model.primary_key_hash(pk)
728
911
  end
729
912
 
730
913
  # Reloads attributes from database and returns self. Also clears all
731
- # cached association and changed_columns information. Raises an Error if the record no longer
914
+ # changed_columns information. Raises an +Error+ if the record no longer
732
915
  # exists in the database.
916
+ #
917
+ # a = Artist[1]
918
+ # a.name = 'Jim'
919
+ # a.refresh
920
+ # a.name # => 'Bob'
733
921
  def refresh
734
922
  _refresh(this)
735
923
  end
@@ -740,56 +928,91 @@ module Sequel
740
928
  end
741
929
 
742
930
  # Creates or updates the record, after making sure the record
743
- # is valid. If the record is not valid, or before_save,
744
- # before_create (if new?), or before_update (if !new?) return
745
- # false, returns nil unless raise_on_save_failure is true (if it
746
- # is true, it raises an error).
747
- # Otherwise, returns self. You can provide an optional list of
748
- # columns to update, in which case it only updates those columns.
931
+ # is valid and before hooks execute successfully. Fails if:
932
+ #
933
+ # * the record is not valid, or
934
+ # * before_save returns false, or
935
+ # * the record is new and before_create returns false, or
936
+ # * the record is not new and before_update returns false.
937
+ #
938
+ # If +save+ fails and either raise_on_save_failure or the
939
+ # :raise_on_failure option is true, it raises ValidationFailed
940
+ # or BeforeHookFailed. Otherwise it returns nil.
941
+ #
942
+ # If it succeeds, it returns self.
943
+ #
944
+ # You can provide an optional list of columns to update, in which
945
+ # case it only updates those columns.
749
946
  #
750
947
  # Takes the following options:
751
948
  #
752
949
  # * :changed - save all changed columns, instead of all columns or the columns given
753
- # * :transaction - set to false not to use a transaction
754
- # * :validate - set to false not to validate the model before saving
950
+ # * :transaction - set to true or false to override the current
951
+ # use_transactions setting
952
+ # * :validate - set to false to skip validation
953
+ # * :raise_on_failure - set to true or false to override the current
954
+ # raise_on_save_failure setting
755
955
  def save(*columns)
756
956
  opts = columns.last.is_a?(Hash) ? columns.pop : {}
757
- if opts[:validate] != false and !valid?
758
- raise(ValidationFailed.new(errors)) if raise_on_save_failure
957
+ if opts[:validate] != false and !valid?(opts)
958
+ raise(ValidationFailed.new(errors)) if raise_on_failure?(opts)
759
959
  return
760
960
  end
761
- checked_save_failure{checked_transaction(opts){_save(columns, opts)}}
961
+ checked_save_failure(opts){checked_transaction(opts){_save(columns, opts)}}
762
962
  end
763
963
 
764
964
  # Saves only changed columns if the object has been modified.
765
965
  # If the object has not been modified, returns nil. If unable to
766
- # save, returns false unless raise_on_save_failure is true.
966
+ # save, returns false unless +raise_on_save_failure+ is true.
967
+ #
968
+ # a = Artist[1]
969
+ # a.save_changes # => nil
970
+ # a.name = 'Jim'
971
+ # a.save_changes # UPDATE artists SET name = 'Bob' WHERE (id = 1)
972
+ # # => #<Artist {:id=>1, :name=>'Jim', ...}
767
973
  def save_changes(opts={})
768
974
  save(opts.merge(:changed=>true)) || false if modified?
769
975
  end
770
976
 
771
977
  # Updates the instance with the supplied values with support for virtual
772
978
  # attributes, raising an exception if a value is used that doesn't have
773
- # a setter method (or ignoring it if strict_param_setting = false).
979
+ # a setter method (or ignoring it if <tt>strict_param_setting = false</tt>).
774
980
  # Does not save the record.
981
+ #
982
+ # artist.set(:name=>'Jim')
983
+ # artist.name # => 'Jim'
775
984
  def set(hash)
776
985
  set_restricted(hash, nil, nil)
777
986
  end
778
987
 
779
988
  # Set all values using the entries in the hash, ignoring any setting of
780
989
  # allowed_columns or restricted columns in the model.
990
+ #
991
+ # Artist.set_restricted_columns(:name)
992
+ # artist.set_all(:name=>'Jim')
993
+ # artist.name # => 'Jim'
781
994
  def set_all(hash)
782
995
  set_restricted(hash, false, false)
783
996
  end
784
997
 
785
998
  # Set all values using the entries in the hash, except for the keys
786
999
  # given in except.
1000
+ #
1001
+ # artist.set_except({:name=>'Jim'}, :hometown)
1002
+ # artist.name # => 'Jim'
787
1003
  def set_except(hash, *except)
788
1004
  set_restricted(hash, false, except.flatten)
789
1005
  end
790
1006
 
791
1007
  # For each of the fields in the given array +fields+, call the setter
792
1008
  # method with the value of that +hash+ entry for the field. Returns self.
1009
+ #
1010
+ # artist.set_fields({:name=>'Jim'}, :name)
1011
+ # artist.name # => 'Jim'
1012
+ #
1013
+ # artist.set_fields({:hometown=>'LA'}, :name)
1014
+ # artist.name # => nil
1015
+ # artist.hometown # => 'Sac'
793
1016
  def set_fields(hash, fields)
794
1017
  fields.each{|f| send("#{f}=", hash[f])}
795
1018
  self
@@ -797,34 +1020,55 @@ module Sequel
797
1020
 
798
1021
  # Set the values using the entries in the hash, only if the key
799
1022
  # is included in only.
1023
+ #
1024
+ # artist.set_only({:name=>'Jim'}, :name)
1025
+ # artist.name # => 'Jim'
1026
+ #
1027
+ # artist.set_only({:hometown=>'LA'}, :name) # Raise error
800
1028
  def set_only(hash, *only)
801
1029
  set_restricted(hash, only.flatten, false)
802
1030
  end
803
1031
 
804
1032
  # Returns (naked) dataset that should return only this instance.
1033
+ #
1034
+ # Artist[1].this
1035
+ # # SELECT * FROM artists WHERE (id = 1) LIMIT 1
805
1036
  def this
806
1037
  @this ||= model.dataset.filter(pk_hash).limit(1).naked
807
1038
  end
808
1039
 
809
1040
  # Runs set with the passed hash and then runs save_changes.
1041
+ #
1042
+ # artist.update(:name=>'Jim') # UPDATE artists SET name = 'Jim' WHERE (id = 1)
810
1043
  def update(hash)
811
1044
  update_restricted(hash, nil, nil)
812
1045
  end
813
1046
 
814
1047
  # Update all values using the entries in the hash, ignoring any setting of
815
1048
  # allowed_columns or restricted columns in the model.
1049
+ #
1050
+ # Artist.set_restricted_columns(:name)
1051
+ # artist.update_all(:name=>'Jim') # UPDATE artists SET name = 'Jim' WHERE (id = 1)
816
1052
  def update_all(hash)
817
1053
  update_restricted(hash, false, false)
818
1054
  end
819
1055
 
820
1056
  # Update all values using the entries in the hash, except for the keys
821
1057
  # given in except.
1058
+ #
1059
+ # artist.update_except({:name=>'Jim'}, :hometown) # UPDATE artists SET name = 'Jim' WHERE (id = 1)
822
1060
  def update_except(hash, *except)
823
1061
  update_restricted(hash, false, except.flatten)
824
1062
  end
825
1063
 
826
1064
  # Update the instances values by calling +set_fields+ with the +hash+
827
1065
  # and +fields+, then save any changes to the record. Returns self.
1066
+ #
1067
+ # artist.update_fields({:name=>'Jim'}, :name)
1068
+ # # UPDATE artists SET name = 'Jim' WHERE (id = 1)
1069
+ #
1070
+ # artist.update_fields({:hometown=>'LA'}, :name)
1071
+ # # UPDATE artists SET name = NULL WHERE (id = 1)
828
1072
  def update_fields(hash, fields)
829
1073
  set_fields(hash, fields)
830
1074
  save_changes
@@ -832,6 +1076,11 @@ module Sequel
832
1076
 
833
1077
  # Update the values using the entries in the hash, only if the key
834
1078
  # is included in only.
1079
+ #
1080
+ # artist.update_only({:name=>'Jim'}, :name)
1081
+ # # UPDATE artists SET name = 'Jim' WHERE (id = 1)
1082
+ #
1083
+ # artist.update_only({:hometown=>'LA'}, :name) # Raise Error
835
1084
  def update_only(hash, *only)
836
1085
  update_restricted(hash, only.flatten, false)
837
1086
  end
@@ -839,15 +1088,21 @@ module Sequel
839
1088
  # Validates the object. If the object is invalid, errors should be added
840
1089
  # to the errors attribute. By default, does nothing, as all models
841
1090
  # are valid by default. See the {"Model Validations" guide}[link:files/doc/validations_rdoc.html].
842
- # for details about validation.
1091
+ # for details about validation. Should not be called directly by
1092
+ # user code, call <tt>valid?</tt> instead to check if an object
1093
+ # is valid.
843
1094
  def validate
844
1095
  end
845
1096
 
846
1097
  # Validates the object and returns true if no errors are reported.
847
- def valid?
1098
+ #
1099
+ # artist(:name=>'Valid').valid? # => true
1100
+ # artist(:name=>'Invalid').valid? # => false
1101
+ # artist.errors.full_messages # => ['name cannot be Invalid']
1102
+ def valid?(opts = {})
848
1103
  errors.clear
849
1104
  if before_validation == false
850
- save_failure(:validation) if raise_on_save_failure
1105
+ raise_hook_failure(:validation) if raise_on_failure?(opts)
851
1106
  return false
852
1107
  end
853
1108
  validate
@@ -873,7 +1128,7 @@ module Sequel
873
1128
  # Internal destroy method, separted from destroy to
874
1129
  # allow running inside a transaction
875
1130
  def _destroy(opts)
876
- return save_failure(:destroy) if before_destroy == false
1131
+ raise_hook_failure(:destroy) if before_destroy == false
877
1132
  _destroy_delete
878
1133
  after_destroy
879
1134
  self
@@ -921,9 +1176,9 @@ module Sequel
921
1176
  # Internal version of save, split from save to allow running inside
922
1177
  # it's own transaction.
923
1178
  def _save(columns, opts)
924
- return save_failure(:save) if before_save == false
1179
+ raise_hook_failure(:save) if before_save == false
925
1180
  if new?
926
- return save_failure(:create) if before_create == false
1181
+ raise_hook_failure(:create) if before_create == false
927
1182
  pk = _insert
928
1183
  @this = nil
929
1184
  @new = false
@@ -933,7 +1188,7 @@ module Sequel
933
1188
  @was_new = nil
934
1189
  pk ? _save_refresh : changed_columns.clear
935
1190
  else
936
- return save_failure(:update) if before_update == false
1191
+ raise_hook_failure(:update) if before_update == false
937
1192
  if columns.empty?
938
1193
  @columns_updated = if opts[:changed]
939
1194
  @values.reject{|k,v| !changed_columns.include?(k)}
@@ -987,10 +1242,10 @@ module Sequel
987
1242
  this
988
1243
  end
989
1244
 
990
- # If raise_on_save_failure is false, check for BeforeHookFailed
991
- # beind raised by yielding and swallow it.
992
- def checked_save_failure
993
- if raise_on_save_failure
1245
+ # If not raising on failure, check for BeforeHookFailed
1246
+ # being raised by yielding and swallow it.
1247
+ def checked_save_failure(opts)
1248
+ if raise_on_failure?(opts)
994
1249
  yield
995
1250
  else
996
1251
  begin
@@ -1010,9 +1265,18 @@ module Sequel
1010
1265
  def inspect_values
1011
1266
  @values.inspect
1012
1267
  end
1013
-
1014
- # Raise an error if raise_on_save_failure is true, return nil otherwise.
1015
- def save_failure(type)
1268
+
1269
+ # Whether to raise or return false if this action fails. If the
1270
+ # :raise_on_failure option is present in the hash, use that, otherwise,
1271
+ # fallback to the object's raise_on_save_failure (if set), or
1272
+ # class's default (if not).
1273
+ def raise_on_failure?(opts)
1274
+ opts.fetch(:raise_on_failure, raise_on_save_failure)
1275
+ end
1276
+
1277
+ # Raise an error appropriate to the hook type. May be swallowed by
1278
+ # checked_save_failure depending on the raise_on_failure? setting.
1279
+ def raise_hook_failure(type)
1016
1280
  raise BeforeHookFailed, "one of the before_#{type} hooks returned false"
1017
1281
  end
1018
1282
 
@@ -1097,19 +1361,32 @@ module Sequel
1097
1361
  # the call to set_dataset.
1098
1362
  module DatasetMethods
1099
1363
  # The model class associated with this dataset
1364
+ #
1365
+ # Artist.dataset.model # => Artist
1100
1366
  attr_accessor :model
1101
1367
 
1102
1368
  # Destroy each row in the dataset by instantiating it and then calling
1103
1369
  # destroy on the resulting model object. This isn't as fast as deleting
1104
1370
  # the dataset, which does a single SQL call, but this runs any destroy
1105
1371
  # hooks on each object in the dataset.
1372
+ #
1373
+ # Artist.dataset.destroy
1374
+ # # DELETE FROM artists WHERE (id = 1)
1375
+ # # DELETE FROM artists WHERE (id = 2)
1376
+ # # ...
1106
1377
  def destroy
1107
- @db.transaction{all{|r| r.destroy}.length}
1378
+ pr = proc{all{|r| r.destroy}.length}
1379
+ model.use_transactions ? @db.transaction(&pr) : pr.call
1108
1380
  end
1109
1381
 
1110
- # This allows you to call to_hash without any arguments, which will
1382
+ # This allows you to call +to_hash+ without any arguments, which will
1111
1383
  # result in a hash with the primary key value being the key and the
1112
1384
  # model object being the value.
1385
+ #
1386
+ # Artist.dataset.to_hash # SELECT * FROM artists
1387
+ # # => {1=>#<Artist {:id=>1, ...}>,
1388
+ # # 2=>#<Artist {:id=>2, ...}>,
1389
+ # # ...}
1113
1390
  def to_hash(key_column=nil, value_column=nil)
1114
1391
  if key_column
1115
1392
  super