sequel 5.61.0 → 5.62.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.
- checksums.yaml +4 -4
- data/CHANGELOG +32 -0
- data/README.rdoc +20 -19
- data/doc/advanced_associations.rdoc +13 -13
- data/doc/association_basics.rdoc +21 -15
- data/doc/cheat_sheet.rdoc +3 -3
- data/doc/model_hooks.rdoc +1 -1
- data/doc/object_model.rdoc +8 -8
- data/doc/opening_databases.rdoc +4 -4
- data/doc/postgresql.rdoc +8 -8
- data/doc/querying.rdoc +1 -1
- data/doc/release_notes/5.62.0.txt +132 -0
- data/doc/schema_modification.rdoc +1 -1
- data/doc/security.rdoc +9 -9
- data/doc/sql.rdoc +13 -13
- data/doc/testing.rdoc +13 -11
- data/doc/transactions.rdoc +6 -6
- data/doc/virtual_rows.rdoc +1 -1
- data/lib/sequel/adapters/postgres.rb +4 -0
- data/lib/sequel/adapters/shared/access.rb +9 -1
- data/lib/sequel/adapters/shared/mssql.rb +9 -5
- data/lib/sequel/adapters/shared/mysql.rb +7 -0
- data/lib/sequel/adapters/shared/oracle.rb +7 -0
- data/lib/sequel/adapters/shared/postgres.rb +275 -152
- data/lib/sequel/adapters/shared/sqlanywhere.rb +7 -0
- data/lib/sequel/adapters/shared/sqlite.rb +5 -0
- data/lib/sequel/connection_pool.rb +42 -28
- data/lib/sequel/database/connecting.rb +24 -0
- data/lib/sequel/database/misc.rb +8 -2
- data/lib/sequel/database/query.rb +37 -0
- data/lib/sequel/dataset/actions.rb +31 -11
- data/lib/sequel/dataset/features.rb +5 -0
- data/lib/sequel/dataset/misc.rb +1 -1
- data/lib/sequel/dataset/query.rb +9 -9
- data/lib/sequel/dataset/sql.rb +5 -1
- data/lib/sequel/extensions/_model_pg_row.rb +0 -12
- data/lib/sequel/extensions/_pretty_table.rb +1 -1
- data/lib/sequel/extensions/async_thread_pool.rb +11 -11
- data/lib/sequel/extensions/auto_literal_strings.rb +1 -1
- data/lib/sequel/extensions/constraint_validations.rb +1 -1
- data/lib/sequel/extensions/date_arithmetic.rb +1 -1
- data/lib/sequel/extensions/migration.rb +1 -1
- data/lib/sequel/extensions/named_timezones.rb +17 -5
- data/lib/sequel/extensions/pg_array.rb +22 -3
- data/lib/sequel/extensions/pg_auto_parameterize.rb +478 -0
- data/lib/sequel/extensions/pg_extended_date_support.rb +12 -0
- data/lib/sequel/extensions/pg_extended_integer_support.rb +116 -0
- data/lib/sequel/extensions/pg_hstore.rb +5 -0
- data/lib/sequel/extensions/pg_inet.rb +9 -10
- data/lib/sequel/extensions/pg_interval.rb +9 -10
- data/lib/sequel/extensions/pg_json.rb +10 -10
- data/lib/sequel/extensions/pg_multirange.rb +5 -10
- data/lib/sequel/extensions/pg_range.rb +5 -10
- data/lib/sequel/extensions/pg_row.rb +18 -13
- data/lib/sequel/model/associations.rb +7 -2
- data/lib/sequel/model/base.rb +6 -5
- data/lib/sequel/plugins/auto_validations.rb +53 -15
- data/lib/sequel/plugins/class_table_inheritance.rb +2 -2
- data/lib/sequel/plugins/composition.rb +2 -2
- data/lib/sequel/plugins/concurrent_eager_loading.rb +4 -4
- data/lib/sequel/plugins/dirty.rb +1 -1
- data/lib/sequel/plugins/finder.rb +3 -1
- data/lib/sequel/plugins/nested_attributes.rb +4 -4
- data/lib/sequel/plugins/pg_auto_constraint_validations.rb +1 -1
- data/lib/sequel/plugins/primary_key_lookup_check_values.rb +154 -0
- data/lib/sequel/plugins/sql_comments.rb +1 -1
- data/lib/sequel/plugins/validation_helpers.rb +20 -0
- data/lib/sequel/version.rb +1 -1
- metadata +10 -5
@@ -241,6 +241,30 @@ module Sequel
|
|
241
241
|
pool.servers
|
242
242
|
end
|
243
243
|
|
244
|
+
# Connect to the given server/shard. Handles database-generic post-connection
|
245
|
+
# setup not handled by #connect, using the :after_connect and :connect_sqls
|
246
|
+
# options.
|
247
|
+
def new_connection(server)
|
248
|
+
conn = connect(server)
|
249
|
+
opts = server_opts(server)
|
250
|
+
|
251
|
+
if ac = opts[:after_connect]
|
252
|
+
if ac.arity == 2
|
253
|
+
ac.call(conn, server)
|
254
|
+
else
|
255
|
+
ac.call(conn)
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
if cs = opts[:connect_sqls]
|
260
|
+
cs.each do |sql|
|
261
|
+
log_connection_execute(conn, sql)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
conn
|
266
|
+
end
|
267
|
+
|
244
268
|
# Returns true if the database is using a single-threaded connection pool.
|
245
269
|
def single_threaded?
|
246
270
|
@single_threaded
|
data/lib/sequel/database/misc.rb
CHANGED
@@ -100,10 +100,14 @@ module Sequel
|
|
100
100
|
# options hash.
|
101
101
|
#
|
102
102
|
# Accepts the following options:
|
103
|
+
# :after_connect :: A callable object called after each new connection is made, with the
|
104
|
+
# connection object (and server argument if the callable accepts 2 arguments),
|
105
|
+
# useful for customizations that you want to apply to all connections.
|
103
106
|
# :before_preconnect :: Callable that runs after extensions from :preconnect_extensions are loaded,
|
104
107
|
# but before any connections are created.
|
105
108
|
# :cache_schema :: Whether schema should be cached for this Database instance
|
106
109
|
# :check_string_typecast_bytesize :: Whether to check the bytesize of strings before typecasting.
|
110
|
+
# :connect_sqls :: An array of sql strings to execute on each new connection, after :after_connect runs.
|
107
111
|
# :default_string_column_size :: The default size of string columns, 255 by default.
|
108
112
|
# :extensions :: Extensions to load into this Database instance. Can be a symbol, array of symbols,
|
109
113
|
# or string with extensions separated by columns. These extensions are loaded after
|
@@ -126,9 +130,11 @@ module Sequel
|
|
126
130
|
# :single_threaded :: Whether to use a single-threaded connection pool.
|
127
131
|
# :sql_log_level :: Method to use to log SQL to a logger, :info by default.
|
128
132
|
#
|
133
|
+
# For sharded connection pools, :after_connect and :connect_sqls can be specified per-shard.
|
134
|
+
#
|
129
135
|
# All options given are also passed to the connection pool. Additional options respected by
|
130
|
-
# the connection pool are :
|
131
|
-
#
|
136
|
+
# the connection pool are :max_connections, :pool_timeout, :servers, and :servers_hash. See the
|
137
|
+
# connection pool documentation for details.
|
132
138
|
def initialize(opts = OPTS)
|
133
139
|
@opts ||= opts
|
134
140
|
@opts = connection_pool_default_options.merge(@opts)
|
@@ -175,6 +175,9 @@ module Sequel
|
|
175
175
|
if !c[:max_length] && c[:type] == :string && (max_length = column_schema_max_length(c[:db_type]))
|
176
176
|
c[:max_length] = max_length
|
177
177
|
end
|
178
|
+
if !c[:max_value] && !c[:min_value] && c[:type] == :integer && (min_max = column_schema_integer_min_max_values(c[:db_type]))
|
179
|
+
c[:min_value], c[:max_value] = min_max
|
180
|
+
end
|
178
181
|
end
|
179
182
|
schema_post_process(cols)
|
180
183
|
|
@@ -272,6 +275,40 @@ module Sequel
|
|
272
275
|
column_schema_default_to_ruby_value(default, type) rescue nil
|
273
276
|
end
|
274
277
|
|
278
|
+
INTEGER1_MIN_MAX = [-128, 127].freeze
|
279
|
+
INTEGER2_MIN_MAX = [-32768, 32767].freeze
|
280
|
+
INTEGER3_MIN_MAX = [-8388608, 8388607].freeze
|
281
|
+
INTEGER4_MIN_MAX = [-2147483648, 2147483647].freeze
|
282
|
+
INTEGER8_MIN_MAX = [-9223372036854775808, 9223372036854775807].freeze
|
283
|
+
UNSIGNED_INTEGER1_MIN_MAX = [0, 255].freeze
|
284
|
+
UNSIGNED_INTEGER2_MIN_MAX = [0, 65535].freeze
|
285
|
+
UNSIGNED_INTEGER3_MIN_MAX = [0, 16777215].freeze
|
286
|
+
UNSIGNED_INTEGER4_MIN_MAX = [0, 4294967295].freeze
|
287
|
+
UNSIGNED_INTEGER8_MIN_MAX = [0, 18446744073709551615].freeze
|
288
|
+
|
289
|
+
# Look at the db_type and guess the minimum and maximum integer values for
|
290
|
+
# the column.
|
291
|
+
def column_schema_integer_min_max_values(db_type)
|
292
|
+
unsigned = /unsigned/i =~ db_type
|
293
|
+
case db_type
|
294
|
+
when /big|int8/i
|
295
|
+
unsigned ? UNSIGNED_INTEGER8_MIN_MAX : INTEGER8_MIN_MAX
|
296
|
+
when /medium/i
|
297
|
+
unsigned ? UNSIGNED_INTEGER3_MIN_MAX : INTEGER3_MIN_MAX
|
298
|
+
when /small|int2/i
|
299
|
+
unsigned ? UNSIGNED_INTEGER2_MIN_MAX : INTEGER2_MIN_MAX
|
300
|
+
when /tiny/i
|
301
|
+
(unsigned || column_schema_tinyint_type_is_unsigned?) ? UNSIGNED_INTEGER1_MIN_MAX : INTEGER1_MIN_MAX
|
302
|
+
else
|
303
|
+
unsigned ? UNSIGNED_INTEGER4_MIN_MAX : INTEGER4_MIN_MAX
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
# Whether the tinyint type (if supported by the database) is unsigned by default.
|
308
|
+
def column_schema_tinyint_type_is_unsigned?
|
309
|
+
false
|
310
|
+
end
|
311
|
+
|
275
312
|
# Look at the db_type and guess the maximum length of the column.
|
276
313
|
# This assumes types such as varchar(255).
|
277
314
|
def column_schema_max_length(db_type)
|
@@ -313,14 +313,18 @@ module Sequel
|
|
313
313
|
|
314
314
|
# Inserts multiple records into the associated table. This method can be
|
315
315
|
# used to efficiently insert a large number of records into a table in a
|
316
|
-
# single query if the database supports it. Inserts
|
317
|
-
#
|
316
|
+
# single query if the database supports it. Inserts are automatically
|
317
|
+
# wrapped in a transaction if necessary.
|
318
318
|
#
|
319
319
|
# This method is called with a columns array and an array of value arrays:
|
320
320
|
#
|
321
321
|
# DB[:table].import([:x, :y], [[1, 2], [3, 4]])
|
322
322
|
# # INSERT INTO table (x, y) VALUES (1, 2)
|
323
|
-
# # INSERT INTO table (x, y) VALUES (3, 4)
|
323
|
+
# # INSERT INTO table (x, y) VALUES (3, 4)
|
324
|
+
#
|
325
|
+
# or, if the database supports it:
|
326
|
+
#
|
327
|
+
# # INSERT INTO table (x, y) VALUES (1, 2), (3, 4)
|
324
328
|
#
|
325
329
|
# This method also accepts a dataset instead of an array of value arrays:
|
326
330
|
#
|
@@ -328,9 +332,13 @@ module Sequel
|
|
328
332
|
# # INSERT INTO table (x, y) SELECT a, b FROM table2
|
329
333
|
#
|
330
334
|
# Options:
|
331
|
-
# :commit_every :: Open a new transaction for every given number of
|
332
|
-
# For example, if you provide a value of 50,
|
333
|
-
# after every 50 records.
|
335
|
+
# :commit_every :: Open a new transaction for every given number of
|
336
|
+
# records. For example, if you provide a value of 50,
|
337
|
+
# will commit after every 50 records. When a
|
338
|
+
# transaction is not required, this option controls
|
339
|
+
# the maximum number of values to insert with a single
|
340
|
+
# statement; it does not force the use of a
|
341
|
+
# transaction.
|
334
342
|
# :return :: When this is set to :primary_key, returns an array of
|
335
343
|
# autoincremented primary key values for the rows inserted.
|
336
344
|
# This does not have an effect if +values+ is a Dataset.
|
@@ -576,7 +584,7 @@ module Sequel
|
|
576
584
|
# # SELECT * FROM table ORDER BY id LIMIT 1000 OFFSET 1000
|
577
585
|
# # ...
|
578
586
|
#
|
579
|
-
# DB[:table].order(:id).paged_each(:
|
587
|
+
# DB[:table].order(:id).paged_each(rows_per_fetch: 100){|row| }
|
580
588
|
# # SELECT * FROM table ORDER BY id LIMIT 100
|
581
589
|
# # SELECT * FROM table ORDER BY id LIMIT 100 OFFSET 100
|
582
590
|
# # ...
|
@@ -1023,18 +1031,19 @@ module Sequel
|
|
1023
1031
|
|
1024
1032
|
# Internals of #import. If primary key values are requested, use
|
1025
1033
|
# separate insert commands for each row. Otherwise, call #multi_insert_sql
|
1026
|
-
# and execute each statement it gives separately.
|
1034
|
+
# and execute each statement it gives separately. A transaction is only used
|
1035
|
+
# if there are multiple statements to execute.
|
1027
1036
|
def _import(columns, values, opts)
|
1028
1037
|
trans_opts = Hash[opts]
|
1029
1038
|
trans_opts[:server] = @opts[:server]
|
1030
1039
|
if opts[:return] == :primary_key
|
1031
|
-
|
1040
|
+
_import_transaction(values, trans_opts){values.map{|v| insert(columns, v)}}
|
1032
1041
|
else
|
1033
1042
|
stmts = multi_insert_sql(columns, values)
|
1034
|
-
|
1043
|
+
_import_transaction(stmts, trans_opts){stmts.each{|st| execute_dui(st)}}
|
1035
1044
|
end
|
1036
1045
|
end
|
1037
|
-
|
1046
|
+
|
1038
1047
|
# Return an array of arrays of values given by the symbols in ret_cols.
|
1039
1048
|
def _select_map_multiple(ret_cols)
|
1040
1049
|
map{|r| r.values_at(*ret_cols)}
|
@@ -1073,6 +1082,17 @@ module Sequel
|
|
1073
1082
|
end
|
1074
1083
|
end
|
1075
1084
|
|
1085
|
+
# Use a transaction when yielding to the block if multiple values/statements
|
1086
|
+
# are provided. When only a single value or statement is provided, then yield
|
1087
|
+
# without using a transaction.
|
1088
|
+
def _import_transaction(values, trans_opts, &block)
|
1089
|
+
if values.length > 1
|
1090
|
+
@db.transaction(trans_opts, &block)
|
1091
|
+
else
|
1092
|
+
yield
|
1093
|
+
end
|
1094
|
+
end
|
1095
|
+
|
1076
1096
|
# Internals of +select_hash+ and +select_hash_groups+
|
1077
1097
|
def _select_hash(meth, key_column, value_column, opts=OPTS)
|
1078
1098
|
select(*(key_column.is_a?(Array) ? key_column : [key_column]) + (value_column.is_a?(Array) ? value_column : [value_column])).
|
@@ -152,6 +152,11 @@ module Sequel
|
|
152
152
|
supports_distinct_on?
|
153
153
|
end
|
154
154
|
|
155
|
+
# Whether placeholder literalizers are supported, true by default.
|
156
|
+
def supports_placeholder_literalizer?
|
157
|
+
true
|
158
|
+
end
|
159
|
+
|
155
160
|
# Whether the dataset supports pattern matching by regular expressions, false by default.
|
156
161
|
def supports_regexp?
|
157
162
|
false
|
data/lib/sequel/dataset/misc.rb
CHANGED
data/lib/sequel/dataset/query.rb
CHANGED
@@ -65,7 +65,7 @@ module Sequel
|
|
65
65
|
Sequel.synchronize{EXTENSIONS[ext] = block}
|
66
66
|
end
|
67
67
|
|
68
|
-
# On Ruby 2.4+, use clone(:
|
68
|
+
# On Ruby 2.4+, use clone(freeze: false) to create clones, because
|
69
69
|
# we use true freezing in that case, and we need to modify the opts
|
70
70
|
# in the frozen copy.
|
71
71
|
#
|
@@ -116,7 +116,7 @@ module Sequel
|
|
116
116
|
# DB[:items].order(:id).distinct(:id) # SQL: SELECT DISTINCT ON (id) * FROM items ORDER BY id
|
117
117
|
# DB[:items].order(:id).distinct{func(:id)} # SQL: SELECT DISTINCT ON (func(id)) * FROM items ORDER BY id
|
118
118
|
#
|
119
|
-
# There is support for
|
119
|
+
# There is support for emulating the DISTINCT ON support in MySQL, but it
|
120
120
|
# does not support the ORDER of the dataset, and also doesn't work in many
|
121
121
|
# cases if the ONLY_FULL_GROUP_BY sql_mode is used, which is the default on
|
122
122
|
# MySQL 5.7.5+.
|
@@ -787,7 +787,7 @@ module Sequel
|
|
787
787
|
# DB[:items].order(Sequel.lit('a + b')) # SELECT * FROM items ORDER BY a + b
|
788
788
|
# DB[:items].order(Sequel[:a] + :b) # SELECT * FROM items ORDER BY (a + b)
|
789
789
|
# DB[:items].order(Sequel.desc(:name)) # SELECT * FROM items ORDER BY name DESC
|
790
|
-
# DB[:items].order(Sequel.asc(:name, :
|
790
|
+
# DB[:items].order(Sequel.asc(:name, nulls: :last)) # SELECT * FROM items ORDER BY name ASC NULLS LAST
|
791
791
|
# DB[:items].order{sum(name).desc} # SELECT * FROM items ORDER BY sum(name) DESC
|
792
792
|
# DB[:items].order(nil) # SELECT * FROM items
|
793
793
|
def order(*columns, &block)
|
@@ -857,13 +857,13 @@ module Sequel
|
|
857
857
|
# DB[:items].returning(nil) # RETURNING NULL
|
858
858
|
# DB[:items].returning(:id, :name) # RETURNING id, name
|
859
859
|
#
|
860
|
-
# DB[:items].returning.insert(:
|
860
|
+
# DB[:items].returning.insert(a: 1) do |hash|
|
861
861
|
# # hash for each row inserted, with values for all columns
|
862
862
|
# end
|
863
|
-
# DB[:items].returning.update(:
|
863
|
+
# DB[:items].returning.update(a: 1) do |hash|
|
864
864
|
# # hash for each row updated, with values for all columns
|
865
865
|
# end
|
866
|
-
# DB[:items].returning.delete(:
|
866
|
+
# DB[:items].returning.delete(a: 1) do |hash|
|
867
867
|
# # hash for each row deleted, with values for all columns
|
868
868
|
# end
|
869
869
|
def returning(*values)
|
@@ -1102,7 +1102,7 @@ module Sequel
|
|
1102
1102
|
# referenced in window functions. See Sequel::SQL::Window for a list of
|
1103
1103
|
# options that can be passed in. Example:
|
1104
1104
|
#
|
1105
|
-
# DB[:items].window(:w, :
|
1105
|
+
# DB[:items].window(:w, partition: :c1, order: :c2)
|
1106
1106
|
# # SELECT * FROM items WINDOW w AS (PARTITION BY c1 ORDER BY c2)
|
1107
1107
|
def window(name, opts)
|
1108
1108
|
clone(:window=>((@opts[:window]||EMPTY_ARRAY) + [[name, SQL::Window.new(opts)].freeze]).freeze)
|
@@ -1163,7 +1163,7 @@ module Sequel
|
|
1163
1163
|
# DB[:t].with_recursive(:t,
|
1164
1164
|
# DB[:i1].select(:id, :parent_id).where(parent_id: nil),
|
1165
1165
|
# DB[:i1].join(:t, id: :parent_id).select(Sequel[:i1][:id], Sequel[:i1][:parent_id]),
|
1166
|
-
# :
|
1166
|
+
# args: [:id, :parent_id])
|
1167
1167
|
#
|
1168
1168
|
# # WITH RECURSIVE t(id, parent_id) AS (
|
1169
1169
|
# # SELECT id, parent_id FROM i1 WHERE (parent_id IS NULL)
|
@@ -1241,7 +1241,7 @@ module Sequel
|
|
1241
1241
|
#
|
1242
1242
|
# You can also provide a method name and arguments to call to get the SQL:
|
1243
1243
|
#
|
1244
|
-
# DB[:items].with_sql(:insert_sql, :
|
1244
|
+
# DB[:items].with_sql(:insert_sql, b: 1) # INSERT INTO items (b) VALUES (1)
|
1245
1245
|
#
|
1246
1246
|
# Note that datasets that specify custom SQL using this method will generally
|
1247
1247
|
# ignore future dataset methods that modify the SQL used, as specifying custom SQL
|
data/lib/sequel/dataset/sql.rb
CHANGED
@@ -1725,7 +1725,7 @@ module Sequel
|
|
1725
1725
|
# Append literalization of the subselect to SQL string.
|
1726
1726
|
def subselect_sql_append(sql, ds)
|
1727
1727
|
sds = subselect_sql_dataset(sql, ds)
|
1728
|
-
sds
|
1728
|
+
subselect_sql_append_sql(sql, sds)
|
1729
1729
|
unless sds.send(:cache_sql?)
|
1730
1730
|
# If subquery dataset does not allow caching SQL,
|
1731
1731
|
# then this dataset should not allow caching SQL.
|
@@ -1737,6 +1737,10 @@ module Sequel
|
|
1737
1737
|
ds.clone(:append_sql=>sql)
|
1738
1738
|
end
|
1739
1739
|
|
1740
|
+
def subselect_sql_append_sql(sql, ds)
|
1741
|
+
ds.sql
|
1742
|
+
end
|
1743
|
+
|
1740
1744
|
# The number of decimal digits of precision to use in timestamps.
|
1741
1745
|
def timestamp_precision
|
1742
1746
|
supports_timestamp_usecs? ? 6 : 0
|
@@ -23,18 +23,6 @@ module Sequel
|
|
23
23
|
super
|
24
24
|
end
|
25
25
|
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
# Handle Sequel::Model instances in bound variable arrays.
|
30
|
-
def bound_variable_array(arg)
|
31
|
-
case arg
|
32
|
-
when Sequel::Model
|
33
|
-
"\"(#{arg.values.values_at(*arg.columns).map{|v| bound_variable_array(v)}.join(',').gsub(/("|\\)/, '\\\\\1')})\""
|
34
|
-
else
|
35
|
-
super
|
36
|
-
end
|
37
|
-
end
|
38
26
|
end
|
39
27
|
end
|
40
28
|
end
|
@@ -5,9 +5,9 @@
|
|
5
5
|
# code
|
6
6
|
#
|
7
7
|
# DB.extension :async_thread_pool
|
8
|
-
# foos = DB[:foos].async.where{:
|
8
|
+
# foos = DB[:foos].async.where{name: 'A'..'M'}.all
|
9
9
|
# bar_names = DB[:bar].async.select_order_map(:name)
|
10
|
-
# baz_1 = DB[:bazes].async.first(:
|
10
|
+
# baz_1 = DB[:bazes].async.first(id: 1)
|
11
11
|
#
|
12
12
|
# All 3 queries will be run in separate threads. +foos+, +bar_names+
|
13
13
|
# and +baz_1+ will be proxy objects. Calling a method on the proxy
|
@@ -15,9 +15,9 @@
|
|
15
15
|
# of calling that method on the result of the query method. For example,
|
16
16
|
# if you run:
|
17
17
|
#
|
18
|
-
# foos = DB[:foos].async.where{:
|
18
|
+
# foos = DB[:foos].async.where{name: 'A'..'M'}.all
|
19
19
|
# bar_names = DB[:bars].async.select_order_map(:name)
|
20
|
-
# baz_1 = DB[:bazes].async.first(:
|
20
|
+
# baz_1 = DB[:bazes].async.first(id: 1)
|
21
21
|
# sleep(1)
|
22
22
|
# foos.size
|
23
23
|
# bar_names.first
|
@@ -26,9 +26,9 @@
|
|
26
26
|
# These three queries will generally be run concurrently in separate
|
27
27
|
# threads. If you instead run:
|
28
28
|
#
|
29
|
-
# DB[:foos].async.where{:
|
29
|
+
# DB[:foos].async.where{name: 'A'..'M'}.all.size
|
30
30
|
# DB[:bars].async.select_order_map(:name).first
|
31
|
-
# DB[:bazes].async.first(:
|
31
|
+
# DB[:bazes].async.first(id: 1).name
|
32
32
|
#
|
33
33
|
# Then will run each query sequentially, since you need the result of
|
34
34
|
# one query before running the next query. The queries will still be
|
@@ -37,11 +37,11 @@
|
|
37
37
|
# What is run in the separate thread is the entire method call that
|
38
38
|
# returns results. So with the original example:
|
39
39
|
#
|
40
|
-
# foos = DB[:foos].async.where{:
|
40
|
+
# foos = DB[:foos].async.where{name: 'A'..'M'}.all
|
41
41
|
# bar_names = DB[:bars].async.select_order_map(:name)
|
42
|
-
# baz_1 = DB[:bazes].async.first(:
|
42
|
+
# baz_1 = DB[:bazes].async.first(id: 1)
|
43
43
|
#
|
44
|
-
# The +all+, <tt>select_order_map(:name)</tt>, and <tt>first(:
|
44
|
+
# The +all+, <tt>select_order_map(:name)</tt>, and <tt>first(id: 1)</tt>
|
45
45
|
# calls are run in separate threads. If a block is passed to a method
|
46
46
|
# such as +all+ or +each+, the block is also run in that thread. If you
|
47
47
|
# have code such as:
|
@@ -156,10 +156,10 @@
|
|
156
156
|
# so that the query will run in the current thread instead of waiting
|
157
157
|
# for an async thread to become available. With the following code:
|
158
158
|
#
|
159
|
-
# foos = DB[:foos].async.where{:
|
159
|
+
# foos = DB[:foos].async.where{name: 'A'..'M'}.all
|
160
160
|
# bar_names = DB[:bar].async.select_order_map(:name)
|
161
161
|
# if foos.length > 4
|
162
|
-
# baz_1 = DB[:bazes].async.first(:
|
162
|
+
# baz_1 = DB[:bazes].async.first(id: 1)
|
163
163
|
# end
|
164
164
|
#
|
165
165
|
# Whether you need the +baz_1+ variable depends on the value of foos.
|
@@ -22,7 +22,7 @@
|
|
22
22
|
#
|
23
23
|
# Named placeholders can also be used with a hash:
|
24
24
|
#
|
25
|
-
# ds.where("name > :a", :
|
25
|
+
# ds.where("name > :a", a: "A")
|
26
26
|
# # SELECT * FROM table WHERE (name > 'A')
|
27
27
|
#
|
28
28
|
# This extension also allows the use of a plain string passed to Dataset#update:
|
@@ -126,7 +126,7 @@
|
|
126
126
|
# be emulated by dropping the table and recreating it with the constraints.
|
127
127
|
# If you want to use this plugin on SQLite with an alter_table block,
|
128
128
|
# you should drop all constraint validation metadata using
|
129
|
-
# <tt>drop_constraint_validations_for(:
|
129
|
+
# <tt>drop_constraint_validations_for(table: 'table')</tt>, and then
|
130
130
|
# readd all constraints you want to use inside the alter table block,
|
131
131
|
# making no other changes inside the alter_table block.
|
132
132
|
#
|
@@ -25,7 +25,7 @@
|
|
25
25
|
# By default, values are casted to the generic timestamp type for the
|
26
26
|
# database. You can override the cast type using the :cast option:
|
27
27
|
#
|
28
|
-
# add = Sequel.date_add(:date_column, {years: 1, months: 2, days: 3}, :
|
28
|
+
# add = Sequel.date_add(:date_column, {years: 1, months: 2, days: 3}, cast: :timestamptz)
|
29
29
|
#
|
30
30
|
# These expressions can be used in your datasets, or anywhere else that
|
31
31
|
# Sequel expressions are allowed:
|
@@ -377,7 +377,7 @@ module Sequel
|
|
377
377
|
# Raise a NotCurrentError unless the migrator is current, takes the same
|
378
378
|
# arguments as #run.
|
379
379
|
def self.check_current(*args)
|
380
|
-
raise(NotCurrentError, '
|
380
|
+
raise(NotCurrentError, 'current migration version does not match latest available version') unless is_current?(*args)
|
381
381
|
end
|
382
382
|
|
383
383
|
# Return whether the migrator is current (i.e. it does not need to make
|
@@ -76,33 +76,45 @@ module Sequel
|
|
76
76
|
raise unless disamb = tzinfo_disambiguator_for(v)
|
77
77
|
period = input_timezone.period_for_local(v, &disamb)
|
78
78
|
offset = period.utc_total_offset
|
79
|
-
|
79
|
+
# :nocov:
|
80
|
+
if defined?(JRUBY_VERSION)
|
81
|
+
Time.at(v.to_i - offset, :in => input_timezone) + v.nsec/1000000000.0
|
82
|
+
# :nocov:
|
83
|
+
else
|
84
|
+
Time.at(v.to_i - offset, v.nsec, :nsec, :in => input_timezone)
|
85
|
+
end
|
80
86
|
end
|
81
87
|
|
82
88
|
# Convert the given input Time to the given output timezone,
|
83
89
|
# which should be a TZInfo::Timezone instance.
|
84
90
|
def convert_output_time_other(v, output_timezone)
|
85
|
-
|
91
|
+
# :nocov:
|
92
|
+
if defined?(JRUBY_VERSION)
|
93
|
+
Time.at(v.to_i, :in => output_timezone) + v.nsec/1000000000.0
|
94
|
+
# :nocov:
|
95
|
+
else
|
96
|
+
Time.at(v.to_i, v.nsec, :nsec, :in => output_timezone)
|
97
|
+
end
|
86
98
|
end
|
87
99
|
# :nodoc:
|
88
100
|
# :nocov:
|
89
101
|
else
|
90
102
|
def convert_input_time_other(v, input_timezone)
|
91
103
|
local_offset = input_timezone.period_for_local(v, &tzinfo_disambiguator_for(v)).utc_total_offset
|
92
|
-
Time.new(1970, 1, 1, 0, 0, 0, local_offset) + v.to_i
|
104
|
+
Time.new(1970, 1, 1, 0, 0, 0, local_offset) + v.to_i + v.nsec/1000000000.0
|
93
105
|
end
|
94
106
|
|
95
107
|
if defined?(TZInfo::VERSION) && TZInfo::VERSION > '2'
|
96
108
|
def convert_output_time_other(v, output_timezone)
|
97
109
|
v = output_timezone.utc_to_local(v.getutc)
|
98
110
|
local_offset = output_timezone.period_for_local(v, &tzinfo_disambiguator_for(v)).utc_total_offset
|
99
|
-
Time.new(1970, 1, 1, 0, 0, 0, local_offset) + v.to_i + local_offset
|
111
|
+
Time.new(1970, 1, 1, 0, 0, 0, local_offset) + v.to_i + v.nsec/1000000000.0 + local_offset
|
100
112
|
end
|
101
113
|
else
|
102
114
|
def convert_output_time_other(v, output_timezone)
|
103
115
|
v = output_timezone.utc_to_local(v.getutc)
|
104
116
|
local_offset = output_timezone.period_for_local(v, &tzinfo_disambiguator_for(v)).utc_total_offset
|
105
|
-
Time.new(1970, 1, 1, 0, 0, 0, local_offset) + v.to_i
|
117
|
+
Time.new(1970, 1, 1, 0, 0, 0, local_offset) + v.to_i + v.nsec/1000000000.0
|
106
118
|
end
|
107
119
|
end
|
108
120
|
# :nodoc:
|
@@ -228,16 +228,27 @@ module Sequel
|
|
228
228
|
when Array
|
229
229
|
"{#{a.map{|i| bound_variable_array(i)}.join(',')}}"
|
230
230
|
when Sequel::SQL::Blob
|
231
|
-
|
231
|
+
bound_variable_array_string(literal(a)[BLOB_RANGE].gsub("''", "'"))
|
232
232
|
when Sequel::LiteralString
|
233
233
|
a
|
234
234
|
when String
|
235
|
-
|
235
|
+
bound_variable_array_string(a)
|
236
236
|
else
|
237
|
-
|
237
|
+
if (s = bound_variable_arg(a, nil)).is_a?(String)
|
238
|
+
bound_variable_array_string(s)
|
239
|
+
else
|
240
|
+
literal(a)
|
241
|
+
end
|
238
242
|
end
|
239
243
|
end
|
240
244
|
|
245
|
+
# Escape strings used as array members in bound variables. Most complex
|
246
|
+
# will create a regular string with bound_variable_arg, and then use this
|
247
|
+
# escaping to format it as an array member.
|
248
|
+
def bound_variable_array_string(s)
|
249
|
+
"\"#{s.gsub(/("|\\)/, '\\\\\1')}\""
|
250
|
+
end
|
251
|
+
|
241
252
|
# Look into both the current database's array schema types and the global
|
242
253
|
# array schema types to get the type symbol for the given database type
|
243
254
|
# string.
|
@@ -457,6 +468,14 @@ module Sequel
|
|
457
468
|
end
|
458
469
|
end
|
459
470
|
|
471
|
+
# Allow automatic parameterization of the receiver if all elements can be
|
472
|
+
# can be automatically parameterized.
|
473
|
+
def sequel_auto_param_type(ds)
|
474
|
+
if array_type && all?{|x| nil == x || ds.send(:auto_param_type, x)}
|
475
|
+
"::#{array_type}[]"
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
460
479
|
private
|
461
480
|
|
462
481
|
# Recursive method that handles multi-dimensional
|