sequel 5.33.0 → 5.35.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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +42 -0
  3. data/doc/association_basics.rdoc +7 -2
  4. data/doc/dataset_filtering.rdoc +2 -2
  5. data/doc/release_notes/5.34.0.txt +40 -0
  6. data/doc/release_notes/5.35.0.txt +56 -0
  7. data/lib/sequel/adapters/oracle.rb +2 -1
  8. data/lib/sequel/adapters/shared/sqlite.rb +8 -2
  9. data/lib/sequel/adapters/tinytds.rb +1 -0
  10. data/lib/sequel/connection_pool/sharded_single.rb +4 -1
  11. data/lib/sequel/connection_pool/sharded_threaded.rb +10 -10
  12. data/lib/sequel/connection_pool/single.rb +1 -1
  13. data/lib/sequel/connection_pool/threaded.rb +1 -1
  14. data/lib/sequel/database/connecting.rb +1 -1
  15. data/lib/sequel/database/misc.rb +16 -10
  16. data/lib/sequel/database/query.rb +2 -0
  17. data/lib/sequel/database/schema_generator.rb +0 -1
  18. data/lib/sequel/database/schema_methods.rb +15 -16
  19. data/lib/sequel/database/transactions.rb +7 -4
  20. data/lib/sequel/dataset/placeholder_literalizer.rb +3 -7
  21. data/lib/sequel/dataset/query.rb +5 -4
  22. data/lib/sequel/deprecated.rb +3 -1
  23. data/lib/sequel/exceptions.rb +2 -0
  24. data/lib/sequel/extensions/_pretty_table.rb +1 -2
  25. data/lib/sequel/extensions/columns_introspection.rb +1 -2
  26. data/lib/sequel/extensions/core_refinements.rb +2 -0
  27. data/lib/sequel/extensions/duplicate_columns_handler.rb +2 -0
  28. data/lib/sequel/extensions/migration.rb +0 -1
  29. data/lib/sequel/extensions/pg_array_ops.rb +4 -0
  30. data/lib/sequel/extensions/pg_enum.rb +2 -0
  31. data/lib/sequel/extensions/pg_extended_date_support.rb +1 -1
  32. data/lib/sequel/extensions/pg_hstore_ops.rb +2 -0
  33. data/lib/sequel/extensions/pg_inet.rb +2 -0
  34. data/lib/sequel/extensions/pg_json_ops.rb +2 -0
  35. data/lib/sequel/extensions/pg_range.rb +3 -7
  36. data/lib/sequel/extensions/pg_range_ops.rb +2 -0
  37. data/lib/sequel/extensions/pg_row.rb +0 -1
  38. data/lib/sequel/extensions/run_transaction_hooks.rb +1 -1
  39. data/lib/sequel/extensions/s.rb +2 -0
  40. data/lib/sequel/extensions/symbol_aref_refinement.rb +2 -0
  41. data/lib/sequel/extensions/symbol_as_refinement.rb +2 -0
  42. data/lib/sequel/extensions/to_dot.rb +9 -3
  43. data/lib/sequel/model.rb +2 -0
  44. data/lib/sequel/model/associations.rb +36 -20
  45. data/lib/sequel/model/base.rb +11 -5
  46. data/lib/sequel/model/plugins.rb +2 -3
  47. data/lib/sequel/plugins/association_pks.rb +60 -18
  48. data/lib/sequel/plugins/blacklist_security.rb +1 -2
  49. data/lib/sequel/plugins/class_table_inheritance.rb +3 -3
  50. data/lib/sequel/plugins/csv_serializer.rb +2 -0
  51. data/lib/sequel/plugins/forbid_lazy_load.rb +2 -0
  52. data/lib/sequel/plugins/instance_specific_default.rb +113 -0
  53. data/lib/sequel/plugins/lazy_attributes.rb +1 -1
  54. data/lib/sequel/plugins/pg_array_associations.rb +2 -3
  55. data/lib/sequel/plugins/prepared_statements.rb +5 -11
  56. data/lib/sequel/plugins/prepared_statements_safe.rb +1 -3
  57. data/lib/sequel/plugins/rcte_tree.rb +10 -16
  58. data/lib/sequel/plugins/string_stripper.rb +1 -1
  59. data/lib/sequel/plugins/validation_class_methods.rb +5 -1
  60. data/lib/sequel/version.rb +1 -1
  61. metadata +7 -2
