mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Support where
with comparison operators (>
, >=
, <
, and <=
)
```ruby posts = Post.order(:id) posts.where("id >": 9).pluck(:id) # => [10, 11] posts.where("id >=": 9).pluck(:id) # => [9, 10, 11] posts.where("id <": 3).pluck(:id) # => [1, 2] posts.where("id <=": 3).pluck(:id) # => [1, 2, 3] ``` From type casting and table/column name resolution's point of view, `where("create_at >=": time)` is better alternative than `where("create_at >= ?", time)`. ```ruby class Post < ActiveRecord::Base attribute :created_at, :datetime, precision: 3 end time = Time.now.utc # => 2020-06-24 10:11:12.123456 UTC Post.create!(created_at: time) # => #<Post id: 1, created_at: "2020-06-24 10:11:12.123000"> # SELECT `posts`.* FROM `posts` WHERE (created_at >= '2020-06-24 10:11:12.123456') Post.where("created_at >= ?", time) # => [] # SELECT `posts`.* FROM `posts` WHERE `posts`.`created_at` >= '2020-06-24 10:11:12.123000' Post.where("created_at >=": time) # => [#<Post id: 1, created_at: "2020-06-24 10:11:12.123000">] ```
This commit is contained in:
parent
da5b1c3bb7
commit
6d6ec6f936
7 changed files with 81 additions and 12 deletions
|
@ -1,3 +1,35 @@
|
||||||
|
* Support `where` with comparison operators (`>`, `>=`, `<`, and `<=`).
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
posts = Post.order(:id)
|
||||||
|
|
||||||
|
posts.where("id >": 9).pluck(:id) # => [10, 11]
|
||||||
|
posts.where("id >=": 9).pluck(:id) # => [9, 10, 11]
|
||||||
|
posts.where("id <": 3).pluck(:id) # => [1, 2]
|
||||||
|
posts.where("id <=": 3).pluck(:id) # => [1, 2, 3]
|
||||||
|
```
|
||||||
|
|
||||||
|
From type casting and table/column name resolution's point of view,
|
||||||
|
`where("create_at >=": time)` is better alternative than `where("create_at >= ?", time)`.
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
class Post < ActiveRecord::Base
|
||||||
|
attribute :created_at, :datetime, precision: 3
|
||||||
|
end
|
||||||
|
|
||||||
|
time = Time.now.utc # => 2020-06-24 10:11:12.123456 UTC
|
||||||
|
|
||||||
|
Post.create!(created_at: time) # => #<Post id: 1, created_at: "2020-06-24 10:11:12.123000">
|
||||||
|
|
||||||
|
# SELECT `posts`.* FROM `posts` WHERE (created_at >= '2020-06-24 10:11:12.123456')
|
||||||
|
Post.where("created_at >= ?", time) # => []
|
||||||
|
|
||||||
|
# SELECT `posts`.* FROM `posts` WHERE `posts`.`created_at` >= '2020-06-24 10:11:12.123000'
|
||||||
|
Post.where("created_at >=": time) # => [#<Post id: 1, created_at: "2020-06-24 10:11:12.123000">]
|
||||||
|
```
|
||||||
|
|
||||||
|
*Ryuta Kamizono*
|
||||||
|
|
||||||
* Deprecate YAML loading from legacy format older than Rails 5.0.
|
* Deprecate YAML loading from legacy format older than Rails 5.0.
|
||||||
|
|
||||||
*Ryuta Kamizono*
|
*Ryuta Kamizono*
|
||||||
|
|
|
@ -57,11 +57,11 @@ module ActiveRecord
|
||||||
@handlers.unshift([klass, handler])
|
@handlers.unshift([klass, handler])
|
||||||
end
|
end
|
||||||
|
|
||||||
def build(attribute, value)
|
def build(attribute, value, operator = nil)
|
||||||
value = value.id if value.is_a?(Base)
|
value = value.id if value.is_a?(Base)
|
||||||
if table.type(attribute.name).force_equality?(value)
|
if operator ||= table.type(attribute.name).force_equality?(value) && :eq
|
||||||
bind = build_bind_attribute(attribute.name, value)
|
bind = build_bind_attribute(attribute.name, value)
|
||||||
attribute.eq(bind)
|
attribute.public_send(operator, bind)
|
||||||
else
|
else
|
||||||
handler_for(value).call(attribute, value)
|
handler_for(value).call(attribute, value)
|
||||||
end
|
end
|
||||||
|
@ -127,12 +127,16 @@ module ActiveRecord
|
||||||
|
|
||||||
grouping_queries(queries)
|
grouping_queries(queries)
|
||||||
end
|
end
|
||||||
|
elsif key.end_with?(">", ">=", "<", "<=") && /\A(?<key>.+?)\s*(?<operator>>|>=|<|<=)\z/ =~ key
|
||||||
|
build(table.arel_attribute(key), value, OPERATORS[-operator])
|
||||||
else
|
else
|
||||||
build(table.arel_attribute(key), value)
|
build(table.arel_attribute(key), value)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
OPERATORS = { ">" => :gt, ">=" => :gteq, "<" => :lt, "<=" => :lteq }.freeze
|
||||||
|
|
||||||
private
|
private
|
||||||
attr_reader :table
|
attr_reader :table
|
||||||
|
|
||||||
|
|
|
@ -94,10 +94,16 @@ if supports_datetime_with_precision?
|
||||||
t.datetime :created_at, precision: 0
|
t.datetime :created_at, precision: 0
|
||||||
t.datetime :updated_at, precision: 4
|
t.datetime :updated_at, precision: 4
|
||||||
end
|
end
|
||||||
|
|
||||||
date = ::Time.utc(2014, 8, 17, 12, 30, 0, 999999)
|
date = ::Time.utc(2014, 8, 17, 12, 30, 0, 999999)
|
||||||
Foo.create!(created_at: date, updated_at: date)
|
Foo.create!(created_at: date, updated_at: date)
|
||||||
assert foo = Foo.find_by(created_at: date)
|
|
||||||
assert_equal 1, Foo.where(updated_at: date).count
|
assert_nil Foo.find_by("created_at >= ?", date)
|
||||||
|
assert_equal 0, Foo.where("updated_at >= ?", date).count
|
||||||
|
|
||||||
|
assert foo = Foo.find_by("created_at >=": date)
|
||||||
|
assert_equal 1, Foo.where("updated_at >=": date).count
|
||||||
|
|
||||||
assert_equal date.to_s, foo.created_at.to_s
|
assert_equal date.to_s, foo.created_at.to_s
|
||||||
assert_equal date.to_s, foo.updated_at.to_s
|
assert_equal date.to_s, foo.updated_at.to_s
|
||||||
assert_equal 000000, foo.created_at.usec
|
assert_equal 000000, foo.created_at.usec
|
||||||
|
|
|
@ -967,7 +967,7 @@ class RelationTest < ActiveRecord::TestCase
|
||||||
assert_equal 11, posts.count(:all)
|
assert_equal 11, posts.count(:all)
|
||||||
assert_equal 11, posts.count(:id)
|
assert_equal 11, posts.count(:id)
|
||||||
|
|
||||||
assert_equal 3, posts.where("comments_count > 1").count
|
assert_equal 3, posts.where("comments_count >": 1).count
|
||||||
assert_equal 6, posts.where(comments_count: 0).count
|
assert_equal 6, posts.where(comments_count: 0).count
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1087,7 +1087,7 @@ class RelationTest < ActiveRecord::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_count_complex_chained_relations
|
def test_count_complex_chained_relations
|
||||||
posts = Post.select("comments_count").where("id is not null").group("author_id").where("comments_count > 0")
|
posts = Post.select("comments_count").where("id is not null").group("author_id").where("comments_count >": 0)
|
||||||
|
|
||||||
expected = { 1 => 4, 2 => 1 }
|
expected = { 1 => 4, 2 => 1 }
|
||||||
assert_equal expected, posts.count
|
assert_equal expected, posts.count
|
||||||
|
@ -1109,7 +1109,7 @@ class RelationTest < ActiveRecord::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_empty_complex_chained_relations
|
def test_empty_complex_chained_relations
|
||||||
posts = Post.select("comments_count").where("id is not null").group("author_id").where("comments_count > 0")
|
posts = Post.select("comments_count").where("id is not null").group("author_id").where("comments_count >": 0)
|
||||||
|
|
||||||
assert_queries(1) { assert_equal false, posts.empty? }
|
assert_queries(1) { assert_equal false, posts.empty? }
|
||||||
assert_not_predicate posts, :loaded?
|
assert_not_predicate posts, :loaded?
|
||||||
|
@ -2153,6 +2153,25 @@ class RelationTest < ActiveRecord::TestCase
|
||||||
assert_not_same first_post, third_post
|
assert_not_same first_post, third_post
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_where_with_comparison_operator
|
||||||
|
posts = Post.order(:id)
|
||||||
|
|
||||||
|
assert_equal [10, 11], posts.where("id >": 9).pluck(:id)
|
||||||
|
assert_equal [9, 10, 11], posts.where("id >=": 9).pluck(:id)
|
||||||
|
assert_equal [1, 2], posts.where("id <": 3).pluck(:id)
|
||||||
|
assert_equal [1, 2, 3], posts.where("id <=": 3).pluck(:id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_where_with_table_name_resolution
|
||||||
|
posts = Post.joins(:comments).order(:id)
|
||||||
|
|
||||||
|
assert_equal [1, 1, 2], posts.where("id <": 3).pluck(:id)
|
||||||
|
|
||||||
|
assert_raise(ActiveRecord::StatementInvalid) do
|
||||||
|
posts.where("id < ?", 3).pluck(:id) # ambiguous column name: id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
test "#skip_query_cache!" do
|
test "#skip_query_cache!" do
|
||||||
Post.cache do
|
Post.cache do
|
||||||
assert_queries(1) do
|
assert_queries(1) do
|
||||||
|
|
|
@ -166,10 +166,10 @@ class DefaultScopingTest < ActiveRecord::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_unscope_string_where_clauses_involved
|
def test_unscope_string_where_clauses_involved
|
||||||
dev_relation = Developer.order("salary DESC").where("legacy_created_at > ?", 1.year.ago)
|
dev_relation = Developer.order("salary DESC").where("created_at >": 1.year.ago)
|
||||||
expected = dev_relation.collect(&:name)
|
expected = dev_relation.collect(&:name)
|
||||||
|
|
||||||
dev_ordered_relation = DeveloperOrderedBySalary.where(name: "Jamis").where("legacy_created_at > ?", 1.year.ago)
|
dev_ordered_relation = DeveloperOrderedBySalary.where(name: "Jamis").where("created_at >": 1.year.ago)
|
||||||
received = dev_ordered_relation.unscope(where: [:name]).collect(&:name)
|
received = dev_ordered_relation.unscope(where: [:name]).collect(&:name)
|
||||||
|
|
||||||
assert_equal expected.sort, received.sort
|
assert_equal expected.sort, received.sort
|
||||||
|
|
|
@ -88,10 +88,16 @@ if supports_datetime_with_precision?
|
||||||
t.time :start, precision: 0
|
t.time :start, precision: 0
|
||||||
t.time :finish, precision: 4
|
t.time :finish, precision: 4
|
||||||
end
|
end
|
||||||
|
|
||||||
time = ::Time.utc(2000, 1, 1, 12, 30, 0, 999999)
|
time = ::Time.utc(2000, 1, 1, 12, 30, 0, 999999)
|
||||||
Foo.create!(start: time, finish: time)
|
Foo.create!(start: time, finish: time)
|
||||||
assert foo = Foo.find_by(start: time)
|
|
||||||
assert_equal 1, Foo.where(finish: time).count
|
assert_nil Foo.find_by("start >= ?", time)
|
||||||
|
assert_equal 0, Foo.where("finish >= ?", time).count
|
||||||
|
|
||||||
|
assert foo = Foo.find_by("start >=": time)
|
||||||
|
assert_equal 1, Foo.where("finish >=": time).count
|
||||||
|
|
||||||
assert_equal time.to_s, foo.start.to_s
|
assert_equal time.to_s, foo.start.to_s
|
||||||
assert_equal time.to_s, foo.finish.to_s
|
assert_equal time.to_s, foo.finish.to_s
|
||||||
assert_equal 000000, foo.start.usec
|
assert_equal 000000, foo.start.usec
|
||||||
|
|
|
@ -156,6 +156,8 @@ class DeveloperFilteredOnJoins < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
class DeveloperOrderedBySalary < ActiveRecord::Base
|
class DeveloperOrderedBySalary < ActiveRecord::Base
|
||||||
|
include Developer::TimestampAliases
|
||||||
|
|
||||||
self.table_name = "developers"
|
self.table_name = "developers"
|
||||||
default_scope { order("salary DESC") }
|
default_scope { order("salary DESC") }
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue