Skip to content

Commit

Permalink
QueryMethods#in_order_of drop records not listed
Browse files Browse the repository at this point in the history
`in_order_of` now filters down to the values provided, to match the behavior of the `Enumerable` version.

*Kevin Newton*
  • Loading branch information
kddnewton committed Jan 6, 2022
1 parent 6fb54c0 commit e7c3219
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 19 deletions.
6 changes: 6 additions & 0 deletions activerecord/CHANGELOG.md
@@ -1,3 +1,9 @@
* Change `QueryMethods#in_order_of` to drop records not listed in values.

`in_order_of` now filters down to the values provided, to match the behavior of the `Enumerable` version.

*Kevin Newton*

* Allow named expression indexes to be revertible.

Previously, the following code would raise an error in a reversible migration executed while rolling back, due to the index name not being used in the index removal.
Expand Down
17 changes: 9 additions & 8 deletions activerecord/lib/active_record/relation/query_methods.rb
Expand Up @@ -432,22 +432,23 @@ def order!(*args) # :nodoc:
# adapter this will either use a CASE statement or a built-in function.
#
# User.in_order_of(:id, [1, 5, 3])
# # SELECT "users".* FROM "users" ORDER BY FIELD("users"."id", 1, 5, 3)
# # SELECT "users".* FROM "users"
# # ORDER BY FIELD("users"."id", 1, 5, 3)
# # WHERE "users"."id" IN (1, 5, 3)
#
def in_order_of(column, values)
klass.disallow_raw_sql!([column], permit: connection.column_name_with_order_matcher)
return spawn.none! if values.empty?

references = column_references([column])
self.references_values |= references unless references.empty?

if values.empty?
spawn.order!(column)
else
values = values.map { |value| type_caster.type_cast_for_database(column, value) }
values = values.map { |value| type_caster.type_cast_for_database(column, value) }
arel_column = column.is_a?(Symbol) ? order_column(column.to_s) : column

arel_column = column.is_a?(Symbol) ? order_column(column.to_s) : column
spawn.order!(connection.field_ordered_value(arel_column, values), column)
end
spawn
.order!(connection.field_ordered_value(arel_column, values))
.where!(arel_column.in(values))
end

# Replaces any existing order defined on the relation with the specified order.
Expand Down
16 changes: 5 additions & 11 deletions activerecord/test/cases/relation/field_ordered_values_test.rb
Expand Up @@ -9,21 +9,15 @@ class FieldOrderedValuesTest < ActiveRecord::TestCase

def test_in_order_of
order = [3, 4, 1]
posts = Post.in_order_of(:id, order).limit(3)
posts = Post.in_order_of(:id, order)

assert_equal(order, posts.map(&:id))
end

def test_unspecified_order
order = [3, 4, 1]
post_ids = Post.in_order_of(:id, order).map(&:id)
expected_order = order + (post_ids - order).sort
assert_equal(expected_order, post_ids)
end

def test_in_order_of_empty
posts = Post.in_order_of(:id, [])
assert_equal(posts.map(&:id).sort, posts.map(&:id))

assert_empty(posts)
end

def test_in_order_of_with_enums_values
Expand Down Expand Up @@ -52,14 +46,14 @@ def test_in_order_of_with_enums_keys

def test_in_order_of_expression
order = [3, 4, 1]
posts = Post.in_order_of(Arel.sql("id * 2"), order.map { |id| id * 2 }).limit(3)
posts = Post.in_order_of(Arel.sql("id * 2"), order.map { |id| id * 2 })

assert_equal(order, posts.map(&:id))
end

def test_in_order_of_after_regular_order
order = [3, 4, 1]
posts = Post.where(type: "Post").order(:type).in_order_of(:id, order).limit(3)
posts = Post.where(type: "Post").order(:type).in_order_of(:id, order)

assert_equal(order, posts.map(&:id))
end
Expand Down

0 comments on commit e7c3219

Please sign in to comment.