sequel 4.7.0 → 4.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/CHANGELOG +46 -0
 - data/README.rdoc +25 -1
 - data/doc/active_record.rdoc +1 -1
 - data/doc/advanced_associations.rdoc +143 -17
 - data/doc/association_basics.rdoc +80 -59
 - data/doc/release_notes/4.8.0.txt +175 -0
 - data/lib/sequel/adapters/odbc.rb +1 -1
 - data/lib/sequel/adapters/odbc/mssql.rb +4 -2
 - data/lib/sequel/adapters/shared/postgres.rb +19 -3
 - data/lib/sequel/adapters/shared/sqlite.rb +3 -3
 - data/lib/sequel/ast_transformer.rb +1 -1
 - data/lib/sequel/dataset/actions.rb +1 -1
 - data/lib/sequel/dataset/graph.rb +23 -9
 - data/lib/sequel/dataset/misc.rb +2 -2
 - data/lib/sequel/dataset/sql.rb +3 -3
 - data/lib/sequel/extensions/columns_introspection.rb +1 -1
 - data/lib/sequel/extensions/mssql_emulate_lateral_with_apply.rb +1 -1
 - data/lib/sequel/extensions/pg_array.rb +1 -1
 - data/lib/sequel/extensions/pg_array_ops.rb +6 -0
 - data/lib/sequel/extensions/pg_hstore_ops.rb +7 -0
 - data/lib/sequel/extensions/pg_json_ops.rb +5 -0
 - data/lib/sequel/extensions/query.rb +8 -2
 - data/lib/sequel/extensions/to_dot.rb +1 -1
 - data/lib/sequel/model/associations.rb +476 -152
 - data/lib/sequel/plugins/class_table_inheritance.rb +11 -3
 - data/lib/sequel/plugins/dataset_associations.rb +21 -18
 - data/lib/sequel/plugins/many_through_many.rb +87 -20
 - data/lib/sequel/plugins/nested_attributes.rb +12 -0
 - data/lib/sequel/plugins/pg_array_associations.rb +31 -12
 - data/lib/sequel/plugins/single_table_inheritance.rb +9 -1
 - data/lib/sequel/sql.rb +1 -0
 - data/lib/sequel/version.rb +1 -1
 - data/spec/adapters/mssql_spec.rb +2 -2
 - data/spec/adapters/postgres_spec.rb +7 -0
 - data/spec/core/object_graph_spec.rb +250 -196
 - data/spec/extensions/core_refinements_spec.rb +1 -1
 - data/spec/extensions/dataset_associations_spec.rb +100 -6
 - data/spec/extensions/many_through_many_spec.rb +1002 -19
 - data/spec/extensions/nested_attributes_spec.rb +24 -0
 - data/spec/extensions/pg_array_associations_spec.rb +17 -12
 - data/spec/extensions/pg_array_spec.rb +4 -2
 - data/spec/extensions/spec_helper.rb +1 -1
 - data/spec/integration/associations_test.rb +1003 -48
 - data/spec/integration/dataset_test.rb +12 -5
 - data/spec/integration/prepared_statement_test.rb +1 -1
 - data/spec/integration/type_test.rb +1 -1
 - data/spec/model/associations_spec.rb +467 -130
 - data/spec/model/eager_loading_spec.rb +332 -5
 - metadata +5 -3
 
| 
         @@ -1,6 +1,12 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # The query extension adds  
     | 
| 
      
 1 
     | 
    
         
            +
            # The query extension adds a query method which allows
         
     | 
| 
       2 
2 
     | 
    
         
             
            # a different way to construct queries instead of the usual
         
     | 
| 
       3 
     | 
    
         
            -
            # method chaining 
     | 
| 
      
 3 
     | 
    
         
            +
            # method chaining:
         
     | 
| 
      
 4 
     | 
    
         
            +
            #
         
     | 
| 
      
 5 
     | 
    
         
            +
            #   dataset = DB[:items].query do
         
     | 
| 
      
 6 
     | 
    
         
            +
            #     select :x, :y, :z
         
     | 
| 
      
 7 
     | 
    
         
            +
            #     filter{(x > 1) & (y > 2)}
         
     | 
| 
      
 8 
     | 
    
         
            +
            #     reverse :z
         
     | 
| 
      
 9 
     | 
    
         
            +
            #   end
         
     | 
| 
       4 
10 
     | 
    
         
             
            #
         
     | 
| 
       5 
11 
     | 
    
         
             
            # You can load this extension into specific datasets:
         
     | 
| 
       6 
12 
     | 
    
         
             
            #
         
     | 
| 
         @@ -70,12 +70,84 @@ module Sequel 
     | 
|
| 
       70 
70 
     | 
    
         
             
                      end
         
     | 
| 
       71 
71 
     | 
    
         
             
                      ds = ds.order(*self[:order]) if self[:order]
         
     | 
| 
       72 
72 
     | 
    
         
             
                      ds = ds.limit(*self[:limit]) if self[:limit]
         
     | 
| 
       73 
     | 
    
         
            -
                      ds = ds.limit(1) if  
     | 
| 
      
 73 
     | 
    
         
            +
                      ds = ds.limit(1) if limit_to_single_row?
         
     | 
| 
       74 
74 
     | 
    
         
             
                      ds = ds.eager(*self[:eager]) if self[:eager]
         
     | 
| 
       75 
75 
     | 
    
         
             
                      ds = ds.distinct if self[:distinct]
         
     | 
| 
       76 
76 
     | 
    
         
             
                      ds
         
     | 
| 
       77 
77 
     | 
    
         
             
                    end
         
     | 
| 
       78 
     | 
    
         
            -
             
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                    # Apply the eager graph limit strategy to the dataset to graph into the current dataset, or return
         
     | 
| 
      
 80 
     | 
    
         
            +
                    # the dataset unmodified if no SQL limit strategy is needed.
         
     | 
| 
      
 81 
     | 
    
         
            +
                    def apply_eager_graph_limit_strategy(strategy, ds)
         
     | 
| 
      
 82 
     | 
    
         
            +
                      case strategy
         
     | 
| 
      
 83 
     | 
    
         
            +
                      when :distinct_on
         
     | 
| 
      
 84 
     | 
    
         
            +
                        apply_distinct_on_eager_limit_strategy(ds.order_prepend(*self[:order]))
         
     | 
| 
      
 85 
     | 
    
         
            +
                      when :window_function
         
     | 
| 
      
 86 
     | 
    
         
            +
                        apply_window_function_eager_limit_strategy(ds.order_prepend(*self[:order])).select(*ds.columns)
         
     | 
| 
      
 87 
     | 
    
         
            +
                      else
         
     | 
| 
      
 88 
     | 
    
         
            +
                        ds
         
     | 
| 
      
 89 
     | 
    
         
            +
                      end
         
     | 
| 
      
 90 
     | 
    
         
            +
                    end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                    # Apply an eager limit strategy to the dataset, or return the dataset
         
     | 
| 
      
 93 
     | 
    
         
            +
                    # unmodified if it doesn't need an eager limit strategy.
         
     | 
| 
      
 94 
     | 
    
         
            +
                    def apply_eager_limit_strategy(ds)
         
     | 
| 
      
 95 
     | 
    
         
            +
                      case eager_limit_strategy
         
     | 
| 
      
 96 
     | 
    
         
            +
                      when :distinct_on
         
     | 
| 
      
 97 
     | 
    
         
            +
                        apply_distinct_on_eager_limit_strategy(ds)
         
     | 
| 
      
 98 
     | 
    
         
            +
                      when :window_function
         
     | 
| 
      
 99 
     | 
    
         
            +
                        apply_window_function_eager_limit_strategy(ds)
         
     | 
| 
      
 100 
     | 
    
         
            +
                      else
         
     | 
| 
      
 101 
     | 
    
         
            +
                        ds
         
     | 
| 
      
 102 
     | 
    
         
            +
                      end
         
     | 
| 
      
 103 
     | 
    
         
            +
                    end
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
                    # Use DISTINCT ON and ORDER BY clauses to limit the results to the first record with matching keys.
         
     | 
| 
      
 106 
     | 
    
         
            +
                    def apply_distinct_on_eager_limit_strategy(ds)
         
     | 
| 
      
 107 
     | 
    
         
            +
                      keys = predicate_key
         
     | 
| 
      
 108 
     | 
    
         
            +
                      ds.distinct(*keys).order_prepend(*keys)
         
     | 
| 
      
 109 
     | 
    
         
            +
                    end
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
                    # Use a window function to limit the results of the eager loading dataset.
         
     | 
| 
      
 112 
     | 
    
         
            +
                    def apply_window_function_eager_limit_strategy(ds)
         
     | 
| 
      
 113 
     | 
    
         
            +
                      rn = ds.row_number_column 
         
     | 
| 
      
 114 
     | 
    
         
            +
                      limit, offset = limit_and_offset
         
     | 
| 
      
 115 
     | 
    
         
            +
                      ds = ds.unordered.select_append{|o| o.row_number{}.over(:partition=>predicate_key, :order=>ds.opts[:order]).as(rn)}.from_self
         
     | 
| 
      
 116 
     | 
    
         
            +
                      ds = if !returns_array?
         
     | 
| 
      
 117 
     | 
    
         
            +
                        ds.where(rn => offset ? offset+1 : 1)
         
     | 
| 
      
 118 
     | 
    
         
            +
                      elsif offset
         
     | 
| 
      
 119 
     | 
    
         
            +
                        offset += 1
         
     | 
| 
      
 120 
     | 
    
         
            +
                        if limit
         
     | 
| 
      
 121 
     | 
    
         
            +
                          ds.where(rn => (offset...(offset+limit))) 
         
     | 
| 
      
 122 
     | 
    
         
            +
                        else
         
     | 
| 
      
 123 
     | 
    
         
            +
                          ds.where{SQL::Identifier.new(rn) >= offset} 
         
     | 
| 
      
 124 
     | 
    
         
            +
                        end
         
     | 
| 
      
 125 
     | 
    
         
            +
                      else
         
     | 
| 
      
 126 
     | 
    
         
            +
                        ds.where{SQL::Identifier.new(rn) <= limit} 
         
     | 
| 
      
 127 
     | 
    
         
            +
                      end
         
     | 
| 
      
 128 
     | 
    
         
            +
                    end
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
                    # If the ruby eager limit strategy is being used, slice the array using the slice
         
     | 
| 
      
 131 
     | 
    
         
            +
                    # range to return the object(s) at the correct offset/limit.
         
     | 
| 
      
 132 
     | 
    
         
            +
                    def apply_ruby_eager_limit_strategy(rows)
         
     | 
| 
      
 133 
     | 
    
         
            +
                      if eager_limit_strategy == :ruby
         
     | 
| 
      
 134 
     | 
    
         
            +
                        name = self[:name]
         
     | 
| 
      
 135 
     | 
    
         
            +
                        if returns_array?
         
     | 
| 
      
 136 
     | 
    
         
            +
                          range = slice_range
         
     | 
| 
      
 137 
     | 
    
         
            +
                          rows.each{|o| o.associations[name] = o.associations[name][range] || []}
         
     | 
| 
      
 138 
     | 
    
         
            +
                        elsif slice_range
         
     | 
| 
      
 139 
     | 
    
         
            +
                          offset = slice_range.begin
         
     | 
| 
      
 140 
     | 
    
         
            +
                          rows.each{|o| o.associations[name] = o.associations[name][offset]}
         
     | 
| 
      
 141 
     | 
    
         
            +
                        end
         
     | 
| 
      
 142 
     | 
    
         
            +
                      end
         
     | 
| 
      
 143 
     | 
    
         
            +
                    end
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
                    # Whether the associations cache should use an array when storing the
         
     | 
| 
      
 146 
     | 
    
         
            +
                    # associated records during eager loading.
         
     | 
| 
      
 147 
     | 
    
         
            +
                    def assign_singular?
         
     | 
| 
      
 148 
     | 
    
         
            +
                      !returns_array?
         
     | 
| 
      
 149 
     | 
    
         
            +
                    end
         
     | 
| 
      
 150 
     | 
    
         
            +
             
     | 
| 
       79 
151 
     | 
    
         
             
                    # Whether this association can have associated objects, given the current
         
     | 
| 
       80 
152 
     | 
    
         
             
                    # object.  Should be false if obj cannot have associated objects because
         
     | 
| 
       81 
153 
     | 
    
         
             
                    # the necessary key columns are NULL.
         
     | 
| 
         @@ -83,6 +155,12 @@ module Sequel 
     | 
|
| 
       83 
155 
     | 
    
         
             
                      true
         
     | 
| 
       84 
156 
     | 
    
         
             
                    end
         
     | 
| 
       85 
157 
     | 
    
         | 
| 
      
 158 
     | 
    
         
            +
                    # Whether you are able to clone from the given association type to the current
         
     | 
| 
      
 159 
     | 
    
         
            +
                    # association type, true by default only if the types match.
         
     | 
| 
      
 160 
     | 
    
         
            +
                    def cloneable?(ref)
         
     | 
| 
      
 161 
     | 
    
         
            +
                      ref[:type] == self[:type]
         
     | 
| 
      
 162 
     | 
    
         
            +
                    end
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
       86 
164 
     | 
    
         
             
                    # Name symbol for the dataset association method
         
     | 
| 
       87 
165 
     | 
    
         
             
                    def dataset_method
         
     | 
| 
       88 
166 
     | 
    
         
             
                      :"#{self[:name]}_dataset"
         
     | 
| 
         @@ -93,23 +171,41 @@ module Sequel 
     | 
|
| 
       93 
171 
     | 
    
         
             
                      true
         
     | 
| 
       94 
172 
     | 
    
         
             
                    end
         
     | 
| 
       95 
173 
     | 
    
         | 
