module Sequel::Plugins::DatasetAssociations::DatasetMethods

  1. lib/sequel/plugins/dataset_associations.rb

Methods

Public Instance

  1. associated

Public Instance methods

associated(name)

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.

[show source]
    # File lib/sequel/plugins/dataset_associations.rb
 83 def associated(name)
 84   raise Error, "unrecognized association name: #{name.inspect}" unless r = model.association_reflection(name)
 85   klass = r.associated_class
 86   sds = opts[:limit] ? self : unordered
 87 
 88   if r.send(:filter_by_associations_limit_strategy) == :lateral_subquery
 89     ds = r.send(:associated_eager_dataset)
 90 
 91     case r[:type]
 92     when :one_to_one, :one_to_many
 93       sds = sds.select(*Array(r.qualified_primary_key))
 94     else
 95       sds = sds.select(*r[:left_primary_keys])
 96       ds = ds.select_all(klass.table_name)
 97       update_select = true
 98     end
 99 
100     ds = r.send(:apply_lateral_subquery_eager_limit_strategy, ds, sds, r.limit_and_offset)
101     ds = ds.clone(:select=>ds.opts[:select][0,1]) if update_select
102     return ds.clone(:eager=>nil, :eager_graph=>nil)
103   end
104 
105   ds = klass.dataset
106   ds = case r[:type]
107   when :many_to_one
108     ds.where(r.qualified_primary_key=>sds.select(*Array(r[:qualified_key])))
109   when :one_to_one, :one_to_many
110     r.send(:apply_filter_by_associations_limit_strategy, ds.where(r.qualified_key=>sds.select(*Array(r.qualified_primary_key))))
111   when :many_to_many, :one_through_one
112     mds = r.associated_class.dataset.
113       join(r[:join_table], r[:right_keys].zip(r.right_primary_keys)).
114       select(*Array(r.qualified_right_key)).
115       where(r.qualify(r.join_table_alias, r[:left_keys])=>sds.select(*r.qualify(model.table_name, r[:left_primary_key_columns])))
116     ds.where(r.qualified_right_primary_key=>r.send(:apply_filter_by_associations_limit_strategy, mds))
117   when :many_through_many, :one_through_many
118     if r.reverse_edges.empty?
119       mds = r.associated_dataset
120       fe = r.edges.first
121       selection = Array(r.qualify(fe[:table], r.final_edge[:left]))
122       predicate_key = r.qualify(fe[:table], fe[:right])
123     else
124       mds = model.dataset
125       iq = model.table_name
126       edges = r.edges.map(&:dup)
127       edges << r.final_edge.dup
128       edges.each do |e|
129         alias_expr = e[:table]
130         aliaz = mds.unused_table_alias(e[:table])
131         unless aliaz == alias_expr
132           alias_expr = Sequel.as(e[:table], aliaz)
133         end
134         e[:alias] = aliaz
135         mds = mds.join(alias_expr, Array(e[:right]).zip(Array(e[:left])), :implicit_qualifier=>iq)
136         iq = nil
137       end
138       fe, f1e, f2e = edges.values_at(0, -1, -2)
139       selection = Array(r.qualify(f2e[:alias], f1e[:left]))
140       predicate_key = r.qualify(fe[:alias], fe[:right])
141     end
142 
143     mds = mds.
144       select(*selection).
145       where(predicate_key=>sds.select(*r.qualify(model.table_name, r[:left_primary_key_columns])))
146     ds.where(r.qualified_right_primary_key=>r.send(:apply_filter_by_associations_limit_strategy, mds))
147   when :pg_array_to_many
148     ds.where(Sequel[r.primary_key=>sds.select{Sequel.pg_array_op(r.qualify(r[:model].table_name, r[:key])).unnest}])
149   when :many_to_pg_array
150     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))
151   else
152     raise Error, "unrecognized association type for association #{name.inspect}: #{r[:type].inspect}"
153   end
154 
155   ds = r.apply_eager_dataset_changes(ds).unlimited
156 
157   if r[:dataset_associations_join]
158     case r[:type]
159     when :many_to_many, :one_through_one
160       ds = ds.join(r[:join_table], r[:right_keys].zip(r.right_primary_keys))
161     when :many_through_many, :one_through_many
162       (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])}
163     end
164   end
165 
166   ds
167 end