sequel 4.48.0 → 4.49.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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +56 -0
  3. data/doc/advanced_associations.rdoc +1 -1
  4. data/doc/opening_databases.rdoc +3 -2
  5. data/doc/release_notes/4.49.0.txt +222 -0
  6. data/lib/sequel/adapters/ibmdb.rb +6 -1
  7. data/lib/sequel/adapters/jdbc.rb +3 -1
  8. data/lib/sequel/adapters/jdbc/h2.rb +10 -1
  9. data/lib/sequel/adapters/jdbc/postgresql.rb +3 -2
  10. data/lib/sequel/adapters/jdbc/sqlserver.rb +9 -2
  11. data/lib/sequel/adapters/mock.rb +3 -0
  12. data/lib/sequel/adapters/mysql2.rb +1 -1
  13. data/lib/sequel/adapters/postgres.rb +2 -1
  14. data/lib/sequel/adapters/shared/mysql.rb +4 -1
  15. data/lib/sequel/adapters/shared/oracle.rb +26 -3
  16. data/lib/sequel/connection_pool.rb +9 -2
  17. data/lib/sequel/connection_pool/sharded_single.rb +1 -1
  18. data/lib/sequel/connection_pool/sharded_threaded.rb +1 -1
  19. data/lib/sequel/connection_pool/single.rb +2 -2
  20. data/lib/sequel/connection_pool/threaded.rb +2 -2
  21. data/lib/sequel/database/connecting.rb +3 -3
  22. data/lib/sequel/database/dataset_defaults.rb +14 -1
  23. data/lib/sequel/dataset.rb +1 -1
  24. data/lib/sequel/dataset/actions.rb +54 -0
  25. data/lib/sequel/dataset/dataset_module.rb +58 -0
  26. data/lib/sequel/dataset/query.rb +3 -3
  27. data/lib/sequel/exceptions.rb +8 -0
  28. data/lib/sequel/extensions/_model_pg_row.rb +5 -2
  29. data/lib/sequel/extensions/current_datetime_timestamp.rb +2 -1
  30. data/lib/sequel/extensions/date_arithmetic.rb +1 -0
  31. data/lib/sequel/extensions/duplicate_columns_handler.rb +2 -2
  32. data/lib/sequel/extensions/migration.rb +5 -2
  33. data/lib/sequel/extensions/null_dataset.rb +1 -0
  34. data/lib/sequel/model/associations.rb +3 -0
  35. data/lib/sequel/model/base.rb +10 -55
  36. data/lib/sequel/model/dataset_module.rb +5 -43
  37. data/lib/sequel/model/errors.rb +2 -1
  38. data/lib/sequel/model/inflections.rb +17 -5
  39. data/lib/sequel/plugins/active_model.rb +2 -2
  40. data/lib/sequel/plugins/class_table_inheritance.rb +1 -0
  41. data/lib/sequel/plugins/composition.rb +2 -2
  42. data/lib/sequel/plugins/dataset_associations.rb +25 -13
  43. data/lib/sequel/plugins/json_serializer.rb +2 -2
  44. data/lib/sequel/plugins/pg_row.rb +4 -2
  45. data/lib/sequel/plugins/serialization.rb +1 -0
  46. data/lib/sequel/plugins/single_table_inheritance.rb +6 -1
  47. data/lib/sequel/plugins/touch.rb +2 -1
  48. data/lib/sequel/plugins/validation_helpers.rb +10 -2
  49. data/lib/sequel/sql.rb +16 -7
  50. data/lib/sequel/version.rb +1 -1
  51. data/spec/adapters/mssql_spec.rb +4 -4
  52. data/spec/adapters/mysql_spec.rb +5 -1
  53. data/spec/adapters/oracle_spec.rb +4 -0
  54. data/spec/bin_spec.rb +7 -1
  55. data/spec/core/connection_pool_spec.rb +28 -14
  56. data/spec/core/database_spec.rb +149 -0
  57. data/spec/core/dataset_spec.rb +173 -0
  58. data/spec/extensions/class_table_inheritance_spec.rb +58 -17
  59. data/spec/extensions/composition_spec.rb +13 -0
  60. data/spec/extensions/dataset_associations_spec.rb +12 -0
  61. data/spec/extensions/many_through_many_spec.rb +4 -4
  62. data/spec/extensions/null_dataset_spec.rb +1 -1
  63. data/spec/extensions/serialization_spec.rb +1 -1
  64. data/spec/extensions/single_table_inheritance_spec.rb +16 -0
  65. data/spec/extensions/validation_helpers_spec.rb +1 -2
  66. data/spec/integration/associations_test.rb +8 -0
  67. data/spec/integration/plugin_test.rb +8 -3
  68. data/spec/model/association_reflection_spec.rb +1 -1
  69. data/spec/model/associations_spec.rb +29 -9
  70. data/spec/model/class_dataset_methods_spec.rb +6 -0
  71. data/spec/model/eager_loading_spec.rb +8 -8
  72. data/spec/model/plugins_spec.rb +34 -0
  73. data/spec/model/record_spec.rb +1 -1
  74. data/spec/spec_config.rb +2 -0
  75. metadata +5 -2