| 
      
 174 
     | 
    
         
            +
                    # Return the symbol used for the row number column if the window function
         
     | 
| 
      
 175 
     | 
    
         
            +
                    # eager limit strategy is being used, or nil otherwise.
         
     | 
| 
      
 176 
     | 
    
         
            +
                    def delete_row_number_column(ds)
         
     | 
| 
      
 177 
     | 
    
         
            +
                      if eager_limit_strategy == :window_function
         
     | 
| 
      
 178 
     | 
    
         
            +
                        ds.row_number_column 
         
     | 
| 
      
 179 
     | 
    
         
            +
                      end
         
     | 
| 
      
 180 
     | 
    
         
            +
                    end
         
     | 
| 
      
 181 
     | 
    
         
            +
             
     | 
| 
      
 182 
     | 
    
         
            +
                    # The eager_graph limit strategy to use for this dataset
         
     | 
| 
      
 183 
     | 
    
         
            +
                    def eager_graph_limit_strategy(strategy)
         
     | 
| 
      
 184 
     | 
    
         
            +
                      if self[:limit] || !returns_array?
         
     | 
| 
      
 185 
     | 
    
         
            +
                        strategy = strategy[self[:name]] if strategy.is_a?(Hash)
         
     | 
| 
      
 186 
     | 
    
         
            +
                        case strategy
         
     | 
| 
      
 187 
     | 
    
         
            +
                        when true
         
     | 
| 
      
 188 
     | 
    
         
            +
                          true_eager_limit_strategy
         
     | 
| 
      
 189 
     | 
    
         
            +
                        when Symbol
         
     | 
| 
      
 190 
     | 
    
         
            +
                          strategy
         
     | 
| 
      
 191 
     | 
    
         
            +
                        else
         
     | 
| 
      
 192 
     | 
    
         
            +
                          if returns_array? || offset
         
     | 
| 
      
 193 
     | 
    
         
            +
                            :ruby
         
     | 
| 
      
 194 
     | 
    
         
            +
                          end
         
     | 
| 
      
 195 
     | 
    
         
            +
                        end
         
     | 
| 
      
 196 
     | 
    
         
            +
                      end
         
     | 
| 
      
 197 
     | 
    
         
            +
                    end
         
     | 
| 
      
 198 
     | 
    
         
            +
                    
         
     | 
| 
       96 
199 
     | 
    
         
             
                    # The eager limit strategy to use for this dataset.
         
     | 
| 
       97 
200 
     | 
    
         
             
                    def eager_limit_strategy
         
     | 
| 
       98 
201 
     | 
    
         
             
                      cached_fetch(:_eager_limit_strategy) do
         
     | 
| 
       99 
     | 
    
         
            -
                        if self[:limit]
         
     | 
