sequel 3.13.0 → 3.14.0

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