Create a #many_through_many association. Arguments:
Same as associate, the name of the association.
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:
The name of the table to join.
The key joining the table to the previous table. Can use an array of symbols for a composite key association.
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:
A proc to use as the block argument to join.
Extra conditions to add to the JOIN ON clause. Must be a hash or array of two pairs.
The join type to use for the join, defaults to :left_outer.
Conditions to use for the join instead of the ones specified by the keys.
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
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
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) 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{|v| v.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
Use #def_many_through_many, since they share pretty much the same code.
# File lib/sequel/plugins/many_through_many.rb, line 274 def def_one_through_many(opts) def_many_through_many(opts) end