Class: ActiveRecord::PredicateBuilder
- Inherits:
-
Object
- Object
- ActiveRecord::PredicateBuilder
- Defined in:
- ext/active_record/relation/predicate_builder.rb
Overview
The last ref that this code was synced with Rails ref: 90a1eaa1b3
Instance Method Summary collapse
Instance Method Details
#expand_from_hash(attributes, &block) ⇒ Object
:nodoc:
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'ext/active_record/relation/predicate_builder.rb', line 8 def (attributes, &block) return [Arel.sql("1=0", retryable: true)] if attributes.empty? attributes.flat_map do |key, value| if key.is_a?(Array) && key.size == 1 key = key.first value = value.flatten end if key.is_a?(Array) queries = Array(value).map do |ids_set| raise ArgumentError, "Expected corresponding value for #{key} to be an Array" unless ids_set.is_a?(Array) (key.zip(ids_set).to_h) end grouping_queries(queries) elsif value.is_a?(Hash) && !table.has_column?(key) ka = table.associated_table(key, &block) .predicate_builder.(value.stringify_keys) if self.table.instance_variable_get(:@klass).sunstone? ka.each { |k| if k.left.is_a?(Arel::Attributes::Attribute) || k.left.is_a?(Arel::Attributes::Relation) k.left = Arel::Attributes::Relation.new(k.left, key) end } end ka # TODO: drop this Rails 8.0 compatibility branch when Rails 8.0 support is # dropped, and always use table.associated_with(key). (8.0 named it associated_with?) elsif (associated_reflection = (table.respond_to?(:associated_with) ? table.associated_with(key) : table.associated_with?(key))) # Find the foreign key when using queries such as: # Post.where(author: author) # # For polymorphic relationships, find the foreign key and type: # PriceEstimate.where(estimate_of: treasure) if associated_reflection.polymorphic? value = [value] unless value.is_a?(Array) klass = PolymorphicArrayValue elsif associated_reflection.through_reflection? associated_table = table.associated_table(key) next associated_table.predicate_builder.( associated_table.primary_key => value ) end klass ||= AssociationQueryValue # TODO: drop this Rails 8.0 compatibility branch when Rails 8.0 support is # dropped, and always pass associated_reflection. # Rails 8.1 threads the reflection through the value objects; 8.0 threads the table metadata. query_source = table.respond_to?(:associated_with) ? associated_reflection : table.associated_table(key) queries = klass.new(query_source, value).queries.map! do |query| # If the query produced is identical to attributes don't go any deeper. # Prevents stack level too deep errors when association and foreign_key are identical. query == attributes ? self[key, value] : (query) end grouping_queries(queries) elsif table.aggregated_with?(key) mapping = table.reflect_on_aggregation(key).mapping values = value.nil? ? [nil] : Array.wrap(value) if mapping.length == 1 || values.empty? column_name, aggr_attr = mapping.first values = values.map do |object| object.respond_to?(aggr_attr) ? object.public_send(aggr_attr) : object end self[column_name, values] else queries = values.map do |object| mapping.map do |field_attr, aggregate_attr| self[field_attr, object.try!(aggregate_attr)] end end grouping_queries(queries) end else self[key, value] end end end |