module Sequel::Plugins::DatasetAssociations::DatasetMethods
Public Instance Methods
associated(name)
click to toggle source
For the association given by name
, return a dataset of associated objects such that it would return the union of calling the association method on all objects returned by the current dataset.
This supports most options that are supported when eager loading. However, it will only work for limited associations or *_one associations with orders if the database supports window functions.
# File lib/sequel/plugins/dataset_associations.rb 80 def associated(name) 81 raise Error, "unrecognized association name: #{name.inspect}" unless r = model.association_reflection(name) 82 ds = r.associated_class.dataset 83 sds = opts[:limit] ? self : unordered 84 ds = case r[:type] 85 when :many_to_one 86 ds.where(r.qualified_primary_key=>sds.select(*Array(r[:qualified_key]))) 87 when :one_to_one, :one_to_many 88 r.send(:apply_filter_by_associations_limit_strategy, ds.where(r.qualified_key=>sds.select(*Array(r.qualified_primary_key)))) 89 when :many_to_many, :one_through_one 90 mds = r.associated_class.dataset. 91 join(r[:join_table], r[:right_keys].zip(r.right_primary_keys)). 92 select(*Array(r.qualified_right_key)). 93 where(r.qualify(r.join_table_alias, r[:left_keys])=>sds.select(*r.qualify(model.table_name, r[:left_primary_key_columns]))) 94 ds.where(r.qualified_right_primary_key=>r.send(:apply_filter_by_associations_limit_strategy, mds)) 95 when :many_through_many, :one_through_many 96 if r.reverse_edges.empty? 97 mds = r.associated_dataset 98 fe = r.edges.first 99 selection = Array(r.qualify(fe[:table], r.final_edge[:left])) 100 predicate_key = r.qualify(fe[:table], fe[:right]) 101 else 102 mds = model.dataset 103 iq = model.table_name 104 edges = r.edges.map(&:dup) 105 edges << r.final_edge.dup 106 edges.each do |e| 107 alias_expr = e[:table] 108 aliaz = mds.unused_table_alias(e[:table]) 109 unless aliaz == alias_expr 110 alias_expr = Sequel.as(e[:table], aliaz) 111 end 112 e[:alias] = aliaz 113 mds = mds.join(alias_expr, Array(e[:right]).zip(Array(e[:left])), :implicit_qualifier=>iq) 114 iq = nil 115 end 116 fe, f1e, f2e = edges.values_at(0, -1, -2) 117 selection = Array(r.qualify(f2e[:alias], f1e[:left])) 118 predicate_key = r.qualify(fe[:alias], fe[:right]) 119 end 120 121 mds = mds. 122 select(*selection). 123 where(predicate_key=>sds.select(*r.qualify(model.table_name, r[:left_primary_key_columns]))) 124 ds.where(r.qualified_right_primary_key=>r.send(:apply_filter_by_associations_limit_strategy, mds)) 125 when :pg_array_to_many 126 ds.where(Sequel[r.primary_key=>sds.select{Sequel.pg_array_op(r.qualify(r[:model].table_name, r[:key])).unnest}]) 127 when :many_to_pg_array 128 ds.where(Sequel.function(:coalesce, Sequel.pg_array_op(r[:key]).overlaps(sds.select{array_agg(r.qualify(r[:model].table_name, r.primary_key))}), false)) 129 else 130 raise Error, "unrecognized association type for association #{name.inspect}: #{r[:type].inspect}" 131 end 132 133 ds = r.apply_eager_dataset_changes(ds).unlimited 134 135 if r[:dataset_associations_join] 136 case r[:type] 137 when :many_to_many, :one_through_one 138 ds = ds.join(r[:join_table], r[:right_keys].zip(r.right_primary_keys)) 139 when :many_through_many, :one_through_many 140 (r.reverse_edges + [r.final_reverse_edge]).each{|e| ds = ds.join(e[:table], e.fetch(:only_conditions, (Array(e[:left]).zip(Array(e[:right])) + Array(e[:conditions]))), :table_alias=>ds.unused_table_alias(e[:table]), :qualify=>:deep, &e[:block])} 141 end 142 end 143 144 ds 145 end