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
@@ -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