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
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.
Generated with the Darkfish Rdoc Generator 1.1.6.