@@ -67,6 +67,7 @@ module Sequel
67
67
  ACCESS_DURATION_UNITS = DURATION_UNITS.zip(%w'yyyy m d h n s'.map(&:freeze)).freeze
68
68
  DB2_DURATION_UNITS = DURATION_UNITS.zip(DURATION_UNITS.map{|s| Sequel.lit(s.to_s).freeze}).freeze
69
69
  FDBSQL_DURATION_UNITS = DURATION_UNITS.zip(DURATION_UNITS.map{|s| Sequel.lit(s.to_s.chop).freeze}).freeze
70
+ Sequel::Deprecation.deprecate_constant(self, :FDBSQL_DURATION_UNITS)
70
71
 
71
72
  # Append the SQL fragment for the DateAdd expression to the SQL query.
72
73
  def date_add_sql_append(sql, da)
@@ -43,6 +43,8 @@ module Sequel
43
43
  clone(:on_duplicate_columns=>handler||block)
44
44
  end
45
45
 
46
+ private
47
+
46
48
  # Override the attr_writer to check for duplicate columns, and call
47
49
  # handle_duplicate_columns if necessary.
48
50
  def columns=(cols)
@@ -52,8 +54,6 @@ module Sequel
52
54
  super
53
55
  end
54
56
 
55
- private
56
-
57
57
  # Invoke the appropriate behavior when duplicate columns are present.
58
58
  def handle_duplicate_columns(cols)
59
59
  message = "#{caller(*CALLER_ARGS).first}: One or more duplicate columns present in #{cols.inspect}"
@@ -352,8 +352,11 @@ module Sequel
352
352
  # Part of the +migration+ extension.
353
353
  class Migrator
354
354
  MIGRATION_FILE_PATTERN = /\A(\d+)_.+\.rb\z/i.freeze
355
+
355
356
  MIGRATION_SPLITTER = '_'.freeze
357
+ Sequel::Deprecation.deprecate_constant(self, :MIGRATION_SPLITTER)
356
358
  MINIMUM_TIMESTAMP = 20000101
359
+ Sequel::Deprecation.deprecate_constant(self, :MINIMUM_TIMESTAMP)
357
360
 
358
361
  # Exception class raised when there is an error with the migrator's
359
362
  # file structure, database, or arguments.
@@ -408,7 +411,7 @@ module Sequel
408
411
  if self.equal?(Migrator)
409
412
  Dir.new(directory).each do |file|
410
413
  next unless MIGRATION_FILE_PATTERN.match(file)
411
- return TimestampMigrator if file.split(MIGRATION_SPLITTER, 2).first.to_i > MINIMUM_TIMESTAMP
414
+ return TimestampMigrator if file.split('_', 2).first.to_i > 20000101
412
415
  end
413
416
  IntegerMigrator
414
417
  else
@@ -497,7 +500,7 @@ module Sequel
497
500
 
498
501
  # Return the integer migration version based on the filename.
499
502
  def migration_version_from_file(filename)
500
- filename.split(MIGRATION_SPLITTER, 2).first.to_i
503
+ filename.split('_', 2).first.to_i
501
504
  end
502
505
  end
503
506
 
