module Sequel::Plugins::ManyThroughMany::ClassMethods

Public Instance Methods

many_through_many(name, through, opts=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 many_to_many.

    # File lib/sequel/plugins/many_through_many.rb
216 def many_through_many(name, through, opts=OPTS, &block)
217   associate(:many_through_many, name, opts.merge(through.is_a?(Hash) ? through : {:through=>through}), &block)
218 end
one_through_many(name, through, opts=OPTS, &block) click to toggle source

Creates a one_through_many association. See many_through_many for arguments.

    # File lib/sequel/plugins/many_through_many.rb
221 def one_through_many(name, through, opts=OPTS, &block)
222   associate(:one_through_many, name, opts.merge(through.is_a?(Hash) ? through : {:through=>through}), &block)
223 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
228 def def_many_through_many(opts)
229   one_through_many = opts[:type] == :one_through_many
230   opts[:read_only] = true
231   if opts[:uniq]
232     opts[:after_load] ||= []
233     opts[:after_load].unshift(:array_uniq!)
234   end
235   opts[:cartesian_product_number] ||= one_through_many ? 0 : 2
236   opts[:through] = opts[:through].map do |e|
237     case e
238     when Array
239       raise(Error, "array elements of the through option/argument for many_through_many associations must have at least three elements") unless e.length == 3
240       {:table=>e[0], :left=>e[1], :right=>e[2]}
241     when Hash
242       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]
243       e
244     else
245       raise(Error, "the through option/argument for many_through_many associations must be an enumerable of arrays or hashes")
246     end
247   end
248 
249   left_key = opts[:left_key] = opts[:through].first[:left]
250   opts[:left_keys] = Array(left_key)
251   opts[:uses_left_composite_keys] = left_key.is_a?(Array)
252   left_pk = (opts[:left_primary_key] ||= self.primary_key)
253   raise(Error, "no primary key specified for #{inspect}") unless left_pk
254   opts[:eager_loader_key] = left_pk unless opts.has_key?(:eager_loader_key)
255   opts[:left_primary_keys] = Array(left_pk)
256   lpkc = opts[:left_primary_key_column] ||= left_pk
257   lpkcs = opts[:left_primary_key_columns] ||= Array(lpkc)
258   opts[:dataset] ||= opts.association_dataset_proc
259 
260   opts[:left_key_alias] ||= opts.default_associated_key_alias
261   opts[:eager_loader] ||= opts.method(:default_eager_loader)
262 
263   join_type = opts[:graph_join_type]
264   select = opts[:graph_select]
265   graph_block = opts[:graph_block]
266   only_conditions = opts[:graph_only_conditions]
267   use_only_conditions = opts.include?(:graph_only_conditions)
268   conditions = opts[:graph_conditions]
269   opts[:eager_grapher] ||= proc do |eo|
270     ds = eo[:self]
271     iq = eo[:implicit_qualifier]
272     egls = eo[:limit_strategy]
273     if egls && egls != :ruby
274       associated_key_array = opts.associated_key_array
275       orig_egds = egds = eager_graph_dataset(opts, eo)
276       opts.reverse_edges.each{|t| egds = egds.join(t[:table], Array(t[:left]).zip(Array(t[:right])), :table_alias=>t[:alias], :qualify=>:deep)}
277       ft = opts.final_reverse_edge
278       egds = egds.join(ft[:table], Array(ft[:left]).zip(Array(ft[:right])), :table_alias=>ft[:alias], :qualify=>:deep).
279         select_all(egds.first_source).
280         select_append(*associated_key_array)
281       egds = opts.apply_eager_graph_limit_strategy(egls, egds)
282       ds.graph(egds, associated_key_array.map(&:alias).zip(Array(lpkcs)) + conditions, :qualify=>:deep, :table_alias=>eo[:table_alias], :implicit_qualifier=>iq, :join_type=>eo[:join_type]||join_type, :join_only=>eo[:join_only], :from_self_alias=>eo[:from_self_alias], :select=>select||orig_egds.columns, &graph_block)
283     else
284       opts.edges.each do |t|
285         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=>eo[:join_type]||t[:join_type], :join_only=>eo[:join_only], :qualify=>:deep, :implicit_qualifier=>iq, :from_self_alias=>eo[:from_self_alias], &t[:block])
286         iq = nil
287       end
288       fe = opts.final_edge
289       ds.graph(opts.associated_class.dataset, use_only_conditions ? only_conditions : (Array(opts.right_primary_key).zip(Array(fe[:left])) + conditions), :select=>select, :table_alias=>eo[:table_alias], :qualify=>:deep, :join_type=>eo[:join_type]||join_type, :join_only=>eo[:join_only], &graph_block)
290     end
291   end
292 end
def_one_through_many(opts) click to toggle source

Use def_many_through_many, since they share pretty much the same code.

    # File lib/sequel/plugins/many_through_many.rb
295 def def_one_through_many(opts)
296   def_many_through_many(opts)
297 end