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
@@ -36,7 +36,6 @@ module Sequel
36
36
  # DB.add_index :posts, :title
37
37
  # DB.add_index :posts, [:author, :title], :unique => true
38
38
  #
39
- #
40
39
  # Options:
41
40
  # * :ignore_errors - Ignore any DatabaseErrors that are raised
42
41
  #
@@ -62,8 +61,8 @@ module Sequel
62
61
  # drop_index [:group, :category]
63
62
  # end
64
63
  #
65
- # Note that #add_column accepts all the options available for column
66
- # definitions using create_table, and #add_index accepts all the options
64
+ # Note that +add_column+ accepts all the options available for column
65
+ # definitions using create_table, and +add_index+ accepts all the options
67
66
  # available for index definition.
68
67
  #
69
68
  # See Schema::AlterTableGenerator and the {"Migrations and Schema Modification" guide}[link:files/doc/migration_rdoc.html].
@@ -84,8 +83,8 @@ module Sequel
84
83
  # end
85
84
  #
86
85
  # Options:
87
- # * :temp - Create the table as a temporary table.
88
- # * :ignore_index_errors - Ignore any errors when creating indexes.
86
+ # :temp :: Create the table as a temporary table.
87
+ # :ignore_index_errors :: Ignore any errors when creating indexes.
89
88
  #
90
89
  # See Schema::Generator and the {"Migrations and Schema Modification" guide}[link:files/doc/migration_rdoc.html].
91
90
  def create_table(name, options={}, &block)
@@ -98,6 +97,10 @@ module Sequel
98
97
  end
99
98
 
100
99
  # Forcibly creates a table, attempting to drop it unconditionally (and catching any errors), then creating it.
100
+ #
101
+ # DB.create_table!(:a){Integer :a}
102
+ # # DROP TABLE a
103
+ # # CREATE TABLE a (a integer)
101
104
  def create_table!(name, options={}, &block)
102
105
  drop_table(name) rescue nil
103
106
  create_table(name, options, &block)
@@ -21,22 +21,30 @@ module Sequel
21
21
 
22
22
  # Returns the first record matching the conditions. Examples:
23
23
  #
24
- # ds[:id=>1] => {:id=1}
24
+ # DB[:table][:id=>1] # SELECT * FROM table WHERE (id = 1) LIMIT 1
25
+ # # => {:id=1}
25
26
  def [](*conditions)
26
27
  raise(Error, ARRAY_ACCESS_ERROR_MSG) if (conditions.length == 1 and conditions.first.is_a?(Integer)) or conditions.length == 0
27
28
  first(*conditions)
28
29
  end
29
30
 
30
- # Update all records matching the conditions
31
- # with the values specified. Examples:
31
+ # Update all records matching the conditions with the values specified.
32
+ # Returns the number of rows affected.
32
33
  #
33
- # ds[:id=>1] = {:id=>2} # SQL: UPDATE ... SET id = 2 WHERE id = 1
34
+ # DB[:table][:id=>1] = {:id=>2} # UPDATE table SET id = 2 WHERE id = 1
35
+ # # => 1 # number of rows affected
34
36
  def []=(conditions, values)
35
37
  filter(conditions).update(values)
36
38
  end
37
39
 
38
40
  # Returns an array with all records in the dataset. If a block is given,
39
41
  # the array is iterated over after all items have been loaded.
42
+ #
43
+ # DB[:table].all # SELECT * FROM table
44
+ # # => [{:id=>1, ...}, {:id=>2, ...}, ...]
45
+ #
46
+ # # Iterate over all rows in the table
47
+ # DB[:table].all{|row| p row}
40
48
  def all(&block)
41
49
  a = []
42
50
  each{|r| a << r}
@@ -46,19 +54,22 @@ module Sequel
46
54
  end
47
55
 
48
56
  # Returns the average value for the given column.
57
+ #
58
+ # DB[:table].avg(:number) # SELECT avg(number) FROM table LIMIT 1
59
+ # # => 3
49
60
  def avg(column)
50
61
  aggregate_dataset.get{avg(column)}
51
62
  end
52
63
 
53
- # Returns the columns in the result set in order.
64
+ # Returns the columns in the result set in order as an array of symbols.
54
65
  # If the columns are currently cached, returns the cached value. Otherwise,
