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 198
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 203
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 210
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)
  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{|v| v.alias}.zip(Array(lpkcs)) + conditions, :qualify=>:deep, :table_alias=>eo[:table_alias], :implicit_qualifier=>iq, :join_type=>eo[:join_type]||join_type, :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], :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, &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 273
def def_one_through_many(opts)
  def_many_through_many(opts)
end