sequel 5.61.0 → 5.62.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|