| 
       100 
     | 
    
         
            -
                          case s = cached_fetch(:eager_limit_strategy){ 
     | 
| 
      
 202 
     | 
    
         
            +
                        if self[:limit] || !returns_array?
         
     | 
| 
      
 203 
     | 
    
         
            +
                          case s = cached_fetch(:eager_limit_strategy){default_eager_limit_strategy}
         
     | 
| 
       101 
204 
     | 
    
         
             
                          when true
         
     | 
| 
       102 
     | 
    
         
            -
                             
     | 
| 
       103 
     | 
    
         
            -
                            if ds.supports_window_functions?
         
     | 
| 
       104 
     | 
    
         
            -
                              :window_function
         
     | 
| 
       105 
     | 
    
         
            -
                            else
         
     | 
| 
       106 
     | 
    
         
            -
                              :ruby
         
     | 
| 
       107 
     | 
    
         
            -
                            end
         
     | 
| 
      
 205 
     | 
    
         
            +
                            true_eager_limit_strategy
         
     | 
| 
       108 
206 
     | 
    
         
             
                          else
         
     | 
| 
       109 
207 
     | 
    
         
             
                            s
         
     | 
| 
       110 
208 
     | 
    
         
             
                          end
         
     | 
| 
       111 
     | 
    
         
            -
                        else
         
     | 
| 
       112 
     | 
    
         
            -
                          nil
         
     | 
| 
       113 
209 
     | 
    
         
             
                        end
         
     | 
| 
       114 
210 
     | 
    
         
             
                      end
         
     | 
| 
       115 
211 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -140,7 +236,7 @@ module Sequel 
     | 
|
| 
       140 
236 
     | 
    
         
             
                    # Whether additional conditions should be added when using the filter
         
     | 
| 
       141 
237 
     | 
    
         
             
                    # by associations support.
         
     | 
| 
       142 
238 
     | 
    
         
             
                    def filter_by_associations_add_conditions?
         
     | 
| 
       143 
     | 
    
         
            -
                      self[:conditions] || self[:eager_block]
         
     | 
| 
      
 239 
     | 
    
         
            +
                      self[:conditions] || self[:eager_block] || self[:limit]
         
     | 
| 
       144 
240 
     | 
    
         
             
                    end
         
     | 
| 
       145 
241 
     | 
    
         | 
| 
       146 
242 
     | 
    
         
             
                    # The expression to use for the additional conditions to be added for
         
     | 
| 
         @@ -158,6 +254,16 @@ module Sequel 
     | 
|
| 
       158 
254 
     | 
    
         
             
                      false
         
     | 
| 
       159 
255 
     | 
    
         
             
                    end
         
     | 
| 
       160 
256 
     | 
    
         | 
| 
      
 257 
     | 
    
         
            +
                    # Initialize the associations cache for the current association for the given objects.
         
     | 
| 
      
 258 
     | 
    
         
            +
                    def initialize_association_cache(objects)
         
     | 
| 
      
 259 
     | 
    
         
            +
                      name = self[:name]
         
     | 
| 
      
 260 
     | 
    
         
            +
                      if assign_singular?
         
     | 
| 
      
 261 
     | 
    
         
            +
                        objects.each{|object| object.associations[name] = nil}
         
     | 
| 
      
 262 
     | 
    
         
            +
                      else
         
     | 
| 
      
 263 
     | 
    
         
            +
                        objects.each{|object| object.associations[name] = []}
         
     | 
| 
      
 264 
     | 
    
         
            +
                      end
         
     | 
| 
      
 265 
     | 
    
         
            +
                    end
         
     | 
| 
      
 266 
     | 
    
         
            +
             
     | 
| 
       161 
267 
     | 
    
         
             
                    # The limit and offset for this association (returned as a two element array).
         
     | 
| 
       162 
268 
     | 
    
         
             
                    def limit_and_offset
         
     | 
| 
       163 
269 
     | 
    
         
             
                      if (v = self[:limit]).is_a?(Array)
         
     | 
| 
         @@ -319,6 +425,48 @@ module Sequel 
     | 
|
| 
       319 
425 
     | 
    
         
             
                      end
         
     | 
| 
       320 
426 
     | 
    
         
             
                    end
         
     | 
| 
       321 
427 
     | 
    
         | 
| 
      
 428 
     | 
    
         
            +
                    # Apply a limit strategy to the given dataset so that filter by
         
     | 
| 
      
 429 
     | 
    
         
            +
                    # associations works with a limited dataset.
         
     | 
| 
      
 430 
     | 
    
         
            +
                    def apply_filter_by_associations_limit_strategy(ds)
         
     | 
| 
      
 431 
     | 
    
         
            +
                      case eager_limit_strategy
         
     | 
| 
      
 432 
     | 
    
         
            +
                      when :distinct_on
         
     | 
| 
      
 433 
     | 
    
         
            +
                        apply_filter_by_associations_distinct_on_limit_strategy(ds)
         
     | 
| 
      
 434 
     | 
    
         
            +
                      when :window_function
         
     | 
| 
      
 435 
     | 
    
         
            +
                        apply_filter_by_associations_window_function_limit_strategy(ds)
         
     | 
| 
      
 436 
     | 
    
         
            +
                      else
         
     | 
| 
      
 437 
     | 
    
         
            +
                        ds
         
     | 
| 
      
 438 
     | 
    
         
            +
                      end
         
     | 
| 
      
 439 
     | 
    
         
            +
                    end
         
     | 
| 
      
 440 
     | 
    
         
            +
             
     | 
| 
      
 441 
     | 
    
         
            +
                    # Apply a distinct on eager limit strategy using IN with a subquery
         
     | 
| 
      
 442 
     | 
    
         
            +
                    # that uses DISTINCT ON to ensure only the first matching record for
         
     | 
| 
      
 443 
     | 
    
         
            +
                    # each key is included.
         
     | 
| 
      
 444 
     | 
    
         
            +
                    def apply_filter_by_associations_distinct_on_limit_strategy(ds)
         
     | 
| 
      
 445 
     | 
    
         
            +
                      k = filter_by_associations_limit_key 
         
     | 
| 
      
 446 
     | 
    
         
            +
                      ds.where(k=>apply_distinct_on_eager_limit_strategy(filter_by_associations_limit_subquery.select(*k)))
         
     | 
| 
      
 447 
     | 
    
         
            +
                    end
         
     | 
| 
      
 448 
     | 
    
         
            +
             
     | 
| 
      
 449 
     | 
    
         
            +
                    # Apply a distinct on eager limit strategy using IN with a subquery
         
     | 
| 
      
 450 
     | 
    
         
            +
                    # that uses a filter on the row_number window function to ensure
         
     | 
| 
      
 451 
     | 
    
         
            +
                    # that only rows inside the limit are returned.
         
     | 
| 
      
 452 
     | 
    
         
            +
                    def apply_filter_by_associations_window_function_limit_strategy(ds)
         
     | 
| 
      
 453 
     | 
    
         
            +
                      ds.where(filter_by_associations_limit_key=>apply_window_function_eager_limit_strategy(filter_by_associations_limit_subquery.select(*filter_by_associations_limit_alias_key)).select(*filter_by_associations_limit_aliases))
         
     | 
| 
      
 454 
     | 
    
         
            +
                    end
         
     | 
| 
      
 455 
     | 
    
         
            +
             
     | 
| 
      
 456 
     | 
    
         
            +
                    # The associated_dataset with the eager_block callback already applied.
         
     | 
| 
      
 457 
     | 
    
         
            +
                    def associated_eager_dataset
         
     | 
| 
      
 458 
     | 
    
         
            +
                      cached_fetch(:associated_eager_dataset) do
         
     | 
| 
      
 459 
     | 
    
         
            +
                        ds = associated_dataset
         
     | 
| 
      
 460 
     | 
    
         
            +
                        ds = self[:eager_block].call(ds) if self[:eager_block]
         
     | 
| 
      
 461 
     | 
    
         
            +
                        ds
         
     | 
| 
      
 462 
     | 
    
         
            +
                      end
         
     | 
| 
      
 463 
     | 
    
         
            +
                    end
         
     | 
| 
      
 464 
     | 
    
         
            +
             
     | 
| 
      
 465 
     | 
    
         
            +
                    # The default eager limit strategy to use for this association
         
     | 
| 
      
 466 
     | 
    
         
            +
                    def default_eager_limit_strategy
         
     | 
| 
      
 467 
     | 
    
         
            +
                      self[:model].default_eager_limit_strategy || :ruby
         
     | 
| 
      
 468 
     | 
    
         
            +
                    end
         
     | 
| 
      
 469 
     | 
    
         
            +
             
     | 
| 
       322 
470 
     | 
    
         
             
                    # The conditions to add to the filter by associations conditions
         
     | 
| 
       323 
471 
     | 
    
         
             
                    # subquery to restrict it to to the object(s) that was used as the
         
     | 
| 
       324 
472 
     | 
    
         
             
                    # filter value.
         
     | 
| 
         @@ -339,13 +487,28 @@ module Sequel 
     | 
|
| 
       339 
487 
     | 
    
         
             
                    # values.
         
     | 
| 
       340 
488 
     | 
    
         
             
                    def filter_by_associations_conditions_dataset
         
     | 
| 
       341 
489 
     | 
    
         
             
                      cached_fetch(:filter_by_associations_conditions_dataset) do
         
     | 
| 
       342 
     | 
    
         
            -
                        ds =  
     | 
| 
      
 490 
     | 
    
         
            +
                        ds = associated_eager_dataset.unordered.unlimited
         
     | 
| 
       343 
491 
     | 
    
         
             
                        ds = filter_by_associations_add_conditions_dataset_filter(ds)
         
     | 
| 
       344 
     | 
    
         
            -
                        ds =  
     | 
| 
      
 492 
     | 
    
         
            +
                        ds = apply_filter_by_associations_limit_strategy(ds)
         
     | 
| 
       345 
493 
     | 
    
         
             
                        ds
         
     | 
| 
       346 
494 
     | 
    
         
             
                      end
         
     | 
| 
       347 
495 
     | 
    
         
             
                    end
         
     | 
| 
       348 
496 
     | 
    
         | 
| 
      
 497 
     | 
    
         
            +
                    # The base subquery to use when filtering by limited associations
         
     | 
| 
      
 498 
     | 
    
         
            +
                    def filter_by_associations_limit_subquery
         
     | 
| 
      
 499 
     | 
    
         
            +
                      associated_eager_dataset.unlimited
         
     | 
| 
      
 500 
     | 
    
         
            +
                    end
         
     | 
| 
      
 501 
     | 
    
         
            +
             
     | 
| 
      
 502 
     | 
    
         
            +
                    # Whether to limit the associated dataset to a single row.
         
     | 
| 
      
 503 
     | 
    
         
            +
                    def limit_to_single_row?
         
     | 
| 
      
 504 
     | 
    
         
            +
                      !returns_array?
         
     | 
| 
      
 505 
     | 
    
         
            +
                    end
         
     | 
| 
      
 506 
     | 
    
         
            +
                    
         
     | 
| 
      
 507 
     | 
    
         
            +
                    # Any offset to use for this association (or nil if there is no offset).
         
     | 
| 
      
 508 
     | 
    
         
            +
                    def offset
         
     | 
| 
      
 509 
     | 
    
         
            +
                      limit_and_offset.last
         
     | 
| 
      
 510 
     | 
    
         
            +
                    end
         
     | 
| 
      
 511 
     | 
    
         
            +
             
     | 
| 
       349 
512 
     | 
    
         
             
                    # Whether the given association reflection is possible reciprocal
         
     | 
| 
       350 
513 
     | 
    
         
             
                    # association for the current association reflection.
         
     | 
| 
       351 
514 
     | 
    
         
             
                    def reciprocal_association?(assoc_reflect)
         
     | 
| 
         @@ -360,6 +523,16 @@ module Sequel 
     | 
|
| 
       360 
523 
     | 
    
         
             
                    def transform(s)
         
     | 
| 
       361 
524 
     | 
    
         
             
                      s.is_a?(Array) ? s.map(&Proc.new) : (yield s)
         
     | 
| 
       362 
525 
     | 
    
         
             
                    end
         
     | 
| 
      
 526 
     | 
    
         
            +
             
     | 
| 
      
 527 
     | 
    
         
            +
                    # The eager limit strategy used when true is given as the value, choosing the
         
     | 
| 
      
 528 
     | 
    
         
            +
                    # best strategy based on what the database supports.
         
     | 
| 
      
 529 
     | 
    
         
            +
                    def true_eager_limit_strategy
         
     | 
| 
      
 530 
     | 
    
         
            +
                      if associated_class.dataset.supports_window_functions?
         
     | 
| 
      
 531 
     | 
    
         
            +
                        :window_function
         
     | 
| 
      
 532 
     | 
    
         
            +
                      else
         
     | 
| 
      
 533 
     | 
    
         
            +
                        :ruby
         
     | 
| 
      
 534 
     | 
    
         
            +
                      end
         
     | 
| 
      
 535 
     | 
    
         
            +
                    end
         
     | 
| 
       363 
536 
     | 
    
         
             
                  end
         
     | 
| 
       364 
537 
     | 
    
         | 
| 
       365 
538 
     | 
    
         
             
                  class ManyToOneAssociationReflection < AssociationReflection
         
     | 
| 
         @@ -388,6 +561,11 @@ module Sequel 
     | 
|
| 
       388 
561 
     | 
    
         
             
                      self[:key].nil?
         
     | 
| 
       389 
562 
     | 
    
         
             
                    end
         
     | 
| 
       390 
563 
     | 
    
         | 
| 
      
 564 
     | 
    
         
            +
                    # many_to_one associations don't need an eager_graph limit strategy
         
     | 
| 
      
 565 
     | 
    
         
            +
                    def eager_graph_limit_strategy(_)
         
     | 
| 
      
 566 
     | 
    
         
            +
                      nil
         
     | 
| 
      
 567 
     | 
    
         
            +
                    end
         
     | 
| 
      
 568 
     | 
    
         
            +
             
     | 
| 
       391 
569 
     | 
    
         
             
                    # many_to_one associations don't need an eager limit strategy
         
     | 
| 
       392 
570 
     | 
    
         
             
                    def eager_limit_strategy
         
     | 
| 
       393 
571 
     | 
    
         
             
                      nil
         
     | 
| 
         @@ -454,6 +632,12 @@ module Sequel 
     | 
|
| 
       454 
632 
     | 
    
         
             
                      qualify(self[:model].table_name, self[:key_column])
         
     | 
| 
       455 
633 
     | 
    
         
             
                    end
         
     | 
| 
       456 
634 
     | 
    
         | 
| 
      
 635 
     | 
    
         
            +
                    # many_to_one associations do not need to be limited to a single row if they
         
     | 
| 
      
 636 
     | 
    
         
            +
                    # explicitly do not have a key.
         
     | 
| 
      
 637 
     | 
    
         
            +
                    def limit_to_single_row?
         
     | 
| 
      
 638 
     | 
    
         
            +
                      super && self[:key]
         
     | 
| 
      
 639 
     | 
    
         
            +
                    end
         
     | 
| 
      
 640 
     | 
    
         
            +
                    
         
     | 
| 
       457 
641 
     | 
    
         
             
                    def reciprocal_association?(assoc_reflect)
         
     | 
| 
       458 
642 
     | 
    
         
             
                      super && self[:keys] == assoc_reflect[:keys] && primary_key == assoc_reflect.primary_key
         
     | 
| 
       459 
643 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -479,6 +663,11 @@ module Sequel 
     | 
|
| 
       479 
663 
     | 
    
         
             
                      !self[:primary_keys].any?{|k| obj.send(k).nil?}
         
     | 
| 
       480 
664 
     | 
    
         
             
                    end
         
     | 
| 
       481 
665 
     | 
    
         | 
| 
      
 666 
     | 
    
         
            +
                    # one_to_many and one_to_one associations can be clones
         
     | 
| 
      
 667 
     | 
    
         
            +
                    def cloneable?(ref)
         
     | 
| 
      
 668 
     | 
    
         
            +
                      ref[:type] == :one_to_many || ref[:type] == :one_to_one
         
     | 
| 
      
 669 
     | 
    
         
            +
                    end
         
     | 
| 
      
 670 
     | 
    
         
            +
             
     | 
| 
       482 
671 
     | 
    
         
             
                    # Default foreign key name symbol for key in associated table that points to
         
     | 
| 
       483 
672 
     | 
    
         
             
                    # current table's primary key.
         
     | 
| 
       484 
673 
     | 
    
         
             
                    def default_key
         
     | 
| 
         @@ -538,6 +727,18 @@ module Sequel 
     | 
|
| 
       538 
727 
     | 
    
         
             
                      qualify(self[:model].table_name, self[:primary_key_column])
         
     | 
| 
       539 
728 
     | 
    
         
             
                    end
         
     | 
| 
       540 
729 
     | 
    
         | 
| 
      
 730 
     | 
    
         
            +
                    def filter_by_associations_limit_alias_key
         
     | 
| 
      
 731 
     | 
    
         
            +
                      Array(filter_by_associations_limit_key)
         
     | 
| 
      
 732 
     | 
    
         
            +
                    end
         
     | 
| 
      
 733 
     | 
    
         
            +
             
     | 
| 
      
 734 
     | 
    
         
            +
                    def filter_by_associations_limit_aliases
         
     | 
| 
      
 735 
     | 
    
         
            +
                      filter_by_associations_limit_alias_key.map{|v| v.column}
         
     | 
| 
      
 736 
     | 
    
         
            +
                    end
         
     | 
| 
      
 737 
     | 
    
         
            +
             
     | 
| 
      
 738 
     | 
    
         
            +
                    def filter_by_associations_limit_key
         
     | 
| 
      
 739 
     | 
    
         
            +
                      qualify(associated_class.table_name, associated_class.primary_key)
         
     | 
| 
      
 740 
     | 
    
         
            +
                    end
         
     | 
| 
      
 741 
     | 
    
         
            +
             
     | 
| 
       541 
742 
     | 
    
         
             
                    def reciprocal_association?(assoc_reflect)
         
     | 
| 
       542 
743 
     | 
    
         
             
                      super && self[:keys] == assoc_reflect[:keys] && primary_key == assoc_reflect.primary_key
         
     | 
| 
       543 
744 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -547,46 +748,48 @@ module Sequel 
     | 
|
| 
       547 
748 
     | 
    
         
             
                      :many_to_one
         
     | 
| 
       548 
749 
     | 
    
         
             
                    end
         
     | 
| 
       549 
750 
     | 
    
         
             
                  end
         
     | 
| 
       550 
     | 
    
         
            -
             
     | 
| 
       551 
     | 
    
         
            -
                   
     | 
| 
       552 
     | 
    
         
            -
             
     | 
| 
       553 
     | 
    
         
            -
             
     | 
| 
       554 
     | 
    
         
            -
                    #  
     | 
| 
       555 
     | 
    
         
            -
                    #  
     | 
| 
       556 
     | 
    
         
            -
                     
     | 
| 
       557 
     | 
    
         
            -
             
     | 
| 
       558 
     | 
    
         
            -
             
     | 
| 
       559 
     | 
    
         
            -
                        case s = self.fetch(:eager_limit_strategy){(self[:model].default_eager_limit_strategy || :ruby) if offset}
         
     | 
| 
       560 
     | 
    
         
            -
                        when Symbol
         
     | 
| 
       561 
     | 
    
         
            -
                          s
         
     | 
| 
       562 
     | 
    
         
            -
                        when true
         
     | 
| 
       563 
     | 
    
         
            -
                          ds = associated_class.dataset
         
     | 
| 
       564 
     | 
    
         
            -
                          if ds.supports_ordered_distinct_on? && offset.nil?
         
     | 
| 
       565 
     | 
    
         
            -
                            :distinct_on
         
     | 
| 
       566 
     | 
    
         
            -
                          elsif ds.supports_window_functions?
         
     | 
| 
       567 
     | 
    
         
            -
                            :window_function
         
     | 
| 
       568 
     | 
    
         
            -
                          else
         
     | 
| 
       569 
     | 
    
         
            -
                            :ruby
         
     | 
| 
       570 
     | 
    
         
            -
                          end
         
     | 
| 
       571 
     | 
    
         
            -
                        else
         
     | 
| 
       572 
     | 
    
         
            -
                          nil
         
     | 
| 
       573 
     | 
    
         
            -
                        end
         
     | 
| 
       574 
     | 
    
         
            -
                      end
         
     | 
| 
      
 751 
     | 
    
         
            +
             
     | 
| 
      
 752 
     | 
    
         
            +
                  # Methods that turn an association that returns multiple objects into an association that
         
     | 
| 
      
 753 
     | 
    
         
            +
                  # returns a single object.
         
     | 
| 
      
 754 
     | 
    
         
            +
                  module SingularAssociationReflection
         
     | 
| 
      
 755 
     | 
    
         
            +
                    # Singular associations do not assign singular if they are using the ruby eager limit strategy
         
     | 
| 
      
 756 
     | 
    
         
            +
                    # and have a slice range, since they need to store the array of associated objects in order to
         
     | 
| 
      
 757 
     | 
    
         
            +
                    # pick the correct one with an offset.
         
     | 
| 
      
 758 
     | 
    
         
            +
                    def assign_singular?
         
     | 
| 
      
 759 
     | 
    
         
            +
                      super && (eager_limit_strategy != :ruby || !slice_range)
         
     | 
| 
       575 
760 
     | 
    
         
             
                    end
         
     | 
| 
       576 
761 
     | 
    
         | 
| 
       577 
     | 
    
         
            -
                    #  
     | 
| 
       578 
     | 
    
         
            -
                     
     | 
| 
       579 
     | 
    
         
            -
             
     | 
| 
       580 
     | 
    
         
            -
             
     | 
| 
       581 
     | 
    
         
            -
                      else
         
     | 
| 
       582 
     | 
    
         
            -
                        [v, nil]
         
     | 
| 
       583 
     | 
    
         
            -
                      end
         
     | 
| 
      
 762 
     | 
    
         
            +
                    # Add conditions when filtering by singular associations with orders, since the
         
     | 
| 
      
 763 
     | 
    
         
            +
                    # underlying relationship is probably not one-to-one.
         
     | 
| 
      
 764 
     | 
    
         
            +
                    def filter_by_associations_add_conditions?
         
     | 
| 
      
 765 
     | 
    
         
            +
                      super || self[:order]
         
     | 
| 
       584 
766 
     | 
    
         
             
                    end
         
     | 
| 
       585 
767 
     | 
    
         | 
| 
       586 
     | 
    
         
            -
                    #  
     | 
| 
      
 768 
     | 
    
         
            +
                    # Singular associations always return a single object, not an array.
         
     | 
| 
       587 
769 
     | 
    
         
             
                    def returns_array?
         
     | 
| 
       588 
770 
     | 
    
         
             
                      false
         
     | 
| 
       589 
771 
     | 
    
         
             
                    end
         
     | 
| 
      
 772 
     | 
    
         
            +
             
     | 
| 
      
 773 
     | 
    
         
            +
                    private
         
     | 
| 
      
 774 
     | 
    
         
            +
             
     | 
| 
      
 775 
     | 
    
         
            +
                    # Only use a eager limit strategy by default if there is an offset or an order.
         
     | 
| 
      
 776 
     | 
    
         
            +
                    def default_eager_limit_strategy
         
     | 
| 
      
 777 
     | 
    
         
            +
                      super if self[:order] || offset
         
     | 
| 
      
 778 
     | 
    
         
            +
                    end
         
     | 
| 
      
 779 
     | 
    
         
            +
             
     | 
| 
      
 780 
     | 
    
         
            +
                    # Use the DISTINCT ON eager limit strategy for true if the database supports it.
         
     | 
| 
      
 781 
     | 
    
         
            +
                    def true_eager_limit_strategy
         
     | 
| 
      
 782 
     | 
    
         
            +
                      if associated_class.dataset.supports_ordered_distinct_on? && !offset
         
     | 
| 
      
 783 
     | 
    
         
            +
                        :distinct_on
         
     | 
| 
      
 784 
     | 
    
         
            +
                      else
         
     | 
| 
      
 785 
     | 
    
         
            +
                        super
         
     | 
| 
      
 786 
     | 
    
         
            +
                      end
         
     | 
| 
      
 787 
     | 
    
         
            +
                    end
         
     | 
| 
      
 788 
     | 
    
         
            +
                  end
         
     | 
| 
      
 789 
     | 
    
         
            +
                  
         
     | 
| 
      
 790 
     | 
    
         
            +
                  class OneToOneAssociationReflection < OneToManyAssociationReflection
         
     | 
| 
      
 791 
     | 
    
         
            +
                    ASSOCIATION_TYPES[:one_to_one] = self
         
     | 
| 
      
 792 
     | 
    
         
            +
                    include SingularAssociationReflection
         
     | 
| 
       590 
793 
     | 
    
         
             
                  end
         
     | 
| 
       591 
794 
     | 
    
         | 
| 
       592 
795 
     | 
    
         
             
                  class ManyToManyAssociationReflection < AssociationReflection
         
     | 
| 
         @@ -597,6 +800,17 @@ module Sequel 
     | 
|
| 
       597 
800 
     | 
    
         
             
                      self[:left_key_alias]
         
     | 
| 
       598 
801 
     | 
    
         
             
                    end
         
     | 
| 
       599 
802 
     | 
    
         | 
| 
      
 803 
     | 
    
         
            +
                    # Array of associated keys used when eagerly loading.
         
     | 
| 
      
 804 
     | 
    
         
            +
                    def associated_key_array
         
     | 
| 
      
 805 
     | 
    
         
            +
                      cached_fetch(:associated_key_array) do
         
     | 
| 
      
 806 
     | 
    
         
            +
                        if self[:uses_left_composite_keys]
         
     | 
| 
      
 807 
     | 
    
         
            +
                          associated_key_alias.zip(predicate_keys).map{|a, k| SQL::AliasedExpression.new(k, a)}
         
     | 
| 
      
 808 
     | 
    
         
            +
                        else
         
     | 
| 
      
 809 
     | 
    
         
            +
                          [SQL::AliasedExpression.new(predicate_key, associated_key_alias)]
         
     | 
| 
      
 810 
     | 
    
         
            +
                        end
         
     | 
| 
      
 811 
     | 
    
         
            +
                      end
         
     | 
| 
      
 812 
     | 
    
         
            +
                    end
         
     | 
| 
      
 813 
     | 
    
         
            +
             
     | 
| 
       600 
814 
     | 
    
         
             
                    # The column to use for the associated key when eagerly loading
         
     | 
| 
       601 
815 
     | 
    
         
             
                    def associated_key_column
         
     | 
| 
       602 
816 
     | 
    
         
             
                      self[:left_key]
         
     | 
| 
         @@ -613,6 +827,11 @@ module Sequel 
     | 
|
| 
       613 
827 
     | 
    
         
             
                      !self[:left_primary_keys].any?{|k| obj.send(k).nil?}
         
     | 
| 
       614 
828 
     | 
    
         
             
                    end
         
     | 
| 
       615 
829 
     | 
    
         | 
| 
      
 830 
     | 
    
         
            +
                    # one_through_one and many_to_many associations can be clones
         
     | 
| 
      
 831 
     | 
    
         
            +
                    def cloneable?(ref)
         
     | 
| 
      
 832 
     | 
    
         
            +
                      ref[:type] == :many_to_many || ref[:type] == :one_through_one
         
     | 
| 
      
 833 
     | 
    
         
            +
                    end
         
     | 
| 
      
 834 
     | 
    
         
            +
             
     | 
| 
       616 
835 
     | 
    
         
             
                    # The default associated key alias(es) to use when eager loading
         
     | 
| 
       617 
836 
     | 
    
         
             
                    # associations via eager.
         
     | 
| 
       618 
837 
     | 
    
         
             
                    def default_associated_key_alias
         
     | 
| 
         @@ -710,7 +929,9 @@ module Sequel 
     | 
|
| 
       710 
929 
     | 
    
         
             
                    private
         
     | 
| 
       711 
930 
     | 
    
         | 
| 
       712 
931 
     | 
    
         
             
                    def filter_by_associations_add_conditions_dataset_filter(ds)
         
     | 
| 
       713 
     | 
    
         
            -
                       
     | 
| 
      
 932 
     | 
    
         
            +
                      k = qualify(join_table_alias, self[:left_keys])
         
     | 
| 
      
 933 
     | 
    
         
            +
                      ds.select(*k).
         
     | 
| 
      
 934 
     | 
    
         
            +
                        where(Sequel.negate(k.zip([]))).
         
     | 
| 
       714 
935 
     | 
    
         
             
                        inner_join(self[:join_table], Array(self[:right_keys]).zip(right_primary_keys), :qualify=>:deep)
         
     | 
| 
       715 
936 
     | 
    
         
             
                    end
         
     | 
| 
       716 
937 
     | 
    
         | 
| 
         @@ -718,6 +939,23 @@ module Sequel 
     | 
|
| 
       718 
939 
     | 
    
         
             
                      qualify(self[:model].table_name, self[:left_primary_key_column])
         
     | 
| 
       719 
940 
     | 
    
         
             
                    end
         
     | 
| 
       720 
941 
     | 
    
         | 
| 
      
 942 
     | 
    
         
            +
                    def filter_by_associations_limit_alias_key
         
     | 
| 
      
 943 
     | 
    
         
            +
                      aliaz = 'a'
         
     | 
| 
      
 944 
     | 
    
         
            +
                      filter_by_associations_limit_key.map{|c| c.as(Sequel.identifier(aliaz = aliaz.next))}
         
     | 
| 
      
 945 
     | 
    
         
            +
                    end
         
     | 
| 
      
 946 
     | 
    
         
            +
             
     | 
| 
      
 947 
     | 
    
         
            +
                    def filter_by_associations_limit_aliases
         
     | 
| 
      
 948 
     | 
    
         
            +
                      filter_by_associations_limit_alias_key.map{|v| v.alias}
         
     | 
| 
      
 949 
     | 
    
         
            +
                    end
         
     | 
| 
      
 950 
     | 
    
         
            +
             
     | 
| 
      
 951 
     | 
    
         
            +
                    def filter_by_associations_limit_key
         
     | 
| 
      
 952 
     | 
    
         
            +
                      qualify(join_table_alias, self[:left_keys]) + Array(qualify(associated_class.table_name, associated_class.primary_key))
         
     | 
| 
      
 953 
     | 
    
         
            +
                    end
         
     | 
| 
      
 954 
     | 
    
         
            +
             
     | 
| 
      
 955 
     | 
    
         
            +
                    def filter_by_associations_limit_subquery
         
     | 
| 
      
 956 
     | 
    
         
            +
                      super.inner_join(self[:join_table], Array(self[:right_keys]).zip(right_primary_keys))
         
     | 
| 
      
 957 
     | 
    
         
            +
                    end
         
     | 
| 
      
 958 
     | 
    
         
            +
             
     | 
| 
       721 
959 
     | 
    
         
             
                    def reciprocal_association?(assoc_reflect)
         
     | 
| 
       722 
960 
     | 
    
         
             
                      super && assoc_reflect[:left_keys] == self[:right_keys] &&
         
     | 
| 
       723 
961 
     | 
    
         
             
                        assoc_reflect[:right_keys] == self[:left_keys] &&
         
     | 
| 
         @@ -736,6 +974,22 @@ module Sequel 
     | 
|
| 
       736 
974 
     | 
    
         
             
                    end
         
     | 
| 
       737 
975 
     | 
    
         
             
                  end
         
     | 
| 
       738 
976 
     | 
    
         | 
| 
      
 977 
     | 
    
         
            +
                  class OneThroughOneAssociationReflection < ManyToManyAssociationReflection
         
     | 
| 
      
 978 
     | 
    
         
            +
                    ASSOCIATION_TYPES[:one_through_one] = self
         
     | 
| 
      
 979 
     | 
    
         
            +
                    include SingularAssociationReflection
         
     | 
| 
      
 980 
     | 
    
         
            +
                    
         
     | 
| 
      
 981 
     | 
    
         
            +
                    # one_through_one associations should not singularize the association name when
         
     | 
| 
      
 982 
     | 
    
         
            +
                    # creating the foreign key.
         
     | 
| 
      
 983 
     | 
    
         
            +
                    def default_right_key
         
     | 
| 
      
 984 
     | 
    
         
            +
                      :"#{self[:name]}_id"
         
     | 
| 
      
 985 
     | 
    
         
            +
                    end
         
     | 
| 
      
 986 
     | 
    
         
            +
                  
         
     | 
| 
      
 987 
     | 
    
         
            +
                    # one_through_one associations have no reciprocals
         
     | 
| 
      
 988 
     | 
    
         
            +
                    def reciprocal
         
     | 
| 
      
 989 
     | 
    
         
            +
                      nil
         
     | 
| 
      
 990 
     | 
    
         
            +
                    end
         
     | 
| 
      
 991 
     | 
    
         
            +
                  end
         
     | 
| 
      
 992 
     | 
    
         
            +
                
         
     | 
| 
       739 
993 
     | 
    
         
             
                  # This module contains methods added to all association datasets
         
     | 
| 
       740 
994 
     | 
    
         
             
                  module AssociationDatasetMethods
         
     | 
| 
       741 
995 
     | 
    
         
             
                    # The model object that created the association dataset
         
     | 
| 
         @@ -839,6 +1093,9 @@ module Sequel 
     | 
|
| 
       839 
1093 
     | 
    
         
             
                    #                 model's primary key.   Each current model object can be associated with
         
     | 
| 
       840 
1094 
     | 
    
         
             
                    #                 more than one associated model objects.  Each associated model object
         
     | 
| 
       841 
1095 
     | 
    
         
             
                    #                 can be associated with only one current model object.
         
     | 
| 
      
 1096 
     | 
    
         
            +
                    # :one_through_one :: Similar to many_to_many in terms of foreign keys, but only one object
         
     | 
| 
      
 1097 
     | 
    
         
            +
                    #                     is associated to the current object through the association.
         
     | 
| 
      
 1098 
     | 
    
         
            +
                    #                     Provides only getter methods, no setter or modification methods.
         
     | 
| 
       842 
1099 
     | 
    
         
             
                    # :one_to_one :: Similar to one_to_many in terms of foreign keys, but
         
     | 
| 
       843 
1100 
     | 
    
         
             
                    #                only one object is associated to the current object through the
         
     | 
| 
       844 
1101 
     | 
    
         
             
                    #                association.  The methods created are similar to many_to_one, except
         
     | 
| 
         @@ -871,11 +1128,11 @@ module Sequel 
     | 
|
| 
       871 
1128 
     | 
    
         
             
                    #                before an item is set using the association setter method.
         
     | 
| 
       872 
1129 
     | 
    
         
             
                    # :cartesian_product_number :: the number of joins completed by this association that could cause more
         
     | 
| 
       873 
1130 
     | 
    
         
             
                    #                              than one row for each row in the current table (default: 0 for
         
     | 
| 
       874 
     | 
    
         
            -
                    #                              many_to_one and  
     | 
| 
       875 
     | 
    
         
            -
                    #                              many_to_many associations).
         
     | 
| 
      
 1131 
     | 
    
         
            +
                    #                              many_to_one, one_to_one, and one_through_one associations, 1
         
     | 
| 
      
 1132 
     | 
    
         
            +
                    #                              for one_to_many and many_to_many associations).
         
     | 
| 
       876 
1133 
     | 
    
         
             
                    # :class :: The associated class or its name as a string or symbol. If not
         
     | 
| 
       877 
1134 
     | 
    
         
             
                    #           given, uses the association's name, which is camelized (and
         
     | 
| 
       878 
     | 
    
         
            -
                    #           singularized unless the type is :many_to_one or  
     | 
| 
      
 1135 
     | 
    
         
            +
                    #           singularized unless the type is :many_to_one, :one_to_one, or one_through_one).  If this is specified
         
     | 
| 
       879 
1136 
     | 
    
         
             
                    #           as a string or symbol, you must specify the full class name (e.g. "SomeModule::MyModel"). 
         
     | 
| 
       880 
1137 
     | 
    
         
             
                    # :clearer :: Proc used to define the private _remove_all_* method for doing the database work
         
     | 
| 
       881 
1138 
     | 
    
         
             
                    #             to remove all objects associated to the current object (*_to_many assocations).
         
     | 
| 
         @@ -895,10 +1152,9 @@ module Sequel 
     | 
|
| 
       895 
1152 
     | 
    
         
             
                    # :eager_graph :: The associations to eagerly load via +eager_graph+ when loading the associated object(s).
         
     | 
| 
       896 
1153 
     | 
    
         
             
                    #                 many_to_many associations with this option cannot be eagerly loaded via +eager+.
         
     | 
| 
       897 
1154 
     | 
    
         
             
                    # :eager_grapher :: A proc to use to implement eager loading via +eager_graph+, overriding the default.
         
     | 
| 
       898 
     | 
    
         
            -
                    #                   Takes an options hash with the entries :self (the receiver of the eager_graph call),
         
     | 
| 
       899 
     | 
    
         
            -
                    #                   :table_alias (the alias to use for table to graph into the association), :implicit_qualifier
         
     | 
| 
       900 
     | 
    
         
            -
                    #                   (the alias that was used for the current table) 
     | 
| 
       901 
     | 
    
         
            -
                    #                   proc accepting the associated dataset, for per-call customization).
         
     | 
| 
      
 1155 
     | 
    
         
            +
                    #                   Takes an options hash with at least the entries :self (the receiver of the eager_graph call),
         
     | 
| 
      
 1156 
     | 
    
         
            +
                    #                   :table_alias (the alias to use for table to graph into the association), and :implicit_qualifier
         
     | 
| 
      
 1157 
     | 
    
         
            +
                    #                   (the alias that was used for the current table).
         
     | 
| 
       902 
1158 
     | 
    
         
             
                    #                   Should return a copy of the dataset with the association graphed into it.
         
     | 
| 
       903 
1159 
     | 
    
         
             
                    # :eager_limit_strategy :: Determines the strategy used for enforcing limits and offsets when eager loading
         
     | 
| 
       904 
1160 
     | 
    
         
             
                    #                          associations via the +eager+ method.  
         
     | 
| 
         @@ -926,6 +1182,10 @@ module Sequel 
     | 
|
| 
       926 
1182 
     | 
    
         
             
                    # :graph_only_conditions :: The conditions to use on the SQL join when eagerly loading
         
     | 
| 
       927 
1183 
     | 
    
         
             
                    #                           the association via +eager_graph+, instead of the default conditions specified by the
         
     | 
| 
       928 
1184 
     | 
    
         
             
                    #                           foreign/primary keys.  This option causes the :graph_conditions option to be ignored.
         
     | 
| 
      
 1185 
     | 
    
         
            +
                    # :graph_order :: Over the order to use when using eager_graph, instead of the default order.  This should be used
         
     | 
| 
      
 1186 
     | 
    
         
            +
                    #                 in the case where :order contains an identifier qualified by the table's name, which may not match
         
     | 
| 
      
 1187 
     | 
    
         
            +
                    #                 the alias used when eager graphing.  By setting this to the unqualified identifier, it will be
         
     | 
| 
      
 1188 
     | 
    
         
            +
                    #                 automatically qualified when using eager_graph.
         
     | 
| 
       929 
1189 
     | 
    
         
             
                    # :graph_select :: A column or array of columns to select from the associated table
         
     | 
| 
       930 
1190 
     | 
    
         
             
                    #                  when eagerly loading the association via +eager_graph+. Defaults to all
         
     | 
| 
       931 
1191 
     | 
    
         
             
                    #                  columns in the associated table.
         
     | 
| 
         @@ -939,7 +1199,8 @@ module Sequel 
     | 
|
| 
       939 
1199 
     | 
    
         
             
                    # :order_eager_graph :: Whether to add the association's order to the graphed dataset's order when graphing
         
     | 
| 
       940 
1200 
     | 
    
         
             
                    #                       via +eager_graph+.  Defaults to true, so set to false to disable.
         
     | 
| 
       941 
1201 
     | 
    
         
             
                    # :read_only :: Do not add a setter method (for many_to_one or one_to_one associations),
         
     | 
| 
       942 
     | 
    
         
            -
                    #               or add_/remove_/remove_all_ methods (for one_to_many and many_to_many associations).
         
     | 
| 
      
 1202 
     | 
    
         
            +
                    #               or add_/remove_/remove_all_ methods (for one_to_many and many_to_many associations). Always
         
     | 
| 
      
 1203 
     | 
    
         
            +
                    #               true for one_through_one associations.
         
     | 
| 
       943 
1204 
     | 
    
         
             
                    # :reciprocal :: the symbol name of the reciprocal association,
         
     | 
| 
       944 
1205 
     | 
    
         
             
                    #                if it exists.  By default, Sequel will try to determine it by looking at the
         
     | 
| 
       945 
1206 
     | 
    
         
             
                    #                associated model's assocations for a association that matches
         
     | 
| 
         @@ -988,7 +1249,7 @@ module Sequel 
     | 
|
| 
       988 
1249 
     | 
    
         
             
                    #                        conjunction with defining a model alias method for the primary key column.
         
     | 
| 
       989 
1250 
     | 
    
         
             
                    # :raise_on_save_failure :: Do not raise exceptions for hook or validation failures when saving associated
         
     | 
| 
       990 
1251 
     | 
    
         
             
                    #                           objects in the add/remove methods (return nil instead) [one_to_many only].
         
     | 
| 
       991 
     | 
    
         
            -
                    # === :many_to_many
         
     | 
| 
      
 1252 
     | 
    
         
            +
                    # === :many_to_many and :one_through_one
         
     | 
| 
       992 
1253 
     | 
    
         
             
                    # :graph_join_table_block :: The block to pass to +join_table+ for
         
     | 
| 
       993 
1254 
     | 
    
         
             
                    #                            the join table when eagerly loading the association via +eager_graph+.
         
     | 
| 
       994 
1255 
     | 
    
         
             
                    # :graph_join_table_conditions :: The additional conditions to use on the SQL join for
         
     | 
| 
         @@ -1034,14 +1295,20 @@ module Sequel 
     | 
|
| 
       1034 
1295 
     | 
    
         | 
| 
       1035 
1296 
     | 
    
         
             
                      # dup early so we don't modify opts
         
     | 
| 
       1036 
1297 
     | 
    
         
             
                      orig_opts = opts.dup
         
     | 
| 
      
 1298 
     | 
    
         
            +
             
     | 
| 
       1037 
1299 
     | 
    
         
             
                      if opts[:clone]
         
     | 
| 
       1038 
1300 
     | 
    
         
             
                        cloned_assoc = association_reflection(opts[:clone])
         
     | 
| 
       1039 
     | 
    
         
            -
                        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]})") unless cloned_assoc[:type] == type || [cloned_assoc[:type], type].all?{|t| [:one_to_many, :one_to_one].include?(t)}
         
     | 
