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

Deprecate passing ranges to #in and #not_in

The goal of these methods should be to generate in nodes, not handle
every possible permutation of more than one value. The `#between` and
`#not_between` methods have been extracted, which better represent the
semantics of handling ranges in SQL.
This commit is contained in:
Sean Griffin 2014-10-25 07:38:56 -05:00
parent df5723dfbe
commit f8d85cf24b
4 changed files with 202 additions and 190 deletions

View file

@ -25,9 +25,23 @@ module Arel
end
def between other
left = Nodes.build_quoted(other.begin, self)
right = Nodes.build_quoted(other.end, self)
Nodes::Between.new(self, left.and(right))
if other.begin == -Float::INFINITY
if other.end == Float::INFINITY
not_in([])
elsif other.exclude_end?
lt(other.end)
else
lteq(other.end)
end
elsif other.end == Float::INFINITY
gteq(other.begin)
elsif other.exclude_end?
gteq(other.begin).and(lt(other.end))
else
left = Nodes.build_quoted(other.begin, self)
right = Nodes.build_quoted(other.end, self)
Nodes::Between.new(self, left.and(right))
end
end
def in other
@ -35,21 +49,12 @@ module Arel
when Arel::SelectManager
Arel::Nodes::In.new(self, other.ast)
when Range
if other.begin == -Float::INFINITY
if other.end == Float::INFINITY
not_in([])
elsif other.exclude_end?
lt(other.end)
else
lteq(other.end)
end
elsif other.end == Float::INFINITY
gteq(other.begin)
elsif other.exclude_end?
gteq(other.begin).and(lt(other.end))
else
between(other)
if $VERBOSE
warn <<-eowarn
Passing a range to `#in` is deprecated. Call `#between`, instead.
eowarn
end
between(other)
when Array
Nodes::In.new self, other.map { |x| Nodes.build_quoted(x, self) }
else
@ -65,30 +70,39 @@ module Arel
grouping_all :in, others
end
def not_between other
if other.begin == -Float::INFINITY # The range begins with negative infinity
if other.end == Float::INFINITY
self.in([])
elsif other.exclude_end?
gteq(other.end)
else
gt(other.end)
end
elsif other.end == Float::INFINITY
lt(other.begin)
else
left = lt(other.begin)
right = if other.exclude_end?
gteq(other.end)
else
gt(other.end)
end
left.or(right)
end
end
def not_in other
case other
when Arel::SelectManager
Arel::Nodes::NotIn.new(self, other.ast)
when Range
if other.begin == -Float::INFINITY # The range begins with negative infinity
if other.end == Float::INFINITY
self.in([])
elsif other.exclude_end?
gteq(other.end)
else
gt(other.end)
end
elsif other.end == Float::INFINITY
lt(other.begin)
else
left = lt(other.begin)
right = if other.exclude_end?
gteq(other.end)
else
gt(other.end)
end
left.or(right)
if $VERBOSE
warn <<-eowarn
Passing a range to `#not_in` is deprecated. Call `#not_between`, instead.
eowarn
end
not_between(other)
when Array
Nodes::NotIn.new self, other.map { |x| Nodes.build_quoted(x, self) }
else

View file