55
- # a SELECT query is performed to get a single row. Adapters are expected
56
- # to fill the columns cache with the column information when a query is performed.
57
- # If the dataset does not have any rows, this may be an empty array depending on how
58
- # the adapter is programmed.
66
+ # a SELECT query is performed to retrieve a single row in order to get the columns.
59
67
  #
60
68
  # If you are looking for all columns for a single table and maybe some information about
61
- # each column (e.g. type), see Database#schema.
69
+ # each column (e.g. database type), see <tt>Database#schema</tt>.
70
+ #
71
+ # DB[:table].columns
72
+ # # => [:id, :name]
62
73
  def columns
63
74
  return @columns if @columns
64
75
  ds = unfiltered.unordered.clone(:distinct => nil, :limit => 1)
@@ -67,20 +78,29 @@ module Sequel
67
78
  @columns || []
68
79
  end
69
80
 
70
- # Remove the cached list of columns and do a SELECT query to find
71
- # the columns.
81
+ # Ignore any cached column information and perform a query to retrieve
82
+ # a row in order to get the columns.
83
+ #
84
+ # DB[:table].columns!
85
+ # # => [:id, :name]
72
86
  def columns!
73
87
  @columns = nil
74
88
  columns
75
89
  end
76
90
 
77
91
  # Returns the number of records in the dataset.
92
+ #
93
+ # DB[:table].count # SELECT COUNT(*) AS count FROM table LIMIT 1
94
+ # # => 3
78
95
  def count
79
96
  aggregate_dataset.get{COUNT(:*){}.as(count)}.to_i
80
97
  end
81
98
 
82
- # Deletes the records in the dataset. The returned value is generally the
83
- # number of records deleted, but that is adapter dependent. See delete_sql.
99
+ # Deletes the records in the dataset. The returned value should be
100
+ # number of records deleted, but that is adapter dependent.
101
+ #
102
+ # DB[:table].delete # DELETE * FROM table
103
+ # # => 3
84
104
  def delete
85
105
  execute_dui(delete_sql)
86
106
  end
@@ -88,10 +108,12 @@ module Sequel
88
108
  # Iterates over the records in the dataset as they are yielded from the
89
109
  # database adapter, and returns self.
90
110
  #
111
+ # DB[:table].each{|row| p row} # SELECT * FROM table
112
+ #
91
113
  # Note that this method is not safe to use on many adapters if you are
92
114
  # running additional queries inside the provided block. If you are
93
115
  # running queries inside the block, you should use +all+ instead of +each+
94
- # for the outer queries, or use a separate thread or shard inside +each+.
116
+ # for the outer queries, or use a separate thread or shard inside +each+:
95
117
  def each(&block)
96
118
  if @opts[:graph]
97
119
  graph_each(&block)
@@ -104,35 +126,51 @@ module Sequel
104
126
  end
105
127
 
106
128
  # Returns true if no records exist in the dataset, false otherwise
129
+ #
130
+ # DB[:table].empty? # SELECT 1 FROM table LIMIT 1
131
+ # # => false
107
132
  def empty?
108
133
  get(1).nil?
109
134
  end
110
135
 
111
136
  # Executes a select query and fetches records, passing each record to the
112
137
  # supplied block. The yielded records should be hashes with symbol keys.
138
+ # This method should probably should not be called by user code, use +each+
139
+ # instead.
113
140
  def fetch_rows(sql, &block)
114
141
  raise NotImplemented, NOTIMPL_MSG
115
142
  end
116
143
 
117
- # If a integer argument is
118
- # given, it is interpreted as a limit, and then returns all
144
+ # If a integer argument is given, it is interpreted as a limit, and then returns all
119
145
  # matching records up to that limit. If no argument is passed,
120
146
  # it returns the first matching record. If any other type of
121
147
  # argument(s) is passed, it is given to filter and the
122
148
  # first matching record is returned. If a block is given, it is used
123
149
  # to filter the dataset before returning anything. Examples:
124
150
  #