@@ -46,6 +46,7 @@ module Sequel
46
46
 
47
47
  # Nullify the current dataset
48
48
  def nullify!
49
+ Sequel::Deprecation.deprecate("Dataset#nullify! from the null_dataset extension", "Use Dataset#nullify, which returned a modified copy")
49
50
  extend NullDataset
50
51
  end
51
52
  end
@@ -327,6 +327,7 @@ module Sequel
327
327
 
328
328
  # Alias of predicate_key, only for backwards compatibility.
329
329
  def eager_loading_predicate_key
330
+ Sequel::Deprecation.deprecate("AssociationReflection#eager_loading_predicate_key", "Use #predicate_key instead")
330
331
  predicate_key
331
332
  end
332
333
 
@@ -1803,6 +1804,7 @@ module Sequel
1803
1804
 
1804
1805
  opts[:eager_block] = opts[:block] unless opts.include?(:eager_block)
1805
1806
  if !opts.has_key?(:predicate_key) && opts.has_key?(:eager_loading_predicate_key)
1807
+ Sequel::Deprecation.deprecate("The :eager_loading_predicate_key association option", "Use the :predicate_key option instead")
1806
1808
  opts[:predicate_key] = opts[:eager_loading_predicate_key]
1807
1809
  end
1808
1810
  opts[:graph_join_type] ||= :left_outer
@@ -2555,6 +2557,7 @@ module Sequel
2555
2557
  end
2556
2558
 
2557
2559
  if res == false and stop_on_false
2560
+ Sequel::Deprecation.deprecate("Having #{callback_type} association callback return false to cancel modification", "Instead, call Model#cancel_action inside the association callback")
2558
2561
  raise(HookFailed, "Unable to modify association for #{inspect}: one of the #{callback_type} hooks returned false")
2559
2562
  end
2560
2563
  end
@@ -26,9 +26,8 @@ module Sequel
26
26
  # (default: not set, so all columns not otherwise restricted are allowed).
27
27
  attr_reader :allowed_columns # SEQUEL5: Deprecate after release
28
28
 
29
- # Whether to cache the anonymous models created by Sequel::Model(). This is
30
- # required for reloading them correctly (avoiding the superclass mismatch). True
31
- # by default for backwards compatibility.
29
+ # Whether to cache the anonymous models created by Sequel::Model(), true by default. This is
30
+ # required for reloading them correctly (avoiding the superclass mismatch).
32
31
  attr_accessor :cache_anonymous_models
33
32
 
34
33
  # Array of modules that extend this model's dataset. Stored
@@ -716,7 +715,7 @@ module Sequel
716
715
  pluralize(underscore(demodulize(name))).to_sym
717
716
  end
718
717
 
719
- # Calls #call with the values hash. Only for backwards compatibility.
718
+ # Calls #call with the values hash.
720
719
  def load(values)
721
720
  call(values)
722
721
  end
@@ -992,7 +991,7 @@ module Sequel
992
991
  end
993
992
 
994
993
  # Add model methods that call dataset methods
995
- Plugins.def_dataset_methods(self, (Dataset::ACTION_METHODS + Dataset::QUERY_METHODS + [:each_server, :where_all, :where_each, :where_single_value]) - [:<<, :and, :or, :[], :columns, :columns!, :delete, :update, :add_graph_aliases])
994
+ Plugins.def_dataset_methods(self, (Dataset::ACTION_METHODS + Dataset::QUERY_METHODS + [:each_server]) - [:<<, :and, :or, :[], :columns, :columns!, :delete, :update, :add_graph_aliases])
996
995
  # SEQUEL5: add :set_graph_aliases to remove list and remove :and
997
996
 
998
997
  private
@@ -1249,6 +1248,7 @@ module Sequel
1249
1248
  rescue LoadError => e
1250
1249
  begin
1251
1250
  require "sequel_#{plugin}"
1251
+ Sequel::Deprecation.deprecate("requiring 'sequel_#{plugin}' to load a plugin", "Update the #{plugin} plugin to be required via 'sequel/plugins/#{plugin}'")
1252
1252
  rescue LoadError => e2
1253
1253
  e.message << "; #{e2.message}"
1254
1254
  raise e