| 
       1040 
1301 
     | 
    
         
             
                        orig_opts = cloned_assoc[:orig_opts].merge(orig_opts)
         
     | 
| 
       1041 
1302 
     | 
    
         
             
                      end
         
     | 
| 
      
 1303 
     | 
    
         
            +
             
     | 
| 
       1042 
1304 
     | 
    
         
             
                      opts = orig_opts.merge(:type => type, :name => name, :cache=>{}, :model => self)
         
     | 
| 
       1043 
1305 
     | 
    
         
             
                      opts[:block] = block if block
         
     | 
| 
       1044 
1306 
     | 
    
         
             
                      opts = assoc_class.new.merge!(opts)
         
     | 
| 
      
 1307 
     | 
    
         
            +
             
     | 
| 
      
 1308 
     | 
    
         
            +
                      if opts[:clone] && !opts.cloneable?(cloned_assoc)
         
     | 
| 
      
 1309 
     | 
    
         
            +
                        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]})")
         
     | 
| 
      
 1310 
     | 
    
         
            +
                      end
         
     | 
| 
      
 1311 
     | 
    
         
            +
             
     | 
| 
       1045 
1312 
     | 
    
         
             
                      opts[:eager_block] = opts[:block] unless opts.include?(:eager_block)
         
     | 
