diff --git a/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb index ee2ece15602db70f7f9e41fc9a12f51ad50d7448..115322ae68fc86b7b790c22b94dc67ecb4d70d1e 100644 --- a/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb +++ b/activerecord/lib/active_record/relation/predicate_builder/array_handler.rb @@ -20,20 +20,17 @@ def call(attribute, value) case values.length when 0 then NullPredicate when 1 then predicate_builder.build(attribute, values.first) - else - values.map! do |v| - predicate_builder.build_bind_attribute(attribute.name, v) - end - values.empty? ? NullPredicate : attribute.in(values) + else attribute.in(values) end - unless nils.empty? + if nils.empty? + return values_predicate if ranges.empty? + else values_predicate = values_predicate.or(predicate_builder.build(attribute, nil)) end - array_predicates = ranges.map { |range| predicate_builder.build(attribute, range) } - array_predicates.unshift(values_predicate) - array_predicates.inject(&:or) + array_predicates = ranges.map! { |range| predicate_builder.build(attribute, range) } + array_predicates.inject(values_predicate, &:or) end private diff --git a/activerecord/lib/active_record/relation/where_clause.rb b/activerecord/lib/active_record/relation/where_clause.rb index affb18bd2fc8a8496a81f95d71499848aa410261..56599be1b75b3d0ba172e4182d738df3ab41f437 100644 --- a/activerecord/lib/active_record/relation/where_clause.rb +++ b/activerecord/lib/active_record/relation/where_clause.rb @@ -85,7 +85,7 @@ def contradiction? predicates.any? do |x| case x when Arel::Nodes::In - Array === x.right && x.right.empty? + Arel::Nodes::CastedArray === x.right && x.right.value.empty? when Arel::Nodes::Equality x.right.respond_to?(:unboundable?) && x.right.unboundable? end diff --git a/activerecord/lib/arel/nodes/casted.rb b/activerecord/lib/arel/nodes/casted.rb index 07996dd25ed5c2130190d65eea5739e20c7d9683..a41fa41225eb5dd03fdcfa7daece1e68cad84fda 100644 --- a/activerecord/lib/arel/nodes/casted.rb +++ b/activerecord/lib/arel/nodes/casted.rb @@ -34,6 +34,16 @@ def eql?(other) alias :== :eql? end + class CastedArray < Casted # :nodoc: + def value_for_database + if attribute.able_to_type_cast? + value.map { |v| attribute.type_cast_for_database(v) } + else + value + end + end + end + class Quoted < Arel::Nodes::Unary # :nodoc: alias :value_for_database :value alias :value_before_type_cast :value diff --git a/activerecord/lib/arel/predications.rb b/activerecord/lib/arel/predications.rb index 0f075630d87eb214e200592c3888a0aa47be9a46..a395478767c1c4214529d5f2c847cec5623fa7bc 100644 --- a/activerecord/lib/arel/predications.rb +++ b/activerecord/lib/arel/predications.rb @@ -31,7 +31,7 @@ def eq_any(others) end def eq_all(others) - grouping_all :eq, quoted_array(others) + grouping_all :eq, others end def between(other) @@ -238,7 +238,7 @@ def quoted_node(other) end def quoted_array(others) - others.map { |v| quoted_node(v) } + Nodes::CastedArray.new(others, self) end def infinity?(value) diff --git a/activerecord/lib/arel/table.rb b/activerecord/lib/arel/table.rb index c40c68715ad4bcdd033e555b191ae634adbcba8b..a4a526377085f070085a1241aa86de52a6090b2f 100644 --- a/activerecord/lib/arel/table.rb +++ b/activerecord/lib/arel/table.rb @@ -98,6 +98,7 @@ def eql?(other) def type_cast_for_database(attribute_name, value) type_caster.type_cast_for_database(attribute_name, value) + rescue ::RangeError end def able_to_type_cast? diff --git a/activerecord/lib/arel/visitors/to_sql.rb b/activerecord/lib/arel/visitors/to_sql.rb index 8ed7a80de9e151a524d60b71f3562cd1f84603ca..fc0c773687048fdb05a02a4d77d71d519d8e097b 100644 --- a/activerecord/lib/arel/visitors/to_sql.rb +++ b/activerecord/lib/arel/visitors/to_sql.rb @@ -81,6 +81,10 @@ def visit_Arel_Nodes_Exists(o, collector) end end + def visit_Arel_Nodes_CastedArray(o, collector) + collector << o.value_for_database.map! { |v| quote(v) }.join(", ") + end + def visit_Arel_Nodes_Casted(o, collector) collector << quote(o.value_for_database).to_s end @@ -512,12 +516,8 @@ def visit_Arel_Table(o, collector) def visit_Arel_Nodes_In(o, collector) attr, values = o.left, o.right - if Array === values - unless values.empty? - values.delete_if { |value| unboundable?(value) } - end - - return collector << "1=0" if values.empty? + if Arel::Nodes::CastedArray === values + return collector << "1=0" if values.value.empty? end visit(attr, collector) << " IN (" @@ -527,12 +527,8 @@ def visit_Arel_Nodes_In(o, collector) def visit_Arel_Nodes_NotIn(o, collector) attr, values = o.left, o.right - if Array === values - unless values.empty? - values.delete_if { |value| unboundable?(value) } - end - - return collector << "1=1" if values.empty? + if Arel::Nodes::CastedArray === values + return collector << "1=1" if values.value.empty? end visit(attr, collector) << " NOT IN (" diff --git a/activerecord/test/cases/arel/attributes/attribute_test.rb b/activerecord/test/cases/arel/attributes/attribute_test.rb index 4c2c61e57ad14da2db051b62954d4ec437d46ad0..8b65a61b9a698a13f0e9f24eb6973417b0f57a30 100644 --- a/activerecord/test/cases/arel/attributes/attribute_test.rb +++ b/activerecord/test/cases/arel/attributes/attribute_test.rb @@ -618,14 +618,14 @@ class AttributeTest < Arel::Spec attribute = Attribute.new nil, nil node = attribute.between(-::Float::INFINITY..::Float::INFINITY) - _(node).must_equal Nodes::NotIn.new(attribute, []) + _(node).must_equal attribute.not_in([]) end it "can be constructed with a quoted infinite range" do attribute = Attribute.new nil, nil node = attribute.between(quoted_range(-::Float::INFINITY, ::Float::INFINITY, false)) - _(node).must_equal Nodes::NotIn.new(attribute, []) + _(node).must_equal attribute.not_in([]) end it "can be constructed with a range ending at Infinity" do @@ -707,11 +707,7 @@ class AttributeTest < Arel::Spec _(node).must_equal Nodes::In.new( attribute, - [ - Nodes::Casted.new(1, attribute), - Nodes::Casted.new(2, attribute), - Nodes::Casted.new(3, attribute), - ] + Nodes::CastedArray.new([1, 2, 3], attribute) ) end @@ -831,14 +827,14 @@ class AttributeTest < Arel::Spec attribute = Attribute.new nil, nil node = attribute.not_between(-::Float::INFINITY..::Float::INFINITY) - _(node).must_equal Nodes::In.new(attribute, []) + _(node).must_equal attribute.in([]) end it "can be constructed with a quoted infinite range" do attribute = Attribute.new nil, nil node = attribute.not_between(quoted_range(-::Float::INFINITY, ::Float::INFINITY, false)) - _(node).must_equal Nodes::In.new(attribute, []) + _(node).must_equal attribute.in([]) end it "can be constructed with a range ending at Infinity" do @@ -934,11 +930,7 @@ class AttributeTest < Arel::Spec _(node).must_equal Nodes::NotIn.new( attribute, - [ - Nodes::Casted.new(1, attribute), - Nodes::Casted.new(2, attribute), - Nodes::Casted.new(3, attribute), - ] + Nodes::CastedArray.new([1, 2, 3], attribute) ) end