@ -548,6 +548,74 @@ module Arel
end
end
describe 'with a range' do
it 'can be constructed with a standard range' do
attribute = Attribute.new nil, nil
node = attribute.between(1..3)
node.must_equal Nodes::Between.new(
attribute,
Nodes::And.new([
Nodes::Casted.new(1, attribute),
Nodes::Casted.new(3, attribute)
])
)
end
it 'can be constructed with a range starting from -Infinity' do
attribute = Attribute.new nil, nil
node = attribute.between(-::Float::INFINITY..3)
node.must_equal Nodes::LessThanOrEqual.new(
attribute,
Nodes::Casted.new(3, attribute)
)
end
it 'can be constructed with an exclusive range starting from -Infinity' do
attribute = Attribute.new nil, nil
node = attribute.between(-::Float::INFINITY...3)
node.must_equal Nodes::LessThan.new(
attribute,
Nodes::Casted.new(3, attribute)
)
end
it 'can be constructed with an infinite range' do
attribute = Attribute.new nil, nil
node = attribute.between(-::Float::INFINITY..::Float::INFINITY)
node.must_equal Nodes::NotIn.new(attribute, [])
end
it 'can be constructed with a range ending at Infinity' do
attribute = Attribute.new nil, nil
node = attribute.between(0..::Float::INFINITY)
node.must_equal Nodes::GreaterThanOrEqual.new(
attribute,
Nodes::Casted.new(0, attribute)
)
end
it 'can be constructed with an exclusive range' do
attribute = Attribute.new nil, nil
node = attribute.between(0...3)
node.must_equal Nodes::And.new([
Nodes::GreaterThanOrEqual.new(
attribute,
Nodes::Casted.new(0, attribute)
),
Nodes::LessThan.new(
attribute,
Nodes::Casted.new(3, attribute)
)
])
end
end
describe '#in' do
it 'can be constructed with a subquery' do
relation = Table.new(:users)
@ -560,74 +628,6 @@ module Arel
node.must_equal Nodes::In.new(attribute, mgr.ast)
end
describe 'with a range' do
it 'can be constructed with a standard range' do
attribute = Attribute.new nil, nil
node = attribute.in(1..3)
node.must_equal Nodes::Between.new(
attribute,
Nodes::And.new([
Nodes::Casted.new(1, attribute),
Nodes::Casted.new(3, attribute)
])
)
end
it 'can be constructed with a range starting from -Infinity' do
attribute = Attribute.new nil, nil
node = attribute.in(-::Float::INFINITY..3)
node.must_equal Nodes::LessThanOrEqual.new(
attribute,
Nodes::Casted.new(3, attribute)
)
end
it 'can be constructed with an exclusive range starting from -Infinity' do
attribute = Attribute.new nil, nil
node = attribute.in(-::Float::INFINITY...3)
node.must_equal Nodes::LessThan.new(
attribute,
Nodes::Casted.new(3, attribute)
)
end
it 'can be constructed with an infinite range' do
attribute = Attribute.new nil, nil
node = attribute.in(-::Float::INFINITY..::Float::INFINITY)
node.must_equal Nodes::NotIn.new(attribute, [])
end
it 'can be constructed with a range ending at Infinity' do
attribute = Attribute.new nil, nil
node = attribute.in(0..::Float::INFINITY)
node.must_equal Nodes::GreaterThanOrEqual.new(
attribute,
Nodes::Casted.new(0, attribute)
)
end
it 'can be constructed with an exclusive range' do
attribute = Attribute.new nil, nil
node = attribute.in(0...3)
node.must_equal Nodes::And.new([
Nodes::GreaterThanOrEqual.new(
attribute,
Nodes::Casted.new(0, attribute)
),
Nodes::LessThan.new(
attribute,
Nodes::Casted.new(3, attribute)
)
])
end
end
it 'can be constructed with a list' do
attribute = Attribute.new nil, nil
node = attribute.in([1, 2, 3])
@ -695,6 +695,77 @@ module Arel
end
end
describe 'with a range' do
it 'can be constructed with a standard range' do
attribute = Attribute.new nil, nil
node = attribute.not_between(1..3)
node.must_equal Nodes::Grouping.new(Nodes::Or.new(
Nodes::LessThan.new(
attribute,
Nodes::Casted.new(1, attribute)
),
Nodes::GreaterThan.new(
attribute,
Nodes::Casted.new(3, attribute)
)
))
end
it 'can be constructed with a range starting from -Infinity' do
attribute = Attribute.new nil, nil
node = attribute.not_between(-::Float::INFINITY..3)
node.must_equal Nodes::GreaterThan.new(
attribute,
Nodes::Casted.new(3, attribute)
)
end
it 'can be constructed with an exclusive range starting from -Infinity' do
attribute = Attribute.new nil, nil
node = attribute.not_between(-::Float::INFINITY...3)
node.must_equal Nodes::GreaterThanOrEqual.new(
attribute,
Nodes::Casted.new(3, attribute)
)
end
it 'can be constructed with an infinite range' do
attribute = Attribute.new nil, nil
node = attribute.not_between(-::Float::INFINITY..::Float::INFINITY)
node.must_equal Nodes::In.new(attribute, [])
end
it 'can be constructed with a range ending at Infinity' do
attribute = Attribute.new nil, nil
node = attribute.not_between(0..::Float::INFINITY)
node.must_equal Nodes::LessThan.new(
attribute,
Nodes::Casted.new(0, attribute)
)
end
it 'can be constructed with an exclusive range' do
attribute = Attribute.new nil, nil
node = attribute.not_between(0...3)
node.must_equal Nodes::Grouping.new(Nodes::Or.new(
Nodes::LessThan.new(
attribute,
Nodes::Casted.new(0, attribute)
),
Nodes::GreaterThanOrEqual.new(
attribute,
Nodes::Casted.new(3, attribute)
)
))
end
end
describe '#not_in' do
it 'can be constructed with a subquery' do
relation = Table.new(:users)
@ -707,77 +778,6 @@ module Arel
node.must_equal Nodes::NotIn.new(attribute, mgr.ast)
end
describe 'with a range' do
it 'can be constructed with a standard range' do
attribute = Attribute.new nil, nil
node = attribute.not_in(1..3)
node.must_equal Nodes::Grouping.new(Nodes::Or.new(
Nodes::LessThan.new(
attribute,
Nodes::Casted.new(1, attribute)
),
Nodes::GreaterThan.new(
attribute,
Nodes::Casted.new(3, attribute)
)
))
end
it 'can be constructed with a range starting from -Infinity' do
attribute = Attribute.new nil, nil
node = attribute.not_in(-::Float::INFINITY..3)
node.must_equal Nodes::GreaterThan.new(
attribute,
Nodes::Casted.new(3, attribute)
)
end
it 'can be constructed with an exclusive range starting from -Infinity' do
attribute = Attribute.new nil, nil
node = attribute.not_in(-::Float::INFINITY...3)
node.must_equal Nodes::GreaterThanOrEqual.new(
attribute,
Nodes::Casted.new(3, attribute)
)
end
it 'can be constructed with an infinite range' do
attribute = Attribute.new nil, nil
node = attribute.not_in(-::Float::INFINITY..::Float::INFINITY)
node.must_equal Nodes::In.new(attribute, [])
end
it 'can be constructed with a range ending at Infinity' do
attribute = Attribute.new nil, nil
node = attribute.not_in(0..::Float::INFINITY)
node.must_equal Nodes::LessThan.new(
attribute,
Nodes::Casted.new(0, attribute)
)
end
it 'can be constructed with an exclusive range' do
attribute = Attribute.new nil, nil
node = attribute.not_in(0...3)
node.must_equal Nodes::Grouping.new(Nodes::Or.new(
Nodes::LessThan.new(
attribute,
Nodes::Casted.new(0, attribute)
),
Nodes::GreaterThanOrEqual.new(
attribute,
Nodes::Casted.new(3, attribute)
)
))
end
end
it 'can be constructed with a list' do
attribute = Attribute.new nil, nil
node = attribute.not_in([1, 2, 3])