| 
       1046 
1313 
     | 
    
         
             
                      if !opts.has_key?(:predicate_key) && opts.has_key?(:eager_loading_predicate_key)
         
     | 
| 
       1047 
1314 
     | 
    
         
             
                        opts[:predicate_key] = opts[:eager_loading_predicate_key]
         
     | 
| 
         @@ -1091,11 +1358,7 @@ module Sequel 
     | 
|
| 
       1091 
1358 
     | 
    
         
             
                      ds = ds.eager(associations) unless Array(associations).empty?
         
     | 
| 
       1092 
1359 
     | 
    
         
             
                      ds = eager_options[:eager_block].call(ds) if eager_options[:eager_block]
         
     | 
| 
       1093 
1360 
     | 
    
         
             
                      if opts.eager_loading_use_associated_key?
         
     | 
| 
       1094 
     | 
    
         
            -
                        ds =  
     | 
| 
       1095 
     | 
    
         
            -
                          ds.select_append(*opts.associated_key_alias.zip(opts.predicate_keys).map{|a, k| SQL::AliasedExpression.new(k, a)})
         
     | 
| 
       1096 
     | 
    
         
            -
                        else
         
     | 
| 
       1097 
     | 
    
         
            -
                          ds.select_append(SQL::AliasedExpression.new(opts.predicate_key, opts.associated_key_alias))
         
     | 
| 
       1098 
     | 
    
         
            -
                        end
         
     | 
| 
      
 1361 
     | 
    
         
            +
                        ds = ds.select_append(*opts.associated_key_array)
         
     | 
| 
       1099 
1362 
     | 
    
         
             
                      end
         
     | 
| 
       1100 
1363 
     | 
    
         
             
                      ds
         
     | 
| 
       1101 
1364 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -1110,6 +1373,11 @@ module Sequel 
     | 
|
| 
       1110 
1373 
     | 
    
         
             
                      associate(:many_to_one, name, opts, &block)
         
     | 
| 
       1111 
1374 
     | 
    
         
             
                    end
         
     | 
| 
       1112 
1375 
     | 
    
         | 
| 
      
 1376 
     | 
    
         
            +
                    # Shortcut for adding a one_through_one association, see #associate.
         
     | 
| 
      
 1377 
     | 
    
         
            +
                    def one_through_one(name, opts=OPTS, &block)
         
     | 
| 
      
 1378 
     | 
    
         
            +
                      associate(:one_through_one, name, opts, &block)
         
     | 
| 
      
 1379 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1380 
     | 
    
         
            +
             
     | 
| 
       1113 
1381 
     | 
    
         
             
                    # Shortcut for adding a one_to_many association, see #associate
         
     | 
| 
       1114 
1382 
     | 
    
         
             
                    def one_to_many(name, opts=OPTS, &block)
         
     | 
| 
       1115 
1383 
     | 
    
         
             
                      associate(:one_to_many, name, opts, &block)
         
     | 
| 
         @@ -1121,29 +1389,10 @@ module Sequel 
     | 
|
| 
       1121 
1389 
     | 
    
         
             
                    end
         
     | 
| 
       1122 
1390 
     | 
    
         | 
| 
       1123 
1391 
     | 
    
         
             
                    Plugins.inherited_instance_variables(self, :@association_reflections=>:dup, :@autoreloading_associations=>:hash_dup, :@default_eager_limit_strategy=>nil)
         
     | 
| 
       1124 
     | 
    
         
            -
                    Plugins.def_dataset_methods(self, [:eager, :eager_graph])
         
     | 
| 
      
 1392 
     | 
    
         
            +
                    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])
         
     | 
| 
       1125 
1393 
     | 
    
         | 
| 
       1126 
1394 
     | 
    
         
             
                    private
         
     | 
| 
       1127 
1395 
     | 
    
         | 
| 
       1128 
     | 
    
         
            -
                    # Use a window function to limit the results of the eager loading dataset.
         
     | 
| 
       1129 
     | 
    
         
            -
                    def apply_window_function_eager_limit_strategy(ds, opts)
         
     | 
| 
       1130 
     | 
    
         
            -
                      rn = ds.row_number_column 
         
     | 
| 
       1131 
     | 
    
         
            -
                      limit, offset = opts.limit_and_offset
         
     | 
| 
       1132 
     | 
    
         
            -
                      ds = ds.unordered.select_append{row_number{}.over(:partition=>opts.predicate_key, :order=>ds.opts[:order]).as(rn)}.from_self
         
     | 
| 
       1133 
     | 
    
         
            -
                      ds = if opts[:type] == :one_to_one
         
     | 
| 
       1134 
     | 
    
         
            -
                        ds.where(rn => offset ? offset+1 : 1)
         
     | 
| 
       1135 
     | 
    
         
            -
                      elsif offset
         
     | 
| 
       1136 
     | 
    
         
            -
                        offset += 1
         
     | 
| 
       1137 
     | 
    
         
            -
                        if limit
         
     | 
| 
       1138 
     | 
    
         
            -
                          ds.where(rn => (offset...(offset+limit))) 
         
     | 
| 
       1139 
     | 
    
         
            -
                        else
         
     | 
| 
       1140 
     | 
    
         
            -
                          ds.where{SQL::Identifier.new(rn) >= offset} 
         
     | 
| 
       1141 
     | 
    
         
            -
                        end
         
     | 
| 
       1142 
     | 
    
         
            -
                      else
         
     | 
| 
       1143 
     | 
    
         
            -
                        ds.where{SQL::Identifier.new(rn) <= limit} 
         
     | 
| 
       1144 
     | 
    
         
            -
                      end
         
     | 
| 
       1145 
     | 
    
         
            -
                    end
         
     | 
| 
       1146 
     | 
    
         
            -
             
     | 
| 
       1147 
1396 
     | 
    
         
             
                    # The module to use for the association's methods.  Defaults to
         
     | 
| 
       1148 
1397 
     | 
    
         
             
                    # the overridable_methods_module.
         
     | 
| 
       1149 
1398 
     | 
    
         
             
                    def association_module(opts=OPTS)
         
     | 
| 
         @@ -1179,8 +1428,10 @@ module Sequel 
     | 
|
| 
       1179 
1428 
     | 
    
         
             
                      association_module_def(opts.association_method, opts){|*dynamic_opts, &block| load_associated_objects(opts, dynamic_opts[0], &block)}
         
     | 
| 
       1180 
1429 
     | 
    
         
             
                    end
         
     | 
| 
       1181 
1430 
     | 
    
         | 
| 
       1182 
     | 
    
         
            -
                    # Configures many_to_many association reflection and adds the related association methods
         
     | 
| 
      
 1431 
     | 
    
         
            +
                    # Configures many_to_many and one_through_one association reflection and adds the related association methods
         
     | 
| 
       1183 
1432 
     | 
    
         
             
                    def def_many_to_many(opts)
         
     | 
| 
      
 1433 
     | 
    
         
            +
                      one_through_one = opts[:type] == :one_through_one
         
     | 
| 
      
 1434 
     | 
    
         
            +
                      opts[:read_only] = true if one_through_one
         
     | 
| 
       1184 
1435 
     | 
    
         
             
                      name = opts[:name]
         
     | 
| 
       1185 
1436 
     | 
    
         
             
                      model = self
         
     | 
| 
       1186 
1437 
     | 
    
         
             
                      left = (opts[:left_key] ||= opts.default_left_key)
         
     | 
| 
         @@ -1199,7 +1450,7 @@ module Sequel 
     | 
|
| 
       1199 
1450 
     | 
    
         
             
                      end
         
     | 
| 
       1200 
1451 
     | 
    
         
             
                      uses_lcks = opts[:uses_left_composite_keys] = lcks.length > 1
         
     | 
| 
       1201 