125
- # ds.first => {:id=>7}
126
- # ds.first(2) => [{:id=>6}, {:id=>4}]
127
- # ds.order(:id).first(2) => [{:id=>1}, {:id=>2}]
128
- # ds.first(:id=>2) => {:id=>2}
129
- # ds.first("id = 3") => {:id=>3}
130
- # ds.first("id = ?", 4) => {:id=>4}
131
- # ds.first{|o| o.id > 2} => {:id=>5}
132
- # ds.order(:id).first{|o| o.id > 2} => {:id=>3}
133
- # ds.first{|o| o.id > 2} => {:id=>5}
134
- # ds.first("id > ?", 4){|o| o.id < 6} => {:id=>5}
135
- # ds.order(:id).first(2){|o| o.id < 2} => [{:id=>1}]
151
+ # DB[:table].first # SELECT * FROM table LIMIT 1
152
+ # # => {:id=>7}
153
+ #
154
+ # DB[:table].first(2) # SELECT * FROM table LIMIT 2
155
+ # # => [{:id=>6}, {:id=>4}]
156
+ #
157
+ # DB[:table].first(:id=>2) # SELECT * FROM table WHERE (id = 2) LIMIT 1
158
+ # # => {:id=>2}
159
+ #
160
+ # DB[:table].first("id = 3") # SELECT * FROM table WHERE (id = 3) LIMIT 1
161
+ # # => {:id=>3}
162
+ #
163
+ # DB[:table].first("id = ?", 4) # SELECT * FROM table WHERE (id = 4) LIMIT 1
164
+ # # => {:id=>4}
165
+ #
166
+ # DB[:table].first{id > 2} # SELECT * FROM table WHERE (id > 2) LIMIT 1
167
+ # # => {:id=>5}
168
+ #
169
+ # DB[:table].first("id > ?", 4){id < 6} # SELECT * FROM table WHERE ((id > 4) AND (id < 6)) LIMIT 1
170
+ # # => {:id=>5}
171
+ #
172
+ # DB[:table].first(2){id < 2} # SELECT * FROM table WHERE (id < 2) LIMIT 2
173
+ # # => [{:id=>1}]
136
174
  def first(*args, &block)
137
175
  ds = block ? filter(&block) : self
138
176
 
@@ -151,8 +189,11 @@ module Sequel
151
189
  # Return the column value for the first matching record in the dataset.
152
190
  # Raises an error if both an argument and block is given.
153
191
  #
154
- # ds.get(:id)
155
- # ds.get{|o| o.sum(:id)}
192
+ # DB[:table].get(:id) # SELECT id FROM table LIMIT 1
193
+ # # => 3
194
+ #
195
+ # ds.get{sum(id)} # SELECT sum(id) FROM table LIMIT 1
196
+ # # => 6
156
197
  def get(column=nil, &block)
157
198
  if column
158
199
  raise(Error, ARG_BLOCK_ERROR_MSG) if block
@@ -169,11 +210,14 @@ module Sequel
169
210
  #
170
211
  # This method is called with a columns array and an array of value arrays:
171
212
  #
172
- # dataset.import([:x, :y], [[1, 2], [3, 4]])
213
+ # DB[:table].import([:x, :y], [[1, 2], [3, 4]])
214
+ # # INSERT INTO table (x, y) VALUES (1, 2)
215
+ # # INSERT INTO table (x, y) VALUES (3, 4)
173
216
  #
174
217
  # This method also accepts a dataset instead of an array of value arrays:
175
218
  #
176
- # dataset.import([:x, :y], other_dataset.select(:a___x, :b___y))
219
+ # DB[:table].import([:x, :y], DB[:table2].select(:a, :b))
220
+ # # INSERT INTO table (x, y) SELECT a, b FROM table2
177
221
  #
178
222
  # The method also accepts a :slice or :commit_every option that specifies
179
223
  # the number of records to insert per transaction. This is useful especially
@@ -202,15 +246,53 @@ module Sequel
202
246
 
203
247
  # Inserts values into the associated table. The returned value is generally
204
248
  # the value of the primary key for the inserted row, but that is adapter dependent.
