diff options
Diffstat (limited to 'activerecord/lib/active_record/relation/predicate_builder.rb')
-rw-r--r-- | activerecord/lib/active_record/relation/predicate_builder.rb | 102 |
1 files changed, 28 insertions, 74 deletions
diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb index 183fe91c05..885c26d7aa 100644 --- a/activerecord/lib/active_record/relation/predicate_builder.rb +++ b/activerecord/lib/active_record/relation/predicate_builder.rb @@ -1,11 +1,4 @@ -require "active_record/relation/predicate_builder/array_handler" -require "active_record/relation/predicate_builder/base_handler" -require "active_record/relation/predicate_builder/basic_object_handler" -require "active_record/relation/predicate_builder/range_handler" -require "active_record/relation/predicate_builder/relation_handler" - -require "active_record/relation/predicate_builder/association_query_value" -require "active_record/relation/predicate_builder/polymorphic_array_value" +# frozen_string_literal: true module ActiveRecord class PredicateBuilder # :nodoc: @@ -15,12 +8,12 @@ module ActiveRecord @table = table @handlers = [] - register_handler(BasicObject, BasicObjectHandler.new) + register_handler(BasicObject, BasicObjectHandler.new(self)) register_handler(Base, BaseHandler.new(self)) - register_handler(Range, RangeHandler.new) - register_handler(RangeHandler::RangeWithBinds, RangeHandler.new) + register_handler(Range, RangeHandler.new(self)) register_handler(Relation, RelationHandler.new) register_handler(Array, ArrayHandler.new(self)) + register_handler(Set, ArrayHandler.new(self)) end def build_from_hash(attributes) @@ -28,11 +21,6 @@ module ActiveRecord expand_from_hash(attributes) end - def create_binds(attributes) - attributes = convert_dot_notation_to_hash(attributes) - create_binds_for_hash(attributes) - end - def self.references(attributes) attributes.map do |key, value| if value.is_a?(Hash) @@ -63,8 +51,11 @@ module ActiveRecord handler_for(value).call(attribute, value) end - # TODO Change this to private once we've dropped Ruby 2.2 support. - # Workaround for Ruby 2.2 "private attribute?" warning. + def build_bind_attribute(column_name, value) + attr = Relation::QueryAttribute.new(column_name.to_s, value, table.type(column_name)) + Arel::Nodes::BindParam.new(attr) + end + protected attr_reader :table @@ -75,29 +66,13 @@ module ActiveRecord attributes.flat_map do |key, value| if value.is_a?(Hash) && !table.has_column?(key) associated_predicate_builder(key).expand_from_hash(value) - else - build(table.arel_attribute(key), value) - end - end - end - - def create_binds_for_hash(attributes) - result = attributes.dup - binds = [] - - attributes.each do |column_name, value| - case - when value.is_a?(Hash) && !table.has_column?(column_name) - attrs, bvs = associated_predicate_builder(column_name).create_binds_for_hash(value) - result[column_name] = attrs - binds += bvs - when table.associated_with?(column_name) + elsif 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) - associated_table = table.associated_table(column_name) + associated_table = table.associated_table(key) if associated_table.polymorphic_association? case value.is_a?(Array) ? value.first : value when Base, Relation @@ -107,35 +82,18 @@ module ActiveRecord end klass ||= AssociationQueryValue - result[column_name] = klass.new(associated_table, value).queries.map do |query| - attrs, bvs = create_binds_for_hash(query) - binds.concat(bvs) - attrs - end - when value.is_a?(Range) && !table.type(column_name).respond_to?(:subtype) - first = value.begin - last = value.end - unless first.respond_to?(:infinite?) && first.infinite? - binds << build_bind_param(column_name, first) - first = Arel::Nodes::BindParam.new + queries = klass.new(associated_table, value).queries.map do |query| + expand_from_hash(query).reduce(&:and) end - unless last.respond_to?(:infinite?) && last.infinite? - binds << build_bind_param(column_name, last) - last = Arel::Nodes::BindParam.new - end - - result[column_name] = RangeHandler::RangeWithBinds.new(first, last, value.exclude_end?) + queries.reduce(&:or) + # FIXME: Deprecate this and provide a public API to force equality + elsif (value.is_a?(Range) || value.is_a?(Array)) && + table.type(key.to_s).respond_to?(:subtype) + BasicObjectHandler.new(self).call(table.arel_attribute(key), value) else - if can_be_bound?(column_name, value) - result[column_name] = Arel::Nodes::BindParam.new - binds << build_bind_param(column_name, value) - elsif value.is_a?(Relation) - binds.concat(value.bound_attributes) - end + build(table.arel_attribute(key), value) end end - - [result, binds] end private @@ -163,18 +121,14 @@ module ActiveRecord def handler_for(object) @handlers.detect { |klass, _| klass === object }.last end - - def can_be_bound?(column_name, value) - case value - when Array, Range - table.type(column_name).respond_to?(:subtype) - else - !value.nil? && handler_for(value).is_a?(BasicObjectHandler) - end - end - - def build_bind_param(column_name, value) - Relation::QueryAttribute.new(column_name.to_s, value, table.type(column_name)) - end end end + +require "active_record/relation/predicate_builder/array_handler" +require "active_record/relation/predicate_builder/base_handler" +require "active_record/relation/predicate_builder/basic_object_handler" +require "active_record/relation/predicate_builder/range_handler" +require "active_record/relation/predicate_builder/relation_handler" + +require "active_record/relation/predicate_builder/association_query_value" +require "active_record/relation/predicate_builder/polymorphic_array_value" |