1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

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]
This commit is contained in:
Sean Griffin 2014-12-26 14:12:16 -07:00
parent af55197d86
commit a3936bbe21
6 changed files with 74 additions and 31 deletions

View file

@ -1,13 +1,23 @@
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 @@ module ActiveRecord
# 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 @@ module ActiveRecord
# )
# 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 @@ module ActiveRecord
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

View file

@ -0,0 +1,9 @@
module ActiveRecord
class PredicateBuilder
class BaseHandler # :nodoc:
def call(attribute, value)
attribute.eq(value.id)
end
end
end
end

View file

@ -0,0 +1,9 @@
module ActiveRecord
class PredicateBuilder
class BasicObjectHandler # :nodoc:
def call(attribute, value)
attribute.eq(value)
end
end
end
end

View file

@ -0,0 +1,19 @@
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

View file

@ -0,0 +1,9 @@
module ActiveRecord
class PredicateBuilder
class RangeHandler # :nodoc:
def call(attribute, value)
attribute.between(value)
end
end
end
end

View file

@ -4,11 +4,13 @@ require 'models/topic'
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