sequel 5.33.0 → 5.34.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +18 -0
- data/doc/release_notes/5.34.0.txt +40 -0
- data/lib/sequel/connection_pool/sharded_single.rb +4 -1
- data/lib/sequel/connection_pool/sharded_threaded.rb +10 -10
- data/lib/sequel/connection_pool/single.rb +1 -1
- data/lib/sequel/connection_pool/threaded.rb +1 -1
- data/lib/sequel/database/connecting.rb +1 -1
- data/lib/sequel/database/misc.rb +16 -10
- data/lib/sequel/database/query.rb +2 -0
- data/lib/sequel/database/schema_generator.rb +0 -1
- data/lib/sequel/database/schema_methods.rb +15 -16
- data/lib/sequel/database/transactions.rb +7 -4
- data/lib/sequel/dataset/placeholder_literalizer.rb +3 -7
- data/lib/sequel/dataset/query.rb +4 -3
- data/lib/sequel/deprecated.rb +2 -0
- data/lib/sequel/exceptions.rb +2 -0
- data/lib/sequel/model.rb +2 -0
- data/lib/sequel/model/associations.rb +12 -13
- data/lib/sequel/model/base.rb +5 -3
- data/lib/sequel/model/plugins.rb +2 -3
- data/lib/sequel/plugins/association_pks.rb +57 -16
- data/lib/sequel/plugins/rcte_tree.rb +2 -2
- data/lib/sequel/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6c87a14904ac28bee61ed778628cc68f7c7318d6cb2f7c1f8aeeaab0ac2e7f22
|
4
|
+
data.tar.gz: 3fdbda6fce44c6a0d168cc7fe0fe3a2e269ef668397ec1f4289120231006e51f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 012717171d1b9aded574e16ba2670c95ccb87ef365b68bcee18b1e6730e5ce04425eaeca3be563c5ba416d2691ed83526bcb5254275b6484526856d0cadf14d1
|
7
|
+
data.tar.gz: 02f430fa24d8b61905192a8f387421b28d877978fcd5ce05fdb5f0768b93a6f7771c02ed445c937863b30f24121ad9fae73c8303293bc7475621f077792b3f78
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
=== 5.34.0 (2020-07-01)
|
2
|
+
|
3
|
+
* Make eager_graph work correctly if called with no associations (jeremyevans)
|
4
|
+
|
5
|
+
* Make :ruby eager limit strategy handle cases where there is no limit or offset (jeremyevans)
|
6
|
+
|
7
|
+
* Do not keep a reference to a Sequel::Database instance that raises an exception during initialization (jeremyevans)
|
8
|
+
|
9
|
+
* Make Database#pool.all_connections not yield for a single connection pool in disconnected state (jeremyevans)
|
10
|
+
|
11
|
+
* Raise an exception if trying to disconnect a server that doesn't exist in the sharded connection pools (jeremyevans)
|
12
|
+
|
13
|
+
* Support :refresh option when calling *_pks getter method in the association_pks plugin (jeremyevans)
|
14
|
+
|
15
|
+
* Support caching of repeated calls to *_pks getter method in the association_pks plugin using :cache_pks association option (jeremyevans)
|
16
|
+
|
17
|
+
* Add *_pks_dataset methods for one_to_many and many_to_many associations when using the association_pks plugin (jeremyevans)
|
18
|
+
|
1
19
|
=== 5.33.0 (2020-06-01)
|
2
20
|
|
3
21
|
* Support custom join types on a per-association basis when using eager_graph/association_join (jeremyevans)
|
@@ -0,0 +1,40 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* The association_pks plugin now creates *_pks_dataset methods for
|
4
|
+
each association. These are similar to the existing *_pks getter
|
5
|
+
methods, but they return a dataset of the keys instead of the keys
|
6
|
+
themselves.
|
7
|
+
|
8
|
+
* The association_pks plugin now supports a :cache_pks association
|
9
|
+
option, which will cache calls to the *_pks getter method. The
|
10
|
+
default behavior remains that the *_pks getter method only returns
|
11
|
+
cached values if the *_pks= setter method has been used to set the
|
12
|
+
values.
|
13
|
+
|
14
|
+
* The *_pks getter methods supported by the association_pks plugin
|
15
|
+
now support a :refresh option to ignore any cached values, similar
|
16
|
+
to how the association getter methods work.
|
17
|
+
|
18
|
+
= Other Improvements
|
19
|
+
|
20
|
+
* If trying to disconnect a server that doesn't exist when using a
|
21
|
+
sharded connection pool, a Sequel::Error is now raised. Previously,
|
22
|
+
the sharded threaded pool raised a NoMethodError and the sharded
|
23
|
+
single connection pool did not raise an error.
|
24
|
+
|
25
|
+
* If using the :savepoint option when savepoints are not supported,
|
26
|
+
a Sequel::InvalidOperation exception is now raised, instead of a
|
27
|
+
NoMethodError.
|
28
|
+
|
29
|
+
* Calling Dataset#eager_graph with no arguments now returns the
|
30
|
+
dataset.
|
31
|
+
|
32
|
+
* If not connected to the database, the single connection pool will
|
33
|
+
not yield any connections to Database#pool.all_connections.
|
34
|
+
|
35
|
+
* Forcing a :ruby eager limit strategy for an association without a
|
36
|
+
limit or offset now works correctly.
|
37
|
+
|
38
|
+
* Multiple unnecessary conditionals have been removed.
|
39
|
+
|
40
|
+
* Sequel core and model code now have 100% branch coverage.
|
@@ -41,7 +41,10 @@ class Sequel::ShardedSingleConnectionPool < Sequel::ConnectionPool
|
|
41
41
|
# :server :: Should be a symbol specifing the server to disconnect from,
|
42
42
|
# or an array of symbols to specify multiple servers.
|
43
43
|
def disconnect(opts=OPTS)
|
44
|
-
(opts[:server] ? Array(opts[:server]) : servers).each
|
44
|
+
(opts[:server] ? Array(opts[:server]) : servers).each do |s|
|
45
|
+
raise Sequel::Error, "invalid server: #{s}" unless @servers.has_key?(s)
|
46
|
+
disconnect_server(s)
|
47
|
+
end
|
45
48
|
end
|
46
49
|
|
47
50
|
def freeze
|
@@ -95,9 +95,7 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
|
|
95
95
|
# or an array of symbols to specify multiple servers.
|
96
96
|
def disconnect(opts=OPTS)
|
97
97
|
(opts[:server] ? Array(opts[:server]) : sync{@servers.keys}).each do |s|
|
98
|
-
|
99
|
-
disconnect_connections(conns)
|
100
|
-
end
|
98
|
+
disconnect_connections(sync{disconnect_server_connections(s)})
|
101
99
|
end
|
102
100
|
end
|
103
101
|
|
@@ -203,9 +201,9 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
|
|
203
201
|
|
204
202
|
until conn = assign_connection(thread, server)
|
205
203
|
elapsed = Sequel.elapsed_seconds_since(timer)
|
204
|
+
# :nocov:
|
206
205
|
raise_pool_timeout(elapsed, server) if elapsed > timeout
|
207
206
|
|
208
|
-
# :nocov:
|
209
207
|
# It's difficult to get to this point, it can only happen if there is a race condition
|
210
208
|
# where a connection cannot be acquired even after the thread is signalled by the condition variable
|
211
209
|
sync do
|
@@ -278,13 +276,15 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
|
|
278
276
|
# Mark any allocated connections to be removed when they are checked back in. The calling
|
279
277
|
# code should already have the mutex before calling this.
|
280
278
|
def disconnect_server_connections(server)
|
281
|
-
|
279
|
+
remove_conns = allocated(server)
|
280
|
+
dis_conns = available_connections(server)
|
281
|
+
raise Sequel::Error, "invalid server: #{server}" unless remove_conns && dis_conns
|
282
282
|
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
283
|
+
@connections_to_remove.concat(remove_conns.values)
|
284
|
+
|
285
|
+
conns = dis_conns.dup
|
286
|
+
dis_conns.clear
|
287
|
+
@waiters[server].signal
|
288
288
|
conns
|
289
289
|
end
|
290
290
|
|
@@ -11,7 +11,7 @@ class Sequel::SingleConnectionPool < Sequel::ConnectionPool
|
|
11
11
|
|
12
12
|
# Yield the connection if one has been made.
|
13
13
|
def all_connections
|
14
|
-
yield @conn.first
|
14
|
+
yield @conn.first unless @conn.empty?
|
15
15
|
end
|
16
16
|
|
17
17
|
# Disconnect the connection from the database.
|
@@ -152,9 +152,9 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
|
|
152
152
|
|
153
153
|
until conn = assign_connection(thread)
|
154
154
|
elapsed = Sequel.elapsed_seconds_since(timer)
|
155
|
+
# :nocov:
|
155
156
|
raise_pool_timeout(elapsed) if elapsed > timeout
|
156
157
|
|
157
|
-
# :nocov:
|
158
158
|
# It's difficult to get to this point, it can only happen if there is a race condition
|
159
159
|
# where a connection cannot be acquired even after the thread is signalled by the condition variable
|
160
160
|
sync do
|
@@ -36,7 +36,7 @@ module Sequel
|
|
36
36
|
c = adapter_class(scheme)
|
37
37
|
uri_options = c.send(:uri_to_options, uri)
|
38
38
|
uri.query.split('&').map{|s| s.split('=')}.each{|k,v| uri_options[k.to_sym] = v if k && !k.empty?} unless uri.query.to_s.strip.empty?
|
39
|
-
uri_options.to_a.each{|k,v| uri_options[k] =
|
39
|
+
uri_options.to_a.each{|k,v| uri_options[k] = URI::DEFAULT_PARSER.unescape(v) if v.is_a?(String)}
|
40
40
|
opts = uri_options.merge(opts).merge!(:orig_opts=>opts.dup, :uri=>conn_string, :adapter=>scheme)
|
41
41
|
end
|
42
42
|
when Hash
|
data/lib/sequel/database/misc.rb
CHANGED
@@ -153,19 +153,23 @@ module Sequel
|
|
153
153
|
reset_default_dataset
|
154
154
|
adapter_initialize
|
155
155
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
156
|
+
keep_reference = typecast_value_boolean(@opts[:keep_reference]) != false
|
157
|
+
begin
|
158
|
+
Sequel.synchronize{::Sequel::DATABASES.push(self)} if keep_reference
|
159
|
+
Sequel::Database.run_after_initialize(self)
|
160
160
|
|
161
|
-
|
161
|
+
initialize_load_extensions(:preconnect_extensions)
|
162
162
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
163
|
+
if typecast_value_boolean(@opts[:preconnect]) && @pool.respond_to?(:preconnect, true)
|
164
|
+
concurrent = typecast_value_string(@opts[:preconnect]) == "concurrently"
|
165
|
+
@pool.send(:preconnect, concurrent)
|
166
|
+
end
|
167
167
|
|
168
|
-
|
168
|
+
initialize_load_extensions(:extensions)
|
169
|
+
rescue
|
170
|
+
Sequel.synchronize{::Sequel::DATABASES.delete(self)} if keep_reference
|
171
|
+
raise
|
172
|
+
end
|
169
173
|
end
|
170
174
|
|
171
175
|
# Freeze internal data structures for the Database instance.
|
@@ -185,7 +189,9 @@ module Sequel
|
|
185
189
|
|
186
190
|
# Disallow dup/clone for Database instances
|
187
191
|
undef_method :dup, :clone, :initialize_copy
|
192
|
+
# :nocov:
|
188
193
|
if RUBY_VERSION >= '1.9.3'
|
194
|
+
# :nocov:
|
189
195
|
undef_method :initialize_clone, :initialize_dup
|
190
196
|
end
|
191
197
|
|
@@ -38,7 +38,6 @@ module Sequel
|
|
38
38
|
@constraints = []
|
39
39
|
@primary_key = nil
|
40
40
|
instance_exec(&block) if block
|
41
|
-
@columns.unshift(@primary_key) if @primary_key && !has_column?(primary_key_name)
|
42
41
|
end
|
43
42
|
|
44
43
|
# Use custom Bignum method to use :Bignum instead of Bignum class, to work
|
@@ -494,7 +494,9 @@ module Sequel
|
|
494
494
|
when :drop_index
|
495
495
|
drop_index_sql(table, op)
|
496
496
|
else
|
497
|
-
|
497
|
+
if sql = alter_table_op_sql(table, op)
|
498
|
+
"ALTER TABLE #{quote_schema_table(table)} #{sql}"
|
499
|
+
end
|
498
500
|
end
|
499
501
|
end
|
500
502
|
|
@@ -811,23 +813,20 @@ module Sequel
|
|
811
813
|
# Proxy the filter_expr call to the dataset, used for creating constraints.
|
812
814
|
# Support passing Proc arguments as blocks, as well as treating plain strings
|
813
815
|
# as literal strings, so that previous migrations that used this API do not break.
|
814
|
-
def filter_expr(
|
815
|
-
if
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
elsif arg.length > 1
|
826
|
-
args = [Sequel.&(*arg)]
|
827
|
-
end
|
816
|
+
def filter_expr(arg=nil, &block)
|
817
|
+
if arg.is_a?(Proc) && !block
|
818
|
+
block = arg
|
819
|
+
arg = nil
|
820
|
+
elsif arg.is_a?(String)
|
821
|
+
arg = Sequel.lit(arg)
|
822
|
+
elsif arg.is_a?(Array)
|
823
|
+
if arg.first.is_a?(String)
|
824
|
+
arg = Sequel.lit(*arg)
|
825
|
+
elsif arg.length > 1
|
826
|
+
arg = Sequel.&(*arg)
|
828
827
|
end
|
829
828
|
end
|
830
|
-
schema_utility_dataset.literal(schema_utility_dataset.send(:filter_expr,
|
829
|
+
schema_utility_dataset.literal(schema_utility_dataset.send(:filter_expr, arg, &block))
|
831
830
|
end
|
832
831
|
|
833
832
|
# SQL statement for creating an index for the table with the given name
|
@@ -205,6 +205,10 @@ module Sequel
|
|
205
205
|
end
|
206
206
|
end
|
207
207
|
|
208
|
+
if opts[:savepoint] && !supports_savepoints?
|
209
|
+
raise Sequel::InvalidOperation, "savepoints not supported on #{database_type}"
|
210
|
+
end
|
211
|
+
|
208
212
|
if already_in_transaction?(conn, opts)
|
209
213
|
if opts[:rollback] == :always && !opts.has_key?(:savepoint)
|
210
214
|
if supports_savepoints?
|
@@ -418,11 +422,10 @@ module Sequel
|
|
418
422
|
end
|
419
423
|
|
420
424
|
# Retrieve the savepoint hooks that should be run for the given
|
421
|
-
# connection and commit status.
|
425
|
+
# connection and commit status. This expacts that you are
|
426
|
+
# already inside a savepoint when calling.
|
422
427
|
def savepoint_hooks(conn, committed)
|
423
|
-
|
424
|
-
_trans(conn)[:savepoints].last[committed ? :after_commit : :after_rollback]
|
425
|
-
end
|
428
|
+
_trans(conn)[:savepoints].last[committed ? :after_commit : :after_rollback]
|
426
429
|
end
|
427
430
|
|
428
431
|
# Retrieve the transaction hooks that should be run for the given
|
@@ -114,10 +114,8 @@ module Sequel
|
|
114
114
|
prepared_sql << sql
|
115
115
|
prepared_sql << "$#{prepared_args[i]}"
|
116
116
|
end
|
117
|
-
|
118
|
-
|
119
|
-
prepared_sql << final_sql
|
120
|
-
end
|
117
|
+
frags << final_sql
|
118
|
+
prepared_sql << final_sql
|
121
119
|
|
122
120
|
[prepared_sql, frags]
|
123
121
|
end
|
@@ -213,9 +211,7 @@ module Sequel
|
|
213
211
|
end
|
214
212
|
ds.literal_append(s, v)
|
215
213
|
end
|
216
|
-
|
217
|
-
s << sql
|
218
|
-
end
|
214
|
+
s << @final_sql
|
219
215
|
s
|
220
216
|
end
|
221
217
|
end
|
data/lib/sequel/dataset/query.rb
CHANGED
@@ -330,16 +330,17 @@ module Sequel
|
|
330
330
|
# # SELECT * FROM a WHERE ((a LIKE '%foo%' ESCAPE '\') AND (b LIKE '%foo%' ESCAPE '\')
|
331
331
|
# # AND (a LIKE '%bar%' ESCAPE '\') AND (b LIKE '%bar%' ESCAPE '\'))
|
332
332
|
def grep(columns, patterns, opts=OPTS)
|
333
|
+
column_op = opts[:all_columns] ? :AND : :OR
|
333
334
|
if opts[:all_patterns]
|
334
335
|
conds = Array(patterns).map do |pat|
|
335
|
-
SQL::BooleanExpression.new(
|
336
|
+
SQL::BooleanExpression.new(column_op, *Array(columns).map{|c| SQL::StringExpression.like(c, pat, opts)})
|
336
337
|
end
|
337
|
-
where(SQL::BooleanExpression.new(
|
338
|
+
where(SQL::BooleanExpression.new(:AND, *conds))
|
338
339
|
else
|
339
340
|
conds = Array(columns).map do |c|
|
340
341
|
SQL::BooleanExpression.new(:OR, *Array(patterns).map{|pat| SQL::StringExpression.like(c, pat, opts)})
|
341
342
|
end
|
342
|
-
where(SQL::BooleanExpression.new(
|
343
|
+
where(SQL::BooleanExpression.new(column_op, *conds))
|
343
344
|
end
|
344
345
|
end
|
345
346
|
|
data/lib/sequel/deprecated.rb
CHANGED
@@ -60,7 +60,9 @@ module Sequel
|
|
60
60
|
# If using ruby 2.3+, use Module#deprecate_constant to deprecate the constant,
|
61
61
|
# otherwise do nothing as the ruby implementation does not support constant deprecation.
|
62
62
|
def self.deprecate_constant(mod, constant)
|
63
|
+
# :nocov:
|
63
64
|
if RUBY_VERSION > '2.3'
|
65
|
+
# :nocov:
|
64
66
|
mod.deprecate_constant(constant)
|
65
67
|
end
|
66
68
|
end
|
data/lib/sequel/exceptions.rb
CHANGED
data/lib/sequel/model.rb
CHANGED
@@ -69,7 +69,9 @@ module Sequel
|
|
69
69
|
require_relative "model/base"
|
70
70
|
require_relative "model/exceptions"
|
71
71
|
require_relative "model/errors"
|
72
|
+
# :nocov:
|
72
73
|
if !defined?(::SEQUEL_NO_ASSOCIATIONS) && !ENV.has_key?('SEQUEL_NO_ASSOCIATIONS')
|
74
|
+
# :nocov:
|
73
75
|
require_relative 'model/associations'
|
74
76
|
plugin Model::Associations
|
75
77
|
end
|
@@ -164,11 +164,11 @@ module Sequel
|
|
164
164
|
# range to return the object(s) at the correct offset/limit.
|
165
165
|
def apply_ruby_eager_limit_strategy(rows, limit_and_offset = limit_and_offset())
|
166
166
|
name = self[:name]
|
167
|
+
return unless range = slice_range(limit_and_offset)
|
167
168
|
if returns_array?
|
168
|
-
range = slice_range(limit_and_offset)
|
169
169
|
rows.each{|o| o.associations[name] = o.associations[name][range] || []}
|
170
|
-
|
171
|
-
offset =
|
170
|
+
else
|
171
|
+
offset = range.begin
|
172
172
|
rows.each{|o| o.associations[name] = o.associations[name][offset]}
|
173
173
|
end
|
174
174
|
end
|
@@ -1244,7 +1244,9 @@ module Sequel
|
|
1244
1244
|
else
|
1245
1245
|
assoc_record.values.delete(left_key_alias)
|
1246
1246
|
end
|
1247
|
-
|
1247
|
+
|
1248
|
+
objects = h[hash_key]
|
1249
|
+
|
1248
1250
|
if assign_singular
|
1249
1251
|
objects.each do |object|
|
1250
1252
|
object.associations[name] ||= assoc_record
|
@@ -1948,10 +1950,8 @@ module Sequel
|
|
1948
1950
|
if opts[:block]
|
1949
1951
|
opts[:block_method] = Plugins.def_sequel_method(association_module(opts), "#{opts[:name]}_block", 1, &opts[:block])
|
1950
1952
|
end
|
1951
|
-
|
1952
|
-
|
1953
|
-
opts[:dataset_opt_method] = Plugins.def_sequel_method(association_module(opts), "#{opts[:name]}_dataset_opt", opts[:dataset_opt_arity], &opts[:dataset])
|
1954
|
-
end
|
1953
|
+
opts[:dataset_opt_arity] = opts[:dataset].arity == 0 ? 0 : 1
|
1954
|
+
opts[:dataset_opt_method] = Plugins.def_sequel_method(association_module(opts), "#{opts[:name]}_dataset_opt", opts[:dataset_opt_arity], &opts[:dataset])
|
1955
1955
|
def_association_method(opts)
|
1956
1956
|
|
1957
1957
|
return if opts[:read_only]
|
@@ -2122,9 +2122,7 @@ module Sequel
|
|
2122
2122
|
|
2123
2123
|
eager_load_results(opts, eo) do |assoc_record|
|
2124
2124
|
hash_key = uses_cks ? pk_meths.map{|k| assoc_record.get_column_value(k)} : assoc_record.get_column_value(opts.primary_key_method)
|
2125
|
-
|
2126
|
-
objects.each{|object| object.associations[name] = assoc_record}
|
2127
|
-
end
|
2125
|
+
h[hash_key].each{|object| object.associations[name] = assoc_record}
|
2128
2126
|
end
|
2129
2127
|
end
|
2130
2128
|
|
@@ -2171,7 +2169,7 @@ module Sequel
|
|
2171
2169
|
eager_load_results(opts, eo) do |assoc_record|
|
2172
2170
|
assoc_record.values.delete(delete_rn) if delete_rn
|
2173
2171
|
hash_key = uses_cks ? km.map{|k| assoc_record.get_column_value(k)} : assoc_record.get_column_value(km)
|
2174
|
-
|
2172
|
+
objects = h[hash_key]
|
2175
2173
|
if assign_singular
|
2176
2174
|
objects.each do |object|
|
2177
2175
|
unless object.associations[name]
|
@@ -3064,6 +3062,8 @@ module Sequel
|
|
3064
3062
|
# significantly slower in some cases (perhaps even the majority of cases), so you should
|
3065
3063
|
# only use this if you have benchmarked that it is faster for your use cases.
|
3066
3064
|
def eager_graph_with_options(associations, opts=OPTS)
|
3065
|
+
return self if associations.empty?
|
3066
|
+
|
3067
3067
|
opts = opts.dup unless opts.frozen?
|
3068
3068
|
associations = [associations] unless associations.is_a?(Array)
|
3069
3069
|
ds = if eg = @opts[:eager_graph]
|
@@ -3190,7 +3190,6 @@ module Sequel
|
|
3190
3190
|
# requirements :: an array, used as a stack for requirements
|
3191
3191
|
# *associations :: the associations to add to the graph
|
3192
3192
|
def eager_graph_associations(ds, model, ta, requirements, *associations)
|
3193
|
-
return ds if associations.empty?
|
3194
3193
|
associations.flatten.each do |association|
|
3195
3194
|
ds = case association
|
3196
3195
|
when Symbol, SQL::AliasedExpression
|
data/lib/sequel/model/base.rb
CHANGED
@@ -593,7 +593,7 @@ module Sequel
|
|
593
593
|
@columns = superclass.instance_variable_get(:@columns)
|
594
594
|
@db_schema = superclass.instance_variable_get(:@db_schema)
|
595
595
|
else
|
596
|
-
@dataset = @dataset.with_extend(*@dataset_method_modules.reverse)
|
596
|
+
@dataset = @dataset.with_extend(*@dataset_method_modules.reverse)
|
597
597
|
@db_schema = get_db_schema
|
598
598
|
end
|
599
599
|
|
@@ -820,7 +820,6 @@ module Sequel
|
|
820
820
|
super
|
821
821
|
ivs = subclass.instance_variables
|
822
822
|
inherited_instance_variables.each do |iv, dup|
|
823
|
-
next if ivs.include?(iv)
|
824
823
|
if (sup_class_value = instance_variable_get(iv)) && dup
|
825
824
|
sup_class_value = case dup
|
826
825
|
when :dup
|
@@ -1116,7 +1115,7 @@ module Sequel
|
|
1116
1115
|
when nil
|
1117
1116
|
return false
|
1118
1117
|
when Array
|
1119
|
-
return false if
|
1118
|
+
return false if pkv.any?(&:nil?)
|
1120
1119
|
end
|
1121
1120
|
|
1122
1121
|
(obj.class == model) && (obj.pk == pkv)
|
@@ -1989,6 +1988,7 @@ module Sequel
|
|
1989
1988
|
|
1990
1989
|
# Get the ruby class or classes related to the given column's type.
|
1991
1990
|
def schema_type_class(column)
|
1991
|
+
# SEQUEL6: Remove
|
1992
1992
|
if (sch = db_schema[column]) && (type = sch[:type])
|
1993
1993
|
db.schema_type_class(type)
|
1994
1994
|
end
|
@@ -2232,7 +2232,9 @@ module Sequel
|
|
2232
2232
|
plugin self
|
2233
2233
|
|
2234
2234
|
singleton_class.send(:undef_method, :dup, :clone, :initialize_copy)
|
2235
|
+
# :nocov:
|
2235
2236
|
if RUBY_VERSION >= '1.9.3'
|
2237
|
+
# :nocov:
|
2236
2238
|
singleton_class.send(:undef_method, :initialize_clone, :initialize_dup)
|
2237
2239
|
end
|
2238
2240
|
end
|
data/lib/sequel/model/plugins.rb
CHANGED
@@ -149,9 +149,8 @@ module Sequel
|
|
149
149
|
required_args = arity
|
150
150
|
arity -= 1 if keyword == :required
|
151
151
|
|
152
|
-
|
153
|
-
|
154
|
-
end
|
152
|
+
# callable currently is always a non-lambda Proc
|
153
|
+
optional_args -= arity
|
155
154
|
|
156
155
|
[required_args, optional_args, rest, keyword]
|
157
156
|
end
|
@@ -2,13 +2,17 @@
|
|
2
2
|
|
3
3
|
module Sequel
|
4
4
|
module Plugins
|
5
|
-
# The association_pks plugin adds association_pks and
|
6
|
-
# instance methods to the model class for each
|
7
|
-
#
|
8
|
-
#
|
5
|
+
# The association_pks plugin adds association_pks, association_pks=, and
|
6
|
+
# association_pks_dataset instance methods to the model class for each
|
7
|
+
# one_to_many and many_to_many association added. These methods allow for
|
8
|
+
# easily returning the primary keys of the associated objects, and easily
|
9
|
+
# modifying which objects are associated:
|
9
10
|
#
|
10
11
|
# Artist.one_to_many :albums
|
11
12
|
# artist = Artist[1]
|
13
|
+
# artist.album_pks_dataset
|
14
|
+
# # SELECT id FROM albums WHERE (albums.artist_id = 1)
|
15
|
+
#
|
12
16
|
# artist.album_pks # [1, 2, 3]
|
13
17
|
# artist.album_pks = [2, 4]
|
14
18
|
# artist.album_pks # [2, 4]
|
@@ -22,11 +26,18 @@ module Sequel
|
|
22
26
|
# This plugin makes modifications directly to the underlying tables,
|
23
27
|
# it does not create or return any model objects, and therefore does
|
24
28
|
# not call any callbacks. If you have any association callbacks,
|
25
|
-
# you probably should not use the setter methods.
|
29
|
+
# you probably should not use the setter methods this plugin adds.
|
26
30
|
#
|
27
31
|
# By default, changes to the association will not happen until the object
|
28
|
-
# is saved. However, using the delay_pks: false option, you can have
|
29
|
-
# changes made immediately when the association_pks setter method is called.
|
32
|
+
# is saved. However, using the delay_pks: false association option, you can have
|
33
|
+
# the changes made immediately when the association_pks setter method is called.
|
34
|
+
#
|
35
|
+
# By default, repeated calls to the association_pks getter method will not be
|
36
|
+
# cached, unless the setter method has been used and the delay_pks: false
|
37
|
+
# association option is not used. You can set caching of repeated calls to the
|
38
|
+
# association_pks getter method using the :cache_pks association option. You can
|
39
|
+
# pass the :refresh option when calling the getter method to ignore any existing
|
40
|
+
# cached values, similar to how the :refresh option works with associations.
|
30
41
|
#
|
31
42
|
# By default, if you pass a nil value to the setter, an exception will be raised.
|
32
43
|
# You can change this behavior by using the :association_pks_nil association option.
|
@@ -60,9 +71,11 @@ module Sequel
|
|
60
71
|
|
61
72
|
# Define a association_pks method using the block for the association reflection
|
62
73
|
def def_association_pks_methods(opts)
|
74
|
+
association_module_def(opts[:pks_dataset_method], &opts[:pks_dataset])
|
75
|
+
|
63
76
|
opts[:pks_getter_method] = :"#{singularize(opts[:name])}_pks_getter"
|
64
77
|
association_module_def(opts[:pks_getter_method], &opts[:pks_getter])
|
65
|
-
association_module_def(:"#{singularize(opts[:name])}_pks", opts){_association_pks_getter(opts)}
|
78
|
+
association_module_def(:"#{singularize(opts[:name])}_pks", opts){|dynamic_opts=OPTS| _association_pks_getter(opts, dynamic_opts)}
|
66
79
|
|
67
80
|
if opts[:pks_setter]
|
68
81
|
opts[:pks_setter_method] = :"#{singularize(opts[:name])}_pks_setter"
|
@@ -84,7 +97,9 @@ module Sequel
|
|
84
97
|
clpk = lpk.is_a?(Array)
|
85
98
|
crk = rk.is_a?(Array)
|
86
99
|
|
87
|
-
opts[:
|
100
|
+
dataset_method = opts[:pks_dataset_method] = :"#{singularize(opts[:name])}_pks_dataset"
|
101
|
+
|
102
|
+
opts[:pks_dataset] = if join_associated_table = opts[:association_pks_use_associated_table]
|
88
103
|
tname = opts[:join_table]
|
89
104
|
lambda do
|
90
105
|
cond = if clpk
|
@@ -95,16 +110,26 @@ module Sequel
|
|
95
110
|
rpk = opts.associated_class.primary_key
|
96
111
|
opts.associated_dataset.
|
97
112
|
naked.where(cond).
|
98
|
-
|
113
|
+
select(*Sequel.public_send(rpk.is_a?(Array) ? :deep_qualify : :qualify, opts.associated_class.table_name, rpk))
|
99
114
|
end
|
100
115
|
elsif clpk
|
101
116
|
lambda do
|
102
117
|
cond = lk.zip(lpk).map{|k, pk| [k, get_column_value(pk)]}
|
103
|
-
_join_table_dataset(opts).where(cond).
|
118
|
+
_join_table_dataset(opts).where(cond).select(*rk)
|
119
|
+
end
|
120
|
+
else
|
121
|
+
lambda do
|
122
|
+
_join_table_dataset(opts).where(lk=>get_column_value(lpk)).select(*rk)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
opts[:pks_getter] = if join_associated_table = opts[:association_pks_use_associated_table]
|
127
|
+
lambda do
|
128
|
+
public_send(dataset_method).map(opts.associated_class.primary_key)
|
104
129
|
end
|
105
130
|
else
|
106
131
|
lambda do
|
107
|
-
|
132
|
+
public_send(dataset_method).map(rk)
|
108
133
|
end
|
109
134
|
end
|
110
135
|
|
@@ -145,8 +170,14 @@ module Sequel
|
|
145
170
|
|
146
171
|
key = opts[:key]
|
147
172
|
|
173
|
+
dataset_method = opts[:pks_dataset_method] = :"#{singularize(opts[:name])}_pks_dataset"
|
174
|
+
|
175
|
+
opts[:pks_dataset] = lambda do
|
176
|
+
public_send(opts[:dataset_method]).select(*opts.associated_class.primary_key)
|
177
|
+
end
|
178
|
+
|
148
179
|
opts[:pks_getter] = lambda do
|
149
|
-
public_send(
|
180
|
+
public_send(dataset_method).map(opts.associated_class.primary_key)
|
150
181
|
end
|
151
182
|
|
152
183
|
unless opts[:read_only]
|
@@ -207,12 +238,22 @@ module Sequel
|
|
207
238
|
# Return the primary keys of the associated objects.
|
208
239
|
# If the receiver is a new object, return any saved
|
209
240
|
# pks, or an empty array if no pks have been saved.
|
210
|
-
def _association_pks_getter(opts)
|
241
|
+
def _association_pks_getter(opts, dynamic_opts=OPTS)
|
242
|
+
do_cache = opts[:cache_pks]
|
211
243
|
delay = opts.fetch(:delay_pks, true)
|
212
|
-
|
244
|
+
cache_or_delay = do_cache || delay
|
245
|
+
|
246
|
+
if dynamic_opts[:refresh] && @_association_pks
|
247
|
+
@_association_pks.delete(opts[:name])
|
248
|
+
end
|
249
|
+
|
250
|
+
if new? && cache_or_delay
|
213
251
|
(@_association_pks ||= {})[opts[:name]] ||= []
|
214
|
-
elsif
|
252
|
+
elsif cache_or_delay && @_association_pks && (objs = @_association_pks[opts[:name]])
|
215
253
|
objs
|
254
|
+
elsif do_cache
|
255
|
+
# pks_getter_method is private
|
256
|
+
(@_association_pks ||= {})[opts[:name]] = send(opts[:pks_getter_method])
|
216
257
|
else
|
217
258
|
# pks_getter_method is private
|
218
259
|
send(opts[:pks_getter_method])
|
@@ -192,7 +192,7 @@ module Sequel
|
|
192
192
|
:args=>((key_aliases + col_aliases) if col_aliases))
|
193
193
|
ds = r.apply_eager_dataset_changes(ds)
|
194
194
|
ds = ds.select_append(ka) unless ds.opts[:select] == nil
|
195
|
-
model.eager_load_results(r, eo.merge(:loader=>false, :
|
195
|
+
model.eager_load_results(r, eo.merge(:loader=>false, :initialize_rows=>false, :dataset=>ds, :id_map=>nil)) do |obj|
|
196
196
|
opk = prkey_conv[obj]
|
197
197
|
if parent_map.has_key?(opk)
|
198
198
|
if idm_obj = parent_map[opk]
|
@@ -300,7 +300,7 @@ module Sequel
|
|
300
300
|
:args=>((key_aliases + col_aliases + (level ? [la] : [])) if col_aliases))
|
301
301
|
ds = r.apply_eager_dataset_changes(ds)
|
302
302
|
ds = ds.select_append(ka) unless ds.opts[:select] == nil
|
303
|
-
model.eager_load_results(r, eo.merge(:loader=>false, :
|
303
|
+
model.eager_load_results(r, eo.merge(:loader=>false, :initialize_rows=>false, :dataset=>ds, :id_map=>nil, :associations=>OPTS)) do |obj|
|
304
304
|
if level
|
305
305
|
no_cache = no_cache_level == obj.values.delete(la)
|
306
306
|
end
|
data/lib/sequel/version.rb
CHANGED
@@ -6,7 +6,7 @@ module Sequel
|
|
6
6
|
|
7
7
|
# The minor version of Sequel. Bumped for every non-patch level
|
8
8
|
# release, generally around once a month.
|
9
|
-
MINOR =
|
9
|
+
MINOR = 34
|
10
10
|
|
11
11
|
# The tiny version of Sequel. Usually 0, only bumped for bugfix
|
12
12
|
# releases that fix regressions from previous versions.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.34.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Evans
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-07-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -181,6 +181,7 @@ extra_rdoc_files:
|
|
181
181
|
- doc/release_notes/5.31.0.txt
|
182
182
|
- doc/release_notes/5.32.0.txt
|
183
183
|
- doc/release_notes/5.33.0.txt
|
184
|
+
- doc/release_notes/5.34.0.txt
|
184
185
|
files:
|
185
186
|
- CHANGELOG
|
186
187
|
- MIT-LICENSE
|
@@ -235,6 +236,7 @@ files:
|
|
235
236
|
- doc/release_notes/5.31.0.txt
|
236
237
|
- doc/release_notes/5.32.0.txt
|
237
238
|
- doc/release_notes/5.33.0.txt
|
239
|
+
- doc/release_notes/5.34.0.txt
|
238
240
|
- doc/release_notes/5.4.0.txt
|
239
241
|
- doc/release_notes/5.5.0.txt
|
240
242
|
- doc/release_notes/5.6.0.txt
|