提交 a3936bbe 编写于 作者: S Sean Griffin

Change `PredicateBuilder` handler methods to instance methods

This will allow us to pass the predicate builder into the constructor of
these handlers. The procs had to be changed to objects, because the
`PredicateBuilder` needs to be marshalable. If we ever decide to make
`register_handler` part of the public API, we should come up with a
better solution which allows procs.

/cc @mrgilman

[Sean Griffin & Melanie Gilman]
上级 af55197d
module ActiveRecord
class PredicateBuilder # :nodoc:
@handlers = []
autoload :RelationHandler, 'active_record/relation/predicate_builder/relation_handler'
autoload :ArrayHandler, 'active_record/relation/predicate_builder/array_handler'
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/class_handler'
require 'active_record/relation/predicate_builder/range_handler'
require 'active_record/relation/predicate_builder/relation_handler'
def initialize(klass, table)
@klass = klass
@table = table
@handlers = []
register_handler(BasicObject, BasicObjectHandler.new)
register_handler(Class, ClassHandler.new)
register_handler(Base, BaseHandler.new)
register_handler(Range, RangeHandler.new)
register_handler(Relation, RelationHandler.new)
register_handler(Array, ArrayHandler.new)
end
def resolve_column_aliases(hash)
......@@ -35,13 +45,13 @@ def expand(column, value)
# PriceEstimate.where(estimate_of: treasure)
if klass && reflection = klass._reflect_on_association(column)
if reflection.polymorphic? && base_class = polymorphic_base_class_from_value(value)
queries << self.class.build(table[reflection.foreign_type], base_class.name)
queries << build(table[reflection.foreign_type], base_class.name)
end
column = reflection.foreign_key
end
queries << self.class.build(table[column], value)
queries << build(table[column], value)
queries
end
......@@ -79,33 +89,10 @@ def self.references(attributes)
# )
# end
# ActiveRecord::PredicateBuilder.register_handler(MyCustomDateRange, handler)
def self.register_handler(klass, handler)
def register_handler(klass, handler)
@handlers.unshift([klass, handler])
end
register_handler(BasicObject, ->(attribute, value) { attribute.eq(value) })
register_handler(Class, ->(attribute, value) { deprecate_class_handler; attribute.eq(value.name) })
register_handler(Base, ->(attribute, value) { attribute.eq(value.id) })
register_handler(Range, ->(attribute, value) { attribute.between(value) })
register_handler(Relation, RelationHandler.new)
register_handler(Array, ArrayHandler.new)
def self.build(attribute, value)
handler_for(value).call(attribute, value)
end
def self.handler_for(object)
@handlers.detect { |klass, _| klass === object }.last
end
private_class_method :handler_for
def self.deprecate_class_handler
ActiveSupport::Deprecation.warn(<<-MSG.squish)
Passing a class as a value in an Active Record query is deprecated and
will be removed. Pass a string instead.
MSG
end
protected
attr_reader :klass, :table
......@@ -141,5 +128,13 @@ def convert_dot_notation_to_hash(attributes)
attributes
end
def build(attribute, value)
handler_for(value).call(attribute, value)
end
def handler_for(object)
@handlers.detect { |klass, _| klass === object }.last
end
end
end
module ActiveRecord
class PredicateBuilder
class BaseHandler # :nodoc:
def call(attribute, value)
attribute.eq(value.id)
end
end
end
end
module ActiveRecord
class PredicateBuilder
class BasicObjectHandler # :nodoc:
def call(attribute, value)
attribute.eq(value)
end
end
end
end
module ActiveRecord
class PredicateBuilder
class ClassHandler # :nodoc:
def call(attribute, value)
print_deprecation_warning
attribute.eq(value.name)
end
private
def print_deprecation_warning
ActiveSupport::Deprecation.warn(<<-MSG.squish)
Passing a class as a value in an Active Record query is deprecated and
will be removed. Pass a string instead.
MSG
end
end
end
end
module ActiveRecord
class PredicateBuilder
class RangeHandler # :nodoc:
def call(attribute, value)
attribute.between(value)
end
end
end
end
......@@ -4,11 +4,13 @@
module ActiveRecord
class PredicateBuilderTest < ActiveRecord::TestCase
def test_registering_new_handlers
PredicateBuilder.register_handler(Regexp, proc do |column, value|
Topic.predicate_builder.register_handler(Regexp, proc do |column, value|
Arel::Nodes::InfixOperation.new('~', column, Arel.sql(value.source))
end)
assert_match %r{["`]topics["`].["`]title["`] ~ rails}i, Topic.where(title: /rails/).to_sql
ensure
Topic.reset_column_information
end
end
end
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册