@@ -114,10 +114,8 @@ module Sequel
114
114
  prepared_sql << sql
115
115
  prepared_sql << "$#{prepared_args[i]}"
116
116
  end
117
- if final_sql
118
- frags << final_sql
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
- if sql = @final_sql
217
- s << sql
218
- end
214
+ s << @final_sql
219
215
  s
220
216
  end
221
217
  end
@@ -81,7 +81,7 @@ module Sequel
81
81
  # If the options changed include options in COLUMN_CHANGE_OPTS, the cached
82
82
  # columns are deleted. This method should generally not be called
83
83
  # directly by user code.
84
- def clone(opts = (return self; nil))
84
+ def clone(opts = nil || (return self))
85
85
  # return self used above because clone is called by almost all
86
86
  # other query methods, and it is the fastest approach
87
87
  c = super(:freeze=>false)
@@ -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(opts[:all_columns] ? :AND : :OR, *Array(columns).map{|c| SQL::StringExpression.like(c, pat, opts)})
336
+ SQL::BooleanExpression.new(column_op, *Array(columns).map{|c| SQL::StringExpression.like(c, pat, opts)})
336
337
  end
337
- where(SQL::BooleanExpression.new(opts[:all_patterns] ? :AND : :OR, *conds))
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(opts[:all_columns] ? :AND : :OR, *conds))
343
+ where(SQL::BooleanExpression.new(column_op, *conds))
343
344
  end
344
345
  end
345
346
 
@@ -39,7 +39,7 @@ module Sequel
39
39
  # Print the message and possibly backtrace to the output.
40
40
  def self.deprecate(method, instead=nil)
41
41
  return unless output
42
- message = instead ? "#{method} is deprecated and will be removed in Sequel 5.1. #{instead}." : method
42
+ message = instead ? "#{method} is deprecated and will be removed in Sequel 6. #{instead}." : method
43
43
  message = "#{prefix}#{message}" if prefix
44
44
  output.puts(message)
45
45
  case b = backtrace_filter
@@ -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
@@ -8,7 +8,9 @@ module Sequel
8
8
  # exception is held here.
9
9
  attr_accessor :wrapped_exception
10
10
 
11
+ # :nocov:
11
12
  if RUBY_VERSION >= '2.1'
13
+ # :nocov:
12
14
  # Returned the wrapped exception if one exists, otherwise use
13
15
  # ruby's default behavior.
14
16
  def cause
@@ -41,8 +41,7 @@ module Sequel
41
41
  def self.column_sizes(records, columns) # :nodoc:
42
42
  sizes = Hash.new {0}
43
43
  columns.each do |c|
44
- s = c.to_s.size
45
- sizes[c] = s if s > sizes[c]
44
+ sizes[c] = c.to_s.size
46
45
  end
47
46
  records.each do |r|
48
47
  columns.each do |c|
@@ -75,8 +75,7 @@ module Sequel
75
75
  when SQL::Identifier
76
76
  c.value.to_sym
77
77
  when SQL::QualifiedIdentifier
78
- col = c.column
79
- col.is_a?(SQL::Identifier) ? col.value.to_sym : col.to_sym
78
+ c.column.to_sym
80
79
  when SQL::AliasedExpression
81
80
  a = c.alias
82
81
  a.is_a?(SQL::Identifier) ? a.value.to_sym : a.to_sym
@@ -10,7 +10,9 @@
10
10
  #
11
11
  # using Sequel::CoreRefinements
12
12
 
13
+ # :nocov:
13
14
  raise(Sequel::Error, "Refinements require ruby 2.0.0 or greater") unless RUBY_VERSION >= '2.0.0'
15
+ # :nocov:
14
16
 
15
17
  module Sequel::CoreRefinements
16
18
  refine Array do
@@ -39,7 +39,9 @@
39
39
 
40
40
  module Sequel
41
41
  module DuplicateColumnsHandler
42
+ # :nocov:
42
43
  CALLER_ARGS = (RUBY_VERSION >= '2.0' ? [0,1] : [0]).freeze
44
+ # :nocov:
43
45
 
44
46
  # Customize handling of duplicate columns for this dataset.
45
47
  def on_duplicate_columns(handler = (raise Error, "Must provide either an argument or a block to on_duplicate_columns" unless block_given?; nil), &block)
@@ -518,7 +518,6 @@ module Sequel
518
518
  def initialize(db, directory, opts=OPTS)