View file

@ -307,13 +307,11 @@ module Arel
table = Table.new :users
@m1 = Arel::SelectManager.new Table.engine, table
@m1.project Arel.star
@m1.where(table[:age].in(18..60))
@m1.where(table[:age].between(18..60))
@m2 = Arel::SelectManager.new Table.engine, table
@m2.project Arel.star
@m2.where(table[:age].in(40..99))
@m2.where(table[:age].between(40..99))
end
it 'should except two managers' do

View file

@ -375,33 +375,33 @@ module Arel
end
it 'can handle two dot ranges' do
node = @attr.in 1..3
node = @attr.between 1..3
compile(node).must_be_like %{
"users"."id" BETWEEN 1 AND 3
}
end
it 'can handle three dot ranges' do
node = @attr.in 1...3
node = @attr.between 1...3
compile(node).must_be_like %{
"users"."id" >= 1 AND "users"."id" < 3
}
end
it 'can handle ranges bounded by infinity' do
node = @attr.in 1..Float::INFINITY
node = @attr.between 1..Float::INFINITY
compile(node).must_be_like %{
"users"."id" >= 1
}
node = @attr.in(-Float::INFINITY..3)
node = @attr.between(-Float::INFINITY..3)
compile(node).must_be_like %{
"users"."id" <= 3
}
node = @attr.in(-Float::INFINITY...3)
node = @attr.between(-Float::INFINITY...3)
compile(node).must_be_like %{
"users"."id" < 3
}
node = @attr.in(-Float::INFINITY..Float::INFINITY)
node = @attr.between(-Float::INFINITY..Float::INFINITY)
compile(node).must_be_like %{1=1}
end
@ -479,33 +479,33 @@ module Arel
end
it 'can handle two dot ranges' do
node = @attr.not_in 1..3
node = @attr.not_between 1..3
compile(node).must_equal(
%{("users"."id" < 1 OR "users"."id" > 3)}
)
end
it 'can handle three dot ranges' do
node = @attr.not_in 1...3
node = @attr.not_between 1...3
compile(node).must_equal(
%{("users"."id" < 1 OR "users"."id" >= 3)}
)
end
it 'can handle ranges bounded by infinity' do
node = @attr.not_in 1..Float::INFINITY
node = @attr.not_between 1..Float::INFINITY
compile(node).must_be_like %{
"users"."id" < 1
}
node = @attr.not_in(-Float::INFINITY..3)
node = @attr.not_between(-Float::INFINITY..3)
compile(node).must_be_like %{
"users"."id" > 3
}
node = @attr.not_in(-Float::INFINITY...3)
node = @attr.not_between(-Float::INFINITY...3)
compile(node).must_be_like %{
"users"."id" >= 3
}
node = @attr.not_in(-Float::INFINITY..Float::INFINITY)
node = @attr.not_between(-Float::INFINITY..Float::INFINITY)
compile(node).must_be_like %{1=0}
end