mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Remove over meta programming in AR::Relation
Introduced low level methods #set_value and #get_value for setting query attributes: relation.set_value(:where, {id: 1}) relation.get_value(:includes) Used those internally when working with relation's attributes at the abstract level
This commit is contained in:
parent
82ec6b3606
commit
5b42628e79
4 changed files with 59 additions and 94 deletions
|
@ -504,15 +504,10 @@ module ActiveRecord
|
|||
# Post.limit(100).delete_all
|
||||
# # => ActiveRecord::ActiveRecordError: delete_all doesn't support limit
|
||||
def delete_all(conditions = nil)
|
||||
invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select { |method|
|
||||
if MULTI_VALUE_METHODS.include?(method)
|
||||
send("#{method}_values").any?
|
||||
elsif SINGLE_VALUE_METHODS.include?(method)
|
||||
send("#{method}_value")
|
||||
elsif CLAUSE_METHODS.include?(method)
|
||||
send("#{method}_clause").any?
|
||||
end
|
||||
}
|
||||
invalid_methods = INVALID_METHODS_FOR_DELETE_ALL.select do |method|
|
||||
value = get_value(method)
|
||||
SINGLE_VALUE_METHODS.include?(method) ? value : value.any?
|
||||
end
|
||||
if invalid_methods.any?
|
||||
raise ActiveRecordError.new("delete_all doesn't support #{invalid_methods.join(', ')}")
|
||||
end
|
||||
|
|
|
@ -151,15 +151,11 @@ module ActiveRecord
|
|||
end
|
||||
end
|
||||
|
||||
CLAUSE_METHOD_NAMES = CLAUSE_METHODS.map do |name|
|
||||
["#{name}_clause", "#{name}_clause="]
|
||||
end
|
||||
|
||||
def merge_clauses
|
||||
CLAUSE_METHOD_NAMES.each do |(reader, writer)|
|
||||
clause = relation.send(reader)
|
||||
other_clause = other.send(reader)
|
||||
relation.send(writer, clause.merge(other_clause))
|
||||
CLAUSE_METHODS.each do |method|
|
||||
clause = relation.get_value(method)
|
||||
other_clause = other.get_value(method)
|
||||
relation.set_value(method, clause.merge(other_clause))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -56,49 +56,25 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
FROZEN_EMPTY_ARRAY = [].freeze
|
||||
Relation::MULTI_VALUE_METHODS.each do |name|
|
||||
class_eval <<-CODE, __FILE__, __LINE__ + 1
|
||||
def #{name}_values
|
||||
@values[:#{name}] || FROZEN_EMPTY_ARRAY
|
||||
end
|
||||
FROZEN_EMPTY_HASH = {}.freeze
|
||||
|
||||
def #{name}_values=(values)
|
||||
assert_mutability!
|
||||
@values[:#{name}] = values
|
||||
end
|
||||
CODE
|
||||
end
|
||||
|
||||
(Relation::SINGLE_VALUE_METHODS - [:create_with]).each do |name|
|
||||
Relation::VALUE_METHODS.each do |name|
|
||||
method_name = case name
|
||||
when *Relation::MULTI_VALUE_METHODS then "#{name}_values"
|
||||
when *Relation::SINGLE_VALUE_METHODS then "#{name}_value"
|
||||
when *Relation::CLAUSE_METHODS then "#{name}_clause"
|
||||
end
|
||||
class_eval <<-CODE, __FILE__, __LINE__ + 1
|
||||
def #{name}_value # def readonly_value
|
||||
@values[:#{name}] # @values[:readonly]
|
||||
def #{method_name} # def includes_values
|
||||
get_value(#{name.inspect}) # get_value(:includes)
|
||||
end # end
|
||||
CODE
|
||||
end
|
||||
|
||||
Relation::SINGLE_VALUE_METHODS.each do |name|
|
||||
class_eval <<-CODE, __FILE__, __LINE__ + 1
|
||||
def #{name}_value=(value) # def readonly_value=(value)
|
||||
assert_mutability! # assert_mutability!
|
||||
@values[:#{name}] = value # @values[:readonly] = value
|
||||
def #{method_name}=(value) # def includes_values=(value)
|
||||
set_value(#{name.inspect}, value) # set_value(:includes, value)
|
||||
end # end
|
||||
CODE
|
||||
end
|
||||
|
||||
Relation::CLAUSE_METHODS.each do |name|
|
||||
class_eval <<-CODE, __FILE__, __LINE__ + 1
|
||||
def #{name}_clause # def where_clause
|
||||
@values[:#{name}] || new_#{name}_clause # @values[:where] || new_where_clause
|
||||
end # end
|
||||
#
|
||||
def #{name}_clause=(value) # def where_clause=(value)
|
||||
assert_mutability! # assert_mutability!
|
||||
@values[:#{name}] = value # @values[:where] = value
|
||||
end # end
|
||||
CODE
|
||||
end
|
||||
|
||||
def bound_attributes
|
||||
if limit_value && !string_containing_comma?(limit_value)
|
||||
limit_bind = Attribute.with_cast_value(
|
||||
|
@ -124,11 +100,6 @@ module ActiveRecord
|
|||
)
|
||||
end
|
||||
|
||||
FROZEN_EMPTY_HASH = {}.freeze
|
||||
def create_with_value # :nodoc:
|
||||
@values[:create_with] || FROZEN_EMPTY_HASH
|
||||
end
|
||||
|
||||
alias extensions extending_values
|
||||
|
||||
# Specify relationships to be included in the result set. For
|
||||
|
@ -418,7 +389,10 @@ module ActiveRecord
|
|||
args.each do |scope|
|
||||
case scope
|
||||
when Symbol
|
||||
symbol_unscoping(scope)
|
||||
if !VALID_UNSCOPING_VALUES.include?(scope)
|
||||
raise ArgumentError, "Called unscope() with invalid unscoping argument ':#{scope}'. Valid arguments are :#{VALID_UNSCOPING_VALUES.to_a.join(", :")}."
|
||||
end
|
||||
set_value(scope, nil)
|
||||
when Hash
|
||||
scope.each do |key, target_value|
|
||||
if key != :where
|
||||
|
@ -950,6 +924,17 @@ module ActiveRecord
|
|||
@arel ||= build_arel
|
||||
end
|
||||
|
||||
# Returns a relation value with a given name
|
||||
def get_value(name) # :nodoc:
|
||||
@values[name] || default_value_for(name)
|
||||
end
|
||||
|
||||
# Sets the relation value with the given name
|
||||
def set_value(name, value) # :nodoc:
|
||||
assert_mutability!
|
||||
@values[name] = value
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def assert_mutability!
|
||||
|
@ -986,29 +971,6 @@ module ActiveRecord
|
|||
arel
|
||||
end
|
||||
|
||||
def symbol_unscoping(scope)
|
||||
if !VALID_UNSCOPING_VALUES.include?(scope)
|
||||
raise ArgumentError, "Called unscope() with invalid unscoping argument ':#{scope}'. Valid arguments are :#{VALID_UNSCOPING_VALUES.to_a.join(", :")}."
|
||||
end
|
||||
|
||||
clause_method = Relation::CLAUSE_METHODS.include?(scope)
|
||||
multi_val_method = Relation::MULTI_VALUE_METHODS.include?(scope)
|
||||
if clause_method
|
||||
unscope_code = "#{scope}_clause="
|
||||
else
|
||||
unscope_code = "#{scope}_value#{'s' if multi_val_method}="
|
||||
end
|
||||
|
||||
case scope
|
||||
when :order
|
||||
result = []
|
||||
else
|
||||
result = [] if multi_val_method
|
||||
end
|
||||
|
||||
send(unscope_code, result)
|
||||
end
|
||||
|
||||
def build_from
|
||||
opts = from_clause.value
|
||||
name = from_clause.name
|
||||
|
@ -1210,28 +1172,39 @@ module ActiveRecord
|
|||
end
|
||||
end
|
||||
|
||||
STRUCTURAL_OR_METHODS = Relation::VALUE_METHODS - [:extending, :where, :having]
|
||||
def structurally_incompatible_values_for_or(other)
|
||||
Relation::SINGLE_VALUE_METHODS.reject { |m| send("#{m}_value") == other.send("#{m}_value") } +
|
||||
(Relation::MULTI_VALUE_METHODS - [:extending]).reject { |m| send("#{m}_values") == other.send("#{m}_values") } +
|
||||
(Relation::CLAUSE_METHODS - [:having, :where]).reject { |m| send("#{m}_clause") == other.send("#{m}_clause") }
|
||||
STRUCTURAL_OR_METHODS.reject do |method|
|
||||
get_value(method) == other.get_value(method)
|
||||
end
|
||||
end
|
||||
|
||||
def new_where_clause
|
||||
Relation::WhereClause.empty
|
||||
end
|
||||
alias new_having_clause new_where_clause
|
||||
|
||||
def where_clause_factory
|
||||
@where_clause_factory ||= Relation::WhereClauseFactory.new(klass, predicate_builder)
|
||||
end
|
||||
alias having_clause_factory where_clause_factory
|
||||
|
||||
def new_from_clause
|
||||
Relation::FromClause.empty
|
||||
end
|
||||
|
||||
def string_containing_comma?(value)
|
||||
::String === value && value.include?(",")
|
||||
end
|
||||
|
||||
def default_value_for(name)
|
||||
case name
|
||||
when :create_with
|
||||
FROZEN_EMPTY_HASH
|
||||
when :readonly
|
||||
false
|
||||
when :where, :having
|
||||
Relation::WhereClause.empty
|
||||
when :from
|
||||
Relation::FromClause.empty
|
||||
when *Relation::MULTI_VALUE_METHODS
|
||||
FROZEN_EMPTY_ARRAY
|
||||
when *Relation::SINGLE_VALUE_METHODS
|
||||
nil
|
||||
else
|
||||
raise ArgumentError, "unknown relation value #{name.inspect}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -40,9 +40,10 @@ module ActiveRecord
|
|||
|
||||
def test_initialize_single_values
|
||||
relation = Relation.new(FakeKlass, :b, nil)
|
||||
(Relation::SINGLE_VALUE_METHODS - [:create_with]).each do |method|
|
||||
(Relation::SINGLE_VALUE_METHODS - [:create_with, :readonly]).each do |method|
|
||||
assert_nil relation.send("#{method}_value"), method.to_s
|
||||
end
|
||||
assert_equal false, relation.readonly_value
|
||||
value = relation.create_with_value
|
||||
assert_equal({}, value)
|
||||
assert_predicate value, :frozen?
|
||||
|
|
Loading…
Reference in a new issue