519
519
  super
520
520
  @current = opts[:current] || current_migration_version
521
- raise(Error, "No current version available") unless current
522
521
 
523
522
  latest_version = latest_migration_version
524
523
  @target = if opts[:target]
@@ -157,7 +157,9 @@ module Sequel
157
157
  else
158
158
  Sequel.function(:hstore, self, wrap_array(arg))
159
159
  end
160
+ # :nocov:
160
161
  if Sequel.respond_to?(:hstore_op)
162
+ # :nocov:
161
163
  v = Sequel.hstore_op(v)
162
164
  end
163
165
  v
@@ -283,7 +285,9 @@ module Sequel
283
285
  end
284
286
  end
285
287
 
288
+ # :nocov:
286
289
  if defined?(PGArray)
290
+ # :nocov:
287
291
  class PGArray
288
292
  # Wrap the PGArray instance in an ArrayOp, allowing you to easily use
289
293
  # the PostgreSQL array functions and operators with literal arrays.
@@ -181,7 +181,9 @@ module Sequel
181
181
  end
182
182
 
183
183
  # support reversible create_enum statements if the migration extension is loaded
184
+ # :nocov:
184
185
  if defined?(MigrationReverser)
186
+ # :nocov:
185
187
  class MigrationReverser
186
188
  private
187
189
  def create_enum(name, _)
@@ -189,7 +189,7 @@ module Sequel
189
189
  if date < DATETIME_YEAR_1
190
190
  date <<= ((date.year) * 24 - 12)
191
191
  date = db.from_application_timestamp(date)
192
- minutes = (date.is_a?(DateTime) ? date.offset * 1440 : date.utc_offset/60).to_i
192
+ minutes = (date.offset * 1440).to_i
193
193
  date.strftime("'%Y-%m-%d %H:%M:%S.%N#{format_timestamp_offset(*minutes.divmod(60))} BC'")
194
194
  else
195
195
  super
@@ -312,7 +312,9 @@ module Sequel
312
312
  end
313
313
  end
314
314
 
315
+ # :nocov:
315
316
  if defined?(HStore)
317
+ # :nocov:
316
318
  class HStore
317
319
  # Wrap the receiver in an HStoreOp so you can easily use the PostgreSQL
318
320
  # hstore functions and operators with it.
@@ -41,7 +41,9 @@ module Sequel
41
41
  db.instance_exec do
42
42
  extend_datasets(InetDatasetMethods)
43
43
 
44
+ # :nocov:
44
45
  if !defined?(SEQUEL_PG_VERSION_INTEGER) || SEQUEL_PG_VERSION_INTEGER >= 11300
46
+ # :nocov:
45
47
  # sequel_pg 1.13.0+ will use inet/cidr conversion procs, but doing so is
46
48
  # slower, so don't add the conversion procs if using sequel_pg 1.13.0+.
47
49
  meth = IPAddr.method(:new)
@@ -554,7 +554,9 @@ module Sequel
554
554
  end
555
555
  end
556
556
 
557
+ # :nocov:
557
558
  if defined?(JSONArray)
559
+ # :nocov:
558
560
  class JSONArray
559
561
  # Wrap the JSONArray instance in an JSONOp, allowing you to easily use
560
562
  # the PostgreSQL json functions and operators with literal jsons.
@@ -158,7 +158,7 @@ module Sequel
158
158
  procs = conversion_procs
159
159
  add_conversion_proc(3908, Parser.new("tsrange", procs[1114]))
160
160
  add_conversion_proc(3910, Parser.new("tstzrange", procs[1184]))
161
- if defined?(PGArray::Creator)
161
+ if respond_to?(:register_array_type) && defined?(PGArray::Creator)
162
162
  add_conversion_proc(3909, PGArray::Creator.new("tsrange", procs[3908]))
163
163
  add_conversion_proc(3911, PGArray::Creator.new("tstzrange", procs[3910]))
164
164
  end
@@ -215,12 +215,6 @@ module Sequel
215
215
 
216
216
  db_type = db_type.to_s.dup.freeze
217
217
 
218
- if converter = opts[:converter]
219
- raise Error, "can't provide both a block and :converter option to register" if block
220
- else
221
- converter = block
222
- end
223
-
224
218
  if soid
225
219
  raise Error, "can't provide both a converter and :subtype_oid option to register" if has_converter