@@ -2684,52 +2684,6 @@ module Sequel
2684
2684
  as_hash(*a)
2685
2685
  end
2686
2686
 
2687
- # Return an array of all rows matching the given filter condition, also
2688
- # yielding each row to the given block. Basically the same as where(cond).all(&block),
2689
- # except it can be optimized to not create an intermediate dataset.
2690
- #
2691
- # Artist.where_all(:id=>[1,2,3])
2692
- # # SELECT * FROM artists WHERE (id IN (1, 2, 3))
2693
- def where_all(cond, &block)
2694
- if loader = _model_where_loader
2695
- loader.all(filter_expr(cond), &block)
2696
- else
2697
- where(cond).all(&block)
2698
- end
2699
- end
2700
-
2701
- # Iterate over all rows matching the given filter condition,
2702
- # yielding each row to the given block. Basically the same as where(cond).each(&block),
2703
- # except it can be optimized to not create an intermediate dataset.
2704
- #
2705
- # Artist.where_each(:id=>[1,2,3]){|row| p row}
2706
- # # SELECT * FROM artists WHERE (id IN (1, 2, 3))
2707
- def where_each(cond, &block)
2708
- if loader = _model_where_loader
2709
- loader.each(filter_expr(cond), &block)
2710
- else
2711
- where(cond).each(&block)
2712
- end
2713
- end
2714
-
2715
- # Filter the datasets using the given filter condition, then return a single value.
2716
- # This assumes that the dataset has already been setup to limit the selection to
2717
- # a single column. Basically the same as where(cond).single_value,
2718
- # except it can be optimized to not create an intermediate dataset.
2719
- #
2720
- # Artist.select(:name).where_single_value(:id=>1)
2721
- # # SELECT name FROM artists WHERE (id = 1) LIMIT 1
2722
- def where_single_value(cond)
2723
- if loader = cached_placeholder_literalizer(:_model_where_single_value_loader) do |pl|
2724
- single_value_ds.where(pl.arg)
2725
- end
2726
-
2727
- loader.get(filter_expr(cond))
2728
- else
2729
- where(cond).single_value
2730
- end
2731
- end
2732
-
2733
2687
  # Given a primary key value, return the first record in the dataset with that primary key
2734
2688
  # value. If no records matches, returns nil.
2735
2689
  #
@@ -2756,11 +2710,12 @@ module Sequel
2756
2710
 
2757
2711
  private
2758
2712
 
2759
- # Loader used for where_all and where_each.
2713
+ # SEQUEL5: Remove
2760
2714
  def _model_where_loader
2761
- cached_placeholder_literalizer(:_model_where_loader) do |pl|
2762
- where(pl.arg)
2763
- end
2715
+ # :nocov:
2716
+ Sequel::Deprecation.deprecate("Dataset#_model_where_loader", "Use _where_loader instead")
2717
+ _where_loader
2718
+ # :nocov:
2764
2719
  end
2765
2720
 
2766
2721
  # If the dataset is not already ordered, and the model has a primary key,
@@ -3,12 +3,11 @@
3
3
  module Sequel
4
4
  class Model
5
5
  # This Module subclass is used by Model.dataset_module
6
- # to add dataset methods to classes. It adds a couple
7
- # of features standard Modules, allowing you to use
8
- # the same subset method you can call on Model, as well
9
- # as making sure that public methods added to the module
10
- # automatically have class methods created for them.
11
- class DatasetModule < ::Module
6
+ # to add dataset methods to classes. In addition to the
7
+ # methods offered by Dataset::DatasetModule, it also
8
+ # automatically creates class methods for public dataset
9
+ # methods.
10
+ class DatasetModule < Dataset::DatasetModule
12
11
  # Store the model related to this dataset module.
13
12
  def initialize(model)
14
13
  @model = model
@@ -19,43 +18,6 @@ module Sequel
19
18
  where(name, *args, &block)
20
19
  end
21
20
 