205
- # See insert_sql.
249
+ #
250
+ # +insert+ handles a number of different argument formats:
251
+ # * No arguments, single empty hash - Uses DEFAULT VALUES
252
+ # * Single hash - Most common format, treats keys as columns an values as values
253
+ # * Single array - Treats entries as values, with no columns
254
+ # * Two arrays - Treats first array as columns, second array as values
255
+ # * Single Dataset - Treats as an insert based on a selection from the dataset given,
256
+ # with no columns
257
+ # * Array and dataset - Treats as an insert based on a selection from the dataset
258
+ # given, with the columns given by the array.
259
+ #
260
+ # DB[:items].insert
261
+ # # INSERT INTO items DEFAULT VALUES
262
+ #
263
+ # DB[:items].insert({})
264
+ # # INSERT INTO items DEFAULT VALUES
265
+ #
266
+ # DB[:items].insert([1,2,3])
267
+ # # INSERT INTO items VALUES (1, 2, 3)
268
+ #
269
+ # DB[:items].insert([:a, :b], [1,2])
270
+ # # INSERT INTO items (a, b) VALUES (1, 2)
271
+ #
272
+ # DB[:items].insert(:a => 1, :b => 2)
273
+ # # INSERT INTO items (a, b) VALUES (1, 2)
274
+ #
275
+ # DB[:items].insert(DB[:old_items])
276
+ # # INSERT INTO items SELECT * FROM old_items
277
+ #
278
+ # DB[:items].insert([:a, :b], DB[:old_items])
279
+ # # INSERT INTO items (a, b) SELECT * FROM old_items
206
280
  def insert(*values)
207
281
  execute_insert(insert_sql(*values))
208
282
  end
209
283
 
210
284
  # Inserts multiple values. If a block is given it is invoked for each
211
- # item in the given array before inserting it. See #multi_insert as
285
+ # item in the given array before inserting it. See +multi_insert+ as
212
286
  # a possible faster version that inserts multiple records in one
213
287
  # SQL statement.
288
+ #
289
+ # DB[:table].insert_multiple([{:x=>1}, {:x=>2}])
290
+ # # INSERT INTO table (x) VALUES (1)
291
+ # # INSERT INTO table (x) VALUES (2)
292
+ #
293
+ # DB[:table].insert_multiple([{:x=>1}, {:x=>2}]){|row| row[:y] = row[:x] * 2}
294
+ # # INSERT INTO table (x, y) VALUES (1, 2)
295
+ # # INSERT INTO table (x, y) VALUES (2, 4)
214
296
  def insert_multiple(array, &block)
215
297
  if block
216
298
  array.each {|i| insert(block[i])}
@@ -221,6 +303,9 @@ module Sequel
221
303
 
222
304
  # Returns the interval between minimum and maximum values for the given
223
305
  # column.
306
+ #
307
+ # DB[:table].interval(:id) # SELECT (max(id) - min(id)) FROM table LIMIT 1
308
+ # # => 6
224
309
  def interval(column)
225
310
  aggregate_dataset.get{max(column) - min(column)}
226
311
  end
@@ -228,18 +313,27 @@ module Sequel
228
313
  # Reverses the order and then runs first. Note that this
229
314
  # will not necessarily give you the last record in the dataset,
230
315
  # unless you have an unambiguous order. If there is not
231
- # currently an order for this dataset, raises an Error.
316
+ # currently an order for this dataset, raises an +Error+.
317
+ #
318
+ # DB[:table].order(:id).last # SELECT * FROM table ORDER BY id DESC LIMIT 1
319
+ # # => {:id=>10}
320
+ #
321
+ # DB[:table].order(:id.desc).last(2) # SELECT * FROM table ORDER BY id ASC LIMIT 2
322
+ # # => [{:id=>1}, {:id=>2}]
232
323
  def last(*args, &block)
233
324
  raise(Error, 'No order specified') unless @opts[:order]
234
325
  reverse.first(*args, &block)
235
326
  end
236
327
 
237
328
  # Maps column values for each record in the dataset (if a column name is
238
- # given), or performs the stock mapping functionality of Enumerable.
239
- # Raises an error if both an argument and block are given. Examples:
329
+ # given), or performs the stock mapping functionality of +Enumerable+ otherwise.
330
+ # Raises an +Error+ if both an argument and block are given.
331
+ #
332
+ # DB[:table].map(:id) # SELECT * FROM table
333
+ # # => [1, 2, 3, ...]
240
334
  #