226
220
  raise Error, "no conversion proc for :subtype_oid=>#{soid.inspect} in conversion_procs" unless converter = conversion_procs[soid]
@@ -471,8 +465,10 @@ module Sequel
471
465
  return @range if @range
472
466
  raise(Error, "cannot create ruby range for an empty PostgreSQL range") if empty?
473
467
  raise(Error, "cannot create ruby range when PostgreSQL range excludes beginning element") if exclude_begin?
468
+ # :nocov:
474
469
  raise(Error, "cannot create ruby range when PostgreSQL range has unbounded beginning") if STARTLESS_RANGE_NOT_SUPPORTED && !self.begin
475
470
  raise(Error, "cannot create ruby range when PostgreSQL range has unbounded ending") if ENDLESS_RANGE_NOT_SUPPORTED && !self.end
471
+ # :nocov:
476
472
  @range = Range.new(self.begin, self.end, exclude_end?)
477
473
  end
478
474
 
@@ -116,7 +116,9 @@ module Sequel
116
116
  end
117
117
  end
118
118
 
119
+ # :nocov:
119
120
  if defined?(PGRange)
121
+ # :nocov:
120
122
  class PGRange
121
123
  # Wrap the PGRange instance in an RangeOp, allowing you to easily use
122
124
  # the PostgreSQL range functions and operators with literal ranges.
@@ -222,7 +222,6 @@ module Sequel
222
222
  # Split the stored string into an array of strings, handling
223
223
  # the different types of quoting.
224
224
  def parse
225
- return @result if @result
226
225
  values = []
227
226
  skip(/\(/)
228
227
  if skip(/\)/)
@@ -48,7 +48,7 @@ class Sequel::Database
48
48
  def _run_transaction_hooks(type, opts)
49
49
  synchronize(opts[:server]) do |conn|
50
50
  unless h = _trans(conn)
51
- raise Error, "Cannot call run_#{type}_hooks outside of a transaction"
51
+ raise Sequel::Error, "Cannot call run_#{type}_hooks outside of a transaction"
52
52
  end
53
53
 
54
54
  if hooks = h[type]
@@ -49,7 +49,9 @@ module Sequel::S
49
49
  Sequel.expr(*a, &block)
50
50
  end
51
51
 
52
+ # :nocov:
52
53
  if RUBY_VERSION >= '2.0.0'
54
+ # :nocov:
53
55
  refine Object do
54
56
  include Sequel::S
55
57
  end
@@ -25,7 +25,9 @@
25
25
  #
26
26
  # Related module: Sequel::SymbolAref
27
27
 
28
+ # :nocov:
28
29
  raise(Sequel::Error, "Refinements require ruby 2.0.0 or greater") unless RUBY_VERSION >= '2.0.0'
30
+ # :nocov:
29
31
 
30
32
  module Sequel::SymbolAref
31
33
  refine Symbol do
@@ -23,7 +23,9 @@
23
23
  #
24
24
  # Related module: Sequel::SymbolAs
25
25
 
26
+ # :nocov:
26
27
  raise(Sequel::Error, "Refinements require ruby 2.0.0 or greater") unless RUBY_VERSION >= '2.0.0'
28
+ # :nocov:
27
29
 
28
30
  module Sequel::SymbolAs
29
31
  refine Symbol do
@@ -53,7 +53,13 @@ module Sequel
53
53
  # is given, it is used directly as the node or transition. Otherwise
54
54
  # a node is created for the current object.
55
55
  def dot(label, j=nil)
56
- @dot << "#{j||@i} [label=#{label.to_s.inspect}];"
56
+ label = case label
57
+ when nil
58
+ "<nil>"
59
+ else
60
+ label.to_s
61
+ end
62
+ @dot << "#{j||@i} [label=#{label.inspect}];"
57
63
  end
58
64
 
59
65
  # Recursive method that parses all of Sequel's internal datastructures,
@@ -61,7 +67,7 @@ module Sequel
61
67
  # structure.
62
68
  def v(e, l)
63
69
  @i += 1
64
- dot(l, "#{@stack.last} -> #{@i}") if l
70
+ dot(l, "#{@stack.last} -> #{@i}")
65
71
  @stack.push(@i)
66
72
  case e
67
73
  when LiteralString
@@ -144,7 +150,7 @@ module Sequel
144
150
  dot "Dataset"
145
151
  TO_DOT_OPTIONS.each do |k|
146
152
  if val = e.opts[k]