22
- %w'where exclude exclude_having having'.map(&:to_sym).each do |meth|
23
- define_method(meth) do |name, *args, &block|
24
- if block || args.flatten.any?{|arg| arg.is_a?(Proc)}
25
- define_method(name){send(meth, *args, &block)}
26
- else
27
- key = :"_#{meth}_#{name}_ds"
28
- define_method(name) do
29
- cached_dataset(key){send(meth, *args)}
30
- end
31
- end
32
- end
33
- end
34
-
35
- meths = (<<-METHS).split.map(&:to_sym)
36
- distinct grep group group_and_count group_append
37
- limit offset order order_append order_prepend
38
- select select_all select_append select_group server
39
- METHS
40
-
41
- # Define a method in the module
42
- def self.def_dataset_caching_method(mod, meth)
43
- mod.send(:define_method, meth) do |name, *args, &block|
44
- if block
45
- define_method(name){send(meth, *args, &block)}
46
- else
47
- key = :"_#{meth}_#{name}_ds"
48
- define_method(name) do
49
- cached_dataset(key){send(meth, *args)}
50
- end
51
- end
52
- end
53
- end
54
-
55
- meths.each do |meth|
56
- def_dataset_caching_method(self, meth)
57
- end
58
-
59
21
  private
60
22
 
61
23
  # Add a class method to the related model that
@@ -6,6 +6,7 @@ module Sequel
6
6
  # with a few convenience methods.
7
7
  class Errors < ::Hash
8
8
  ATTRIBUTE_JOINER = ' and '.freeze
9
+ Sequel::Deprecation.deprecate_constant(self, :ATTRIBUTE_JOINER)
9
10
 
10
11
  # Adds an error for the given attribute.
11
12
  #
@@ -40,7 +41,7 @@ module Sequel
40
41
  def full_messages
41
42
  inject([]) do |m, kv|
42
43
  att, errors = *kv
43
- errors.each {|e| m << (e.is_a?(LiteralString) ? e : "#{Array(att).join(ATTRIBUTE_JOINER)} #{e}")}
44
+ errors.each {|e| m << (e.is_a?(LiteralString) ? e : "#{Array(att).join(' and ')} #{e}")}
44
45
  m
45
46
  end
46
47
  end
@@ -26,17 +26,29 @@ module Sequel
26
26
  # already have been loaded.
27
27
  module Inflections
28
28
  CAMELIZE_CONVERT_REGEXP = /(^|_)(.)/.freeze
29
+ Sequel::Deprecation.deprecate_constant(self, :CAMELIZE_CONVERT_REGEXP)
29
30
  CAMELIZE_MODULE_REGEXP = /\/(.?)/.freeze
31
+ Sequel::Deprecation.deprecate_constant(self, :CAMELIZE_MODULE_REGEXP)
30
32
  DASH = '-'.freeze
33
+ Sequel::Deprecation.deprecate_constant(self, :DASH)
31
34
  DEMODULIZE_CONVERT_REGEXP = /^.*::/.freeze
35
+ Sequel::Deprecation.deprecate_constant(self, :DEMODULIZE_CONVERT_REGEXP)
32
36
  EMPTY_STRING= ''.freeze
37
+ Sequel::Deprecation.deprecate_constant(self, :EMPTY_STRING)
33
38
  SLASH = '/'.freeze
39
+ Sequel::Deprecation.deprecate_constant(self, :SLASH)
34
40
  VALID_CONSTANT_NAME_REGEXP = /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/.freeze
41
+ Sequel::Deprecation.deprecate_constant(self, :VALID_CONSTANT_NAME_REGEXP)
35
42
  UNDERSCORE = '_'.freeze
43
+ Sequel::Deprecation.deprecate_constant(self, :UNDERSCORE)
36
44
  UNDERSCORE_CONVERT_REGEXP1 = /([A-Z]+)([A-Z][a-z])/.freeze
45
+ Sequel::Deprecation.deprecate_constant(self, :UNDERSCORE_CONVERT_REGEXP1)
37
46
  UNDERSCORE_CONVERT_REGEXP2 = /([a-z\d])([A-Z])/.freeze
47
+ Sequel::Deprecation.deprecate_constant(self, :UNDERSCORE_CONVERT_REGEXP2)
38
48
  UNDERSCORE_CONVERT_REPLACE = '\1_\2'.freeze
49
+ Sequel::Deprecation.deprecate_constant(self, :UNDERSCORE_CONVERT_REPLACE)
39
50
  UNDERSCORE_MODULE_REGEXP = /::/.freeze