241
- # ds.map(:id) => [1, 2, 3, ...]
242
- # ds.map{|r| r[:id] * 2} => [2, 4, 6, ...]
335
+ # DB[:table].map{|r| r[:id] * 2} # SELECT * FROM table
336
+ # # => [2, 4, 6, ...]
243
337
  def map(column=nil, &block)
244
338
  if column
245
339
  raise(Error, ARG_BLOCK_ERROR_MSG) if block
@@ -250,11 +344,17 @@ module Sequel
250
344
  end
251
345
 
252
346
  # Returns the maximum value for the given column.
347
+ #
348
+ # DB[:table].max(:id) # SELECT max(id) FROM table LIMIT 1
349
+ # # => 10
253
350
  def max(column)
254
351
  aggregate_dataset.get{max(column)}
255
352
  end
256
353
 
257
354
  # Returns the minimum value for the given column.
355
+ #
356
+ # DB[:table].min(:id) # SELECT min(id) FROM table LIMIT 1
357
+ # # => 1
258
358
  def min(column)
259
359
  aggregate_dataset.get{min(column)}
260
360
  end
@@ -262,7 +362,9 @@ module Sequel
262
362
  # This is a front end for import that allows you to submit an array of
263
363
  # hashes instead of arrays of columns and values:
264
364
  #
265
- # dataset.multi_insert([{:x => 1}, {:x => 2}])
365
+ # DB[:table].multi_insert([{:x => 1}, {:x => 2}])
366
+ # # INSERT INTO table (x) VALUES (1)
367
+ # # INSERT INTO table (x) VALUES (2)
266
368
  #
267
369
  # Be aware that all hashes should have the same keys if you use this calling method,
268
370
  # otherwise some columns could be missed or set to null instead of to default
@@ -275,8 +377,11 @@ module Sequel
275
377
  import(columns, hashes.map{|h| columns.map{|c| h[c]}}, opts)
276
378
  end
277
379
 
278
- # Returns a Range object made from the minimum and maximum values for the
380
+ # Returns a +Range+ instance made from the minimum and maximum values for the
279
381
  # given column.
382
+ #
383
+ # DB[:table].range(:id) # SELECT max(id) AS v1, min(id) AS v2 FROM table LIMIT 1
384
+ # # => 1..10
280
385
  def range(column)
281
386
  if r = aggregate_dataset.select{[min(column).as(v1), max(column).as(v2)]}.first
282
387
  (r[:v1]..r[:v2])
@@ -285,6 +390,9 @@ module Sequel
285
390
 
286
391
  # Returns a hash with key_column values as keys and value_column values as
287
392
  # values. Similar to to_hash, but only selects the two columns.
393
+ #
394
+ # DB[:table].select_hash(:id, :name) # SELECT id, name FROM table
395
+ # # => {1=>'a', 2=>'b', ...}
288
396
  def select_hash(key_column, value_column)
289
397
  select(key_column, value_column).to_hash(hash_key_symbol(key_column), hash_key_symbol(value_column))
290
398
  end
@@ -293,6 +401,12 @@ module Sequel
293
401
  # returns an array of all values of that column in the dataset. If you
294
402
  # give a block argument that returns an array with multiple entries,
295
403
  # the contents of the resulting array are undefined.
404
+ #
405
+ # DB[:table].select_map(:id) # SELECT id FROM table
406
+ # # => [3, 5, 8, 1, ...]
407
+ #
408
+ # DB[:table].select_map{abs(id)} # SELECT abs(id) FROM table
409
+ # # => [3, 5, 8, 1, ...]
296
410
  def select_map(column=nil, &block)
297
411
  ds = naked.ungraphed
298
412
  ds = if column
@@ -305,6 +419,12 @@ module Sequel
305
419
  end
306
420
 
307
421
  # The same as select_map, but in addition orders the array by the column.
422
+ #
423
+ # DB[:table].select_order_map(:id) # SELECT id FROM table ORDER BY id
424
+ # # => [1, 2, 3, 4, ...]
425
+ #
426
+ # DB[:table].select_order_map{abs(id)} # SELECT abs(id) FROM table ORDER BY abs(id)
427
+ # # => [1, 2, 3, 4, ...]
308
428
  def select_order_map(column=nil, &block)