147
- v(val, k.to_s)
153
+ v(val, k)
148
154
  end
149
155
  end
150
156
  else
@@ -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
- elsif sr = slice_range(limit_and_offset)
171
- offset = sr.begin
170
+ else
171
+ offset = range.begin
172
172
  rows.each{|o| o.associations[name] = o.associations[name][offset]}
173
173
  end
174
174
  end
@@ -356,7 +356,7 @@ module Sequel
356
356
  def finalize
357
357
  return unless cache = self[:cache]
358
358
 
359
- finalize_settings.each do |meth, key|
359
+ finalizer = proc do |meth, key|
360
360
  next if has_key?(key)
361
361
 
362
362
  # Allow calling private methods to make sure caching is done appropriately
@@ -364,6 +364,13 @@ module Sequel
364
364
  self[key] = cache.delete(key) if cache.has_key?(key)
365
365
  end
366
366
 
367
+ finalize_settings.each(&finalizer)
368
+
369
+ unless self[:instance_specific]
370
+ finalizer.call(:associated_eager_dataset, :associated_eager_dataset)
371
+ finalizer.call(:filter_by_associations_conditions_dataset, :filter_by_associations_conditions_dataset)
372
+ end
373
+
367
374
  nil
368
375
  end
369
376
 
@@ -371,9 +378,7 @@ module Sequel
371
378
  FINALIZE_SETTINGS = {
372
379
  :associated_class=>:class,
373
380
  :associated_dataset=>:_dataset,
374
- :associated_eager_dataset=>:associated_eager_dataset,
375
381
  :eager_limit_strategy=>:_eager_limit_strategy,
376
- :filter_by_associations_conditions_dataset=>:filter_by_associations_conditions_dataset,
377
382
  :placeholder_loader=>:placeholder_loader,
378
383
  :predicate_key=>:predicate_key,
379
384
  :predicate_keys=>:predicate_keys,
@@ -432,7 +437,11 @@ module Sequel
432
437
  if use_placeholder_loader?
433
438
  cached_fetch(:placeholder_loader) do
434
439
  Sequel::Dataset::PlaceholderLiteralizer.loader(associated_dataset) do |pl, ds|
435
- ds.where(Sequel.&(*predicate_keys.map{|k| SQL::BooleanExpression.new(:'=', k, pl.arg)}))
440
+ ds = ds.where(Sequel.&(*predicate_keys.map{|k| SQL::BooleanExpression.new(:'=', k, pl.arg)}))
441
+ if self[:block]
442
+ ds = self[:block].call(ds)
443
+ end
444
+ ds
436
445
  end
437
446
  end
438
447
  end
@@ -796,7 +805,7 @@ module Sequel
796
805
 
797
806
  # Whether the placeholder loader can be used to load the association.
798
807
  def use_placeholder_loader?
799
- !self[:instance_specific] && !self[:eager_graph]
808
+ self[:use_placeholder_loader]
800
809
  end
801
810
  end
802
811
 
@@ -1244,7 +1253,9 @@ module Sequel
1244
1253
  else
1245
1254
  assoc_record.values.delete(left_key_alias)
1246
1255
  end
1247
- next unless objects = h[hash_key]
1256
+
1257
+ objects = h[hash_key]
1258
+
1248
1259
  if assign_singular
1249
1260
  objects.each do |object|
1250
1261
  object.associations[name] ||= assoc_record
@@ -1791,11 +1802,12 @@ module Sequel
1791
1802
  opts.merge!(:type => type, :name => name, :cache=>({} if cache_associations), :model => self)
1792
1803
 
1793
1804
  opts[:block] = block if block
1794
- if !opts.has_key?(:instance_specific) && (block || orig_opts[:block] || orig_opts[:dataset])
1805
+ opts[:instance_specific] = true if orig_opts[:dataset]
1806
+ if !opts.has_key?(:instance_specific) && (block || orig_opts[:block])
1795
1807
  # It's possible the association is instance specific, in that it depends on
1796
1808
  # values other than the foreign key value. This needs to be checked for
1797
1809
  # in certain places to disable optimizations.
1798
- opts[:instance_specific] = true
1810
+ opts[:instance_specific] = _association_instance_specific_default(name)
1799
1811
  end
1800
1812
  opts = assoc_class.new.merge!(opts)
1801
1813
 
@@ -1803,6 +1815,7 @@ module Sequel
1803
1815
  raise(Error, "cannot clone an association to an association of different type (association #{name} with type #{type} cloning #{opts[:clone]} with type #{cloned_assoc[:type]})")
1804
1816
  end
1805
1817
 
1818
+ opts[:use_placeholder_loader] = !opts[:instance_specific] && !opts[:eager_graph]
1806
1819
  opts[:eager_block] = opts[:block] unless opts.include?(:eager_block)
1807
1820
  opts[:graph_join_type] ||= :left_outer
1808
1821
  opts[:order_eager_graph] = true unless opts.include?(:order_eager_graph)
@@ -1899,6 +1912,12 @@ module Sequel
1899
1912
  Plugins.def_dataset_methods(self, [:eager, :eager_graph, :eager_graph_with_options, :association_join, :association_full_join, :association_inner_join, :association_left_join, :association_right_join])
1900
1913
 
1901
1914
  private
1915
+
1916
+ # The default value for the instance_specific option, if the association
1917
+ # could be instance specific and the :instance_specific option is not specified.
1918
+ def _association_instance_specific_default(_)
1919
+ true
1920
+ end
1902
1921
 
1903
1922
  # The module to use for the association's methods. Defaults to
1904
1923
  # the overridable_methods_module.
@@ -1948,10 +1967,8 @@ module Sequel
1948
1967
  if opts[:block]
1949
1968
  opts[:block_method] = Plugins.def_sequel_method(association_module(opts), "#{opts[:name]}_block", 1, &opts[:block])
1950
1969
  end
1951
- if opts[:dataset]
1952
- opts[:dataset_opt_arity] = opts[:dataset].arity == 0 ? 0 : 1
1953
- opts[:dataset_opt_method] = Plugins.def_sequel_method(association_module(opts), "#{opts[:name]}_dataset_opt", opts[:dataset_opt_arity], &opts[:dataset])
1954
- end
1970
+ opts[:dataset_opt_arity] = opts[:dataset].arity == 0 ? 0 : 1
1971
+ opts[:dataset_opt_method] = Plugins.def_sequel_method(association_module(opts), "#{opts[:name]}_dataset_opt", opts[:dataset_opt_arity], &opts[:dataset])
1955
1972
  def_association_method(opts)
1956
1973
 
1957
1974
  return if opts[:read_only]
@@ -2122,9 +2139,7 @@ module Sequel
2122
2139
 
2123
2140
  eager_load_results(opts, eo) do |assoc_record|
2124
2141
  hash_key = uses_cks ? pk_meths.map{|k| assoc_record.get_column_value(k)} : assoc_record.get_column_value(opts.primary_key_method)
2125
- if objects = h[hash_key]
2126
- objects.each{|object| object.associations[name] = assoc_record}
2127
- end
2142
+ h[hash_key].each{|object| object.associations[name] = assoc_record}
2128
2143
  end
2129
2144
  end
2130
2145
 
@@ -2171,7 +2186,7 @@ module Sequel
2171
2186
  eager_load_results(opts, eo) do |assoc_record|
2172
2187
  assoc_record.values.delete(delete_rn) if delete_rn
2173
2188
  hash_key = uses_cks ? km.map{|k| assoc_record.get_column_value(k)} : assoc_record.get_column_value(km)
2174
- next unless objects = h[hash_key]
2189
+ objects = h[hash_key]
2175
2190
  if assign_singular
2176
2191
  objects.each do |object|
2177
2192
  unless object.associations[name]
@@ -3064,6 +3079,8 @@ module Sequel
3064
3079
  # significantly slower in some cases (perhaps even the majority of cases), so you should
3065
3080
  # only use this if you have benchmarked that it is faster for your use cases.
3066
3081
  def eager_graph_with_options(associations, opts=OPTS)
3082
+ return self if associations.empty?
3083
+
3067
3084
  opts = opts.dup unless opts.frozen?
3068
3085
  associations = [associations] unless associations.is_a?(Array)
3069
3086
  ds = if eg = @opts[:eager_graph]
@@ -3190,7 +3207,6 @@ module Sequel
3190
3207
  # requirements :: an array, used as a stack for requirements
3191
3208
  # *associations :: the associations to add to the graph
3192
3209
  def eager_graph_associations(ds, model, ta, requirements, *associations)
3193
- return ds if associations.empty?
3194
3210
  associations.flatten.each do |association|
3195
3211
  ds = case association
3196
3212
  when Symbol, SQL::AliasedExpression