diff options
Diffstat (limited to 'activerecord/lib/active_record/relation/predicate_builder.rb')
-rw-r--r-- | activerecord/lib/active_record/relation/predicate_builder.rb | 71 |
1 files changed, 42 insertions, 29 deletions
diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb index df663a84ed..29422bf131 100644 --- a/activerecord/lib/active_record/relation/predicate_builder.rb +++ b/activerecord/lib/active_record/relation/predicate_builder.rb @@ -4,6 +4,7 @@ module ActiveRecord require "active_record/relation/predicate_builder/association_query_handler" require "active_record/relation/predicate_builder/base_handler" require "active_record/relation/predicate_builder/basic_object_handler" + require "active_record/relation/predicate_builder/case_sensitive_handler" require "active_record/relation/predicate_builder/class_handler" require "active_record/relation/predicate_builder/polymorphic_array_handler" require "active_record/relation/predicate_builder/range_handler" @@ -16,6 +17,7 @@ module ActiveRecord @handlers = [] register_handler(BasicObject, BasicObjectHandler.new) + register_handler(CaseSensitiveHandler::Value, CaseSensitiveHandler.new) register_handler(Class, ClassHandler.new(self)) register_handler(Base, BaseHandler.new(self)) register_handler(Range, RangeHandler.new) @@ -31,19 +33,9 @@ module ActiveRecord expand_from_hash(attributes) end - def create_binds(attributes) + def create_binds(attributes, options) attributes = convert_dot_notation_to_hash(attributes) - create_binds_for_hash(attributes) - end - - def expand(column, value) - # 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) - value = AssociationQueryHandler.value_for(table, column, value) if table.associated_with?(column) - build(table.arel_attribute(column), value) + create_binds_for_hash(attributes, options) end def self.references(attributes) @@ -84,28 +76,28 @@ module ActiveRecord return ["1=0"] if attributes.empty? attributes.flat_map do |key, value| - if value.is_a?(Hash) + if value.is_a?(Hash) && !table.has_column?(key) associated_predicate_builder(key).expand_from_hash(value) else - expand(key, value) + build(table.arel_attribute(key), value) end end end - - def create_binds_for_hash(attributes) + def create_binds_for_hash(attributes, options) result = attributes.dup binds = [] attributes.each do |column_name, value| - case value - when Hash - attrs, bvs = associated_predicate_builder(column_name).create_binds_for_hash(value) + case + when value.is_a?(Hash) && !table.has_column?(column_name) + attrs, bvs = associated_predicate_builder(column_name).create_binds_for_hash(value, options) result[column_name] = attrs binds += bvs - when Relation + next + when value.is_a?(Relation) binds += value.bound_attributes - when Range + 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? @@ -118,11 +110,24 @@ module ActiveRecord end result[column_name] = RangeHandler::RangeWithBinds.new(first, last, value.exclude_end?) - else - if can_be_bound?(column_name, value) - result[column_name] = Arel::Nodes::BindParam.new - binds << build_bind_param(column_name, value) - end + when can_be_bound?(column_name, value) + result[column_name] = + if perform_case_sensitive?(options) + CaseSensitiveHandler::Value.new( + Arel::Nodes::BindParam.new, table, options[:case_sensitive]) + else + Arel::Nodes::BindParam.new + end + binds << build_bind_param(column_name, value) + end + + # 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 table.associated_with?(column_name) + result[column_name] = AssociationQueryHandler.value_for(table, column_name, value) end end @@ -156,9 +161,17 @@ module ActiveRecord end def can_be_bound?(column_name, value) - !value.nil? && - handler_for(value).is_a?(BasicObjectHandler) && - !table.associated_with?(column_name) + return if table.associated_with?(column_name) + case value + when Array, Range + table.type(column_name).respond_to?(:subtype) + else + !value.nil? && handler_for(value).is_a?(BasicObjectHandler) + end + end + + def perform_case_sensitive?(options) + options.key?(:case_sensitive) end def build_bind_param(column_name, value) |