1452 
     | 
    
         
             
                      opts[:uses_right_composite_keys] = rcks.length > 1
         
     | 
| 
       1202 
     | 
    
         
            -
                      opts[:cartesian_product_number] ||= 1
         
     | 
| 
      
 1453 
     | 
    
         
            +
                      opts[:cartesian_product_number] ||= one_through_one ? 0 : 1
         
     | 
| 
       1203 
1454 
     | 
    
         
             
                      join_table = (opts[:join_table] ||= opts.default_join_table)
         
     | 
| 
       1204 
1455 
     | 
    
         
             
                      left_key_alias = opts[:left_key_alias] ||= opts.default_associated_key_alias
         
     | 
| 
       1205 
1456 
     | 
    
         
             
                      graph_jt_conds = opts[:graph_join_table_conditions] = opts.fetch(:graph_join_table_conditions, []).to_a
         
     | 
| 
         @@ -1211,28 +1462,34 @@ module Sequel 
     | 
|
| 
       1211 
1462 
     | 
    
         
             
                      opts[:eager_loader] ||= proc do |eo|
         
     | 
| 
       1212 
1463 
     | 
    
         
             
                        h = eo[:id_map]
         
     | 
| 
       1213 
1464 
     | 
    
         
             
                        rows = eo[:rows]
         
     | 
| 
       1214 
     | 
    
         
            -
                        rows.each{|object| object.associations[name] = []}
         
     | 
| 
       1215 
1465 
     | 
    
         
             
                        r = rcks.zip(opts.right_primary_keys)
         
     | 
| 
       1216 
1466 
     | 
    
         
             
                        l = [[opts.predicate_key, h.keys]]
         
     | 
| 
      
 1467 
     | 
    
         
            +
             
     | 
| 
       1217 
1468 
     | 
    
         
             
                        ds = model.eager_loading_dataset(opts, opts.associated_class.inner_join(join_table, r + l, :qualify=>:deep), nil, eo[:associations], eo)
         
     | 
| 
       1218 
     | 
    
         
            -
                         
     | 
| 
       1219 
     | 
    
         
            -
             
     | 
| 
       1220 
     | 
    
         
            -
             
     | 
| 
       1221 
     | 
    
         
            -
             
     | 
| 
       1222 
     | 
    
         
            -
                         
     | 
| 
      
 1469 
     | 
    
         
            +
                        ds = opts.apply_eager_limit_strategy(ds)
         
     | 
| 
      
 1470 
     | 
    
         
            +
                        opts.initialize_association_cache(rows)
         
     | 
| 
      
 1471 
     | 
    
         
            +
             
     | 
| 
      
 1472 
     | 
    
         
            +
                        assign_singular = opts.assign_singular?
         
     | 
| 
      
 1473 
     | 
    
         
            +
                        delete_rn = opts.delete_row_number_column(ds)
         
     | 
| 
       1223 
1474 
     | 
    
         
             
                        ds.all do |assoc_record|
         
     | 
