123456789_123456789_123456789_123456789_123456789_

Class: ActiveRecord::PredicateBuilder::AssociationQueryValue

Do not use. This class is for internal use only.

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

.new(reflection, value, origin_class) ⇒ AssociationQueryValue

[ GitHub ]

  
# File 'activerecord/lib/active_record/relation/predicate_builder/association_query_value.rb', line 6

def initialize(reflection, value, origin_class)
  @reflection = reflection
  @value = value
  @origin_class = origin_class
end

Instance Attribute Details

#reflection (readonly, private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/relation/predicate_builder/association_query_value.rb', line 25

attr_reader :reflection, :value

#value (readonly, private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/relation/predicate_builder/association_query_value.rb', line 25

attr_reader :reflection, :value

Instance Method Details

#association_route_for(target) (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/relation/predicate_builder/association_query_value.rb', line 83

def association_route_for(target)
  destination_class = case target
  when Relation
    target.model
  when Base
    target.class
  else
    reflection.klass
  end
  (@routes ||= {})[destination_class] ||= reflection.association_route(origin_class: @origin_class, destination_class: destination_class)
end

#convert_to_id(value, destination_key) (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/relation/predicate_builder/association_query_value.rb', line 99

def convert_to_id(value, destination_key)
  if value.is_a?(Base)
    destination_key.value_of(value)
  elsif value.respond_to?(destination_key.name)
    value.public_send(destination_key.name)
  else
    value
  end
end

#ensure_ids_are_sufficient! (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/relation/predicate_builder/association_query_value.rb', line 39

def ensure_ids_are_sufficient!
  return if association_route_for(nil).predicate_accepts_bare_id?

  items = value.is_a?(Array) ? value : [value]
  if items.any? { |item| !item.nil? && !record_or_relation?(item) }
    raise ArgumentError, "#{reflection.active_record}##{reflection.name} matches on more than one column, " \
      "so it must be queried with records or relations rather than ids"
  end
end

#ids(query_value, route) (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/relation/predicate_builder/association_query_value.rb', line 63

def ids(query_value, route)
  destination_key = route.destination_key
  case query_value
  when Relation
    relation = query_value
    relation = relation.select(destination_key.name) if relation.select_values.empty?
    route.destination_fixed_values.each do |column, value|
      physical_column = relation.model.attribute_aliases[column] || column
      unless relation.where_values_hash.has_key?(physical_column)
        relation = relation.where(column => value)
      end
    end
    relation
  when Array
    query_value.map { |item| convert_to_id(item, destination_key) }
  else
    [convert_to_id(query_value, destination_key)]
  end
end

#nil_query (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/relation/predicate_builder/association_query_value.rb', line 56

def nil_query
  # Query-constraint columns may still be populated when a reference is
  # unset, so a nil query should only match against the reference columns.
  key = association_route_for(nil).reference_origin_key
  key.where_hash(key.map_value { nil })
end

#queries

[ GitHub ]

  
# File 'activerecord/lib/active_record/relation/predicate_builder/association_query_value.rb', line 12

def queries
  ensure_ids_are_sufficient!

  if value.nil?
    [nil_query]
  elsif value.is_a?(Array)
    queries_for_array(value)
  else
    queries_for_route(value, association_route_for(value))
  end
end

#queries_for_array(values) (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/relation/predicate_builder/association_query_value.rb', line 27

def queries_for_array(values)
  if values.none? { |item| item.nil? || record_or_relation?(item) }
    return queries_for_route(values, association_route_for(nil))
  end

  items_by_route = values.group_by { |item| association_route_for(item) unless item.nil? }
  nils = items_by_route.delete(nil)
  queries = items_by_route.flat_map { |route, items| queries_for_route(items, route) }
  queries << nil_query if nils
  queries
end

#queries_for_route(query_value, route) (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/relation/predicate_builder/association_query_value.rb', line 49

def queries_for_route(query_value, route)
  id_list = ids(query_value, route)
  id_list = id_list.pluck(route.destination_key.name) if route.origin_key.composite? && id_list.is_a?(Relation)

  route.origin_key.where_clauses(id_list)
end

#record_or_relation?(target) ⇒ Boolean (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/relation/predicate_builder/association_query_value.rb', line 95

def record_or_relation?(target)
  target.is_a?(Base) || target.is_a?(Relation)
end