309
429
  ds = naked.ungraphed
310
430
  ds = if column
@@ -322,14 +442,17 @@ module Sequel
322
442
  update(*args)
323
443
  end
324
444
 
325
- # Returns the first record in the dataset.
445
+ # Returns the first record in the dataset, or nil if the dataset
446
+ # has no records. Users should probably use +first+ instead of
447
+ # this method.
326
448
  def single_record
327
449
  clone(:limit=>1).each{|r| return r}
328
450
  nil
329
451
  end
330
452
 
331
453
  # Returns the first value of the first record in the dataset.
332
- # Returns nil if dataset is empty.
454
+ # Returns nil if dataset is empty. Users should generally use
455
+ # +get+ instead of this method.
333
456
  def single_value
334
457
  if r = naked.ungraphed.single_record
335
458
  r.values.first
@@ -337,6 +460,9 @@ module Sequel
337
460
  end
338
461
 
339
462
  # Returns the sum for the given column.
463
+ #
464
+ # DB[:table].sum(:id) # SELECT sum(id) FROM table LIMIT 1
465
+ # # => 55
340
466
  def sum(column)
341
467
  aggregate_dataset.get{sum(column)}
342
468
  end
@@ -349,6 +475,11 @@ module Sequel
349
475
  # This does not use a CSV library or handle quoting of values in
350
476
  # any way. If any values in any of the rows could include commas or line
351
477
  # endings, you shouldn't use this.
478
+ #
479
+ # puts DB[:table].to_csv # SELECT * FROM table
480
+ # # id,name
481
+ # # 1,Jim
482
+ # # 2,Bob
352
483
  def to_csv(include_column_titles = true)
353
484
  n = naked
354
485
  cols = n.columns
@@ -362,6 +493,12 @@ module Sequel
362
493
  # If rows have duplicate values for the key column, the latter row(s)
363
494
  # will overwrite the value of the previous row(s). If the value_column
364
495
  # is not given or nil, uses the entire hash as the value.
496
+ #
497
+ # DB[:table].to_hash(:id, :name) # SELECT * FROM table
498
+ # # {1=>'Jim', 2=>'Bob', ...}
499
+ #
500
+ # DB[:table].to_hash(:id) # SELECT * FROM table
501
+ # # {1=>{:id=>1, :name=>'Jim'}, 2=>{:id=>2, :name=>'Bob'}, ...}
365
502
  def to_hash(key_column, value_column = nil)
366
503
  inject({}) do |m, r|
367
504
  m[r[key_column]] = value_column ? r[value_column] : r
@@ -370,12 +507,23 @@ module Sequel
370
507
  end
371
508
 
372
509
  # Truncates the dataset. Returns nil.
510
+ #
511
+ # DB[:table].truncate # TRUNCATE table
512
+ # # => nil
373
513
  def truncate
374
514
  execute_ddl(truncate_sql)
375
515
  end
376
516
 
377
517
  # Updates values for the dataset. The returned value is generally the
378
- # number of rows updated, but that is adapter dependent. See update_sql.
518
+ # number of rows updated, but that is adapter dependent. +values+ should
519
+ # a hash where the keys are columns to set and values are the values to
520
+ # which to set the columns.
521
+ #
522
+ # DB[:table].update(:x=>nil) # UPDATE table SET x = NULL
523
+ # # => 10
524
+ #
525
+ # DB[:table].update(:x=>:x+1, :y=>0) # UPDATE table SET x = (x + 1), :y = 0
526
+ # # => 10
379
527
  def update(values={})
380
528
  execute_dui(update_sql(values))
381
529
  end
@@ -387,7 +535,8 @@ module Sequel
387
535
  {:server=>@opts[:server] || :default}.merge(opts)
388
536
  end
389
537
 
390
- # Execute the given SQL on the database using execute.
538
+ # Execute the given select SQL on the database using execute. Use the
539
+ # :read_only server unless a specific server is set.
391
540
  def execute(sql, opts={}, &block)
392
541
  @db.execute(sql, {:server=>@opts[:server] || :read_only}.merge(opts), &block)
393
542
  end