Module | Sequel::Plugins::DatasetAssociations::DatasetMethods |
In: |
lib/sequel/plugins/dataset_associations.rb
|
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, line 80 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