| 
       1224 
     | 
    
         
            -
                          assoc_record.values.delete( 
     | 
| 
      
 1475 
     | 
    
         
            +
                          assoc_record.values.delete(delete_rn) if delete_rn
         
     | 
| 
       1225 
1476 
     | 
    
         
             
                          hash_key = if uses_lcks
         
     | 
| 
       1226 
1477 
     | 
    
         
             
                            left_key_alias.map{|k| assoc_record.values.delete(k)}
         
     | 
| 
       1227 
1478 
     | 
    
         
             
                          else
         
     | 
| 
       1228 
1479 
     | 
    
         
             
                            assoc_record.values.delete(left_key_alias)
         
     | 
| 
       1229 
1480 
     | 
    
         
             
                          end
         
     | 
| 
       1230 
1481 
     | 
    
         
             
                          next unless objects = h[hash_key]
         
     | 
| 
       1231 
     | 
    
         
            -
                           
     | 
| 
       1232 
     | 
    
         
            -
             
     | 
| 
       1233 
     | 
    
         
            -
             
     | 
| 
       1234 
     | 
    
         
            -
             
     | 
| 
      
 1482 
     | 
    
         
            +
                          if assign_singular
         
     | 
| 
      
 1483 
     | 
    
         
            +
                            objects.each do |object| 
         
     | 
| 
      
 1484 
     | 
    
         
            +
                              object.associations[name] ||= assoc_record
         
     | 
| 
      
 1485 
     | 
    
         
            +
                            end
         
     | 
| 
      
 1486 
     | 
    
         
            +
                          else
         
     | 
| 
      
 1487 
     | 
    
         
            +
                            objects.each do |object|
         
     | 
| 
      
 1488 
     | 
    
         
            +
                              object.associations[name].push(assoc_record)
         
     | 
| 
      
 1489 
     | 
    
         
            +
                            end
         
     | 
| 
      
 1490 
     | 
    
         
            +
                          end
         
     | 
| 
       1235 
1491 
     | 
    
         
             
                        end
         
     | 
| 
      
 1492 
     | 
    
         
            +
                        opts.apply_ruby_eager_limit_strategy(rows)
         
     | 
| 
       1236 
1493 
     | 
    
         
             
                      end
         
     | 
| 
       1237 
1494 
     | 
    
         | 
| 
       1238 
1495 
     | 
    
         
             
                      join_type = opts[:graph_join_type]
         
     | 
| 
         @@ -1247,13 +1504,25 @@ module Sequel 
     | 
|
| 
       1247 
1504 
     | 
    
         
             
                      jt_graph_block = opts[:graph_join_table_block]
         
     | 
| 
       1248 
1505 
     | 
    
         
             
                      opts[:eager_grapher] ||= proc do |eo|
         
     | 
| 
       1249 
1506 
     | 
    
         
             
                        ds = eo[:self]
         
     | 
| 
       1250 
     | 
    
         
            -
                         
     | 
| 
       1251 
     | 
    
         
            -
                         
     | 
| 
      
 1507 
     | 
    
         
            +
                        egls = eo[:limit_strategy]
         
     | 
| 
      
 1508 
     | 
    
         
            +
                        if egls && egls != :ruby
         
     | 
| 
      
 1509 
     | 
    
         
            +
                          associated_key_array = opts.associated_key_array
         
     | 
| 
      
 1510 
     | 
    
         
            +
                          orig_egds = egds = eager_graph_dataset(opts, eo)
         
     | 
| 
      
 1511 
     | 
    
         
            +
                          egds = egds.
         
     | 
| 
      
 1512 
     | 
    
         
            +
                            inner_join(join_table, rcks.zip(opts.right_primary_keys) + graph_jt_conds, :qualify=>:deep).
         
     | 
| 
      
 1513 
     | 
    
         
            +
                            select_all(egds.first_source).
         
     | 
| 
      
 1514 
     | 
    
         
            +
                            select_append(*associated_key_array)
         
     | 
| 
      
 1515 
     | 
    
         
            +
                          egds = opts.apply_eager_graph_limit_strategy(egls, egds)
         
     | 
| 
      
 1516 
     | 
    
         
            +
                          ds.graph(egds, associated_key_array.map{|v| v.alias}.zip(lpkcs) + conditions, :qualify=>:deep, :table_alias=>eo[:table_alias], :implicit_qualifier=>eo[:implicit_qualifier], :join_type=>eo[:join_type]||join_type, :from_self_alias=>eo[:from_self_alias], :select=>select||orig_egds.columns, &graph_block)
         
     | 
| 
      
 1517 
     | 
    
         
            +
                        else
         
     | 
| 
      
 1518 
     | 
    
         
            +
                          ds = ds.graph(join_table, use_jt_only_conditions ? jt_only_conditions : lcks.zip(lpkcs) + graph_jt_conds, :select=>false, :table_alias=>ds.unused_table_alias(join_table, [eo[:table_alias]]), :join_type=>eo[:join_type]||jt_join_type, :implicit_qualifier=>eo[:implicit_qualifier], :qualify=>:deep, :from_self_alias=>eo[:from_self_alias], &jt_graph_block)
         
     | 
| 
      
 1519 
     | 
    
         
            +
                          ds.graph(eager_graph_dataset(opts, eo), use_only_conditions ? only_conditions : opts.right_primary_keys.zip(rcks) + conditions, :select=>select, :table_alias=>eo[:table_alias], :qualify=>:deep, :join_type=>eo[:join_type]||join_type, &graph_block)
         
     | 
| 
      
 1520 
     | 
    
         
            +
                        end
         
     | 
| 
       1252 
1521 
     | 
    
         
             
                      end
         
     | 
| 
       1253 
1522 
     | 
    
         | 
| 
       1254 
1523 
     | 
    
         
             
                      def_association_dataset_methods(opts)
         
     | 
| 
       1255 
1524 
     | 
    
         | 
| 
       1256 
     | 
    
         
            -
                      return if opts[:read_only]
         
     | 
| 
      
 1525 
     | 
    
         
            +
                      return if opts[:read_only] || one_through_one
         
     | 
| 
       1257 
1526 
     | 
    
         | 
| 
       1258 
1527 
     | 
    
         
             
                      adder = opts[:adder] || proc do |o|
         
     | 
| 
       1259 
1528 
     | 
    
         
             
                        h = {}
         
     | 
| 
         @@ -1311,9 +1580,9 @@ module Sequel 
     | 
|
| 
       1311 
1580 
     | 
    
         
             
                      opts[:eager_loader] ||= proc do |eo|
         
     | 
| 
       1312 
1581 
     | 
    
         
             
                        h = eo[:id_map]
         
     | 
| 
       1313 
1582 
     | 
    
         
             
                        keys = h.keys
         
     | 
| 
       1314 
     | 
    
         
            -
             
     | 
| 
       1315 
     | 
    
         
            -
                         
     | 
| 
       1316 
     | 
    
         
            -
             
     | 
| 
      
 1583 
     | 
    
         
            +
             
     | 
| 
      
 1584 
     | 
    
         
            +
                        opts.initialize_association_cache(eo[:rows])
         
     | 
| 
      
 1585 
     | 
    
         
            +
             
     | 
| 
       1317 
1586 
     | 
    
         
             
                        # Skip eager loading if no objects have a foreign key for this association
         
     | 
| 
       1318 
1587 
     | 
    
         
             
                        unless keys.empty?
         
     | 
| 
       1319 
1588 
     | 
    
         
             
                          klass = opts.associated_class
         
     | 
| 
         @@ -1334,7 +1603,7 @@ module Sequel 
     | 
|
| 
       1334 
1603 
     | 
    
         
             
                      graph_cks = opts[:graph_keys]
         
     | 
| 
       1335 
1604 
     | 
    
         
             
                      opts[:eager_grapher] ||= proc do |eo|
         
     | 
| 
       1336 
1605 
     | 
    
         
             
                        ds = eo[:self]
         
     | 
| 
       1337 
     | 
    
         
            -
                        ds.graph(eager_graph_dataset(opts, eo), use_only_conditions ? only_conditions : opts.primary_keys.zip(graph_cks) + conditions, eo.merge(:select=>select, :join_type=>join_type, :qualify=>:deep, :from_self_alias=> 
     | 
| 
      
 1606 
     | 
    
         
            +
                        ds.graph(eager_graph_dataset(opts, eo), use_only_conditions ? only_conditions : opts.primary_keys.zip(graph_cks) + conditions, eo.merge(:select=>select, :join_type=>eo[:join_type]||join_type, :qualify=>:deep, :from_self_alias=>eo[:from_self_alias]), &graph_block)
         
     | 
| 
       1338 
1607 
     | 
    
         
             
                      end
         
     | 
| 
       1339 
1608 
     | 
    
         | 
| 
       1340 
1609 
     | 
    
         
             
                      def_association_dataset_methods(opts)
         
     | 
| 
         @@ -1371,26 +1640,15 @@ module Sequel 
     | 
|
| 
       1371 
1640 
     | 
    
         
             
                        rows = eo[:rows]
         
     | 
| 
       1372 
1641 
     | 
    
         
             
                        reciprocal = opts.reciprocal
         
     | 
| 
       1373 
1642 
     | 
    
         
             
                        klass = opts.associated_class
         
     | 
| 
       1374 
     | 
    
         
            -
             
     | 
| 
       1375 
     | 
    
         
            -
                        ds = model.eager_loading_dataset(opts, klass.where( 
     | 
| 
       1376 
     | 
    
         
            -
                         
     | 
| 
       1377 
     | 
    
         
            -
                         
     | 
| 
       1378 
     | 
    
         
            -
             
     | 
| 
       1379 
     | 
    
         
            -
             
     | 
| 
       1380 
     | 
    
         
            -
                         
     | 
| 
       1381 
     | 
    
         
            -
                          delete_rn = true
         
     | 
| 
       1382 
     | 
    
         
            -
                          rn = ds.row_number_column
         
     | 
| 
       1383 
     | 
    
         
            -
                          ds = apply_window_function_eager_limit_strategy(ds, opts)
         
     | 
| 
       1384 
     | 
    
         
            -
                        when :ruby
         
     | 
| 
       1385 
     | 
    
         
            -
                          assign_singular = false if one_to_one && slice_range
         
     | 
| 
       1386 
     | 
    
         
            -
                        end
         
     | 
| 
       1387 
     | 
    
         
            -
                        if assign_singular
         
     | 
| 
       1388 
     | 
    
         
            -
                          rows.each{|object| object.associations[name] = nil}
         
     | 
| 
       1389 
     | 
    
         
            -
                        else
         
     | 
| 
       1390 
     | 
    
         
            -
                          rows.each{|object| object.associations[name] = []}
         
     | 
| 
       1391 
     | 
    
         
            -
                        end
         
     | 
| 
      
 1643 
     | 
    
         
            +
             
     | 
| 
      
 1644 
     | 
    
         
            +
                        ds = model.eager_loading_dataset(opts, klass.where(opts.predicate_key=>h.keys), nil, eo[:associations], eo)
         
     | 
| 
      
 1645 
     | 
    
         
            +
                        ds = opts.apply_eager_limit_strategy(ds)
         
     | 
| 
      
 1646 
     | 
    
         
            +
                        opts.initialize_association_cache(rows)
         
     | 
| 
      
 1647 
     | 
    
         
            +
             
     | 
| 
      
 1648 
     | 
    
         
            +
                        assign_singular = opts.assign_singular?
         
     | 
| 
      
 1649 
     | 
    
         
            +
                        delete_rn = opts.delete_row_number_column(ds)
         
     | 
| 
       1392 
1650 
     | 
    
         
             
                        ds.all do |assoc_record|
         
     | 
| 
       1393 
     | 
    
         
            -
                          assoc_record.values.delete( 
     | 
| 
      
 1651 
     | 
    
         
            +
                          assoc_record.values.delete(delete_rn) if delete_rn
         
     | 
| 
       1394 
1652 
     | 
    
         
             
                          hash_key = uses_cks ? km.map{|k| assoc_record.send(k)} : assoc_record.send(km)
         
     | 
| 
       1395 
1653 
     | 
    
         
             
                          next unless objects = h[hash_key]
         
     | 
| 
       1396 
1654 
     | 
    
         
             
                          if assign_singular
         
     | 
| 
         @@ -1407,15 +1665,7 @@ module Sequel 
     | 
|
| 
       1407 
1665 
     | 
    
         
             
                            end
         
     | 
| 
       1408 
1666 
     | 
    
         
             
                          end
         
     | 
| 
       1409 
1667 
     | 
    
         
             
                        end
         
     | 
| 
       1410 
     | 
    
         
            -
                         
     | 
| 
       1411 
     | 
    
         
            -
                          if one_to_one
         
     | 
| 
       1412 
     | 
    
         
            -
                            if slice_range
         
     | 
| 
       1413 
     | 
    
         
            -
                              rows.each{|o| o.associations[name] = o.associations[name][slice_range.begin]}
         
     | 
| 
       1414 
     | 
    
         
            -
                            end
         
     | 
| 
       1415 
     | 
    
         
            -
                          else
         
     | 
| 
       1416 
     | 
    
         
            -
                            rows.each{|o| o.associations[name] = o.associations[name][slice_range] || []}
         
     | 
| 
       1417 
     | 
    
         
            -
                          end
         
     | 
| 
       1418 
     | 
    
         
            -
                        end
         
     | 
| 
      
 1668 
     | 
    
         
            +
                        opts.apply_ruby_eager_limit_strategy(rows)
         
     | 
| 
       1419 
1669 
     | 
    
         
             
                      end
         
     | 
| 
       1420 
1670 
     | 
    
         | 
| 
       1421 
1671 
     | 
    
         
             
                      join_type = opts[:graph_join_type]
         
     | 
| 
         @@ -1427,7 +1677,7 @@ module Sequel 
     | 
|
| 
       1427 
1677 
     | 
    
         
             
                      graph_block = opts[:graph_block]
         
     | 
| 
       1428 
1678 
     | 
    
         
             
                      opts[:eager_grapher] ||= proc do |eo|
         
     | 
| 
       1429 
1679 
     | 
    
         
             
                        ds = eo[:self]
         
     | 
| 
       1430 
     | 
    
         
            -
                        ds = ds.graph(eager_graph_dataset(opts, eo), use_only_conditions ? only_conditions : cks.zip(pkcs) + conditions, eo.merge(:select=>select, :join_type=>join_type, :qualify=>:deep, :from_self_alias=> 
     | 
| 
      
 1680 
     | 
    
         
            +
                        ds = ds.graph(opts.apply_eager_graph_limit_strategy(eo[:limit_strategy], eager_graph_dataset(opts, eo)), use_only_conditions ? only_conditions : cks.zip(pkcs) + conditions, eo.merge(:select=>select, :join_type=>eo[:join_type]||join_type, :qualify=>:deep, :from_self_alias=>eo[:from_self_alias]), &graph_block)
         
     | 
| 
       1431 
1681 
     | 
    
         
             
                        # We only load reciprocals for one_to_many associations, as other reciprocals don't make sense
         
     | 
| 
       1432 
1682 
     | 
    
         
             
                        ds.opts[:eager_graph][:reciprocals][eo[:table_alias]] = opts.reciprocal
         
     | 
| 
       1433 
1683 
     | 
    
         
             
                        ds
         
     | 
| 
         @@ -1481,6 +1731,11 @@ module Sequel 
     | 
|
| 
       1481 
1731 
     | 
    
         
             
                      end
         
     | 
| 
       1482 
1732 
     | 
    
         
             
                    end
         
     | 
| 
       1483 
1733 
     | 
    
         | 
| 
      
 1734 
     | 
    
         
            +
                    # Alias of def_many_to_many, since they share pretty much the same code.
         
     | 
| 
      
 1735 
     | 
    
         
            +
                    def def_one_through_one(opts)
         
     | 
| 
      
 1736 
     | 
    
         
            +
                      def_many_to_many(opts)
         
     | 
| 
      
 1737 
     | 
    
         
            +
                    end
         
     | 
| 
      
 1738 
     | 
    
         
            +
                    
         
     | 
| 
       1484 
1739 
     | 
    
         
             
                    # Alias of def_one_to_many, since they share pretty much the same code.
         
     | 
| 
       1485 
1740 
     | 
    
         
             
                    def def_one_to_one(opts)
         
     | 
| 
       1486 
1741 
     | 
    
         
             
                      def_one_to_many(opts)
         
     | 
| 
         @@ -1844,6 +2099,26 @@ module Sequel 
     | 
|
| 
       1844 
2099 
     | 
    
         
             
                  #   Artist.eager(:albums => {proc{|ds| ds.where{year > 1990}}=>{:tracks => :genre}})
         
     | 
| 
       1845 
2100 
     | 
    
         
             
                  module DatasetMethods
         
     | 
| 
       1846 
2101 
     | 
    
         
             
                    Sequel::Dataset.def_mutation_method(:eager, :eager_graph, :module=>self)
         
     | 
| 
      
 2102 
     | 
    
         
            +
             
     | 
| 
      
 2103 
     | 
    
         
            +
                    %w'inner left right full'.each do |type|
         
     | 
| 
      
 2104 
     | 
    
         
            +
                      class_eval <<END, __FILE__, __LINE__+1
         
     | 
| 
      
 2105 
     | 
    
         
            +
                        def association_#{type}_join(*associations)
         
     | 
| 
      
 2106 
     | 
    
         
            +
                          _association_join(:#{type}, associations)
         
     | 
| 
      
 2107 
     | 
    
         
            +
                        end
         
     | 
| 
      
 2108 
     | 
    
         
            +
            END
         
     | 
| 
      
 2109 
     | 
    
         
            +
                    end
         
     | 
| 
      
 2110 
     | 
    
         
            +
             
     | 
| 
      
 2111 
     | 
    
         
            +
                    # Adds one or more INNER JOINs to the existing dataset using the keys and conditions
         
     | 
| 
      
 2112 
     | 
    
         
            +
                    # specified by the given association.  The following methods also exist for specifying
         
     | 
| 
      
 2113 
     | 
    
         
            +
                    # a different type of JOIN:
         
     | 
| 
      
 2114 
     | 
    
         
            +
                    #
         
     | 
| 
      
 2115 
     | 
    
         
            +
                    # association_full_join :: FULL JOIN
         
     | 
| 
      
 2116 
     | 
    
         
            +
                    # association_inner_join :: INNER JOIN
         
     | 
| 
      
 2117 
     | 
    
         
            +
                    # association_left_join :: LEFT JOIN
         
     | 
| 
      
 2118 
     | 
    
         
            +
                    # association_right_join :: RIGHT JOIN
         
     | 
| 
      
 2119 
     | 
    
         
            +
                    def association_join(*associations)
         
     | 
| 
      
 2120 
     | 
    
         
            +
                      association_inner_join(*associations)
         
     | 
| 
      
 2121 
     | 
    
         
            +
                    end
         
     | 
| 
       1847 
2122 
     | 
    
         | 
| 
       1848 
2123 
     | 
    
         
             
                    # If the expression is in the form <tt>x = y</tt> where +y+ is a <tt>Sequel::Model</tt>
         
     | 
| 
       1849 
2124 
     | 
    
         
             
                    # instance, array of <tt>Sequel::Model</tt> instances, or a <tt>Sequel::Model</tt> dataset,
         
     | 
| 
         @@ -1951,7 +2226,7 @@ module Sequel 
     | 
|
| 
       1951 
2226 
     | 
    
         
             
                    # 
         
     | 
| 
       1952 
2227 
     | 
    
         
             
                    # Each association's order, if definied, is respected. +eager_graph+ probably
         
     | 
| 
       1953 
2228 
     | 
    
         
             
                    # won't work correctly on a limited dataset, unless you are
         
     | 
| 
       1954 
     | 
    
         
            -
                    # only graphing many_to_one and  
     | 
| 
      
 2229 
     | 
    
         
            +
                    # only graphing many_to_one, one_to_one, and one_through_one associations.
         
     | 
| 
       1955 
2230 
     | 
    
         
             
                    # 
         
     | 
| 
       1956 
2231 
     | 
    
         
             
                    # Does not use the block defined for the association, since it does a single query for
         
     | 
| 
       1957 
2232 
     | 
    
         
             
                    # all objects.  You can use the :graph_* association options to modify the SQL query.
         
     | 
| 
         @@ -1959,22 +2234,48 @@ module Sequel 
     | 
|
| 
       1959 
2234 
     | 
    
         
             
                    # Like +eager+, you need to call +all+ on the dataset for the eager loading to work.  If you just
         
     | 
| 
       1960 
2235 
     | 
    
         
             
                    # call +each+, it will yield plain hashes, each containing all columns from all the tables.
         
     | 
| 
       1961 
2236 
     | 
    
         
             
                    def eager_graph(*associations)
         
     | 
| 
      
 2237 
     | 
    
         
            +
                      eager_graph_with_options(associations)
         
     | 
| 
      
 2238 
     | 
    
         
            +
                    end
         
     | 
| 
      
 2239 
     | 
    
         
            +
             
     | 
| 
      
 2240 
     | 
    
         
            +
                    # Run eager_graph with some options specific to just this call. Unlike eager_graph, this takes
         
     | 
| 
      
 2241 
     | 
    
         
            +
                    # the associations as a single argument instead of multiple arguments.
         
     | 
| 
      
 2242 
     | 
    
         
            +
                    #
         
     | 
| 
      
 2243 
     | 
    
         
            +
                    # Options:
         
     | 
| 
      
 2244 
     | 
    
         
            +
                    #
         
     | 
| 
      
 2245 
     | 
    
         
            +
                    # :join_type :: Override the join type specified in the association
         
     | 
| 
      
 2246 
     | 
    
         
            +
                    # :limit_strategy :: Use a strategy for handling limits on associations.
         
     | 
| 
      
 2247 
     | 
    
         
            +
                    #                    Appropriate :limit_strategy values are:
         
     | 
| 
      
 2248 
     | 
    
         
            +
                    #                    true :: Pick the most appropriate based on what the database supports
         
     | 
| 
      
 2249 
     | 
    
         
            +
                    #                    :distinct_on :: Force use of DISTINCT ON stategy (*_one associations only)
         
     | 
| 
      
 2250 
     | 
    
         
            +
                    #                    :window_function :: Force use of window function strategy
         
     | 
| 
      
 2251 
     | 
    
         
            +
                    #                    :ruby :: Don't modify the SQL, implement limits/offsets with array slicing
         
     | 
| 
      
 2252 
     | 
    
         
            +
                    #
         
     | 
| 
      
 2253 
     | 
    
         
            +
                    #                    This can also be a hash with association name symbol keys and one of the above values,
         
     | 
| 
      
 2254 
     | 
    
         
            +
                    #                    to use different strategies per association.
         
     | 
| 
      
 2255 
     | 
    
         
            +
                    #
         
     | 
| 
      
 2256 
     | 
    
         
            +
                    #                    The default is the :ruby strategy.  Choosing a different strategy can make your code
         
     | 
| 
      
 2257 
     | 
    
         
            +
                    #                    significantly slower in some cases (perhaps even the majority of cases), so you should
         
     | 
| 
      
 2258 
     | 
    
         
            +
                    #                    only use this if you have benchmarked that it is faster for your use cases.
         
     | 
| 
      
 2259 
     | 
    
         
            +
                    def eager_graph_with_options(associations, opts=OPTS)
         
     | 
| 
      
 2260 
     | 
    
         
            +
                      associations = [associations] unless associations.is_a?(Array)
         
     | 
| 
       1962 
2261 
     | 
    
         
             
                      if eg = @opts[:eager_graph]
         
     | 
| 
       1963 
2262 
     | 
    
         
             
                        eg = eg.dup
         
     | 
| 
       1964 
     | 
    
         
            -
                        [:requirements, :reflections, :reciprocals].each{|k| eg[k] = eg[k].dup}
         
     | 
| 
      
 2263 
     | 
    
         
            +
                        [:requirements, :reflections, :reciprocals, :limits].each{|k| eg[k] = eg[k].dup}
         
     | 
| 
      
 2264 
     | 
    
         
            +
                        eg[:local] = opts
         
     | 
| 
       1965 
2265 
     | 
    
         
             
                        ds = clone(:eager_graph=>eg)
         
     | 
| 
       1966 
2266 
     | 
    
         
             
                        ds.eager_graph_associations(ds, model, ds.opts[:eager_graph][:master], [], *associations)
         
     | 
| 
       1967 
2267 
     | 
    
         
             
                      else
         
     | 
| 
       1968 
2268 
     | 
    
         
             
                        # Each of the following have a symbol key for the table alias, with the following values: 
         
     | 
| 
       1969 
     | 
    
         
            -
                        # :reciprocals  
     | 
| 
       1970 
     | 
    
         
            -
                        # :reflections  
     | 
| 
       1971 
     | 
    
         
            -
                        # :requirements  
     | 
| 
       1972 
     | 
    
         
            -
                         
     | 
| 
       1973 
     | 
    
         
            -
                         
     | 
| 
       1974 
     | 
    
         
            -
             
     | 
| 
      
 2269 
     | 
    
         
            +
                        # :reciprocals :: the reciprocal value to use for this association
         
     | 
| 
      
 2270 
     | 
    
         
            +
                        # :reflections :: AssociationReflection instance related to this association
         
     | 
| 
      
 2271 
     | 
    
         
            +
                        # :requirements :: array of requirements for this association
         
     | 
| 
      
 2272 
     | 
    
         
            +
                        # :limits :: Any limit/offset array slicing that need to be handled in ruby land after loading
         
     | 
| 
      
 2273 
     | 
    
         
            +
                        opts = {:requirements=>{}, :master=>alias_symbol(first_source), :reflections=>{}, :reciprocals=>{}, :limits=>{}, :local=>opts, :cartesian_product_number=>0, :row_proc=>row_proc}
         
     | 
| 
      
 2274 
     | 
    
         
            +
                        ds = clone(:eager_graph=>opts)
         
     | 
| 
      
 2275 
     | 
    
         
            +
                        ds.eager_graph_associations(ds, model, ds.opts[:eager_graph][:master], [], *associations).naked
         
     | 
| 
       1975 
2276 
     | 
    
         
             
                      end
         
     | 
| 
       1976 
2277 
     | 
    
         
             
                    end
         
     | 
| 
       1977 
     | 
    
         
            -
             
     | 
| 
      
 2278 
     | 
    
         
            +
             
     | 
| 
       1978 
2279 
     | 
    
         
             
                    # Do not attempt to split the result set into associations,
         
     | 
| 
       1979 
2280 
     | 
    
         
             
                    # just return results as simple objects.  This is useful if you
         
     | 
| 
       1980 
2281 
     | 
    
         
             
                    # want to use eager_graph as a shortcut to have all of the joins
         
     | 
| 
         @@ -2004,7 +2305,7 @@ module Sequel 
     | 
|
| 
       2004 
2305 
     | 
    
         
             
                    # *associations :: any associations dependent on this one
         
     | 
| 
       2005 
2306 
     | 
    
         
             
                    def eager_graph_association(ds, model, ta, requirements, r, *associations)
         
     | 
| 
       2006 
2307 
     | 
    
         
             
                      if r.is_a?(SQL::AliasedExpression)
         
     | 
| 
       2007 
     | 
    
         
            -
                        alias_base = r. 
     | 
| 
      
 2308 
     | 
    
         
            +
                        alias_base = r.alias
         
     | 
| 
       2008 
2309 
     | 
    
         
             
                        r = r.expression
         
     | 
| 
       2009 
2310 
     | 
    
         
             
                      else
         
     | 
| 
       2010 
2311 
     | 
    
         
             
                        alias_base = r[:graph_alias_base]
         
     | 
| 
         @@ -2020,11 +2321,19 @@ module Sequel 
     | 
|
| 
       2020 
2321 
     | 
    
         
             
                          associations = assoc.is_a?(Array) ? assoc : [assoc]
         
     | 
| 
       2021 
2322 
     | 
    
         
             
                        end
         
     | 
| 
       2022 
2323 
     | 
    
         
             
                      end
         
     | 
| 
       2023 
     | 
    
         
            -
                       
     | 
| 
       2024 
     | 
    
         
            -
                       
     | 
| 
      
 2324 
     | 
    
         
            +
                      orig_ds = ds
         
     | 
| 
      
 2325 
     | 
    
         
            +
                      local_opts = ds.opts[:eager_graph][:local]
         
     | 
| 
      
 2326 
     | 
    
         
            +
                      limit_strategy = r.eager_graph_limit_strategy(local_opts[:limit_strategy])
         
     | 
| 
      
 2327 
     | 
    
         
            +
                      ds = loader.call(:self=>ds, :table_alias=>assoc_table_alias, :implicit_qualifier=>ta, :callback=>callback, :join_type=>local_opts[:join_type], :limit_strategy=>limit_strategy, :from_self_alias=>ds.opts[:eager_graph][:master])
         
     | 
| 
      
 2328 
     | 
    
         
            +
                      if r[:order_eager_graph] && (order = r.fetch(:graph_order, r[:order]))
         
     | 
| 
      
 2329 
     | 
    
         
            +
                        ds = ds.order_more(*qualified_expression(order, assoc_table_alias))
         
     | 
| 
      
 2330 
     | 
    
         
            +
                      end
         
     | 
| 
       2025 
2331 
     | 
    
         
             
                      eager_graph = ds.opts[:eager_graph]
         
     | 
| 
       2026 
2332 
     | 
    
         
             
                      eager_graph[:requirements][assoc_table_alias] = requirements.dup
         
     | 
| 
       2027 
2333 
     | 
    
         
             
                      eager_graph[:reflections][assoc_table_alias] = r
         
     | 
| 
      
 2334 
     | 
    
         
            +
                      if limit_strategy == :ruby
         
     | 
| 
      
 2335 
     | 
    
         
            +
                        eager_graph[:limits][assoc_table_alias] = r.limit_and_offset 
         
     | 
| 
      
 2336 
     | 
    
         
            +
                      end
         
     | 
| 
       2028 
2337 
     | 
    
         
             
                      eager_graph[:cartesian_product_number] += r[:cartesian_product_number] || 2
         
     | 
| 
       2029 
2338 
     | 
    
         
             
                      ds = ds.eager_graph_associations(ds, r.associated_class, assoc_table_alias, requirements + [assoc_table_alias], *associations) unless associations.empty?
         
     | 
| 
       2030 
2339 
     | 
    
         
             
                      ds
         
     | 
| 
         @@ -2065,12 +2374,18 @@ module Sequel 
     | 
|
| 
       2065 
2374 
     | 
    
         | 
| 
       2066 
2375 
     | 
    
         
             
                    private
         
     | 
| 
       2067 
2376 
     | 
    
         | 
| 
      
 2377 
     | 
    
         
            +
                    # Return a new dataset with JOINs of the given type added, using the tables and
         
     | 
| 
      
 2378 
     | 
    
         
            +
                    # conditions specified by the associations.
         
     | 
| 
      
 2379 
     | 
    
         
            +
                    def _association_join(type, associations)
         
     | 
| 
      
 2380 
     | 
    
         
            +
                      clone(:join=>clone(:graph_from_self=>false).eager_graph_with_options(associations, :join_type=>type).opts[:join])
         
     | 
| 
      
 2381 
     | 
    
         
            +
                    end
         
     | 
| 
      
 2382 
     | 
    
         
            +
             
     | 
| 
       2068 
2383 
     | 
    
         
             
                    # If the association has conditions itself, then it requires additional filters be
         
     | 
| 
       2069 
2384 
     | 
    
         
             
                    # added to the current dataset to ensure that the passed in object would also be
         
     | 
| 
       2070 
2385 
     | 
    
         
             
                    # included by the association's conditions.
         
     | 
| 
       2071 
2386 
     | 
    
         
             
                    def add_association_filter_conditions(ref, obj, expr)
         
     | 
| 
       2072 
2387 
     | 
    
         
             
                      if expr != SQL::Constants::FALSE && ref.filter_by_associations_add_conditions?
         
     | 
| 
       2073 
     | 
    
         
            -
                        Sequel 
     | 
| 
      
 2388 
     | 
    
         
            +
                        Sequel.expr(ref.filter_by_associations_conditions_expression(obj))
         
     | 
| 
       2074 
2389 
     | 
    
         
             
                      else
         
     | 
| 
       2075 
2390 
     | 
    
         
             
                        expr
         
     | 
| 
       2076 
2391 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -2130,7 +2445,7 @@ module Sequel 
     | 
|
| 
       2130 
2445 
     | 
    
         
             
                    # per-call determining of the alias base.
         
     | 
| 
       2131 
2446 
     | 
    
         
             
                    def eager_graph_check_association(model, association)
         
     | 
| 
       2132 
2447 
     | 
    
         
             
                      if association.is_a?(SQL::AliasedExpression)
         
     | 
| 
       2133 
     | 
    
         
            -
                        SQL::AliasedExpression.new(check_association(model, association.expression), association. 
     | 
| 
      
 2448 
     | 
    
         
            +
                        SQL::AliasedExpression.new(check_association(model, association.expression), association.alias)
         
     | 
| 
       2134 
2449 
     | 
    
         
             
                      else
         
     | 
| 
       2135 
2450 
     | 
    
         
             
                        check_association(model, association)
         
     | 
| 
       2136 
2451 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -2210,6 +2525,7 @@ module Sequel 
     | 
|
| 
       2210 
2525 
     | 
    
         | 
| 
       2211 
2526 
     | 
    
         
             
                      association_filter_handle_inversion(op, expr, Array(lpks))
         
     | 
| 
       2212 
2527 
     | 
    
         
             
                    end
         
     | 
| 
      
 2528 
     | 
    
         
            +
                    alias one_through_one_association_filter_expression many_to_many_association_filter_expression
         
     | 
| 
       2213 
2529 
     | 
    
         | 
| 
       2214 
2530 
     | 
    
         
             
                    # Return a simple equality expression for filering by a many_to_one association
         
     | 
| 
       2215 
2531 
     | 
    
         
             
                    def many_to_one_association_filter_expression(op, ref, obj)
         
     | 
| 
         @@ -2304,17 +2620,20 @@ module Sequel 
     | 
|
| 
       2304 
2620 
     | 
    
         
             
                      requirements = eager_graph[:requirements]
         
     | 
| 
       2305 
2621 
     | 
    
         
             
                      reflection_map = @reflection_map = eager_graph[:reflections]
         
     | 
| 
       2306 
2622 
     | 
    
         
             
                      reciprocal_map = @reciprocal_map = eager_graph[:reciprocals]
         
     | 
| 
      
 2623 
     | 
    
         
            +
                      limit_map = @limit_map = eager_graph[:limits]
         
     | 
| 
       2307 
2624 
     | 
    
         
             
                      @unique = eager_graph[:cartesian_product_number] > 1
         
     | 
| 
       2308 
2625 
     | 
    
         | 
| 
       2309 
2626 
     | 
    
         
             
                      alias_map = @alias_map = {}
         
     | 
| 
       2310 
2627 
     | 
    
         
             
                      type_map = @type_map = {}
         
     | 
| 
       2311 
2628 
     | 
    
         
             
                      after_load_map = @after_load_map = {}
         
     | 
| 
       2312 
     | 
    
         
            -
                      limit_map = @limit_map = {}
         
     | 
| 
       2313 
2629 
     | 
    
         
             
                      reflection_map.each do |k, v|
         
     | 
| 
       2314 
2630 
     | 
    
         
             
                        alias_map[k] = v[:name]
         
     | 
| 
       2315 
     | 
    
         
            -
                        type_map[k] = v.returns_array?
         
     | 
| 
       2316 
2631 
     | 
    
         
             
                        after_load_map[k] = v[:after_load] unless v[:after_load].empty?
         
     | 
| 
       2317 
     | 
    
         
            -
                         
     | 
| 
      
 2632 
     | 
    
         
            +
                        type_map[k] = if v.returns_array?
         
     | 
| 
      
 2633 
     | 
    
         
            +
                          true
         
     | 
| 
      
 2634 
     | 
    
         
            +
                        elsif (limit_and_offset = limit_map[k]) && !limit_and_offset.last.nil?
         
     | 
| 
      
 2635 
     | 
    
         
            +
                          :offset
         
     | 
| 
      
 2636 
     | 
    
         
            +
                        end
         
     | 
| 
       2318 
2637 
     | 
    
         
             
                      end
         
     | 
| 
       2319 
2638 
     | 
    
         | 
| 
       2320 
2639 
     | 
    
         
             
                      # Make dependency map hash out of requirements array for each association.
         
     | 
| 
         @@ -2523,9 +2842,14 @@ module Sequel 
     | 
|
| 
       2523 
2842 
     | 
    
         
             
                            if lo = limit_map[ta]
         
     | 
| 
       2524 
2843 
     | 
    
         
             
                              limit, offset = lo
         
     | 
| 
       2525 
2844 
     | 
    
         
             
                              offset ||= 0
         
     | 
| 
       2526 
     | 
    
         
            -
                               
     | 
| 
      
 2845 
     | 
    
         
            +
                              if type_map[ta] == :offset
         
     | 
| 
      
 2846 
     | 
    
         
            +
                                [record.associations[assoc_name] = list[offset]]
         
     | 
| 
      
 2847 
     | 
    
         
            +
                              else
         
     | 
| 
      
 2848 
     | 
    
         
            +
                                list.replace(list[(offset)..(limit ? (offset)+limit-1 : -1)] || [])
         
     | 
| 
      
 2849 
     | 
    
         
            +
                              end
         
     | 
| 
      
 2850 
     | 
    
         
            +
                            else
         
     | 
| 
      
 2851 
     | 
    
         
            +
                              list
         
     | 
| 
       2527 
2852 
     | 
    
         
             
                            end
         
     | 
| 
       2528 
     | 
    
         
            -
                            list
         
     | 
| 
       2529 
2853 
     | 
    
         
             
                          elsif list
         
     | 
| 
       2530 
2854 
     | 
    
         
             
                            [list]
         
     | 
| 
       2531 
2855 
     | 
    
         
             
                          else
         
     |