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