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, line 216
def many_through_many(name, through, opts=OPTS, &block)
  associate(:many_through_many, name, opts.merge(through.is_a?(Hash) ? through : {:through=>through}), &block)
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, line 221
def one_through_many(name, through, opts=OPTS, &block)
  associate(:one_through_many, name, opts.merge(through.is_a?(Hash) ? through : {:through=>through}), &block)
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 228
def def_many_through_many(opts)
  one_through_many = opts[:type] == :one_through_many
  opts[:read_only] = true
  opts[:after_load].unshift(:array_uniq!) if opts[:uniq]
  opts[:cartesian_product_number] ||= one_through_many ? 0 : 2
  opts[:through] = opts[:through].map do |e|
    case e
    when Array
      raise(Error, "array elements of the through option/argument for many_through_many associations must have at least three elements") unless e.length == 3
      {:table=>e[0], :left=>e[1], :right=>e[2]}
    when Hash
      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]
      e
    else
      raise(Error, "the through option/argument for many_through_many associations must be an enumerable of arrays or hashes")
    end
  end

  left_key = opts[:left_key] = opts[:through].first[:left]
  opts[:left_keys] = Array(left_key)
  opts[:uses_left_composite_keys] = left_key.is_a?(Array)
  left_pk = (opts[:left_primary_key] ||= self.primary_key)
  raise(Error, "no primary key specified for #{inspect}") unless left_pk
  opts[:eager_loader_key] = left_pk unless opts.has_key?(:eager_loader_key)
  opts[:left_primary_keys] = Array(left_pk)
  lpkc = opts[:left_primary_key_column] ||= left_pk
  lpkcs = opts[:left_primary_key_columns] ||= Array(lpkc)
  opts[:dataset] ||= opts.association_dataset_proc

  opts[:left_key_alias] ||= opts.default_associated_key_alias
  opts[:eager_loader] ||= opts.method(:default_eager_loader)

  join_type = opts[:graph_join_type]
  select = opts[:graph_select]
  graph_block = opts[:graph_block]
  only_conditions = opts[:graph_only_conditions]
  use_only_conditions = opts.include?(:graph_only_conditions)
  conditions = opts[:graph_conditions]
  opts[:eager_grapher] ||= proc do |eo|
    ds = eo[:self]
    iq = eo[:implicit_qualifier]
    egls = eo[:limit_strategy]
    if egls && egls != :ruby
      associated_key_array = opts.associated_key_array
      orig_egds = egds = eager_graph_dataset(opts, eo)
      opts.reverse_edges.each{|t| egds = egds.join(t[:table], Array(t[:left]).zip(Array(t[:right])), :table_alias=>t[:alias], :qualify=>:deep)}
      ft = opts.final_reverse_edge
      egds = egds.join(ft[:table], Array(ft[:left]).zip(Array(ft[:right])), :table_alias=>ft[:alias], :qualify=>:deep).
        select_all(egds.first_source).
        select_append(*associated_key_array)
      egds = opts.apply_eager_graph_limit_strategy(egls, egds)
      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)
    else
      opts.edges.each do |t|
        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])
        iq = nil
      end
      fe = opts.final_edge
      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], :qualify=>:deep, :join_type=>eo[:join_type]||join_type, :join_only=>eo[:join_only], &graph_block)
    end
  end
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, line 292
def def_one_through_many(opts)
  def_many_through_many(opts)
end