Class Index [+]

Quicksearch

Sequel::Plugins::ManyThroughMany::ClassMethods

Public Instance Methods

many_through_many(name, through, opts={}, &block) click to toggle source

Create a many_through_many association. Arguments:

  • name - Same as associate, the name of the association.

  • through - The tables and keys to join between the current table and the associated table. Must be an array, with elements that are either 3 element arrays, or hashes with keys :table, :left, and :right. The required entries in the array/hash are:

    • :table (first array element) - The name of the table to join.

    • :left (middle array element) - The key joining the table to the previous table. Can use an array of symbols for a composite key association.

    • :right (last array element) - The key joining the table to the next table. Can use an array of symbols for a composite key association.

    If a hash is provided, the following keys are respected when using eager_graph:

    • :block - A proc to use as the block argument to join.

    • :conditions - Extra conditions to add to the JOIN ON clause. Must be a hash or array of two pairs.

    • :join_type - The join type to use for the join, defaults to :left_outer.

    • :only_conditions - Conditions to use for the join instead of the ones specified by the keys.

  • opts - The options for the associaion. Takes the same options as associate, and supports these additional options:

    • :left_primary_key - column in current table that the first :left option in through points to, as a symbol. Defaults to primary key of current table. Can use an array of symbols for a composite key association.

    • :right_primary_key - column in associated table that the final :right option in through points to, as a symbol. Defaults to primary key of the associated table. Can use an array of symbols for a composite key association.

    • :uniq - Adds a after_load callback that makes the array of objects unique.

     # File lib/sequel/plugins/many_through_many.rb, line 144
144:         def many_through_many(name, through, opts={}, &block)
145:           associate(:many_through_many, name, opts.merge(through.is_a?(Hash) ? through : {:through=>through}), &block)
146:         end

Private Instance Methods

def_many_through_many(opts) click to toggle source

Create the association methods and :eager_loader and :eager_grapher procs.

     # File lib/sequel/plugins/many_through_many.rb, line 151
151:         def def_many_through_many(opts)
152:           name = opts[:name]
153:           model = self
154:           opts[:read_only] = true
155:           opts[:after_load].unshift(:array_uniq!) if opts[:uniq]
156:           opts[:cartesian_product_number] ||= 2
157:           opts[:through] = opts[:through].map do |e|
158:             case e
159:             when Array
160:               raise(Error, "array elements of the through option/argument for many_through_many associations must have at least three elements") unless e.length == 3
161:               {:table=>e[0], :left=>e[1], :right=>e[2]}
162:             when Hash
163:               raise(Error, "hash elements of the through option/argument for many_through_many associations must contain :table, :left, and :right keys") unless e[:table] && e[:left] && e[:right]
164:               e
165:             else
166:               raise(Error, "the through option/argument for many_through_many associations must be an enumerable of arrays or hashes")
167:             end
168:           end
169: 
170:           left_key = opts[:left_key] = opts[:through].first[:left]
171:           uses_lcks = opts[:uses_left_composite_keys] = left_key.is_a?(Array)
172:           left_keys = Array(left_key)
173:           left_pk = (opts[:left_primary_key] ||= self.primary_key)
174:           left_pks = opts[:left_primary_keys] = Array(left_pk)
175:           opts[:dataset] ||= lambda do
176:             ds = opts.associated_class
177:             opts.reverse_edges.each{|t| ds = ds.join(t[:table], Array(t[:left]).zip(Array(t[:right])), :table_alias=>t[:alias])}
178:             ft = opts.final_reverse_edge
179:             ds.join(ft[:table],  Array(ft[:left]).zip(Array(ft[:right])) + left_keys.zip(left_pks.map{|k| send(k)}), :table_alias=>ft[:alias])
180:           end
181: 
182:           left_key_alias = opts[:left_key_alias] ||= opts.default_associated_key_alias
183:           opts[:eager_loader] ||= lambda do |eo|
184:             h = eo[:key_hash][left_pk]
185:             rows = eo[:rows]
186:             rows.each{|object| object.associations[name] = []}
187:             ds = opts.associated_class 
188:             opts.reverse_edges.each{|t| ds = ds.join(t[:table], Array(t[:left]).zip(Array(t[:right])), :table_alias=>t[:alias])}
189:             ft = opts.final_reverse_edge
190:             ds = ds.join(ft[:table], Array(ft[:left]).zip(Array(ft[:right])) + [[opts.eager_loading_predicate_key, h.keys]], :table_alias=>ft[:alias])
191:             ds = model.eager_loading_dataset(opts, ds, nil, eo[:associations], eo)
192:             case opts.eager_limit_strategy
193:             when :window_function
194:               delete_rn = true
195:               rn = ds.row_number_column
196:               ds = apply_window_function_eager_limit_strategy(ds, opts)
197:             when :correlated_subquery
198:               ds = apply_correlated_subquery_eager_limit_strategy(ds, opts) do |xds|
199:                 dsa = ds.send(:dataset_alias, 2)
200:                 opts.reverse_edges.each{|t| xds = xds.join(t[:table], Array(t[:left]).zip(Array(t[:right])), :table_alias=>t[:alias])}
201:                 xds.join(ft[:table], Array(ft[:left]).zip(Array(ft[:right])) + left_keys.map{|k| [k, SQL::QualifiedIdentifier.new(ft[:table], k)]}, :table_alias=>dsa)
202:               end
203:             end
204:             ds.all do |assoc_record|
205:               assoc_record.values.delete(rn) if delete_rn
206:               hash_key = if uses_lcks
207:                 left_key_alias.map{|k| assoc_record.values.delete(k)}
208:               else
209:                 assoc_record.values.delete(left_key_alias)
210:               end
211:               next unless objects = h[hash_key]
212:               objects.each{|object| object.associations[name].push(assoc_record)}
213:             end
214:             if opts.eager_limit_strategy == :ruby
215:               limit, offset = opts.limit_and_offset
216:               rows.each{|o| o.associations[name] = o.associations[name].slice(offset||0, limit) || []}
217:             end
218:           end
219: 
220:           join_type = opts[:graph_join_type]
221:           select = opts[:graph_select]
222:           graph_block = opts[:graph_block]
223:           only_conditions = opts[:graph_only_conditions]
224:           use_only_conditions = opts.include?(:graph_only_conditions)
225:           conditions = opts[:graph_conditions]
226:           opts[:eager_grapher] ||= proc do |eo|
227:             ds = eo[:self]
228:             iq = eo[:implicit_qualifier]
229:             opts.edges.each do |t|
230:               ds = ds.graph(t[:table], t.fetch(:only_conditions, (Array(t[:right]).zip(Array(t[:left])) + t[:conditions])), :select=>false, :table_alias=>ds.unused_table_alias(t[:table]), :join_type=>t[:join_type], :implicit_qualifier=>iq, &t[:block])
231:               iq = nil
232:             end
233:             fe = opts.final_edge
234:             ds.graph(opts.associated_class, use_only_conditions ? only_conditions : (Array(opts.right_primary_key).zip(Array(fe[:left])) + conditions), :select=>select, :table_alias=>eo[:table_alias], :join_type=>join_type, &graph_block)
235:           end
236: 
237:           def_association_dataset_methods(opts)
238:         end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.