sequel 3.21.0 → 3.29.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 +413 -3
- data/README.rdoc +20 -6
- data/Rakefile +23 -16
- data/bin/sequel +1 -5
- data/doc/association_basics.rdoc +210 -43
- data/doc/dataset_basics.rdoc +4 -4
- data/doc/mass_assignment.rdoc +54 -0
- data/doc/migration.rdoc +15 -538
- data/doc/model_hooks.rdoc +72 -27
- data/doc/opening_databases.rdoc +86 -50
- data/doc/prepared_statements.rdoc +40 -13
- data/doc/reflection.rdoc +8 -2
- data/doc/release_notes/3.22.0.txt +39 -0
- data/doc/release_notes/3.23.0.txt +172 -0
- data/doc/release_notes/3.24.0.txt +420 -0
- data/doc/release_notes/3.25.0.txt +88 -0
- data/doc/release_notes/3.26.0.txt +88 -0
- data/doc/release_notes/3.27.0.txt +82 -0
- data/doc/release_notes/3.28.0.txt +304 -0
- data/doc/release_notes/3.29.0.txt +459 -0
- data/doc/schema_modification.rdoc +547 -0
- data/doc/sharding.rdoc +7 -1
- data/doc/testing.rdoc +115 -0
- data/doc/transactions.rdoc +137 -0
- data/doc/virtual_rows.rdoc +2 -2
- data/lib/sequel/adapters/ado/mssql.rb +18 -6
- data/lib/sequel/adapters/ado.rb +40 -18
- data/lib/sequel/adapters/amalgalite.rb +15 -7
- data/lib/sequel/adapters/db2.rb +175 -86
- data/lib/sequel/adapters/dbi.rb +15 -15
- data/lib/sequel/adapters/do/mysql.rb +0 -5
- data/lib/sequel/adapters/do/postgres.rb +0 -5
- data/lib/sequel/adapters/do/sqlite.rb +0 -5
- data/lib/sequel/adapters/do.rb +17 -36
- data/lib/sequel/adapters/firebird.rb +27 -208
- data/lib/sequel/adapters/ibmdb.rb +448 -0
- data/lib/sequel/adapters/informix.rb +6 -23
- data/lib/sequel/adapters/jdbc/as400.rb +5 -31
- data/lib/sequel/adapters/jdbc/db2.rb +44 -0
- data/lib/sequel/adapters/jdbc/derby.rb +217 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +29 -0
- data/lib/sequel/adapters/jdbc/h2.rb +26 -17
- data/lib/sequel/adapters/jdbc/hsqldb.rb +166 -0
- data/lib/sequel/adapters/jdbc/informix.rb +26 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +29 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +0 -32
- data/lib/sequel/adapters/jdbc/mysql.rb +9 -10
- data/lib/sequel/adapters/jdbc/oracle.rb +67 -25
- data/lib/sequel/adapters/jdbc/postgresql.rb +6 -11
- data/lib/sequel/adapters/jdbc/sqlite.rb +0 -5
- data/lib/sequel/adapters/jdbc/sqlserver.rb +41 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
- data/lib/sequel/adapters/jdbc.rb +107 -38
- data/lib/sequel/adapters/mock.rb +315 -0
- data/lib/sequel/adapters/mysql.rb +78 -182
- data/lib/sequel/adapters/mysql2.rb +24 -23
- data/lib/sequel/adapters/odbc/db2.rb +17 -0
- data/lib/sequel/adapters/odbc/mssql.rb +0 -5
- data/lib/sequel/adapters/odbc.rb +28 -9
- data/lib/sequel/adapters/openbase.rb +2 -4
- data/lib/sequel/adapters/oracle.rb +349 -51
- data/lib/sequel/adapters/postgres.rb +169 -21
- data/lib/sequel/adapters/shared/access.rb +21 -6
- data/lib/sequel/adapters/shared/db2.rb +288 -0
- data/lib/sequel/adapters/shared/firebird.rb +214 -0
- data/lib/sequel/adapters/shared/informix.rb +45 -0
- data/lib/sequel/adapters/shared/mssql.rb +108 -65
- data/lib/sequel/adapters/shared/mysql.rb +56 -13
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +149 -0
- data/lib/sequel/adapters/shared/oracle.rb +185 -34
- data/lib/sequel/adapters/shared/postgres.rb +107 -58
- data/lib/sequel/adapters/shared/progress.rb +0 -6
- data/lib/sequel/adapters/shared/sqlite.rb +168 -41
- data/lib/sequel/adapters/sqlite.rb +27 -18
- data/lib/sequel/adapters/swift/mysql.rb +9 -5
- data/lib/sequel/adapters/swift/postgres.rb +0 -5
- data/lib/sequel/adapters/swift/sqlite.rb +6 -4
- data/lib/sequel/adapters/swift.rb +5 -5
- data/lib/sequel/adapters/tinytds.rb +152 -17
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +63 -0
- data/lib/sequel/ast_transformer.rb +190 -0
- data/lib/sequel/connection_pool/threaded.rb +3 -2
- data/lib/sequel/connection_pool.rb +1 -1
- data/lib/sequel/core.rb +46 -5
- data/lib/sequel/database/connecting.rb +5 -6
- data/lib/sequel/database/dataset.rb +4 -4
- data/lib/sequel/database/dataset_defaults.rb +59 -1
- data/lib/sequel/database/logging.rb +1 -1
- data/lib/sequel/database/misc.rb +100 -19
- data/lib/sequel/database/query.rb +153 -58
- data/lib/sequel/database/schema_generator.rb +8 -5
- data/lib/sequel/database/schema_methods.rb +59 -29
- data/lib/sequel/dataset/actions.rb +194 -57
- data/lib/sequel/dataset/features.rb +81 -8
- data/lib/sequel/dataset/graph.rb +8 -7
- data/lib/sequel/dataset/misc.rb +50 -23
- data/lib/sequel/dataset/mutation.rb +5 -6
- data/lib/sequel/dataset/prepared_statements.rb +32 -15
- data/lib/sequel/dataset/query.rb +223 -42
- data/lib/sequel/dataset/sql.rb +58 -61
- data/lib/sequel/dataset.rb +8 -0
- data/lib/sequel/exceptions.rb +4 -0
- data/lib/sequel/extensions/columns_introspection.rb +61 -0
- data/lib/sequel/extensions/migration.rb +6 -4
- data/lib/sequel/extensions/named_timezones.rb +5 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
- data/lib/sequel/extensions/to_dot.rb +95 -83
- data/lib/sequel/model/associations.rb +997 -331
- data/lib/sequel/model/base.rb +386 -129
- data/lib/sequel/model/errors.rb +1 -1
- data/lib/sequel/model/exceptions.rb +5 -1
- data/lib/sequel/model.rb +15 -8
- data/lib/sequel/plugins/association_pks.rb +22 -4
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/dataset_associations.rb +100 -0
- data/lib/sequel/plugins/defaults_setter.rb +58 -0
- data/lib/sequel/plugins/force_encoding.rb +6 -6
- data/lib/sequel/plugins/identity_map.rb +114 -7
- data/lib/sequel/plugins/many_through_many.rb +65 -7
- data/lib/sequel/plugins/prepared_statements.rb +151 -0
- data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
- data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
- data/lib/sequel/plugins/rcte_tree.rb +29 -15
- data/lib/sequel/plugins/serialization.rb +6 -1
- data/lib/sequel/plugins/serialization_modification_detection.rb +51 -0
- data/lib/sequel/plugins/sharding.rb +12 -25
- data/lib/sequel/plugins/single_table_inheritance.rb +3 -1
- data/lib/sequel/plugins/typecast_on_load.rb +9 -12
- data/lib/sequel/plugins/update_primary_key.rb +2 -2
- data/lib/sequel/plugins/xml_serializer.rb +3 -3
- data/lib/sequel/sql.rb +107 -51
- data/lib/sequel/timezones.rb +44 -35
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/db2_spec.rb +146 -0
- data/spec/adapters/mssql_spec.rb +65 -29
- data/spec/adapters/mysql_spec.rb +122 -123
- data/spec/adapters/oracle_spec.rb +48 -76
- data/spec/adapters/postgres_spec.rb +213 -61
- data/spec/adapters/spec_helper.rb +6 -5
- data/spec/adapters/sqlite_spec.rb +35 -21
- data/spec/core/connection_pool_spec.rb +71 -92
- data/spec/core/core_sql_spec.rb +20 -31
- data/spec/core/database_spec.rb +729 -508
- data/spec/core/dataset_spec.rb +980 -1044
- data/spec/core/expression_filters_spec.rb +159 -42
- data/spec/core/mock_adapter_spec.rb +378 -0
- data/spec/core/object_graph_spec.rb +48 -114
- data/spec/core/schema_generator_spec.rb +3 -3
- data/spec/core/schema_spec.rb +298 -38
- data/spec/core/spec_helper.rb +6 -48
- data/spec/extensions/association_pks_spec.rb +38 -0
- data/spec/extensions/class_table_inheritance_spec.rb +1 -1
- data/spec/extensions/columns_introspection_spec.rb +91 -0
- data/spec/extensions/dataset_associations_spec.rb +199 -0
- data/spec/extensions/defaults_setter_spec.rb +64 -0
- data/spec/extensions/identity_map_spec.rb +162 -0
- data/spec/extensions/instance_hooks_spec.rb +71 -0
- data/spec/extensions/many_through_many_spec.rb +195 -20
- data/spec/extensions/migration_spec.rb +17 -17
- data/spec/extensions/named_timezones_spec.rb +22 -2
- data/spec/extensions/nested_attributes_spec.rb +4 -0
- data/spec/extensions/prepared_statements_associations_spec.rb +126 -0
- data/spec/extensions/prepared_statements_safe_spec.rb +79 -0
- data/spec/extensions/prepared_statements_spec.rb +72 -0
- data/spec/extensions/prepared_statements_with_pk_spec.rb +38 -0
- data/spec/extensions/schema_dumper_spec.rb +2 -2
- data/spec/extensions/schema_spec.rb +13 -21
- data/spec/extensions/serialization_modification_detection_spec.rb +37 -0
- data/spec/extensions/serialization_spec.rb +5 -8
- data/spec/extensions/single_table_inheritance_spec.rb +11 -0
- data/spec/extensions/spec_helper.rb +7 -1
- data/spec/extensions/thread_local_timezones_spec.rb +22 -2
- data/spec/extensions/to_dot_spec.rb +3 -5
- data/spec/extensions/typecast_on_load_spec.rb +1 -6
- data/spec/extensions/xml_serializer_spec.rb +16 -4
- data/spec/integration/associations_test.rb +522 -21
- data/spec/integration/database_test.rb +4 -2
- data/spec/integration/dataset_test.rb +375 -62
- data/spec/integration/eager_loader_test.rb +19 -21
- data/spec/integration/model_test.rb +80 -1
- data/spec/integration/plugin_test.rb +304 -116
- data/spec/integration/prepared_statement_test.rb +200 -120
- data/spec/integration/schema_test.rb +161 -30
- data/spec/integration/spec_helper.rb +39 -30
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +172 -5
- data/spec/integration/type_test.rb +17 -3
- data/spec/model/association_reflection_spec.rb +174 -7
- data/spec/model/associations_spec.rb +849 -661
- data/spec/model/base_spec.rb +255 -95
- data/spec/model/dataset_methods_spec.rb +7 -27
- data/spec/model/eager_loading_spec.rb +640 -676
- data/spec/model/hooks_spec.rb +309 -67
- data/spec/model/model_spec.rb +207 -167
- data/spec/model/plugins_spec.rb +24 -13
- data/spec/model/record_spec.rb +321 -218
- data/spec/model/spec_helper.rb +13 -71
- data/spec/model/validations_spec.rb +11 -0
- metadata +95 -38
|
@@ -1,22 +1,27 @@
|
|
|
1
1
|
module Sequel
|
|
2
2
|
class Dataset
|
|
3
3
|
# ---------------------
|
|
4
|
-
# :section: Methods that execute code on the database
|
|
4
|
+
# :section: 2 - Methods that execute code on the database
|
|
5
5
|
# These methods all execute the dataset's SQL on the database.
|
|
6
6
|
# They don't return modified datasets, so if used in a method chain
|
|
7
7
|
# they should be the last method called.
|
|
8
8
|
# ---------------------
|
|
9
9
|
|
|
10
10
|
# Action methods defined by Sequel that execute code on the database.
|
|
11
|
-
ACTION_METHODS =
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
ACTION_METHODS = (<<-METHS).split.map{|x| x.to_sym}
|
|
12
|
+
<< [] []= all avg count columns columns! delete each
|
|
13
|
+
empty? fetch_rows first get import insert insert_multiple interval last
|
|
14
|
+
map max min multi_insert range select_hash select_map select_order_map
|
|
15
|
+
set single_record single_value sum to_csv to_hash truncate update
|
|
16
|
+
METHS
|
|
15
17
|
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
# Inserts the given argument into the database. Returns self so it
|
|
19
|
+
# can be used safely when chaining:
|
|
20
|
+
#
|
|
21
|
+
# DB[:items] << {:id=>0, :name=>'Zero'} << DB[:old_items].select(:id, name)
|
|
22
|
+
def <<(arg)
|
|
23
|
+
insert(arg)
|
|
24
|
+
self
|
|
20
25
|
end
|
|
21
26
|
|
|
22
27
|
# Returns the first record matching the conditions. Examples:
|
|
@@ -72,7 +77,7 @@ module Sequel
|
|
|
72
77
|
# # => [:id, :name]
|
|
73
78
|
def columns
|
|
74
79
|
return @columns if @columns
|
|
75
|
-
ds = unfiltered.unordered.clone(:distinct => nil, :limit => 1)
|
|
80
|
+
ds = unfiltered.unordered.clone(:distinct => nil, :limit => 1, :offset=>nil)
|
|
76
81
|
ds.each{break}
|
|
77
82
|
@columns = ds.instance_variable_get(:@columns)
|
|
78
83
|
@columns || []
|
|
@@ -101,10 +106,15 @@ module Sequel
|
|
|
101
106
|
#
|
|
102
107
|
# DB[:table].delete # DELETE * FROM table
|
|
103
108
|
# # => 3
|
|
104
|
-
def delete
|
|
105
|
-
|
|
109
|
+
def delete(&block)
|
|
110
|
+
sql = delete_sql
|
|
111
|
+
if uses_returning?(:delete)
|
|
112
|
+
returning_fetch_rows(sql, &block)
|
|
113
|
+
else
|
|
114
|
+
execute_dui(sql)
|
|
115
|
+
end
|
|
106
116
|
end
|
|
107
|
-
|
|
117
|
+
|
|
108
118
|
# Iterates over the records in the dataset as they are yielded from the
|
|
109
119
|
# database adapter, and returns self.
|
|
110
120
|
#
|
|
@@ -248,14 +258,16 @@ module Sequel
|
|
|
248
258
|
# the value of the primary key for the inserted row, but that is adapter dependent.
|
|
249
259
|
#
|
|
250
260
|
# +insert+ handles a number of different argument formats:
|
|
251
|
-
#
|
|
252
|
-
#
|
|
253
|
-
#
|
|
254
|
-
#
|
|
255
|
-
#
|
|
256
|
-
#
|
|
257
|
-
#
|
|
258
|
-
#
|
|
261
|
+
# no arguments or single empty hash :: Uses DEFAULT VALUES
|
|
262
|
+
# single hash :: Most common format, treats keys as columns an values as values
|
|
263
|
+
# single array :: Treats entries as values, with no columns
|
|
264
|
+
# two arrays :: Treats first array as columns, second array as values
|
|
265
|
+
# single Dataset :: Treats as an insert based on a selection from the dataset given,
|
|
266
|
+
# with no columns
|
|
267
|
+
# array and dataset :: Treats as an insert based on a selection from the dataset
|
|
268
|
+
# given, with the columns given by the array.
|
|
269
|
+
#
|
|
270
|
+
# Examples:
|
|
259
271
|
#
|
|
260
272
|
# DB[:items].insert
|
|
261
273
|
# # INSERT INTO items DEFAULT VALUES
|
|
@@ -277,8 +289,13 @@ module Sequel
|
|
|
277
289
|
#
|
|
278
290
|
# DB[:items].insert([:a, :b], DB[:old_items])
|
|
279
291
|
# # INSERT INTO items (a, b) SELECT * FROM old_items
|
|
280
|
-
def insert(*values)
|
|
281
|
-
|
|
292
|
+
def insert(*values, &block)
|
|
293
|
+
sql = insert_sql(*values)
|
|
294
|
+
if uses_returning?(:insert)
|
|
295
|
+
returning_fetch_rows(sql, &block)
|
|
296
|
+
else
|
|
297
|
+
execute_insert(sql)
|
|
298
|
+
end
|
|
282
299
|
end
|
|
283
300
|
|
|
284
301
|
# Inserts multiple values. If a block is given it is invoked for each
|
|
@@ -310,7 +327,7 @@ module Sequel
|
|
|
310
327
|
aggregate_dataset.get{max(column) - min(column)}
|
|
311
328
|
end
|
|
312
329
|
|
|
313
|
-
# Reverses the order and then runs first. Note that this
|
|
330
|
+
# Reverses the order and then runs #first with the given arguments and block. Note that this
|
|
314
331
|
# will not necessarily give you the last record in the dataset,
|
|
315
332
|
# unless you have an unambiguous order. If there is not
|
|
316
333
|
# currently an order for this dataset, raises an +Error+.
|
|
@@ -334,10 +351,20 @@ module Sequel
|
|
|
334
351
|
#
|
|
335
352
|
# DB[:table].map{|r| r[:id] * 2} # SELECT * FROM table
|
|
336
353
|
# # => [2, 4, 6, ...]
|
|
354
|
+
#
|
|
355
|
+
# You can also provide an array of column names:
|
|
356
|
+
#
|
|
357
|
+
# DB[:table].map([:id, :name]) # SELECT * FROM table
|
|
358
|
+
# # => [[1, 'A'], [2, 'B'], [3, 'C'], ...]
|
|
337
359
|
def map(column=nil, &block)
|
|
338
360
|
if column
|
|
339
361
|
raise(Error, ARG_BLOCK_ERROR_MSG) if block
|
|
340
|
-
|
|
362
|
+
return naked.map(column) if row_proc
|
|
363
|
+
if column.is_a?(Array)
|
|
364
|
+
super(){|r| r.values_at(*column)}
|
|
365
|
+
else
|
|
366
|
+
super(){|r| r[column]}
|
|
367
|
+
end
|
|
341
368
|
else
|
|
342
369
|
super(&block)
|
|
343
370
|
end
|
|
@@ -393,49 +420,63 @@ module Sequel
|
|
|
393
420
|
#
|
|
394
421
|
# DB[:table].select_hash(:id, :name) # SELECT id, name FROM table
|
|
395
422
|
# # => {1=>'a', 2=>'b', ...}
|
|
423
|
+
#
|
|
424
|
+
# You can also provide an array of column names for either the key_column,
|
|
425
|
+
# the value column, or both:
|
|
426
|
+
#
|
|
427
|
+
# DB[:table].select_hash([:id, :foo], [:name, :bar]) # SELECT * FROM table
|
|
428
|
+
# # {[1, 3]=>['a', 'c'], [2, 4]=>['b', 'd'], ...}
|
|
396
429
|
def select_hash(key_column, value_column)
|
|
397
|
-
|
|
430
|
+
if key_column.is_a?(Array)
|
|
431
|
+
if value_column.is_a?(Array)
|
|
432
|
+
select(*(key_column + value_column)).to_hash(key_column.map{|c| hash_key_symbol(c)}, value_column.map{|c| hash_key_symbol(c)})
|
|
433
|
+
else
|
|
434
|
+
select(*(key_column + [value_column])).to_hash(key_column.map{|c| hash_key_symbol(c)}, hash_key_symbol(value_column))
|
|
435
|
+
end
|
|
436
|
+
elsif value_column.is_a?(Array)
|
|
437
|
+
select(key_column, *value_column).to_hash(hash_key_symbol(key_column), value_column.map{|c| hash_key_symbol(c)})
|
|
438
|
+
else
|
|
439
|
+
select(key_column, value_column).to_hash(hash_key_symbol(key_column), hash_key_symbol(value_column))
|
|
440
|
+
end
|
|
398
441
|
end
|
|
399
442
|
|
|
400
443
|
# Selects the column given (either as an argument or as a block), and
|
|
401
444
|
# returns an array of all values of that column in the dataset. If you
|
|
402
445
|
# give a block argument that returns an array with multiple entries,
|
|
403
|
-
# the contents of the resulting array are undefined.
|
|
446
|
+
# the contents of the resulting array are undefined. Raises an Error
|
|
447
|
+
# if called with both an argument and a block.
|
|
404
448
|
#
|
|
405
449
|
# DB[:table].select_map(:id) # SELECT id FROM table
|
|
406
450
|
# # => [3, 5, 8, 1, ...]
|
|
407
451
|
#
|
|
408
|
-
# DB[:table].select_map{
|
|
409
|
-
# # => [
|
|
452
|
+
# DB[:table].select_map{id * 2} # SELECT (id * 2) FROM table
|
|
453
|
+
# # => [6, 10, 16, 2, ...]
|
|
454
|
+
#
|
|
455
|
+
# You can also provide an array of column names:
|
|
456
|
+
#
|
|
457
|
+
# DB[:table].select_map([:id, :name]) # SELECT id, name FROM table
|
|
458
|
+
# # => [[1, 'A'], [2, 'B'], [3, 'C'], ...]
|
|
410
459
|
def select_map(column=nil, &block)
|
|
411
|
-
|
|
412
|
-
ds = if column
|
|
413
|
-
raise(Error, ARG_BLOCK_ERROR_MSG) if block
|
|
414
|
-
ds.select(column)
|
|
415
|
-
else
|
|
416
|
-
ds.select(&block)
|
|
417
|
-
end
|
|
418
|
-
ds.map{|r| r.values.first}
|
|
460
|
+
_select_map(column, false, &block)
|
|
419
461
|
end
|
|
462
|
+
|
|
420
463
|
|
|
421
464
|
# The same as select_map, but in addition orders the array by the column.
|
|
422
465
|
#
|
|
423
466
|
# DB[:table].select_order_map(:id) # SELECT id FROM table ORDER BY id
|
|
424
467
|
# # => [1, 2, 3, 4, ...]
|
|
425
468
|
#
|
|
426
|
-
# DB[:table].select_order_map{
|
|
427
|
-
# # => [
|
|
469
|
+
# DB[:table].select_order_map{id * 2} # SELECT (id * 2) FROM table ORDER BY (id * 2)
|
|
470
|
+
# # => [2, 4, 6, 8, ...]
|
|
471
|
+
#
|
|
472
|
+
# You can also provide an array of column names:
|
|
473
|
+
#
|
|
474
|
+
# DB[:table].select_order_map([:id, :name]) # SELECT id, name FROM table ORDER BY id, name
|
|
475
|
+
# # => [[1, 'A'], [2, 'B'], [3, 'C'], ...]
|
|
428
476
|
def select_order_map(column=nil, &block)
|
|
429
|
-
|
|
430
|
-
ds = if column
|
|
431
|
-
raise(Error, ARG_BLOCK_ERROR_MSG) if block
|
|
432
|
-
ds.select(column).order(unaliased_identifier(column))
|
|
433
|
-
else
|
|
434
|
-
ds.select(&block).order(&block)
|
|
435
|
-
end
|
|
436
|
-
ds.map{|r| r.values.first}
|
|
477
|
+
_select_map(column, true, &block)
|
|
437
478
|
end
|
|
438
|
-
|
|
479
|
+
|
|
439
480
|
# Alias for update, but not aliased directly so subclasses
|
|
440
481
|
# don't have to override both methods.
|
|
441
482
|
def set(*args)
|
|
@@ -499,11 +540,38 @@ module Sequel
|
|
|
499
540
|
#
|
|
500
541
|
# DB[:table].to_hash(:id) # SELECT * FROM table
|
|
501
542
|
# # {1=>{:id=>1, :name=>'Jim'}, 2=>{:id=>2, :name=>'Bob'}, ...}
|
|
543
|
+
#
|
|
544
|
+
# You can also provide an array of column names for either the key_column,
|
|
545
|
+
# the value column, or both:
|
|
546
|
+
#
|
|
547
|
+
# DB[:table].to_hash([:id, :foo], [:name, :bar]) # SELECT * FROM table
|
|
548
|
+
# # {[1, 3]=>['Jim', 'bo'], [2, 4]=>['Bob', 'be'], ...}
|
|
549
|
+
#
|
|
550
|
+
# DB[:table].to_hash([:id, :name]) # SELECT * FROM table
|
|
551
|
+
# # {[1, 'Jim']=>{:id=>1, :name=>'Jim'}, [2, 'Bob'=>{:id=>2, :name=>'Bob'}, ...}
|
|
502
552
|
def to_hash(key_column, value_column = nil)
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
553
|
+
h = {}
|
|
554
|
+
if value_column
|
|
555
|
+
return naked.to_hash(key_column, value_column) if row_proc
|
|
556
|
+
if value_column.is_a?(Array)
|
|
557
|
+
if key_column.is_a?(Array)
|
|
558
|
+
each{|r| h[r.values_at(*key_column)] = r.values_at(*value_column)}
|
|
559
|
+
else
|
|
560
|
+
each{|r| h[r[key_column]] = r.values_at(*value_column)}
|
|
561
|
+
end
|
|
562
|
+
else
|
|
563
|
+
if key_column.is_a?(Array)
|
|
564
|
+
each{|r| h[r.values_at(*key_column)] = r[value_column]}
|
|
565
|
+
else
|
|
566
|
+
each{|r| h[r[key_column]] = r[value_column]}
|
|
567
|
+
end
|
|
568
|
+
end
|
|
569
|
+
elsif key_column.is_a?(Array)
|
|
570
|
+
each{|r| h[r.values_at(*key_column)] = r}
|
|
571
|
+
else
|
|
572
|
+
each{|r| h[r[key_column]] = r}
|
|
506
573
|
end
|
|
574
|
+
h
|
|
507
575
|
end
|
|
508
576
|
|
|
509
577
|
# Truncates the dataset. Returns nil.
|
|
@@ -522,14 +590,51 @@ module Sequel
|
|
|
522
590
|
# DB[:table].update(:x=>nil) # UPDATE table SET x = NULL
|
|
523
591
|
# # => 10
|
|
524
592
|
#
|
|
525
|
-
# DB[:table].update(:x=>:x+1, :y=>0) # UPDATE table SET x = (x + 1),
|
|
593
|
+
# DB[:table].update(:x=>:x+1, :y=>0) # UPDATE table SET x = (x + 1), y = 0
|
|
526
594
|
# # => 10
|
|
527
|
-
def update(values={})
|
|
528
|
-
|
|
595
|
+
def update(values={}, &block)
|
|
596
|
+
sql = update_sql(values)
|
|
597
|
+
if uses_returning?(:update)
|
|
598
|
+
returning_fetch_rows(sql, &block)
|
|
599
|
+
else
|
|
600
|
+
execute_dui(sql)
|
|
601
|
+
end
|
|
529
602
|
end
|
|
530
603
|
|
|
604
|
+
protected
|
|
605
|
+
|
|
606
|
+
# Return an array of arrays of values given by the symbols in ret_cols.
|
|
607
|
+
def _select_map_multiple(ret_cols)
|
|
608
|
+
map{|r| r.values_at(*ret_cols)}
|
|
609
|
+
end
|
|
610
|
+
|
|
611
|
+
# Returns an array of the first value in each row.
|
|
612
|
+
def _select_map_single
|
|
613
|
+
map{|r| r.values.first}
|
|
614
|
+
end
|
|
615
|
+
|
|
531
616
|
private
|
|
532
617
|
|
|
618
|
+
# Internals of +select_map+ and +select_order_map+
|
|
619
|
+
def _select_map(column, order, &block)
|
|
620
|
+
ds = naked.ungraphed
|
|
621
|
+
if column
|
|
622
|
+
raise(Error, ARG_BLOCK_ERROR_MSG) if block
|
|
623
|
+
columns = Array(column)
|
|
624
|
+
select_cols = order ? columns.map{|c| c.is_a?(SQL::OrderedExpression) ? c.expression : c} : columns
|
|
625
|
+
ds = ds.select(*select_cols)
|
|
626
|
+
ds = ds.order(*columns.map{|c| unaliased_identifier(c)}) if order
|
|
627
|
+
else
|
|
628
|
+
ds = ds.select(&block)
|
|
629
|
+
ds = ds.order(&block) if order
|
|
630
|
+
end
|
|
631
|
+
if column.is_a?(Array)
|
|
632
|
+
ds._select_map_multiple(select_cols.map{|c| hash_key_symbol(c)})
|
|
633
|
+
else
|
|
634
|
+
ds._select_map_single
|
|
635
|
+
end
|
|
636
|
+
end
|
|
637
|
+
|
|
533
638
|
# Set the server to use to :default unless it is already set in the passed opts
|
|
534
639
|
def default_server_opts(opts)
|
|
535
640
|
{:server=>@opts[:server] || :default}.merge(opts)
|
|
@@ -561,9 +666,19 @@ module Sequel
|
|
|
561
666
|
# specifying the symbol that is likely to be used as the hash key
|
|
562
667
|
# for the column when records are returned.
|
|
563
668
|
def hash_key_symbol(s)
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
669
|
+
case s
|
|
670
|
+
when Symbol
|
|
671
|
+
_, c, a = split_symbol(s)
|
|
672
|
+
(a || c).to_sym
|
|
673
|
+
when SQL::Identifier
|
|
674
|
+
hash_key_symbol(s.value)
|
|
675
|
+
when SQL::QualifiedIdentifier
|
|
676
|
+
hash_key_symbol(s.column)
|
|
677
|
+
when SQL::AliasedExpression
|
|
678
|
+
hash_key_symbol(s.aliaz)
|
|
679
|
+
else
|
|
680
|
+
raise(Error, "#{s.inspect} is not supported, should be a Symbol, String, SQL::Identifier, SQL::QualifiedIdentifier, or SQL::AliasedExpression")
|
|
681
|
+
end
|
|
567
682
|
end
|
|
568
683
|
|
|
569
684
|
# Modify the identifier returned from the database based on the
|
|
@@ -580,6 +695,20 @@ module Sequel
|
|
|
580
695
|
def post_load(all_records)
|
|
581
696
|
end
|
|
582
697
|
|
|
698
|
+
# Called by insert/update/delete when returning is used.
|
|
699
|
+
# Yields each row as a plain hash to the block if one is given, or returns
|
|
700
|
+
# an array of plain hashes for all rows if a block is not given
|
|
701
|
+
def returning_fetch_rows(sql, &block)
|
|
702
|
+
if block
|
|
703
|
+
default_server.fetch_rows(sql, &block)
|
|
704
|
+
nil
|
|
705
|
+
else
|
|
706
|
+
rows = []
|
|
707
|
+
default_server.fetch_rows(sql){|r| rows << r}
|
|
708
|
+
rows
|
|
709
|
+
end
|
|
710
|
+
end
|
|
711
|
+
|
|
583
712
|
# Return the unaliased part of the identifier. Handles both
|
|
584
713
|
# implicit aliases in symbols, as well as SQL::AliasedExpression
|
|
585
714
|
# objects. Other objects are returned as is.
|
|
@@ -590,6 +719,14 @@ module Sequel
|
|
|
590
719
|
c_table ? SQL::QualifiedIdentifier.new(c_table, column.to_sym) : column.to_sym
|
|
591
720
|
when SQL::AliasedExpression
|
|
592
721
|
c.expression
|
|
722
|
+
when SQL::OrderedExpression
|
|
723
|
+
expr = c.expression
|
|
724
|
+
if expr.is_a?(Symbol)
|
|
725
|
+
expr = unaliased_identifier(expr)
|
|
726
|
+
SQL::OrderedExpression.new(unaliased_identifier(c.expression), c.descending, :nulls=>c.nulls)
|
|
727
|
+
else
|
|
728
|
+
c
|
|
729
|
+
end
|
|
593
730
|
else
|
|
594
731
|
c
|
|
595
732
|
end
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
module Sequel
|
|
2
2
|
class Dataset
|
|
3
3
|
# ---------------------
|
|
4
|
-
# :section: Methods that describe what the dataset supports
|
|
4
|
+
# :section: 4 - Methods that describe what the dataset supports
|
|
5
5
|
# These methods all return booleans, with most describing whether or not the
|
|
6
6
|
# dataset supports a feature.
|
|
7
7
|
# ---------------------
|
|
8
8
|
|
|
9
|
-
# Method used to check if WITH is supported
|
|
10
|
-
WITH_SUPPORTED=:select_with_sql
|
|
11
|
-
|
|
12
9
|
# Whether this dataset quotes identifiers.
|
|
13
10
|
def quote_identifiers?
|
|
14
|
-
@quote_identifiers
|
|
11
|
+
if defined?(@quote_identifiers)
|
|
12
|
+
@quote_identifiers
|
|
13
|
+
elsif db.respond_to?(:quote_identifiers?)
|
|
14
|
+
@quote_identifiers = db.quote_identifiers?
|
|
15
|
+
else
|
|
16
|
+
@quote_identifiers = false
|
|
17
|
+
end
|
|
15
18
|
end
|
|
16
19
|
|
|
17
20
|
# Whether this dataset will provide accurate number of rows matched for
|
|
@@ -21,22 +24,49 @@ module Sequel
|
|
|
21
24
|
true
|
|
22
25
|
end
|
|
23
26
|
|
|
27
|
+
# Whether you must use a column alias list for recursive CTEs (false by
|
|
28
|
+
# default).
|
|
29
|
+
def recursive_cte_requires_column_aliases?
|
|
30
|
+
false
|
|
31
|
+
end
|
|
32
|
+
|
|
24
33
|
# Whether the dataset requires SQL standard datetimes (false by default,
|
|
25
34
|
# as most allow strings with ISO 8601 format).
|
|
26
35
|
def requires_sql_standard_datetimes?
|
|
27
36
|
false
|
|
28
37
|
end
|
|
29
38
|
|
|
39
|
+
# Whether type specifiers are required for prepared statement/bound
|
|
40
|
+
# variable argument placeholders (i.e. :bv__integer)
|
|
41
|
+
def requires_placeholder_type_specifiers?
|
|
42
|
+
false
|
|
43
|
+
end
|
|
44
|
+
|
|
30
45
|
# Whether the dataset supports common table expressions (the WITH clause).
|
|
31
|
-
|
|
32
|
-
|
|
46
|
+
# If given, +type+ can be :select, :insert, :update, or :delete, in which case it
|
|
47
|
+
# determines whether WITH is supported for the respective statement type.
|
|
48
|
+
def supports_cte?(type=:select)
|
|
49
|
+
send(:"#{type}_clause_methods").include?(:"#{type}_with_sql")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Whether the dataset supports common table expressions (the WITH clause)
|
|
53
|
+
# in subqueries. If false, applies the WITH clause to the main query, which can cause issues
|
|
54
|
+
# if multiple WITH clauses use the same name.
|
|
55
|
+
def supports_cte_in_subqueries?
|
|
56
|
+
false
|
|
33
57
|
end
|
|
34
58
|
|
|
35
|
-
# Whether the dataset supports the DISTINCT ON clause, false by default.
|
|
59
|
+
# Whether the dataset supports or can emulate the DISTINCT ON clause, false by default.
|
|
36
60
|
def supports_distinct_on?
|
|
37
61
|
false
|
|
38
62
|
end
|
|
39
63
|
|
|
64
|
+
# Whether this dataset supports the +insert_select+ method for returning all columns values
|
|
65
|
+
# directly from an insert query.
|
|
66
|
+
def supports_insert_select?
|
|
67
|
+
supports_returning?(:insert)
|
|
68
|
+
end
|
|
69
|
+
|
|
40
70
|
# Whether the dataset supports the INTERSECT and EXCEPT compound operations, true by default.
|
|
41
71
|
def supports_intersect_except?
|
|
42
72
|
true
|
|
@@ -67,7 +97,24 @@ module Sequel
|
|
|
67
97
|
def supports_multiple_column_in?
|
|
68
98
|
true
|
|
69
99
|
end
|
|
100
|
+
|
|
101
|
+
# Whether the dataset supports or can fully emulate the DISTINCT ON clause,
|
|
102
|
+
# including respecting the ORDER BY clause, false by default
|
|
103
|
+
def supports_ordered_distinct_on?
|
|
104
|
+
supports_distinct_on?
|
|
105
|
+
end
|
|
70
106
|
|
|
107
|
+
# Whether the RETURNING clause is supported for the given type of query.
|
|
108
|
+
# +type+ can be :insert, :update, or :delete.
|
|
109
|
+
def supports_returning?(type)
|
|
110
|
+
send(:"#{type}_clause_methods").include?(:"#{type}_returning_sql")
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Whether the database supports SELECT *, column FROM table
|
|
114
|
+
def supports_select_all_and_column?
|
|
115
|
+
true
|
|
116
|
+
end
|
|
117
|
+
|
|
71
118
|
# Whether the dataset supports timezones in literal timestamps
|
|
72
119
|
def supports_timestamp_timezones?
|
|
73
120
|
false
|
|
@@ -82,5 +129,31 @@ module Sequel
|
|
|
82
129
|
def supports_window_functions?
|
|
83
130
|
false
|
|
84
131
|
end
|
|
132
|
+
|
|
133
|
+
# Whether the dataset supports WHERE TRUE (or WHERE 1 for databases that
|
|
134
|
+
# that use 1 for true).
|
|
135
|
+
def supports_where_true?
|
|
136
|
+
true
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
private
|
|
140
|
+
|
|
141
|
+
# Whether insert(nil) or insert({}) must be emulated by
|
|
142
|
+
# using at least one value, false by default.
|
|
143
|
+
def insert_supports_empty_values?
|
|
144
|
+
true
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Whether using an offset returns an extra row number column that should be
|
|
148
|
+
# eliminated, false by default.
|
|
149
|
+
def offset_returns_row_number_column?
|
|
150
|
+
false
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Whether the RETURNING clause is used for the given dataset.
|
|
154
|
+
# +type+ can be :insert, :update, or :delete.
|
|
155
|
+
def uses_returning?(type)
|
|
156
|
+
opts[:returning] && !@opts[:sql] && supports_returning?(type)
|
|
157
|
+
end
|
|
85
158
|
end
|
|
86
159
|
end
|
data/lib/sequel/dataset/graph.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module Sequel
|
|
2
2
|
class Dataset
|
|
3
3
|
# ---------------------
|
|
4
|
-
# :section: Methods related to dataset graphing
|
|
4
|
+
# :section: 5 - Methods related to dataset graphing
|
|
5
5
|
# Dataset graphing changes the dataset to yield hashes where keys are table
|
|
6
6
|
# name symbols and values are hashes representing the columns related to
|
|
7
7
|
# that table. All of these methods return modified copies of the receiver.
|
|
@@ -113,6 +113,8 @@ module Sequel
|
|
|
113
113
|
add_table = options[:select] == false ? false : true
|
|
114
114
|
# Whether to add the columns to the list of column aliases
|
|
115
115
|
add_columns = !ds.opts.include?(:graph_aliases)
|
|
116
|
+
# columns to select
|
|
117
|
+
select = (opts[:select] || []).dup
|
|
116
118
|
|
|
117
119
|
# Setup the initial graph data structure if it doesn't exist
|
|
118
120
|
unless graph = opts[:graph]
|
|
@@ -130,7 +132,6 @@ module Sequel
|
|
|
130
132
|
# aliased, but are not included if set_graph_aliases
|
|
131
133
|
# has been used.
|
|
132
134
|
if add_columns
|
|
133
|
-
select = opts[:select] = []
|
|
134
135
|
columns.each do |column|
|
|
135
136
|
column_aliases[column] = [master, column]
|
|
136
137
|
select.push(SQL::QualifiedIdentifier.new(master, column))
|
|
@@ -147,7 +148,6 @@ module Sequel
|
|
|
147
148
|
|
|
148
149
|
# Add the columns to the selection unless we are ignoring them
|
|
149
150
|
if add_table && add_columns
|
|
150
|
-
select = opts[:select]
|
|
151
151
|
column_aliases = graph[:column_aliases]
|
|
152
152
|
ca_num = graph[:column_alias_num]
|
|
153
153
|
# Which columns to add to the result set
|
|
@@ -165,15 +165,16 @@ module Sequel
|
|
|
165
165
|
column_alias = :"#{column_alias}_#{column_alias_num}"
|
|
166
166
|
ca_num[column_alias] += 1
|
|
167
167
|
end
|
|
168
|
-
[column_alias, SQL::QualifiedIdentifier.new(table_alias, column)
|
|
168
|
+
[column_alias, SQL::AliasedExpression.new(SQL::QualifiedIdentifier.new(table_alias, column), column_alias)]
|
|
169
169
|
else
|
|
170
|
-
|
|
170
|
+
ident = SQL::QualifiedIdentifier.new(table_alias, column)
|
|
171
|
+
[column, ident]
|
|
171
172
|
end
|
|
172
173
|
column_aliases[col_alias] = [table_alias, column]
|
|
173
174
|
select.push(identifier)
|
|
174
175
|
end
|
|
175
176
|
end
|
|
176
|
-
ds
|
|
177
|
+
ds.select(*select)
|
|
177
178
|
end
|
|
178
179
|
|
|
179
180
|
# This allows you to manually specify the graph aliases to use
|
|
@@ -225,7 +226,7 @@ module Sequel
|
|
|
225
226
|
column ||= col_alias
|
|
226
227
|
gas[col_alias] = [table, column]
|
|
227
228
|
identifier = value || SQL::QualifiedIdentifier.new(table, column)
|
|
228
|
-
identifier = SQL::AliasedExpression.new(identifier, col_alias) if value
|
|
229
|
+
identifier = SQL::AliasedExpression.new(identifier, col_alias) if value || column != col_alias
|
|
229
230
|
identifier
|
|
230
231
|
end
|
|
231
232
|
[identifiers, gas]
|