mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Decouple the building Arel ASTs for uniqueness validator
Currently uniqueness validator is coupled with building Arel ASTs. This commit extracts `WhereClauseFactory#build_for_case_sensitive` for decouple the building Arel ASTs.
This commit is contained in:
parent
e8ba0c0f21
commit
41bc3edcaa
4 changed files with 48 additions and 38 deletions
|
@ -442,14 +442,14 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
def case_sensitive_comparison(table, attribute, column, value)
|
||||
table[attribute].eq(Arel::Nodes::BindParam.new)
|
||||
table[attribute].eq(value)
|
||||
end
|
||||
|
||||
def case_insensitive_comparison(table, attribute, column, value)
|
||||
if can_perform_case_insensitive_comparison_for?(column)
|
||||
table[attribute].lower.eq(table.lower(Arel::Nodes::BindParam.new))
|
||||
table[attribute].lower.eq(table.lower(value))
|
||||
else
|
||||
table[attribute].eq(Arel::Nodes::BindParam.new)
|
||||
table[attribute].eq(value)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -615,7 +615,7 @@ module ActiveRecord
|
|||
|
||||
def case_sensitive_comparison(table, attribute, column, value)
|
||||
if column.collation && !column.case_sensitive?
|
||||
table[attribute].eq(Arel::Nodes::Bin.new(Arel::Nodes::BindParam.new))
|
||||
table[attribute].eq(Arel::Nodes::Bin.new(value))
|
||||
else
|
||||
super
|
||||
end
|
||||
|
|
|
@ -15,9 +15,12 @@ module ActiveRecord
|
|||
attributes = klass.send(:expand_hash_conditions_for_aggregates, attributes)
|
||||
attributes.stringify_keys!
|
||||
|
||||
if perform_case_sensitive?(options = other.last)
|
||||
parts, binds = build_for_case_sensitive(attributes, options)
|
||||
else
|
||||
attributes, binds = predicate_builder.create_binds(attributes)
|
||||
|
||||
parts = predicate_builder.build_from_hash(attributes)
|
||||
end
|
||||
when Arel::Nodes::Node
|
||||
parts = [opts]
|
||||
else
|
||||
|
@ -32,6 +35,43 @@ module ActiveRecord
|
|||
protected
|
||||
|
||||
attr_reader :klass, :predicate_builder
|
||||
|
||||
private
|
||||
|
||||
def perform_case_sensitive?(options)
|
||||
options && options.key?(:case_sensitive)
|
||||
end
|
||||
|
||||
def build_for_case_sensitive(attributes, options)
|
||||
parts, binds = [], []
|
||||
table = klass.arel_table
|
||||
|
||||
attributes.each do |attribute, value|
|
||||
if reflection = klass._reflect_on_association(attribute)
|
||||
attribute = reflection.foreign_key.to_s
|
||||
value = value[reflection.klass.primary_key] unless value.nil?
|
||||
end
|
||||
|
||||
if value.nil?
|
||||
parts << table[attribute].eq(value)
|
||||
else
|
||||
column = klass.column_for_attribute(attribute)
|
||||
|
||||
binds << predicate_builder.send(:build_bind_param, attribute, value)
|
||||
value = Arel::Nodes::BindParam.new
|
||||
|
||||
predicate = if options[:case_sensitive]
|
||||
klass.connection.case_sensitive_comparison(table, attribute, column, value)
|
||||
else
|
||||
klass.connection.case_insensitive_comparison(table, attribute, column, value)
|
||||
end
|
||||
|
||||
parts << predicate
|
||||
end
|
||||
end
|
||||
|
||||
[parts, binds]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -50,37 +50,7 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
def build_relation(klass, attribute, value)
|
||||
if reflection = klass._reflect_on_association(attribute)
|
||||
attribute = reflection.foreign_key
|
||||
value = value.attributes[reflection.klass.primary_key] unless value.nil?
|
||||
end
|
||||
|
||||
if value.nil?
|
||||
return klass.unscoped.where!(attribute => value)
|
||||
end
|
||||
|
||||
# the attribute may be an aliased attribute
|
||||
if klass.attribute_alias?(attribute)
|
||||
attribute = klass.attribute_alias(attribute)
|
||||
end
|
||||
|
||||
attribute_name = attribute.to_s
|
||||
|
||||
table = klass.arel_table
|
||||
column = klass.columns_hash[attribute_name]
|
||||
cast_type = klass.type_for_attribute(attribute_name)
|
||||
|
||||
comparison = if !options[:case_sensitive]
|
||||
# will use SQL LOWER function before comparison, unless it detects a case insensitive collation
|
||||
klass.connection.case_insensitive_comparison(table, attribute, column, value)
|
||||
else
|
||||
klass.connection.case_sensitive_comparison(table, attribute, column, value)
|
||||
end
|
||||
klass.unscoped.tap do |scope|
|
||||
parts = [comparison]
|
||||
binds = [Relation::QueryAttribute.new(attribute_name, value, cast_type)]
|
||||
scope.where_clause += Relation::WhereClause.new(parts, binds)
|
||||
end
|
||||
klass.unscoped.where!({ attribute => value }, options)
|
||||
end
|
||||
|
||||
def scope_relation(record, relation) # :doc:
|
||||
|
|
Loading…
Reference in a new issue