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:
parent
af55197d86
commit
a3936bbe21
6 changed files with 74 additions and 31 deletions
|
@ -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
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
module ActiveRecord
|
||||
class PredicateBuilder
|
||||
class BaseHandler # :nodoc:
|
||||
def call(attribute, value)
|
||||
attribute.eq(value.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,9 @@
|
|||
module ActiveRecord
|
||||
class PredicateBuilder
|
||||
class BasicObjectHandler # :nodoc:
|
||||
def call(attribute, value)
|
||||
attribute.eq(value)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -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
|
|
@ -0,0 +1,9 @@
|
|||
module ActiveRecord
|
||||
class PredicateBuilder
|
||||
class RangeHandler # :nodoc:
|
||||
def call(attribute, value)
|
||||
attribute.between(value)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue