sequel 3.13.0 → 3.14.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +36 -0
- data/doc/release_notes/3.14.0.txt +118 -0
- data/lib/sequel/adapters/oracle.rb +7 -2
- data/lib/sequel/adapters/shared/mssql.rb +9 -3
- data/lib/sequel/connection_pool/sharded_threaded.rb +1 -1
- data/lib/sequel/connection_pool/threaded.rb +3 -3
- data/lib/sequel/database/connecting.rb +47 -11
- data/lib/sequel/database/dataset.rb +17 -6
- data/lib/sequel/database/dataset_defaults.rb +15 -3
- data/lib/sequel/database/logging.rb +4 -3
- data/lib/sequel/database/misc.rb +33 -21
- data/lib/sequel/database/query.rb +61 -22
- data/lib/sequel/database/schema_generator.rb +108 -45
- data/lib/sequel/database/schema_methods.rb +8 -5
- data/lib/sequel/dataset/actions.rb +194 -45
- data/lib/sequel/dataset/features.rb +1 -1
- data/lib/sequel/dataset/graph.rb +51 -43
- data/lib/sequel/dataset/misc.rb +29 -5
- data/lib/sequel/dataset/mutation.rb +0 -1
- data/lib/sequel/dataset/prepared_statements.rb +14 -2
- data/lib/sequel/dataset/query.rb +268 -125
- data/lib/sequel/dataset/sql.rb +33 -44
- data/lib/sequel/extensions/migration.rb +3 -2
- data/lib/sequel/extensions/pagination.rb +1 -1
- data/lib/sequel/model/associations.rb +89 -87
- data/lib/sequel/model/base.rb +386 -109
- data/lib/sequel/model/errors.rb +15 -1
- data/lib/sequel/model/exceptions.rb +3 -3
- data/lib/sequel/model/inflections.rb +2 -2
- data/lib/sequel/model/plugins.rb +9 -5
- data/lib/sequel/plugins/rcte_tree.rb +43 -15
- data/lib/sequel/plugins/schema.rb +6 -5
- data/lib/sequel/plugins/serialization.rb +1 -1
- data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
- data/lib/sequel/plugins/tree.rb +33 -1
- data/lib/sequel/timezones.rb +16 -10
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +36 -2
- data/spec/adapters/mysql_spec.rb +4 -4
- data/spec/adapters/postgres_spec.rb +1 -1
- data/spec/adapters/spec_helper.rb +2 -2
- data/spec/core/database_spec.rb +8 -1
- data/spec/core/dataset_spec.rb +36 -1
- data/spec/extensions/pagination_spec.rb +1 -1
- data/spec/extensions/rcte_tree_spec.rb +40 -8
- data/spec/extensions/schema_spec.rb +5 -0
- data/spec/extensions/serialization_spec.rb +4 -4
- data/spec/extensions/single_table_inheritance_spec.rb +7 -0
- data/spec/extensions/tree_spec.rb +36 -0
- data/spec/integration/dataset_test.rb +19 -0
- data/spec/integration/prepared_statement_test.rb +2 -2
- data/spec/integration/schema_test.rb +1 -1
- data/spec/integration/spec_helper.rb +4 -4
- data/spec/integration/timezone_test.rb +27 -21
- data/spec/model/associations_spec.rb +5 -5
- data/spec/model/dataset_methods_spec.rb +13 -0
- data/spec/model/hooks_spec.rb +31 -0
- data/spec/model/record_spec.rb +24 -7
- data/spec/model/validations_spec.rb +9 -4
- 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
|
66
|
-
# definitions using create_table, and
|
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
|
-
#
|
88
|
-
#
|
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
|
-
#
|
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
|
-
#
|
31
|
+
# Update all records matching the conditions with the values specified.
|
32
|
+
# Returns the number of rows affected.
|
32
33
|
#
|
33
|
-
#
|
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
|
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
|
-
#
|
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
|
83
|
-
# number of records deleted, but that is adapter dependent.
|
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
|
-
#
|
126
|
-
#
|
127
|
-
#
|
128
|
-
#
|
129
|
-
#
|
130
|
-
#
|
131
|
-
#
|
132
|
-
#
|
133
|
-
#
|
134
|
-
#
|
135
|
-
#
|
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
|
-
#
|
155
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
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
|
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
|
-
#
|
242
|
-
#
|
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
|
-
#
|
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
|
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.
|
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
|