51
+ Sequel::Deprecation.deprecate_constant(self, :UNDERSCORE_MODULE_REGEXP)
40
52
 
41
53
  @plurals, @singulars, @uncountables = [], [], []
42
54
 
@@ -113,7 +125,7 @@ module Sequel
113
125
  def camelize(s)
114
126
  s = s.to_s
115
127
  return s.camelize if s.respond_to?(:camelize)
116
- s = s.gsub(CAMELIZE_MODULE_REGEXP){|x| "::#{x[-1..-1].upcase unless x == SLASH}"}.gsub(CAMELIZE_CONVERT_REGEXP){|x| x[-1..-1].upcase}
128
+ s = s.gsub(/\/(.?)/){|x| "::#{x[-1..-1].upcase unless x == '/'}"}.gsub(/(^|_)(.)/){|x| x[-1..-1].upcase}
117
129
  s
118
130
  end
119
131
 
@@ -123,7 +135,7 @@ module Sequel
123
135
  def constantize(s)
124
136
  s = s.to_s
125
137
  return s.constantize if s.respond_to?(:constantize)
126
- raise(NameError, "#{s.inspect} is not a valid constant name!") unless m = VALID_CONSTANT_NAME_REGEXP.match(s)
138
+ raise(NameError, "#{s.inspect} is not a valid constant name!") unless m = /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/.match(s)
127
139
  Object.module_eval("::#{m[1]}", __FILE__, __LINE__)
128
140
  end
129
141
 
@@ -131,7 +143,7 @@ module Sequel
131
143
  def demodulize(s)
132
144
  s = s.to_s
133
145
  return s.demodulize if s.respond_to?(:demodulize)
134
- s.gsub(DEMODULIZE_CONVERT_REGEXP, EMPTY_STRING)
146
+ s.gsub(/^.*::/, '')
135
147
  end
136
148
 
137
149
  # Returns the plural form of the word in the string.
@@ -157,8 +169,8 @@ module Sequel
157
169
  def underscore(s)
158
170
  s = s.to_s
159
171
  return s.underscore if s.respond_to?(:underscore)
160
- s.gsub(UNDERSCORE_MODULE_REGEXP, SLASH).gsub(UNDERSCORE_CONVERT_REGEXP1, UNDERSCORE_CONVERT_REPLACE).
161
- gsub(UNDERSCORE_CONVERT_REGEXP2, UNDERSCORE_CONVERT_REPLACE).tr(DASH, UNDERSCORE).downcase
172
+ s.gsub('::', '/').gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
173
+ gsub(/([a-z\d])([A-Z])/, '\1_\2').tr('-', '_').downcase
162
174
  end
163
175
  end
164
176
  end
@@ -18,8 +18,8 @@ module Sequel
18
18
  # # Make the Album class active_model compliant
19
19
  # Album.plugin :active_model
20
20
  module ActiveModel
21
- # The default string to join composite primary keys with in to_param.
22
21
  DEFAULT_TO_PARAM_JOINER = '-'.freeze
22
+ Sequel::Deprecation.deprecate_constant(self, :DEFAULT_TO_PARAM_JOINER)
23
23
 
24
24
  # ActiveModel compliant error class
25
25
  class Errors < Sequel::Model::Errors
@@ -119,7 +119,7 @@ module Sequel
119
119
 
120
120
  # The string to use to join composite primary key param strings.
121
121
  def to_param_joiner
122
- DEFAULT_TO_PARAM_JOINER
122
+ '-'
123
123
  end
124
124
  end
125
125
  end
@@ -242,6 +242,7 @@ module Sequel
242
242
  # giving the columns to update in each backing database table.
243
243
  # For backwards compatibility.
244
244
  def cti_columns
245
+ Sequel::Deprecation.deprecate("#{self}.cti_columns", "Use #{self}.cti_models to get the models, cti_table_name to get the name for the model, and cti_table_columns to get the columns for the model")
245
246
  h = {}
246
247
  cti_models.each { |m| h[m.cti_table_name] = m.cti_table_columns }
247
248
  h
@@ -123,9 +123,9 @@ module Sequel
123
123
  setters = setter_meths.zip(cov_methods)
124
124
  opts[:decomposer] = proc do
125
125
  if (o = compositions[name]).nil?
126
- setter_meths.each{|sm| get_column_value(sm, nil)}
126
+ setter_meths.each{|sm| set_column_value(sm, nil)}
127
127
  else
128
- setters.each{|sm, cm| get_column_value(sm, o.send(cm))}
128
+ setters.each{|sm, cm| set_column_value(sm, o.send(cm))}
129
129
  end
130
130
  end
131
131
  end
@@ -93,22 +93,34 @@ module Sequel
93
93
  where(r.qualify(r.join_table_alias, r[:left_keys])=>sds.select(*r.qualify(model.table_name, r[:left_primary_key_columns])))
94
94
  ds.where(r.qualified_right_primary_key=>r.send(:apply_filter_by_associations_limit_strategy, mds))
95
95
  when :many_through_many, :one_through_many
96
- fe, *edges = r.edges
97
- edges << r.final_edge
98
- if fre = r.reverse_edges.first
99
- table = fre[:table]
100
- left = fre[:left]
101
- mds = model.join(fe[:table], Array(fe[:right]).zip(Array(fe[:left])), :implicit_qualifier=>model.table_name)
102
- else
103
- table = fe[:table]
104
- left = edges.first[:left]
105
- edges = []
96
+ if r.reverse_edges.empty?
106
97
  mds = r.associated_dataset
98
+ fe = r.edges.first
99
+ selection = Array(r.qualify(fe[:table], r.final_edge[:left]))
100
+ predicate_key = r.qualify(fe[:table], fe[:right])
101
+ else
102
+ mds = model.dataset
103
+ iq = model.table_name
104
+ edges = r.edges.map(&:dup)
105
+ edges << r.final_edge.dup
106
+ edges.each do |e|
107
+ alias_expr = e[:table]
108
+ aliaz = mds.unused_table_alias(e[:table])
109
+ unless aliaz == alias_expr
110
+ alias_expr = Sequel.as(e[:table], aliaz)
111
+ end
112
+ e[:alias] = aliaz
113
+ mds = mds.join(alias_expr, Array(e[:right]).zip(Array(e[:left])), :implicit_qualifier=>iq)
114
+ iq = nil
115
+ end
116
+ fe, f1e, f2e = edges.values_at(0, -1, -2)
117
+ selection = Array(r.qualify(f2e[:alias], f1e[:left]))
118
+ predicate_key = r.qualify(fe[:alias], fe[:right])
107
119
  end
120
+
108
121
  mds = mds.
109
- select(*Array(r.qualify(table, left))).
110
- where(r.qualify(fe[:table], fe[:right])=>sds.select(*r.qualify(model.table_name, r[:left_primary_key_columns])))
111
- edges.each{|e| mds = mds.join(e[:table], Array(e[:right]).zip(Array(e[:left])))}
122
+ select(*selection).
123
+ where(predicate_key=>sds.select(*r.qualify(model.table_name, r[:left_primary_key_columns])))
112
124
  ds.where(r.qualified_right_primary_key=>r.send(:apply_filter_by_associations_limit_strategy, mds))
113
125
  when :pg_array_to_many
114
126
  ds.where(Sequel[r.primary_key=>sds.select{Sequel.pg_array_op(r.qualify(r[:model].table_name, r[:key])).unnest}])
@@ -321,7 +321,7 @@ module Sequel
321
321
  if inc.is_a?(Hash)
322
322
  inc.each do |k, v|
323
323
  if k.is_a?(Sequel::SQL::AliasedExpression)
324
- key_name = k.aliaz.to_s
324
+ key_name = k.alias.to_s
325
325
  k = k.expression
326
326
  else
327
327
  key_name = k.to_s
@@ -346,7 +346,7 @@ module Sequel
346
346
  else
347
347
  Array(inc).each do |c|
348
348
  if c.is_a?(Sequel::SQL::AliasedExpression)
349
- key_name = c.aliaz.to_s
349
+ key_name = c.alias.to_s
350
350
  c = c.expression
351
351
  else
352
352
  key_name = c.to_s